diff --git a/res/shaders/simple.frag b/res/shaders/simple.frag index f571640..4127d9a 100644 --- a/res/shaders/simple.frag +++ b/res/shaders/simple.frag @@ -1,102 +1,95 @@ #version 430 core -in layout(location = 0) vec3 normal; -in layout(location = 1) vec3 vertex; +in layout(location = 0) vec3 vertex; +in layout(location = 1) vec3 normal; in layout(location = 2) vec2 UV; in layout(location = 3) mat3 TBN; layout(binding = 0) uniform sampler2D diffuseTexture; layout(binding = 1) uniform sampler2D normalTexture; +layout(binding = 2) uniform sampler2D displacementTexture; +uniform float displacementCoefficient; uniform mat4 MVP; uniform mat4 MV; uniform mat4 MVnormal; +uniform float shininess; + uniform bool isIlluminated; uniform bool isTextured; uniform bool isNormalMapped; +uniform bool isDisplacementMapped; uniform bool isInverted; // lights -struct Light { // coordinates in MV space +struct Light { // point lights, coordinates in MV space vec3 position; - vec3 spot_target; + vec3 attenuation; // 1 / (x + y*l + z*l*l) + vec3 color_emissive; + vec3 color_diffuse; + vec3 color_specular; + bool is_spot; // false means point light + vec3 spot_target; + float spot_cuttof_angle; }; -//named -#define N_LIGHTS 3 - +#define N_LIGHTS 1 uniform Light light[N_LIGHTS]; + out vec4 color; -// constants -float shininess = 15; -vec3 c_diffuse = vec3(0.75390625, 0.4296875, 0.4375); -vec3 c_emissive = vec3(0.01171875, 0.0, 0.15234375); -vec3 c_specular = vec3(0.9453125, 0.94921875, 0.84765625); -float spot_cuttof_angle = cos(1.5 / 180.0 * 3.1415926535); - -void main_(vec4 basecolor) { - vec3 nnormal; +vec4 phong(vec4 basecolor) { + vec3 nnormal; // normalized normal if (isNormalMapped) { vec3 tangential = texture(normalTexture, UV).rgb * 2.0 - 1.0; - nnormal = TBN * -normalize(tangential); - } else { + nnormal = TBN * normalize(tangential); + } + else { nnormal = normalize(normal); } - float diffuse_intensity = 0.0; - float specular_intensity = 0.0; + vec3 emmissive_component = vec3(0.0); + vec3 diffuse_component = vec3(0.0); + vec3 specular_component = vec3(0.0); - for (int i = 0; i<3; i++) { + for (int i = 0; i 0) diffuse_intensity += attenuation*diffuse_i; - if (specular_i > 0) specular_intensity += attenuation*specular_i; + emmissive_component += light[i].color_emissive; + if (diffuse_i>0) diffuse_component += light[i].color_diffuse * diffuse_i * attenuation; + if (specular_i>0) specular_component += light[i].color_specular * specular_i * attenuation; } - //diffuse_intensity *= 1.0 / N_LIGHTS; - //specular_intensity *= 1.0 / N_LIGHTS; - - - //float intensity = dot(normalize(normal), normalize(light_pos_2)); - //color = vec4(0.5 * normal + 0.5, 1.0); - - color = basecolor * vec4(c_emissive - + c_diffuse*diffuse_intensity, 1.0f) - + vec4(c_specular*specular_intensity, 1.0f); + return vec4(basecolor.rgb * (emmissive_component + diffuse_component) + specular_component, basecolor.a); } - - void main() { if(isIlluminated) { if (isTextured) { - c_diffuse = vec3(0.9); - c_emissive = vec3(0.2); - main_(texture(diffuseTexture, UV)); + color = phong(texture(diffuseTexture, UV)); } else { - main_(vec4(1.0)); - + color = phong(vec4(1.0)); } } else { color = texture(diffuseTexture, UV); diff --git a/res/shaders/simple.vert b/res/shaders/simple.vert index 722219c..7e6bb2a 100644 --- a/res/shaders/simple.vert +++ b/res/shaders/simple.vert @@ -6,6 +6,9 @@ in layout(location = 2) vec2 UV; in layout(location = 3) vec3 tangent; in layout(location = 4) vec3 bitangent; +layout(binding = 2) uniform sampler2D displacementTexture; +uniform float displacementCoefficient; + uniform mat4 MVP; uniform mat4 MV; uniform mat4 MVnormal; @@ -13,8 +16,8 @@ uniform bool isIlluminated; uniform bool isTextured; uniform bool isNormalMapped; -out layout(location = 0) vec3 normal_out; -out layout(location = 1) vec3 vertex_out; +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; diff --git a/src/gamelogic.cpp b/src/gamelogic.cpp index 0a27400..fd47152 100644 --- a/src/gamelogic.cpp +++ b/src/gamelogic.cpp @@ -39,7 +39,8 @@ SceneNode* padNode; SceneNode* hudNode; SceneNode* textNode; -SceneNode* lightNode[3]; +const uint N_LIGHTS = 1; +SceneNode* lightNode[N_LIGHTS]; // These are heap allocated, because they should not be initialised at the start of the program sf::Sound* sound; @@ -122,7 +123,7 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) { plainNode->setTexture(&t_plain_diff, &t_plain_normal); // add lights - for (int i = 0; i<3; i++) { + for (uint i = 0; ilightID = i; } @@ -151,8 +152,6 @@ void updateNodeTransformations(SceneNode* node, mat4 transformationThusFar, mat4 mat4 transformationMatrix(1.0); switch(node->nodeType) { - case NORMAL_TEXTURED_GEOMETRY: - case TEXTURED_GEOMETRY: case GEOMETRY: transformationMatrix = glm::translate(mat4(1.0), node->position) @@ -254,19 +253,29 @@ 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; + vec3 position; + vec3 spot_target; + bool is_spot; + float spot_cuttof_angle; + vec3 attenuation; + vec3 color_emissive; + vec3 color_diffuse; + vec3 color_specular; void push_to_shader(Gloom::Shader* shader, uint id) { #define l(x) shader->location("light[" + std::to_string(id) + "]." + #x) - glUniform3fv (l(position) , 1, glm::value_ptr(position)); - glUniform3fv (l(spot_target), 1, glm::value_ptr(spot_target)); - glUniform1i (l(is_spot) , is_spot); + 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)); #undef l } }; - static Light lights[3]; + static Light lights[N_LIGHTS]; static Gloom::Shader* s = nullptr; // The currently active shader // activate the correct shader @@ -279,26 +288,24 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader) uint i = 0; for (Light l : lights) l.push_to_shader(s, i++); } - // load uniforms - 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)); - glUniform1ui(s->location("isNormalMapped"), false); - glUniform1ui(s->location("isTextured"), false); - switch(node->nodeType) { - case NORMAL_TEXTURED_GEOMETRY: - glUniform1ui(s->location("isNormalMapped"), true); - glBindTextureUnit(1, node->normalTextureID); - [[fallthrough]]; - case TEXTURED_GEOMETRY: - glUniform1ui(s->location("isTextured"), true); - glBindTextureUnit(0, node->diffuseTextureID); - [[fallthrough]]; case GEOMETRY: if(node->vertexArrayObjectID != -1) { - glUniform1ui(s->location("isIlluminated"), node->isIlluminated); - glUniform1ui(s->location("isInverted"), node->isInverted); + // load uniforms + 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)); + glUniform1f( s->location("shinyness"), node->shinyness); + glUniform1f( s->location("displacementCoefficient"), node->displacementCoefficient); + glUniform1ui(s->location("isTextured"), node->isTextured); + glUniform1ui(s->location("isNormalMapped"), node->isNormalMapped); + glUniform1ui(s->location("isDisplacementMapped"), node->isDisplacementMapped); + glUniform1ui(s->location("isIlluminated"), node->isIlluminated); + glUniform1ui(s->location("isInverted"), node->isInverted); + + if (node->isTextured) glBindTextureUnit(0, node->diffuseTextureID); + if (node->isNormalMapped) glBindTextureUnit(1, node->normalTextureID); + if (node->isDisplacementMapped) glBindTextureUnit(2, node->displacementTextureID); glBindVertexArray(node->vertexArrayObjectID); glDrawElements(GL_TRIANGLES, node->VAOIndexCount, GL_UNSIGNED_INT, nullptr); } @@ -306,9 +313,14 @@ 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].is_spot = node->nodeType == SPOT_LIGHT; - lights[id].spot_target = node->rotation; + lights[id].position = vec3(node->MV * glm::vec4(node->position, 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].attenuation = node->attenuation; + lights[id].color_emissive = node->color_emissive; + lights[id].color_diffuse = node->color_diffuse; + lights[id].color_specular = node->color_specular; lights[id].push_to_shader(s, id); break; } diff --git a/src/sceneGraph.hpp b/src/sceneGraph.hpp index 6c0766e..42e7e7c 100644 --- a/src/sceneGraph.hpp +++ b/src/sceneGraph.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -22,7 +23,9 @@ using std::vector; typedef unsigned int uint; enum SceneNodeType { - GEOMETRY, POINT_LIGHT, SPOT_LIGHT, TEXTURED_GEOMETRY, NORMAL_TEXTURED_GEOMETRY + GEOMETRY, + POINT_LIGHT, + SPOT_LIGHT, }; struct SceneNode { @@ -34,58 +37,84 @@ struct SceneNode { static map cache; if (cache.find(mesh) == cache.end()) - cache[mesh] = generateBuffer(*mesh, nodeType==NORMAL_TEXTURED_GEOMETRY); + cache[mesh] = generateBuffer(*mesh, isNormalMapped || isDisplacementMapped); vertexArrayObjectID = cache[mesh]; VAOIndexCount = mesh->indices.size(); } - void setTexture(PNGImage* diffuse, PNGImage* normal = nullptr) { + void setTexture(PNGImage* diffuse, PNGImage* normal=nullptr, PNGImage* displacement=nullptr) { static map cache; + assert(vertexArrayObjectID==-1); - if (cache.find(diffuse) == cache.end()) cache[diffuse] = generateTexture(*diffuse); - diffuseTextureID = cache[diffuse]; + if (diffuse) { + if (cache.find(diffuse) == cache.end()) + cache[diffuse] = generateTexture(*diffuse); + diffuseTextureID = cache[diffuse]; + isTextured = true; + } - if (!normal) return; - if (cache.find(normal) == cache.end()) cache[normal] = generateTexture(*normal); - normalTextureID = cache[normal]; + if (normal) { + if (cache.find(normal) == cache.end()) + cache[normal] = generateTexture(*normal); + normalTextureID = cache[normal]; + isNormalMapped = true; + } + + if (displacement) { + if (cache.find(displacement) == cache.end()) + cache[displacement] = generateTexture(*displacement); + displacementTextureID = cache[displacement]; + isDisplacementMapped = true; + } } + // this node + SceneNodeType nodeType; vector children; + // light specific: + uint lightID = -1; + vec3 color_emissive = vec3(0.0); + vec3 color_diffuse = vec3(0.8); + vec3 color_specular = vec3(0.5); + 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 + // The node's position and rotation relative to its parent vec3 position = vec3(0, 0, 0); - vec3 rotation = vec3(0, 0, 0); + vec3 rotation = vec3(0, 0, 0); // also used as spot-target vec3 scale = vec3(1, 1, 1); - - // set this if the shape uses a custom shader other than the inherited one - Gloom::Shader* shader = nullptr; - - // A transformation matrix representing the transformation of the node's location relative to its parent. This matrix is updated every frame. - mat4 MVP; // MVP - mat4 MV; // MV - mat4 MVnormal; // transpose(inverse(MV)) - - // The location of the node's reference point (center of rotation) - vec3 referencePoint = vec3(0, 0, 0); + vec3 referencePoint = vec3(0, 0, 0); // center of rotation, in model space // VAO IDs refering to a loaded Mesh and its length int vertexArrayObjectID = -1; uint VAOIndexCount = 0; - + // textures + float shinyness = 10.0; // specular power uint diffuseTextureID; uint normalTextureID; - + uint displacementTextureID; + float displacementCoefficient = 0.1; // in units + // shader flags + bool isTextured = false; + bool isNormalMapped = false; + bool isDisplacementMapped = false; bool isIlluminated = true; bool isInverted = false; - // Node type is used to determine how to handle the contents of a node - SceneNodeType nodeType; + // rendering + Gloom::Shader* shader = nullptr; + mat4 MVP; // MVP + mat4 MV; // MV + mat4 MVnormal; // transpose(inverse(MV)) + + + + - // for lights: - uint lightID; - SceneNode* targeted_by = nullptr; // spot }; // Struct for keeping track of 2D coordinates diff --git a/src/utilities/glutils.cpp b/src/utilities/glutils.cpp index 4221bb1..fb69904 100644 --- a/src/utilities/glutils.cpp +++ b/src/utilities/glutils.cpp @@ -64,7 +64,7 @@ void addTangents(uint vaoID, Mesh& mesh) { vec2 deltaUV1 = uv2 - uv1; vec2 deltaUV2 = uv3 - uv1; - float f = -1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); + float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); vec3 tangent{ f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x),