#include "BumpMapDemo.h" BumpMapDemo::BumpMapDemo() : height_scale(0.2), render_shader(Shader("Shader/bump.vs", "Shader/bump.fs")), camera(Camera(90, 1920, 1080, 0.1, 1000.0)), albedo("Resources/Textures/PavingStones/PavingStones070_2K_Color.jpg", Texture::Settings()), bump("Resources/Textures/PavingStones/PavingStones070_2K_Displacement.jpg", Texture::Settings()), normal("Resources/Textures/PavingStones/PavingStones070_2K_Normal.jpg", Texture::Settings()) { // Move and rotate the camera so we see the quad well camera.translate(glm::vec3(0.0, -1.0, 1.0)); camera.rotate(30, glm::vec3(1.0, 0.0, 0.0)); } // renders a 1x1 quad in NDC with manually calculated tangent vectors // ------------------------------------------------------------------ unsigned int quadVAO = 0; unsigned int quadVBO; void renderQuad() { if (quadVAO == 0) { // positions glm::vec3 pos1(-1.0f, 1.0f, 0.0f); glm::vec3 pos2(-1.0f, -1.0f, 0.0f); glm::vec3 pos3(1.0f, -1.0f, 0.0f); glm::vec3 pos4(1.0f, 1.0f, 0.0f); // texture coordinates glm::vec2 uv1(0.0f, 1.0f); glm::vec2 uv2(0.0f, 0.0f); glm::vec2 uv3(1.0f, 0.0f); glm::vec2 uv4(1.0f, 1.0f); // normal vector glm::vec3 nm(0.0f, 0.0f, 1.0f); // calculate tangent/bitangent vectors of both triangles glm::vec3 tangent1, bitangent1; glm::vec3 tangent2, bitangent2; // triangle 1 // ---------- glm::vec3 edge1 = pos2 - pos1; glm::vec3 edge2 = pos3 - pos1; glm::vec2 deltaUV1 = uv2 - uv1; glm::vec2 deltaUV2 = uv3 - uv1; float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x); tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y); tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z); tangent1 = glm::normalize(tangent1); bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x); bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y); bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z); bitangent1 = glm::normalize(bitangent1); // triangle 2 // ---------- edge1 = pos3 - pos1; edge2 = pos4 - pos1; deltaUV1 = uv3 - uv1; deltaUV2 = uv4 - uv1; f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); tangent2.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x); tangent2.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y); tangent2.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z); tangent2 = glm::normalize(tangent2); bitangent2.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x); bitangent2.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y); bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z); bitangent2 = glm::normalize(bitangent2); float quadVertices[] = { // positions // normal // texcoords // tangent // bitangent pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x, uv2.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z, pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z, pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z, pos4.x, pos4.y, pos4.z, nm.x, nm.y, nm.z, uv4.x, uv4.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z}; // configure plane VAO glGenVertexArrays(1, &quadVAO); glGenBuffers(1, &quadVBO); glBindVertexArray(quadVAO); glBindBuffer(GL_ARRAY_BUFFER, quadVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)(3 * sizeof(float))); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)(6 * sizeof(float))); glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)(8 * sizeof(float))); glEnableVertexAttribArray(4); glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)(11 * sizeof(float))); } glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); } void BumpMapDemo::render(float delta) { glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glm::mat4 projection = camera.get_projection(); glm::mat4 view = camera.get_view(); render_shader.use(); render_shader.setMat4("projection", projection); render_shader.setMat4("view", view); glm::mat4 quad_model = glm::mat4(1.0f); quad_model = glm::rotate( quad_model, glm::radians((float)glfwGetTime() * 20.0f), glm::normalize(glm::vec3( 0.0, 0.0, 1.0))); // rotate the quad to show parallax mapping from multiple directions render_shader.setMat4("model", quad_model); render_shader.setVec3("viewPos", camera.get_translation()); render_shader.setVec3("lightPos", glm::vec3(0.0, 1.0, 5.0)); render_shader.setFloat("height_scale", height_scale); albedo.bind_to(0); normal.bind_to(1); bump.bind_to(2); renderQuad(); }