From c9e4332a651c1bcf30e21c6b78010f64b323ae3d Mon Sep 17 00:00:00 2001 From: Peder Bergebakken Sundt Date: Sun, 17 Mar 2019 15:17:44 +0100 Subject: [PATCH] Add displacement mapping with TBN being affected --- res/shaders/simple.frag | 38 ++++++++++++++++---- res/shaders/simple.vert | 35 ++++++++++++------ src/gamelogic.cpp | 78 +++++++++++++++++++---------------------- src/sceneGraph.hpp | 13 +++---- 4 files changed, 99 insertions(+), 65 deletions(-) diff --git a/res/shaders/simple.frag b/res/shaders/simple.frag index 24302a9..2b36a5b 100644 --- a/res/shaders/simple.frag +++ b/res/shaders/simple.frag @@ -3,7 +3,8 @@ in layout(location = 0) vec3 vertex; in layout(location = 1) vec3 normal; in layout(location = 2) vec2 UV; -in layout(location = 3) mat3 TBN; +in layout(location = 3) vec3 tangent; +in layout(location = 4) vec3 bitangent; layout(binding = 0) uniform sampler2D diffuseTexture; layout(binding = 1) uniform sampler2D normalTexture; @@ -45,11 +46,36 @@ out vec4 color; vec4 phong(vec4 basecolor) { vec3 nnormal; // normalized normal if (isNormalMapped) { - vec3 tangential = texture(normalTexture, UV).rgb * 2.0 - 1.0; - nnormal = TBN * normalize(tangential); + mat3 TBN; + if (isDisplacementMapped) { + float o = texture(displacementTexture, UV).r * 2.0 - 1.0; + float u = (texture(displacementTexture, UV + vec2(0.0001, 0.0)).r*2.0-1.0 - o) / 0.0004; // magic numbers are great + float v = (texture(displacementTexture, UV + vec2(0.0, 0.0001)).r*2.0-1.0 - o) / 0.0004; // magic numbers are great + TBN = mat3( + normalize(tangent + normal*u), + normalize(bitangent + normal*v), + normalize(cross(tangent + normal*u, bitangent + normal*v)) + ); + } + else { + TBN = mat3( + normalize(tangent), + normalize(bitangent), + normalize(normal) + ); + } + nnormal = TBN * normalize(texture(normalTexture, UV).rgb * 2.0 - 1.0); } else { - nnormal = normalize(normal); + if (isDisplacementMapped) { + float o = texture(displacementTexture, UV).r * 2.0 - 1.0; + float u = (texture(displacementTexture, UV + vec2(0.0001, 0.0)).r*2.0-1.0 - o) / 0.0004; + float v = (texture(displacementTexture, UV + vec2(0.0, 0.0001)).r*2.0-1.0 - o) / 0.0004; + nnormal = normalize(cross(tangent + normal*u, bitangent + normal*v)); + } + else { + nnormal = normalize(normal); + } } vec3 emmissive_component = vec3(0.0); @@ -74,14 +100,14 @@ vec4 phong(vec4 basecolor) { ), 0.0, 1.25); float diffuse_i = dot(nnormal, L); - float specular_i = dot(reflect(-L, nnormal), vec3(0.0)-normalize(vertex)); + float specular_i = dot(reflect(-L, nnormal), -normalize(vertex)); specular_i = (specular_i>0) ? pow(specular_i, shinyness) : 0; emmissive_component += light[i].color_emissive; - if (diffuse_i>0) diffuse_component += light[i].color_diffuse * diffuse_i * attenuation; specular_component += light[i].color_specular * specular_i * attenuation; + if (diffuse_i>0) diffuse_component += light[i].color_diffuse * diffuse_i * attenuation; } return vec4(basecolor.rgb * (emmissive_component + diffuse_component) + specular_component, basecolor.a); diff --git a/res/shaders/simple.vert b/res/shaders/simple.vert index 7e6bb2a..fbed9ca 100644 --- a/res/shaders/simple.vert +++ b/res/shaders/simple.vert @@ -1,7 +1,7 @@ #version 430 core in layout(location = 0) vec3 position; -in layout(location = 1) vec3 normal_in; +in layout(location = 1) vec3 normal; in layout(location = 2) vec2 UV; in layout(location = 3) vec3 tangent; in layout(location = 4) vec3 bitangent; @@ -12,24 +12,37 @@ uniform float displacementCoefficient; uniform mat4 MVP; uniform mat4 MV; uniform mat4 MVnormal; + +uniform float shinyness; +uniform vec2 uvOffset; + uniform bool isIlluminated; uniform bool isTextured; uniform bool isNormalMapped; +uniform bool isDisplacementMapped; +uniform bool isInverted; out layout(location = 0) vec3 vertex_out; out layout(location = 1) vec3 normal_out; out layout(location = 2) vec2 uv_out; -out layout(location = 3) mat3 TBN; +out layout(location = 3) vec3 tangent_out; +out layout(location = 4) vec3 bitangent_out; void main() { - TBN = mat3( - normalize(vec3(MV * vec4(tangent, 0.0))), - normalize(vec3(MV * vec4(bitangent, 0.0))), - normalize(vec3(MV * vec4(normal_in, 0.0))) - ); + vec3 displacement = vec3(0.0); + if (isDisplacementMapped){ + float o = texture(displacementTexture, UV + uvOffset).r * 2.0 - 1.0; + float u = (texture(displacementTexture, UV + uvOffset + vec2(0.001, 0.0)).r*2.0-1.0 - o) / 0.004; + float v = (texture(displacementTexture, UV + uvOffset + vec2(0.0, 0.001)).r*2.0-1.0 - o) / 0.004; + + displacement = normal * displacementCoefficient * o; + } - normal_out = normalize(vec3(MVnormal * vec4(normal_in, 1.0f))); - vertex_out = vec3(MV*vec4(position, 1.0f)); - uv_out = UV; - gl_Position = MVP * vec4(position, 1.0f); + normal_out = normalize(vec3(MVnormal * vec4(normal, 1.0f))); + vertex_out = vec3(MV * vec4(position+displacement, 1.0f)); + uv_out = UV + uvOffset; + gl_Position = MVP * vec4(position+displacement, 1.0f); + + tangent_out = normalize(vec3(MVnormal * vec4(tangent, 1.0f))); + bitangent_out = normalize(vec3(MVnormal * vec4(bitangent, 1.0f))); } diff --git a/src/gamelogic.cpp b/src/gamelogic.cpp index 6d19561..2f3453f 100644 --- a/src/gamelogic.cpp +++ b/src/gamelogic.cpp @@ -19,6 +19,7 @@ #include using glm::vec3; +using glm::vec4; using glm::mat4; typedef unsigned int uint; @@ -153,40 +154,30 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) { std::cout << "Ready. Click to start!" << std::endl; } -void updateNodeTransformations(SceneNode* node, mat4 transformationThusFar, mat4 V, mat4 P) { - mat4 transformationMatrix(1.0); +void updateNodeTransformations(SceneNode* node, mat4 transformationThusFar, mat4 const& V, mat4 const& P) { + mat4 transformationMatrix + = glm::translate(mat4(1.0), node->position) + * glm::translate(mat4(1.0), node->referencePoint) + * glm::rotate(mat4(1.0), node->rotation.z, vec3(0,0,1)) + * glm::rotate(mat4(1.0), node->rotation.y, vec3(0,1,0)) + * glm::rotate(mat4(1.0), node->rotation.x, vec3(1,0,0)) + * glm::scale(mat4(1.0), node->scale) + * glm::translate(mat4(1.0), -node->referencePoint); - switch(node->nodeType) { - case GEOMETRY: - transformationMatrix = - glm::translate(mat4(1.0), node->position) - * glm::translate(mat4(1.0), node->referencePoint) - * glm::rotate(mat4(1.0), node->rotation.z, vec3(0,0,1)) - * glm::rotate(mat4(1.0), node->rotation.y, vec3(0,1,0)) - * glm::rotate(mat4(1.0), node->rotation.x, vec3(1,0,0)) - * glm::translate(mat4(1.0), -node->referencePoint) - * glm::scale(mat4(1.0), node->scale); - break; - case POINT_LIGHT: - case SPOT_LIGHT: - transformationMatrix = - glm::translate(mat4(1.0), node->position); - break; - } mat4 M = transformationThusFar * transformationMatrix; - mat4 MV = V*M; - node->MV = MV; - node->MVP = P*MV; - node->MVnormal = glm::inverse(glm::transpose(MV)); + node->MV = V*M; + node->MVP = P*node->MV; + node->MVnormal = glm::inverse(glm::transpose(node->MV)); for(SceneNode* child : node->children) { updateNodeTransformations(child, M, V, P); } + // move this into the renderNode method and have it be targeted_node from the spot if (node->targeted_by != nullptr) { assert(node->targeted_by->nodeType == SPOT_LIGHT); - node->targeted_by->rotation = vec3(MV*glm::vec4(node->position, 1.0)); + node->targeted_by->rotation = vec3(node->MV*vec4(node->position, 1.0)); } } @@ -236,10 +227,9 @@ void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight) { mat4 projection = glm::perspective( glm::radians(45.0f), // fovy float(windowWidth) / float(windowHeight), // aspect - 0.1f, 50000.f // near, far + 0.1f, 5000.f // near, far ); - // hardcoded camera position... mat4 cameraTransform = glm::lookAt(cameraPosition, cameraLookAt, cameraUpward); @@ -258,25 +248,28 @@ void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight) { void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader) { struct Light { // lights as stored in the shader // coordinates in MV space - vec3 position; - vec3 spot_target; - bool is_spot; - float spot_cuttof_angle; + vec3 position; // MV vec3 attenuation; vec3 color_emissive; vec3 color_diffuse; vec3 color_specular; + bool is_spot; + vec3 spot_target; // MV + float spot_cuttof_angle; + void push_to_shader(Gloom::Shader* shader, uint id) { - #define l(x) shader->location("light[" + std::to_string(id) + "]." + #x) - glUniform1i (l(is_spot) , is_spot); - glUniform1f (l(spot_cuttof_angle), spot_cuttof_angle); - glUniform3fv(l(position) , 1, glm::value_ptr(position)); - glUniform3fv(l(spot_target) , 1, glm::value_ptr(spot_target)); - glUniform3fv(l(attenuation) , 1, glm::value_ptr(attenuation)); - glUniform3fv(l(color_emissive) , 1, glm::value_ptr(color_emissive)); - glUniform3fv(l(color_diffuse) , 1, glm::value_ptr(color_diffuse)); - glUniform3fv(l(color_specular) , 1, glm::value_ptr(color_specular)); + #define L(x) shader->location("light[" + std::to_string(id) + "]." #x) + #define V(x) glUniform3fv(L(x), 1, glm::value_ptr(x)) + glUniform1i (L(is_spot) , is_spot); + glUniform1f (L(spot_cuttof_angle), spot_cuttof_angle); + V(position); + V(spot_target); + V(attenuation); + V(color_emissive); + V(color_diffuse); + V(color_specular); + #undef v #undef l } }; @@ -300,6 +293,7 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader) glUniformMatrix4fv(s->location("MVP") , 1, GL_FALSE, glm::value_ptr(node->MVP)); glUniformMatrix4fv(s->location("MV") , 1, GL_FALSE, glm::value_ptr(node->MV)); glUniformMatrix4fv(s->location("MVnormal"), 1, GL_FALSE, glm::value_ptr(node->MVnormal)); + glUniform2fv(s->location("uvOffset") , 1, glm::value_ptr(node->uvOffset)); glUniform1f( s->location("shinyness"), node->shinyness); glUniform1f( s->location("displacementCoefficient"), node->displacementCoefficient); glUniform1ui(s->location("isTextured"), node->isTextured); @@ -318,10 +312,10 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader) case SPOT_LIGHT: case POINT_LIGHT: { uint id = node->lightID; - lights[id].position = vec3(node->MV * glm::vec4(node->position, 1.0)); + lights[id].position = vec3(node->MV * vec4(1.0)); lights[id].is_spot = node->nodeType == SPOT_LIGHT; - lights[id].spot_target = node->rotation; - lights[id].spot_cuttof_angle = node->spot_cuttof_angle; + lights[id].spot_target = node->rotation; // already MV space, todo: change this + lights[id].spot_cuttof_angle = glm::sin(node->spot_cuttof_angle); lights[id].attenuation = node->attenuation; lights[id].color_emissive = node->color_emissive; lights[id].color_diffuse = node->color_diffuse; diff --git a/src/sceneGraph.hpp b/src/sceneGraph.hpp index 42e7e7c..cd7e1ad 100644 --- a/src/sceneGraph.hpp +++ b/src/sceneGraph.hpp @@ -16,6 +16,7 @@ #include #include +using glm::vec2; using glm::vec3; using glm::mat4; using std::map; @@ -45,6 +46,9 @@ struct SceneNode { void setTexture(PNGImage* diffuse, PNGImage* normal=nullptr, PNGImage* displacement=nullptr) { static map cache; assert(vertexArrayObjectID==-1); + isTextured = false; + isNormalMapped = false; + isDisplacementMapped = false; if (diffuse) { if (cache.find(diffuse) == cache.end()) @@ -75,8 +79,8 @@ struct SceneNode { // light specific: uint lightID = -1; vec3 color_emissive = vec3(0.0); - vec3 color_diffuse = vec3(0.8); - vec3 color_specular = vec3(0.5); + vec3 color_diffuse = vec3(0.0); + vec3 color_specular = vec3(0.0); vec3 attenuation = vec3(1.0, 0.0, 0.001); // 1 / (x + y*l + z*l*l) float spot_cuttof_angle = glm::radians(1.5); // radians SceneNode* targeted_by = nullptr; // spot will follow this node @@ -93,6 +97,7 @@ struct SceneNode { // textures float shinyness = 10.0; // specular power + vec2 uvOffset = vec2(0.0, 0.0); // specular power uint diffuseTextureID; uint normalTextureID; uint displacementTextureID; @@ -111,10 +116,6 @@ struct SceneNode { mat4 MV; // MV mat4 MVnormal; // transpose(inverse(MV)) - - - - }; // Struct for keeping track of 2D coordinates