diff --git a/shaders/EDAF80/phong.frag b/shaders/EDAF80/phong.frag new file mode 100644 index 0000000..3ee8eee --- /dev/null +++ b/shaders/EDAF80/phong.frag @@ -0,0 +1,68 @@ +#version 410 core + +// Inputs from vertex shader +in vec3 FragPos; // Position in world space +in vec3 Normal; // Normal in world space +in vec3 ViewDir; // View direction +in vec3 textCoords; //Texture +in vec3 Tangent; //Tangent +in vec3 Bitangent; //Bitangent +// Uniforms +uniform vec3 light_position; +uniform vec3 diffuse_colour; +uniform vec3 specular_colour; +uniform vec3 ambient_colour; +uniform float shininess_value; +uniform bool use_normal_mapping; + +uniform sampler2D demo_diffuse_texture; +uniform sampler2D demo_specular_texture; +uniform sampler2D demo_normal_texture; +// Output color +out vec4 FragColor; + +void main() +{ + vec3 ambient = ambient_colour; + + if(use_normal_mapping){ + vec3 T = normalize(Tangent); + vec3 B = normalize(Bitangent); + vec3 N = normalize(Normal); + mat3 TBN = mat3(T, B, N); + + vec3 normalMap = texture(demo_normal_texture, textCoords.xy).rgb; + normalMap = normalize(normalMap * 2.0 - 1.0); + vec3 normal = normalize(TBN * normalMap); + + vec3 light_dir = normalize(light_position - FragPos); // Light direction + float diff = max(dot(normal, light_dir), 0.0); // Angle between light and normal + vec3 diffuse = diff * texture(demo_diffuse_texture, textCoords.xy).rgb; + + // Specular lighting (Phong reflectance) + vec3 reflect_dir = reflect(-light_dir, normal); // Reflect the light direction around the normal + float spec = pow(max(dot(ViewDir, reflect_dir), 0.0), shininess_value); // Specular intensity + vec3 specular = spec * texture(demo_specular_texture, textCoords.xy).rgb; + // Combine all three components (ambient + diffuse + specular) + vec3 result = (ambient + diffuse + specular); + FragColor = vec4(result, 1.0); + } else + { + vec3 normal = normalize(Normal); + + vec3 light_dir = normalize(light_position - FragPos); // Light direction + float diff = max(dot(normal, light_dir), 0.0); // Angle between light and normal + vec3 diffuse = diff * texture(demo_diffuse_texture, textCoords.xy).rgb; + + // Specular lighting (Phong reflectance) + vec3 reflect_dir = reflect(-light_dir, normal); // Reflect the light direction around the normal + float spec = pow(max(dot(ViewDir, reflect_dir), 0.0), shininess_value); // Specular intensity + vec3 specular = spec * texture(demo_specular_texture, textCoords.xy).rgb; + + // Combine all three components (ambient + diffuse + specular) + vec3 result = (ambient + diffuse + specular); + + // Output the final color (with alpha value of 1.0) + FragColor = vec4(result, 1.0); + } +} diff --git a/shaders/EDAF80/phong.vert b/shaders/EDAF80/phong.vert new file mode 100644 index 0000000..4dcdd76 --- /dev/null +++ b/shaders/EDAF80/phong.vert @@ -0,0 +1,41 @@ +#version 410 core + +// Vertex attributes +layout (location = 0) in vec3 position; +layout (location = 1) in vec3 normal; +layout (location = 2) in vec3 textures; +layout (location = 3) in vec3 tangent; +layout (location = 4) in vec3 bitangent; + +// Uniforms +uniform mat4 normal_model_to_world; +uniform mat4 vertex_model_to_world; +uniform mat4 vertex_world_to_clip; +uniform vec3 camera_position; // Camera position (for specular reflections) +// Outputs to fragment shader +out vec3 FragPos; // Position in world space +out vec3 Normal; // Normal in world space +out vec3 ViewDir; // View direction (camera position - fragment position) +out vec3 textCoords; +out vec3 Tangent; +out vec3 Bitangent; +void main() +{ + // Transform the vertex position to world space + FragPos = vec3(vertex_model_to_world * vec4(position, 1.0)); + + // Pass the normal in world space + Normal = (normal_model_to_world * vec4(normal, 0.0)).xyz; + + Tangent = (normal_model_to_world * vec4(tangent, 0.0)).xyz; + + Bitangent = (normal_model_to_world * vec4(bitangent, 0.0)).xyz; + + // Calculate view direction (camera position - fragment position) + ViewDir = normalize(camera_position - FragPos); + + textCoords = textures; + + // Transform the position to clip space for rasterization + gl_Position = vertex_world_to_clip * vec4(FragPos, 1.0); +} diff --git a/shaders/EDAF80/skybox.frag b/shaders/EDAF80/skybox.frag index ec10f27..def14e3 100644 --- a/shaders/EDAF80/skybox.frag +++ b/shaders/EDAF80/skybox.frag @@ -8,5 +8,4 @@ uniform samplerCube skybox; void main() { FragColor = texture(skybox, textCoords); - // FragColor = vec4(1.0, 0.0, 0.0, 1.0); } \ No newline at end of file diff --git a/shaders/EDAF80/skybox.vert b/shaders/EDAF80/skybox.vert index 6c29069..5c53ddf 100644 --- a/shaders/EDAF80/skybox.vert +++ b/shaders/EDAF80/skybox.vert @@ -9,7 +9,8 @@ uniform mat4 vertex_world_to_clip; void main() { + textCoords = vec3(aPos.x, aPos.y, -aPos.z); //Test vec4 pos = vertex_world_to_clip * vertex_model_to_world * vec4(aPos, 1.0f); gl_Position = vec4(pos.x, pos.y, pos.w, pos.w); - textCoords = vec3(aPos.x, aPos.y, -aPos.z); //Test + } \ No newline at end of file diff --git a/src/EDAF80/assignment3.cpp b/src/EDAF80/assignment3.cpp index cb003cf..e2375f3 100644 --- a/src/EDAF80/assignment3.cpp +++ b/src/EDAF80/assignment3.cpp @@ -92,6 +92,15 @@ void edaf80::Assignment3::run() skybox_shader); if (skybox_shader == 0u) LogError("Failed to load skybox shader"); + + GLuint phong_shader = 0u; + program_manager.CreateAndRegisterProgram("Phong Shading", + {{ShaderType::vertex, "EDAF80/phong.vert"}, + {ShaderType::fragment, "EDAF80/phong.frag"}}, + phong_shader); + if (phong_shader == 0u) + LogError("Failed to load phong shader"); + auto light_position = glm::vec3(-2.0f, 4.0f, 2.0f); auto const set_uniforms = [&light_position](GLuint program) @@ -111,57 +120,12 @@ void edaf80::Assignment3::run() // // Set up the two spheres used. // - auto skybox_shape = parametric_shapes::createSphere(20.0f, 100u, 100u); + auto skybox_shape = parametric_shapes::createSphere(200.0f, 1000u, 1000u); //Increased value to give the illusion of an infinite skybox if (skybox_shape.vao == 0u) { LogError("Failed to retrieve the mesh for the skybox"); return; } - /*float skyboxVertices[] = - { - -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}; - unsigned int skyboxIndices[] = - { - // Right - 1, 2, 6, - 6, 5, 1, - // Left - 0, 4, 7, - 7, 3, 0, - // Top - 4, 5, 6, - 6, 7, 4, - // Bottom - 0, 3, 2, - 2, 1, 0, - // Back - 0, 1, 5, - 5, 4, 0, - // Front - 3, 7, 6, - 6, 2, 3}; - - unsigned int skyboxVAO, skyboxVBO, skyboxEBO; - glGenVertexArrays(1, &skyboxVAO); - glGenBuffers(1, &skyboxVBO); - glGenBuffers(1, &skyboxEBO); - glBindVertexArray(skyboxVAO); - glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, skyboxEBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxIndices), &skyboxIndices, GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);*/ GLuint cubeMap = bonobo::loadTextureCubeMap("/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/cubemaps/LarnacaCastle/posx.jpg", "/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/cubemaps/LarnacaCastle/negx.jpg", "/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/cubemaps/LarnacaCastle/posy.jpg", "/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/cubemaps/LarnacaCastle/negy.jpg", "/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/cubemaps/LarnacaCastle/posz.jpg", "/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/cubemaps/LarnacaCastle/negz.jpg", @@ -190,11 +154,21 @@ void edaf80::Assignment3::run() demo_material.specular = glm::vec3(1.0f, 1.0f, 1.0f); demo_material.shininess = 10.0f; + GLuint demo_diffuse_texture = bonobo::loadTexture2D("/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/textures/leather_red_02_coll1_2k.jpg", true); + GLuint demo_specular_texture = bonobo::loadTexture2D("/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/textures/leather_red_02_rough_2k.jpg", true); + GLuint demo_normal_texture = bonobo::loadTexture2D("/home/manni/LTH/Year3/Datorgrafik/AAA_Programing/CG_Labs/res/textures/leather_red_02_nor_2k.jpg", true); + + Log("demoTexture value: %d\n", demo_diffuse_texture); Node demo_sphere; demo_sphere.set_geometry(demo_shape); demo_sphere.set_material_constants(demo_material); - demo_sphere.set_program(&fallback_shader, phong_set_uniforms); + demo_sphere.set_program(&phong_shader, phong_set_uniforms); + demo_sphere.add_texture("demo_diffuse_texture", demo_diffuse_texture, GL_TEXTURE_2D); + demo_sphere.add_texture("demo_specular_texture", demo_specular_texture, GL_TEXTURE_2D); + demo_sphere.add_texture("demo_normal_texture", demo_normal_texture, GL_TEXTURE_2D); + + // Here we should implement the smaller sphere to change its color, phong shading glClearDepthf(1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glEnable(GL_DEPTH_TEST); @@ -263,9 +237,11 @@ void edaf80::Assignment3::run() glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); bonobo::changePolygonMode(polygon_mode); + glDepthFunc(GL_LEQUAL); skybox.render(mCamera.GetWorldToClipMatrix()); - glDepthFunc(GL_LESS); + glDepthFunc(GL_LESS); + demo_sphere.render(mCamera.GetWorldToClipMatrix()); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); diff --git a/src/EDAF80/parametric_shapes.cpp b/src/EDAF80/parametric_shapes.cpp index a2b0711..3a19631 100644 --- a/src/EDAF80/parametric_shapes.cpp +++ b/src/EDAF80/parametric_shapes.cpp @@ -11,23 +11,20 @@ #include - bonobo::mesh_data parametric_shapes::createQuad(float const width, float const height, - unsigned int const horizontal_split_count, - unsigned int const vertical_split_count) + unsigned int const horizontal_split_count, + unsigned int const vertical_split_count) { auto const vertices = std::array{ - glm::vec3(0.0f, 0.0f, 0.0f), - glm::vec3(width, 0.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(width, 0.0f, 0.0f), glm::vec3(width, height, 0.0f), - glm::vec3(0.0f, height, 0.0f) - }; + glm::vec3(0.0f, height, 0.0f)}; auto const index_sets = std::array{ glm::uvec3(0u, 1u, 2u), - glm::uvec3(0u, 2u, 3u) - }; + glm::uvec3(0u, 2u, 3u)}; bonobo::mesh_data data; @@ -53,8 +50,6 @@ parametric_shapes::createQuad(float const width, float const height, // pass a pointer to `data.vao`. glGenVertexArrays(1, &data.vao); - - // To be able to store information, the Vertex Array has to be bound // first. glBindVertexArray(data.vao); @@ -74,7 +69,7 @@ parametric_shapes::createQuad(float const width, float const height, // and therefore bind the buffer to the corresponding target. glBindBuffer(GL_ARRAY_BUFFER, data.bo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW); // The glBufferData copies the previously defined vertex data into the buffer's memory + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW); // The glBufferData copies the previously defined vertex data into the buffer's memory // Vertices have been just stored into a buffer, but we still need to // tell Vertex Array where to find them, and how to interpret the data // within that buffer. @@ -95,11 +90,11 @@ parametric_shapes::createQuad(float const width, float const height, // GL_ARRAY_BUFFER as its source for the data. How to interpret it is // specified below: glVertexAttribPointer(static_cast(bonobo::shader_bindings::vertices), - 3, - GL_FLOAT, - GL_FALSE, - 3 * sizeof(float), - reinterpret_cast(0x0)); + 3, + GL_FLOAT, + GL_FALSE, + 3 * sizeof(float), + reinterpret_cast(0x0)); // Now, let's allocate a second one for the indices. // @@ -111,7 +106,7 @@ parametric_shapes::createQuad(float const width, float const height, glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index_sets), index_sets.data(), GL_STATIC_DRAW); - data.indices_nb = index_sets.size() * 3; + data.indices_nb = index_sets.size() * 3; // All the data has been recorded, we can unbind them. glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -121,153 +116,149 @@ parametric_shapes::createQuad(float const width, float const height, } bonobo::mesh_data parametric_shapes::createSphere(float const radius, - unsigned int const longitude_split_count, - unsigned int const latitude_split_count) + unsigned int const longitude_split_count, + unsigned int const latitude_split_count) { - bonobo::mesh_data data; - - if (longitude_split_count == 0u || latitude_split_count == 0u) - { - LogError("parametric_shapes::createSphere() requires non-zero splits."); - return data; - } - - unsigned int vertex_count = (longitude_split_count + 1) * (latitude_split_count + 1); - - // Vectors for storing vertices, normals, tangents, binormals, uvs, and indices - std::vector vertices(vertex_count); - std::vector normals(vertex_count); - std::vector tangents(vertex_count); // Tangent vectors (∂p/∂θ) - std::vector binormals(vertex_count); // Binormal vectors (∂p/∂φ) - std::vector textcoords(vertex_count); - std::vector index_sets; - // Create vertices, normals, tangents, and binormals - for (unsigned int lat = 0; lat <= latitude_split_count; ++lat) - { - float phi = glm::pi() * static_cast(lat) / static_cast(latitude_split_count); // Latitude (ϕ): [0, π] - float sin_phi = glm::sin(phi); - float cos_phi = glm::cos(phi); - - for (unsigned int lon = 0; lon <= longitude_split_count; ++lon) - { - float theta = 2.0f * glm::pi() * static_cast(lon) / static_cast(longitude_split_count); // Longitude (θ): [0, 2π] - float sin_theta = glm::sin(theta); - float cos_theta = glm::cos(theta); - - // Vertex position (p(θ, ϕ)) - glm::vec3 vertex = glm::vec3( - radius * sin_theta * sin_phi, // X: longitude (left/right) - radius * cos_phi, // Y: latitude (up/down) - radius * cos_theta * sin_phi // Z: longitude (forward/back) - ); - - // Tangent - glm::vec3 tangent = glm::vec3( - radius * cos_theta, // ∂p/∂θ X //We need to simplify - 0.0f, // ∂p/∂θ Y - -radius * sin_theta // ∂p/∂θ Z - ); - - // Binormal - glm::vec3 binormal = glm::vec3( - radius * sin_theta * cos_phi, // ∂p/∂ϕ X - radius * sin_phi, // ∂p/∂ϕ Y - radius * cos_theta * cos_phi // ∂p/∂ϕ Z - ); - //glm::vec3 normal = glm::normalize(vertex); - glm::vec3 normal = glm::vec3( - glm::cross(tangent, binormal) + + + unsigned int vertex_count = (longitude_split_count + 1) * (latitude_split_count + 1); + + // Vectors for storing vertices, normals, tangents, binormals, uvs, and indices + std::vector vertices(vertex_count); + std::vector normals(vertex_count); + std::vector tangents(vertex_count); // Tangent vectors (∂p/∂θ) + std::vector binormals(vertex_count); // Binormal vectors (∂p/∂φ) + std::vector textcoords(vertex_count); + std::vector index_sets; + // Create vertices, normals, tangents, and binormals + for (unsigned int lat = 0; lat <= latitude_split_count; ++lat) + { + float phi = glm::pi() * static_cast(lat) / static_cast(latitude_split_count); // Latitude (ϕ): [0, π] + float sin_phi = glm::sin(phi); + float cos_phi = glm::cos(phi); + + for (unsigned int lon = 0; lon <= longitude_split_count; ++lon) + { + float theta = 2.0f * glm::pi() * static_cast(lon) / static_cast(longitude_split_count); // Longitude (θ): [0, 2π] + float sin_theta = glm::sin(theta); + float cos_theta = glm::cos(theta); + + // Vertex position (p(θ, ϕ)) + glm::vec3 vertex = glm::vec3( + radius * sin_theta * sin_phi, // X: longitude (left/right) + radius * cos_phi, // Y: latitude (up/down) + radius * cos_theta * sin_phi // Z: longitude (forward/back) + ); + + // Tangent + glm::vec3 tangent = glm::vec3( + radius * cos_theta, // ∂p/∂θ X //We need to simplify + 0.0f, // ∂p/∂θ Y + -radius * sin_theta // ∂p/∂θ Z ); - // Texture coordinates (u, v) - glm::vec2 texcoord = glm::vec2(static_cast(lon) / static_cast(longitude_split_count), - static_cast(lat) / static_cast(latitude_split_count)); - - // Store vertex, normal, tangent, binormal, and uv - unsigned int index = lat * (longitude_split_count + 1) + lon; - vertices[index] = vertex; - normals[index] = normal; - tangents[index] = tangent; - binormals[index] = binormal; - textcoords[index] = texcoord; - } - } + // Binormal + glm::vec3 binormal = glm::vec3( + radius * sin_theta * cos_phi, // ∂p/∂ϕ X + radius * sin_phi, // ∂p/∂ϕ Y + radius * cos_theta * cos_phi // ∂p/∂ϕ Z + ); + // glm::vec3 normal = glm::normalize(vertex); + glm::vec3 normal = glm::vec3( + glm::cross(tangent, binormal)); + + // Texture coordinates (u, v) + glm::vec3 texcoord = glm::vec3(static_cast(lon) / static_cast(longitude_split_count), + static_cast(lat) / static_cast(latitude_split_count), + 0.0f); + + // Store vertex, normal, tangent, binormal, and uv + unsigned int index = lat * (longitude_split_count + 1) + lon; + vertices[index] = vertex; + normals[index] = normal; + tangents[index] = tangent; + binormals[index] = binormal; + textcoords[index] = texcoord; + } + } index_sets = std::vector(2u * longitude_split_count * latitude_split_count); size_t index = 0u; for (unsigned int lat = 0u; lat < latitude_split_count; ++lat) { - for (unsigned int lon = 0u; lon < longitude_split_count; ++lon) - { - unsigned int first = lat * (longitude_split_count + 1) + lon; - unsigned int second = first + longitude_split_count + 1; - - // First triangle of the quad (counter-clockwise winding) - index_sets[index] = glm::uvec3(first, second, first + 1); - ++index; - - // Second triangle of the quad (counter-clockwise winding) - index_sets[index] = glm::uvec3(second, second + 1, first + 1); - ++index; - } -} + for (unsigned int lon = 0u; lon < longitude_split_count; ++lon) + { + unsigned int first = lat * (longitude_split_count + 1) + lon; + unsigned int second = first + longitude_split_count + 1; + // First triangle of the quad (counter-clockwise winding) + index_sets[index] = glm::uvec3(first, second, first + 1); + ++index; - // Generate and bind the VAO - glGenVertexArrays(1, &data.vao); - glBindVertexArray(data.vao); - - // Generate and bind the vertex buffer (positions) - glGenBuffers(1, &data.bo); - glBindBuffer(GL_ARRAY_BUFFER, data.bo); - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW); - - // Enable the vertex position attribute and set the data layout - glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::vertices)); - glVertexAttribPointer(static_cast(bonobo::shader_bindings::vertices), 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - // Generate and bind the normal buffer - GLuint normal_bo; - glGenBuffers(1, &normal_bo); - glBindBuffer(GL_ARRAY_BUFFER, normal_bo); - glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW); - - // Enable the normal attribute and set the data layout - glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::normals)); - glVertexAttribPointer(static_cast(bonobo::shader_bindings::normals), 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - // Generate and bind the UV buffer - GLuint textcoord_bo; - glGenBuffers(1, &textcoord_bo); - glBindBuffer(GL_ARRAY_BUFFER, textcoord_bo); - glBufferData(GL_ARRAY_BUFFER, textcoords.size() * sizeof(glm::vec2), textcoords.data(), GL_STATIC_DRAW); - - // Enable the UV attribute and set the data layout - glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::texcoords)); - glVertexAttribPointer(static_cast(bonobo::shader_bindings::texcoords), 2, GL_FLOAT, GL_FALSE, 0, nullptr); - - // Generate and bind the index buffer - glGenBuffers(1, &data.ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_sets.size() * sizeof(glm::uvec3), index_sets.data(), GL_STATIC_DRAW); - // Set the number of indices - data.indices_nb = static_cast(index_sets.size() * 3); // Each uvec3 contains 3 indices - - // Unbind the VAO and buffers - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - return data; -} + // Second triangle of the quad (counter-clockwise winding) + index_sets[index] = glm::uvec3(second, second + 1, first + 1); + ++index; + } + } + bonobo::mesh_data data; + glGenVertexArrays(1, &data.vao); + assert(data.vao != 0u); + glBindVertexArray(data.vao); + auto const vertices_offset = 0u; + auto const vertices_size = static_cast(vertices.size() * sizeof(glm::vec3)); + auto const normals_offset = vertices_size; + auto const normals_size = static_cast(normals.size() * sizeof(glm::vec3)); + auto const texcoords_offset = normals_offset + normals_size; + auto const texcoords_size = static_cast(textcoords.size() * sizeof(glm::vec3)); + auto const tangents_offset = texcoords_offset + texcoords_size; + auto const tangents_size = static_cast(tangents.size() * sizeof(glm::vec3)); + auto const binormals_offset = tangents_offset + tangents_size; + auto const binormals_size = static_cast(binormals.size() * sizeof(glm::vec3)); + auto const bo_size = static_cast(vertices_size + normals_size + texcoords_size + tangents_size + binormals_size); + + glGenBuffers(1, &data.bo); + assert(data.bo != 0u); + glBindBuffer(GL_ARRAY_BUFFER, data.bo); + glBufferData(GL_ARRAY_BUFFER, bo_size, nullptr, GL_STATIC_DRAW); + + glBufferSubData(GL_ARRAY_BUFFER, vertices_offset, vertices_size, static_cast(vertices.data())); + glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::vertices)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::vertices), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0x0)); + + glBufferSubData(GL_ARRAY_BUFFER, normals_offset, normals_size, static_cast(normals.data())); + glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::normals)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::normals), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(normals_offset)); + + glBufferSubData(GL_ARRAY_BUFFER, texcoords_offset, texcoords_size, static_cast(textcoords.data())); + glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::texcoords)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::texcoords), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(texcoords_offset)); + + glBufferSubData(GL_ARRAY_BUFFER, tangents_offset, tangents_size, static_cast(tangents.data())); + glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::tangents)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::tangents), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(tangents_offset)); + glBufferSubData(GL_ARRAY_BUFFER, binormals_offset, binormals_size, static_cast(binormals.data())); + glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::binormals)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::binormals), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(binormals_offset)); + + glBindBuffer(GL_ARRAY_BUFFER, 0u); + + data.indices_nb = static_cast(index_sets.size() * 3u); + glGenBuffers(1, &data.ibo); + assert(data.ibo != 0u); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast(index_sets.size() * sizeof(glm::uvec3)), reinterpret_cast(index_sets.data()), GL_STATIC_DRAW); + glBindVertexArray(0u); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0u); + return data; +} bonobo::mesh_data parametric_shapes::createTorus(float const major_radius, - float const minor_radius, - unsigned int const major_split_count, - unsigned int const minor_split_count) + float const minor_radius, + unsigned int const major_split_count, + unsigned int const minor_split_count) { //! \todo (Optional) Implement this function return bonobo::mesh_data(); @@ -275,9 +266,9 @@ parametric_shapes::createTorus(float const major_radius, bonobo::mesh_data parametric_shapes::createCircleRing(float const radius, - float const spread_length, - unsigned int const circle_split_count, - unsigned int const spread_split_count) + float const spread_length, + unsigned int const circle_split_count, + unsigned int const spread_split_count) { auto const circle_slice_edges_count = circle_split_count + 1u; auto const spread_slice_edges_count = spread_split_count + 1u; @@ -285,10 +276,10 @@ parametric_shapes::createCircleRing(float const radius, auto const spread_slice_vertices_count = spread_slice_edges_count + 1u; auto const vertices_nb = circle_slice_vertices_count * spread_slice_vertices_count; - auto vertices = std::vector(vertices_nb); - auto normals = std::vector(vertices_nb); + auto vertices = std::vector(vertices_nb); + auto normals = std::vector(vertices_nb); auto texcoords = std::vector(vertices_nb); - auto tangents = std::vector(vertices_nb); + auto tangents = std::vector(vertices_nb); auto binormals = std::vector(vertices_nb); float const spread_start = radius - 0.5f * spread_length; @@ -298,21 +289,23 @@ parametric_shapes::createCircleRing(float const radius, // generate vertices iteratively size_t index = 0u; float theta = 0.0f; - for (unsigned int i = 0u; i < circle_slice_vertices_count; ++i) { + for (unsigned int i = 0u; i < circle_slice_vertices_count; ++i) + { float const cos_theta = std::cos(theta); float const sin_theta = std::sin(theta); float distance_to_centre = spread_start; - for (unsigned int j = 0u; j < spread_slice_vertices_count; ++j) { + for (unsigned int j = 0u; j < spread_slice_vertices_count; ++j) + { // vertex vertices[index] = glm::vec3(distance_to_centre * cos_theta, - distance_to_centre * sin_theta, - 0.0f); + distance_to_centre * sin_theta, + 0.0f); // texture coordinates texcoords[index] = glm::vec3(static_cast(j) / (static_cast(spread_slice_vertices_count)), - static_cast(i) / (static_cast(circle_slice_vertices_count)), - 0.0f); + static_cast(i) / (static_cast(circle_slice_vertices_count)), + 0.0f); // tangent auto const t = glm::vec3(cos_theta, sin_theta, 0.0f); @@ -343,17 +336,17 @@ parametric_shapes::createCircleRing(float const radius, for (unsigned int j = 0u; j < spread_slice_edges_count; ++j) { index_sets[index] = glm::uvec3(spread_slice_vertices_count * (i + 0u) + (j + 0u), - spread_slice_vertices_count * (i + 0u) + (j + 1u), - spread_slice_vertices_count * (i + 1u) + (j + 1u)); + spread_slice_vertices_count * (i + 0u) + (j + 1u), + spread_slice_vertices_count * (i + 1u) + (j + 1u)); ++index; index_sets[index] = glm::uvec3(spread_slice_vertices_count * (i + 0u) + (j + 0u), - spread_slice_vertices_count * (i + 1u) + (j + 1u), - spread_slice_vertices_count * (i + 1u) + (j + 0u)); + spread_slice_vertices_count * (i + 1u) + (j + 1u), + spread_slice_vertices_count * (i + 1u) + (j + 0u)); ++index; } } - + bonobo::mesh_data data; glGenVertexArrays(1, &data.vao); assert(data.vao != 0u); @@ -369,36 +362,31 @@ parametric_shapes::createCircleRing(float const radius, auto const tangents_size = static_cast(tangents.size() * sizeof(glm::vec3)); auto const binormals_offset = tangents_offset + tangents_size; auto const binormals_size = static_cast(binormals.size() * sizeof(glm::vec3)); - auto const bo_size = static_cast(vertices_size - +normals_size - +texcoords_size - +tangents_size - +binormals_size - ); + auto const bo_size = static_cast(vertices_size + normals_size + texcoords_size + tangents_size + binormals_size); glGenBuffers(1, &data.bo); assert(data.bo != 0u); glBindBuffer(GL_ARRAY_BUFFER, data.bo); glBufferData(GL_ARRAY_BUFFER, bo_size, nullptr, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, vertices_offset, vertices_size, static_cast(vertices.data())); + glBufferSubData(GL_ARRAY_BUFFER, vertices_offset, vertices_size, static_cast(vertices.data())); glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::vertices)); - glVertexAttribPointer(static_cast(bonobo::shader_bindings::vertices), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0x0)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::vertices), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(0x0)); - glBufferSubData(GL_ARRAY_BUFFER, normals_offset, normals_size, static_cast(normals.data())); + glBufferSubData(GL_ARRAY_BUFFER, normals_offset, normals_size, static_cast(normals.data())); glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::normals)); - glVertexAttribPointer(static_cast(bonobo::shader_bindings::normals), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(normals_offset)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::normals), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(normals_offset)); - glBufferSubData(GL_ARRAY_BUFFER, texcoords_offset, texcoords_size, static_cast(texcoords.data())); + glBufferSubData(GL_ARRAY_BUFFER, texcoords_offset, texcoords_size, static_cast(texcoords.data())); glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::texcoords)); - glVertexAttribPointer(static_cast(bonobo::shader_bindings::texcoords), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(texcoords_offset)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::texcoords), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(texcoords_offset)); - glBufferSubData(GL_ARRAY_BUFFER, tangents_offset, tangents_size, static_cast(tangents.data())); + glBufferSubData(GL_ARRAY_BUFFER, tangents_offset, tangents_size, static_cast(tangents.data())); glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::tangents)); - glVertexAttribPointer(static_cast(bonobo::shader_bindings::tangents), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(tangents_offset)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::tangents), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(tangents_offset)); - glBufferSubData(GL_ARRAY_BUFFER, binormals_offset, binormals_size, static_cast(binormals.data())); + glBufferSubData(GL_ARRAY_BUFFER, binormals_offset, binormals_size, static_cast(binormals.data())); glEnableVertexAttribArray(static_cast(bonobo::shader_bindings::binormals)); - glVertexAttribPointer(static_cast(bonobo::shader_bindings::binormals), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(binormals_offset)); + glVertexAttribPointer(static_cast(bonobo::shader_bindings::binormals), 3, GL_FLOAT, GL_FALSE, 0, reinterpret_cast(binormals_offset)); glBindBuffer(GL_ARRAY_BUFFER, 0u); @@ -406,7 +394,7 @@ parametric_shapes::createCircleRing(float const radius, glGenBuffers(1, &data.ibo); assert(data.ibo != 0u); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast(index_sets.size() * sizeof(glm::uvec3)), reinterpret_cast(index_sets.data()), GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast(index_sets.size() * sizeof(glm::uvec3)), reinterpret_cast(index_sets.data()), GL_STATIC_DRAW); glBindVertexArray(0u); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0u); diff --git a/src/core/node.cpp b/src/core/node.cpp index 4066ada..13bd087 100644 --- a/src/core/node.cpp +++ b/src/core/node.cpp @@ -30,7 +30,7 @@ Node::render(glm::mat4 const& view_projection, glm::mat4 const& world, GLuint pr glUniformMatrix4fv(glGetUniformLocation(program, "vertex_model_to_world"), 1, GL_FALSE, glm::value_ptr(world)); glUniformMatrix4fv(glGetUniformLocation(program, "normal_model_to_world"), 1, GL_FALSE, glm::value_ptr(normal_model_to_world)); - glUniformMatrix4fv(glGetUniformLocation(program, "vertex_world_to_clip"), 1, GL_FALSE, glm::value_ptr(view_projection)); + glUniformMatrix4fv(glGetUniformLocation(program, "vertex_world_to_clip"), 1, GL_FALSE, glm::value_ptr(view_projection)); for (size_t i = 0u; i < _textures.size(); ++i) { auto const& texture = _textures[i];