diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/cg1_purple.iml b/.idea/cg1_purple.iml
new file mode 100644
index 0000000..4c94235
--- /dev/null
+++ b/.idea/cg1_purple.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
new file mode 100644
index 0000000..855412d
--- /dev/null
+++ b/.idea/editor.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..9fc3e1c
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/fragmentShader.glsl b/src/fragmentShader.glsl
index 79e05d1..92c8570 100644
--- a/src/fragmentShader.glsl
+++ b/src/fragmentShader.glsl
@@ -5,7 +5,7 @@ in vec3 fragmentPosition;
in vec2 textureCoordinate;
flat in mat3 TBN;
-
+in vec3 skyboxCoord;
uniform float shininess;
@@ -18,41 +18,49 @@ uniform sampler2D night;
uniform sampler2D clouds;
uniform sampler2D ocean;
uniform sampler2D normalMap;
+uniform samplerCube skyboxSampler;
+uniform bool isSkybox;
float emissionStrength = 0.0;
void main() {
- vec4 color = vec4(texture(day, textureCoordinate).rgb, 1.0);
+ if (isSkybox) {
+ // for skybox-texture
+ gl_FragColor = texture(skyboxSampler, skyboxCoord);
+ } else {
+ // for regular-textures
+ vec4 color = vec4(texture(day, textureCoordinate).rgb, 1.0);
- float nightBrightness = texture(night, textureCoordinate).r;
- vec4 nightColor = vec4(nightBrightness, nightBrightness * 0.7, nightBrightness * 0.5, 1.0);
- float shininessMultiplier = texture(ocean, textureCoordinate).r;
+ float nightBrightness = texture(night, textureCoordinate).r;
+ vec4 nightColor = vec4(nightBrightness, nightBrightness * 0.7, nightBrightness * 0.5, 1.0);
+ float shininessMultiplier = texture(ocean, textureCoordinate).r;
- vec4 cloudColor = texture(clouds, textureCoordinate).rgba;
+ vec4 cloudColor = texture(clouds, textureCoordinate).rgba;
- vec3 norm = normalize(normal);
+ vec3 norm = normalize(normal);
- vec3 lightDir = normalize(lightPosition - fragmentPosition);
- vec3 eyeDir = (-normalize(fragmentPosition));
+ vec3 lightDir = normalize(lightPosition - fragmentPosition);
+ vec3 eyeDir = (-normalize(fragmentPosition));
- float diff = max(dot(norm, lightDir), 0.0);
+ float diff = max(dot(norm, lightDir), 0.0);
- vec3 halfway = (lightDir + eyeDir) / length(lightDir + eyeDir);
- float specular = pow(max(dot(halfway, norm), 0.0), shininess) * shininessMultiplier;
+ vec3 halfway = (lightDir + eyeDir) / length(lightDir + eyeDir);
+ float specular = pow(max(dot(halfway, norm), 0.0), shininess) * shininessMultiplier;
- gl_FragColor =
- // EMISSION
- color * emissionStrength +
+ gl_FragColor =
+ // EMISSION
+ color * emissionStrength +
- // // AMBIENT
- ambientLight * color +
+ // // AMBIENT
+ ambientLight * color +
- // DIFFUSION
- mix(nightColor * (vec4(1,1,1,1) - cloudColor) + (cloudColor * ambientLight), color + cloudColor, diff) +
+ // DIFFUSION
+ mix(nightColor * (vec4(1,1,1,1) - cloudColor) + (cloudColor * ambientLight), color + cloudColor, diff) +
- // SPECULAR
- specular * lightColor * color;
+ // SPECULAR
+ specular * lightColor * color;
+ }
}
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index f877312..d0a2130 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,4 @@
#include
-
#include
#include
@@ -9,6 +8,7 @@
#include "matrixMath.h"
#include "transformation.h"
#include "wavefrontobj.h"
+#include "sceneGraph.h"
#define STB_IMAGE_IMPLEMENTATION
#include "../lib/stb_image.h"
@@ -61,6 +61,13 @@ vec3 cameraPosition = {0.0f, 3.0f, 5.5f};
char* defaultModel = "../obj/monkey.obj";
char* model;
+// Define a global scene graph root node
+SceneNode* rootNode;
+
+// skybox date
+GLuint skyboxVAO, skyboxVBO;
+GLuint skyboxTexture;
+
// input handler for camera movement
void handleInputs(double deltaTime) {
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
@@ -92,6 +99,12 @@ void keyboardHandler(GLFWwindow* window, int key, int scancode, int action, int
}
}
+// Define the function to render a node (e.g., rendering an object)
+void renderNode(SceneNode* node) {
+ glUniformMatrix4fv(glGetUniformLocation(program, "modelView"), 1, GL_FALSE, (GLfloat*)&node->worldTransformation);
+ glDrawArrays(GL_TRIANGLES, 0, numFaces * 3);
+}
+
void loadTexture(char* textureFile, GLuint* texture) {
int width, height, nrChannels;
unsigned char* image = stbi_load(textureFile, &width, &height, &nrChannels, 0);
@@ -120,6 +133,115 @@ void loadTexture(char* textureFile, GLuint* texture) {
stbi_image_free(image);
}
+void loadCubemap(const char* faces[6], GLuint* textureID) {
+ glGenTextures(1, textureID);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, *textureID);
+
+ int width, height, nrChannels;
+ for (unsigned int i = 0; i < 6; i++) {
+ unsigned char* data = stbi_load(faces[i], &width, &height, &nrChannels, 0);
+ if (data) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
+ 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
+ stbi_image_free(data);
+ } else {
+ printf("Cubemap texture failed to load at path: %s\n", faces[i]);
+ stbi_image_free(data);
+ }
+ }
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+}
+
+void initSkybox() {
+ float skyboxVertices[] = {
+ // positions
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, -1.0f,
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+
+ -1.0f, -1.0f, 1.0f,
+ -1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f,
+ -1.0f, -1.0f, 1.0f,
+
+ -1.0f, 1.0f, -1.0f,
+ 1.0f, 1.0f, -1.0f,
+ 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f,
+ -1.0f, 1.0f, 1.0f,
+ -1.0f, 1.0f, -1.0f,
+
+ -1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, -1.0f,
+ 1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, 1.0f
+ };
+
+ glGenVertexArrays(1, &skyboxVAO);
+ glGenBuffers(1, &skyboxVBO);
+ glBindVertexArray(skyboxVAO);
+ glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
+ glBindVertexArray(0);
+
+ const char* faces[6] = {
+ "../texture/skybox/right.jpg",
+ "../texture/skybox/left.jpg",
+ "../texture/skybox/top.jpg",
+ "../texture/skybox/bottom.jpg",
+ "../texture/skybox/front.jpg",
+ "../texture/skybox/back.jpg"
+ };
+ loadCubemap(faces, &skyboxTexture);
+}
+
+void renderSkybox(mat4* viewMatrix, mat4* projectionMatrix) {
+ glDepthFunc(GL_LEQUAL);
+ glUseProgram(program);
+
+ mat4 view = *viewMatrix;
+ view.m30 = 0.0f;
+ view.m31 = 0.0f;
+ view.m32 = 0.0f;
+ glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, GL_FALSE, (GLfloat*)&view);
+ glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, (GLfloat*)projectionMatrix);
+
+ glBindVertexArray(skyboxVAO);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture);
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+ glBindVertexArray(0);
+
+ glDepthFunc(GL_LESS);
+}
+
void init(void) {
// create and compile vertex shader
const GLchar *vertexTextConst = vertexShader_glsl;
@@ -262,6 +384,17 @@ void init(void) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
+ // Create the root scene node
+ rootNode = createSceneNode();
+
+ // Create a child node (e.g., for the model)
+ SceneNode* modelNode = createSceneNode();
+ modelNode->render = renderNode;
+ addChild(rootNode, modelNode);
+
+ // Set transformations for the modelNode (example)
+ rotateY(&modelNode->transformation, &modelNode->transformation, pi / 4);
+
// ENABLE BACKFACE CULLING
glFrontFace(GL_CCW);
@@ -271,6 +404,9 @@ void init(void) {
glEnable(GL_DEPTH_TEST);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
+
+ // initialize skybox
+ initSkybox();
}
void updateStats() {
@@ -297,9 +433,15 @@ void draw(void) {
handleInputs(deltaTime);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glUseProgram(program);
+ glUseProgram(program);
glBindVertexArray(vao);
+ // Update and render the scene graph
+ mat4 identityMatrix;
+ identity(&identityMatrix);
+ updateSceneNode(rootNode, &identityMatrix);
+ renderSceneNode(rootNode);
+
// step for rotations
// counts up to 1.0 and then resets back to 0.0 forever
step += deltaTime / 15;
@@ -408,6 +550,9 @@ void draw(void) {
// draw!!1
glDrawArrays(GL_TRIANGLES, 0, numFaces * 3);
+
+ // draw skybox
+ renderSkybox(&viewingTransformation, &projectionTransformation);
}
// change viewport size and adjust aspect ratio when changing window size
@@ -457,11 +602,10 @@ int main(int argc, char **argv) {
// exit when window should close or exit is requested (ESC)
while (!glfwWindowShouldClose(window) && !exitRequested) {
draw();
-
glfwSwapBuffers(window);
glfwPollEvents();
}
-
+ freeSceneNode(rootNode);
glfwTerminate();
return 0;
diff --git a/src/sceneGraph.c b/src/sceneGraph.c
new file mode 100644
index 0000000..804cf5f
--- /dev/null
+++ b/src/sceneGraph.c
@@ -0,0 +1,44 @@
+// sceneGraph.c
+
+#include "sceneGraph.h"
+#include
+
+SceneNode* createSceneNode() {
+ SceneNode* node = (SceneNode*)malloc(sizeof(SceneNode));
+ identity(&node->transformation);
+ identity(&node->worldTransformation);
+ node->render = NULL;
+ node->children = NULL;
+ node->numChildren = 0;
+ return node;
+}
+
+void addChild(SceneNode* parent, SceneNode* child) {
+ parent->children = (SceneNode**)realloc(parent->children, sizeof(SceneNode*) * (parent->numChildren + 1));
+ parent->children[parent->numChildren] = child;
+ parent->numChildren++;
+}
+
+void updateSceneNode(SceneNode* node, mat4* parentTransformation) {
+ multiply(&node->worldTransformation, parentTransformation, &node->transformation);
+ for (int i = 0; i < node->numChildren; i++) {
+ updateSceneNode(node->children[i], &node->worldTransformation);
+ }
+}
+
+void renderSceneNode(SceneNode* node) {
+ if (node->render) {
+ node->render(node);
+ }
+ for (int i = 0; i < node->numChildren; i++) {
+ renderSceneNode(node->children[i]);
+ }
+}
+
+void freeSceneNode(SceneNode* node) {
+ for (int i = 0; i < node->numChildren; i++) {
+ freeSceneNode(node->children[i]);
+ }
+ free(node->children);
+ free(node);
+}
\ No newline at end of file
diff --git a/src/sceneGraph.h b/src/sceneGraph.h
new file mode 100644
index 0000000..0fe5d57
--- /dev/null
+++ b/src/sceneGraph.h
@@ -0,0 +1,23 @@
+// sceneGraph.h
+
+#ifndef SCENE_GRAPH_H
+#define SCENE_GRAPH_H
+
+#include
+#include "matrixMath.h"
+
+typedef struct SceneNode {
+ mat4 transformation; // Local transformation matrix
+ mat4 worldTransformation; // World transformation matrix
+ void (*render)(struct SceneNode*); // Function pointer to render this node
+ struct SceneNode** children; // Array of pointers to child nodes
+ int numChildren; // Number of child nodes
+} SceneNode;
+
+SceneNode* createSceneNode();
+void addChild(SceneNode* parent, SceneNode* child);
+void updateSceneNode(SceneNode* node, mat4* parentTransformation);
+void renderSceneNode(SceneNode* node);
+void freeSceneNode(SceneNode* node);
+
+#endif
\ No newline at end of file
diff --git a/src/vertexShader.glsl b/src/vertexShader.glsl
index 551573f..d94a0ff 100644
--- a/src/vertexShader.glsl
+++ b/src/vertexShader.glsl
@@ -7,30 +7,45 @@ layout (location = 3) in vec3 aTangent;
uniform mat4 modelView;
uniform mat3 normalModelView;
uniform mat4 projection;
+uniform bool isSkybox;
out vec3 normal;
out vec3 fragmentPosition;
out vec2 textureCoordinate;
flat out mat3 TBN;
+out vec3 skyboxCoord;
+
void main() {
- textureCoordinate = aTextureCoordinate;
+ if (isSkybox) {
+ // for skybox
+ skyboxCoord = aPosition;
- vec3 tangent = normalize(normalModelView * aTangent);
- normal = normalize(normalModelView * aNormal);
+ vec4 modelViewPos = modelView * vec4(aPosition, 1.0);
- vec3 bitangent = normalize(cross(normal, tangent));
+ gl_position = projection * vec4(aPosition, 1.0);
- TBN = transpose(mat3(
- tangent,
- bitangent,
- normal
- ));
+ fragmentPosition = vec3(modelViewPos);
+ } else {
+ // for regular objects
+ textureCoordinate = aTextureCoordinate;
+
+ vec3 tangent = normalize(normalModelView * aTangent);
+ normal = normalize(normalModelView * aNormal);
+
+ vec3 bitangent = normalize(cross(normal, tangent));
+
+ TBN = transpose(mat3(
+ tangent,
+ bitangent,
+ normal
+ ));
- vec4 modelViewPos = modelView * vec4(aPosition, 1.0);
+ vec4 modelViewPos = modelView * vec4(aPosition, 1.0);
- gl_Position = projection * modelViewPos;
+ gl_Position = projection * modelViewPos;
- fragmentPosition = vec3(modelViewPos);
+ fragmentPosition = vec3(modelViewPos);
+ }
}
\ No newline at end of file
diff --git a/texture/Cubemaps/Test_map.png b/texture/Cubemaps/Test_map.png
new file mode 100644
index 0000000..0d64445
Binary files /dev/null and b/texture/Cubemaps/Test_map.png differ