Add displacement mapping with TBN being affected

This commit is contained in:
Peder Bergebakken Sundt 2019-03-17 15:17:44 +01:00
parent 15dfce421e
commit c9e4332a65
4 changed files with 99 additions and 65 deletions

View File

@ -3,7 +3,8 @@
in layout(location = 0) vec3 vertex; in layout(location = 0) vec3 vertex;
in layout(location = 1) vec3 normal; in layout(location = 1) vec3 normal;
in layout(location = 2) vec2 UV; 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 = 0) uniform sampler2D diffuseTexture;
layout(binding = 1) uniform sampler2D normalTexture; layout(binding = 1) uniform sampler2D normalTexture;
@ -45,11 +46,36 @@ out vec4 color;
vec4 phong(vec4 basecolor) { vec4 phong(vec4 basecolor) {
vec3 nnormal; // normalized normal vec3 nnormal; // normalized normal
if (isNormalMapped) { if (isNormalMapped) {
vec3 tangential = texture(normalTexture, UV).rgb * 2.0 - 1.0; mat3 TBN;
nnormal = TBN * normalize(tangential); 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 { 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); vec3 emmissive_component = vec3(0.0);
@ -74,14 +100,14 @@ vec4 phong(vec4 basecolor) {
), 0.0, 1.25); ), 0.0, 1.25);
float diffuse_i = dot(nnormal, L); 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) specular_i = (specular_i>0)
? pow(specular_i, shinyness) ? pow(specular_i, shinyness)
: 0; : 0;
emmissive_component += light[i].color_emissive; 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; 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); return vec4(basecolor.rgb * (emmissive_component + diffuse_component) + specular_component, basecolor.a);

View File

@ -1,7 +1,7 @@
#version 430 core #version 430 core
in layout(location = 0) vec3 position; 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 = 2) vec2 UV;
in layout(location = 3) vec3 tangent; in layout(location = 3) vec3 tangent;
in layout(location = 4) vec3 bitangent; in layout(location = 4) vec3 bitangent;
@ -12,24 +12,37 @@ uniform float displacementCoefficient;
uniform mat4 MVP; uniform mat4 MVP;
uniform mat4 MV; uniform mat4 MV;
uniform mat4 MVnormal; uniform mat4 MVnormal;
uniform float shinyness;
uniform vec2 uvOffset;
uniform bool isIlluminated; uniform bool isIlluminated;
uniform bool isTextured; uniform bool isTextured;
uniform bool isNormalMapped; uniform bool isNormalMapped;
uniform bool isDisplacementMapped;
uniform bool isInverted;
out layout(location = 0) vec3 vertex_out; out layout(location = 0) vec3 vertex_out;
out layout(location = 1) vec3 normal_out; out layout(location = 1) vec3 normal_out;
out layout(location = 2) vec2 uv_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() { void main() {
TBN = mat3( vec3 displacement = vec3(0.0);
normalize(vec3(MV * vec4(tangent, 0.0))), if (isDisplacementMapped){
normalize(vec3(MV * vec4(bitangent, 0.0))), float o = texture(displacementTexture, UV + uvOffset).r * 2.0 - 1.0;
normalize(vec3(MV * vec4(normal_in, 0.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))); normal_out = normalize(vec3(MVnormal * vec4(normal, 1.0f)));
vertex_out = vec3(MV*vec4(position, 1.0f)); vertex_out = vec3(MV * vec4(position+displacement, 1.0f));
uv_out = UV; uv_out = UV + uvOffset;
gl_Position = MVP * vec4(position, 1.0f); 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)));
} }

View File

@ -19,6 +19,7 @@
#include <utilities/timeutils.h> #include <utilities/timeutils.h>
using glm::vec3; using glm::vec3;
using glm::vec4;
using glm::mat4; using glm::mat4;
typedef unsigned int uint; typedef unsigned int uint;
@ -153,40 +154,30 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) {
std::cout << "Ready. Click to start!" << std::endl; std::cout << "Ready. Click to start!" << std::endl;
} }
void updateNodeTransformations(SceneNode* node, mat4 transformationThusFar, mat4 V, mat4 P) { void updateNodeTransformations(SceneNode* node, mat4 transformationThusFar, mat4 const& V, mat4 const& P) {
mat4 transformationMatrix(1.0); 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 M = transformationThusFar * transformationMatrix;
mat4 MV = V*M;
node->MV = MV; node->MV = V*M;
node->MVP = P*MV; node->MVP = P*node->MV;
node->MVnormal = glm::inverse(glm::transpose(MV)); node->MVnormal = glm::inverse(glm::transpose(node->MV));
for(SceneNode* child : node->children) { for(SceneNode* child : node->children) {
updateNodeTransformations(child, M, V, P); 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) { if (node->targeted_by != nullptr) {
assert(node->targeted_by->nodeType == SPOT_LIGHT); 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( mat4 projection = glm::perspective(
glm::radians(45.0f), // fovy glm::radians(45.0f), // fovy
float(windowWidth) / float(windowHeight), // aspect float(windowWidth) / float(windowHeight), // aspect
0.1f, 50000.f // near, far 0.1f, 5000.f // near, far
); );
// hardcoded camera position...
mat4 cameraTransform mat4 cameraTransform
= glm::lookAt(cameraPosition, cameraLookAt, cameraUpward); = 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) { void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader) {
struct Light { // lights as stored in the shader struct Light { // lights as stored in the shader
// coordinates in MV space // coordinates in MV space
vec3 position; vec3 position; // MV
vec3 spot_target;
bool is_spot;
float spot_cuttof_angle;
vec3 attenuation; vec3 attenuation;
vec3 color_emissive; vec3 color_emissive;
vec3 color_diffuse; vec3 color_diffuse;
vec3 color_specular; vec3 color_specular;
bool is_spot;
vec3 spot_target; // MV
float spot_cuttof_angle;
void push_to_shader(Gloom::Shader* shader, uint id) { void push_to_shader(Gloom::Shader* shader, uint id) {
#define l(x) shader->location("light[" + std::to_string(id) + "]." + #x) #define L(x) shader->location("light[" + std::to_string(id) + "]." #x)
glUniform1i (l(is_spot) , is_spot); #define V(x) glUniform3fv(L(x), 1, glm::value_ptr(x))
glUniform1f (l(spot_cuttof_angle), spot_cuttof_angle); glUniform1i (L(is_spot) , is_spot);
glUniform3fv(l(position) , 1, glm::value_ptr(position)); glUniform1f (L(spot_cuttof_angle), spot_cuttof_angle);
glUniform3fv(l(spot_target) , 1, glm::value_ptr(spot_target)); V(position);
glUniform3fv(l(attenuation) , 1, glm::value_ptr(attenuation)); V(spot_target);
glUniform3fv(l(color_emissive) , 1, glm::value_ptr(color_emissive)); V(attenuation);
glUniform3fv(l(color_diffuse) , 1, glm::value_ptr(color_diffuse)); V(color_emissive);
glUniform3fv(l(color_specular) , 1, glm::value_ptr(color_specular)); V(color_diffuse);
V(color_specular);
#undef v
#undef l #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("MVP") , 1, GL_FALSE, glm::value_ptr(node->MVP));
glUniformMatrix4fv(s->location("MV") , 1, GL_FALSE, glm::value_ptr(node->MV)); glUniformMatrix4fv(s->location("MV") , 1, GL_FALSE, glm::value_ptr(node->MV));
glUniformMatrix4fv(s->location("MVnormal"), 1, GL_FALSE, glm::value_ptr(node->MVnormal)); 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("shinyness"), node->shinyness);
glUniform1f( s->location("displacementCoefficient"), node->displacementCoefficient); glUniform1f( s->location("displacementCoefficient"), node->displacementCoefficient);
glUniform1ui(s->location("isTextured"), node->isTextured); glUniform1ui(s->location("isTextured"), node->isTextured);
@ -318,10 +312,10 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader)
case SPOT_LIGHT: case SPOT_LIGHT:
case POINT_LIGHT: { case POINT_LIGHT: {
uint id = node->lightID; 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].is_spot = node->nodeType == SPOT_LIGHT;
lights[id].spot_target = node->rotation; lights[id].spot_target = node->rotation; // already MV space, todo: change this
lights[id].spot_cuttof_angle = node->spot_cuttof_angle; lights[id].spot_cuttof_angle = glm::sin(node->spot_cuttof_angle);
lights[id].attenuation = node->attenuation; lights[id].attenuation = node->attenuation;
lights[id].color_emissive = node->color_emissive; lights[id].color_emissive = node->color_emissive;
lights[id].color_diffuse = node->color_diffuse; lights[id].color_diffuse = node->color_diffuse;

View File

@ -16,6 +16,7 @@
#include <utilities/shader.hpp> #include <utilities/shader.hpp>
#include <vector> #include <vector>
using glm::vec2;
using glm::vec3; using glm::vec3;
using glm::mat4; using glm::mat4;
using std::map; using std::map;
@ -45,6 +46,9 @@ struct SceneNode {
void setTexture(PNGImage* diffuse, PNGImage* normal=nullptr, PNGImage* displacement=nullptr) { void setTexture(PNGImage* diffuse, PNGImage* normal=nullptr, PNGImage* displacement=nullptr) {
static map<PNGImage*, int> cache; static map<PNGImage*, int> cache;
assert(vertexArrayObjectID==-1); assert(vertexArrayObjectID==-1);
isTextured = false;
isNormalMapped = false;
isDisplacementMapped = false;
if (diffuse) { if (diffuse) {
if (cache.find(diffuse) == cache.end()) if (cache.find(diffuse) == cache.end())
@ -75,8 +79,8 @@ struct SceneNode {
// light specific: // light specific:
uint lightID = -1; uint lightID = -1;
vec3 color_emissive = vec3(0.0); vec3 color_emissive = vec3(0.0);
vec3 color_diffuse = vec3(0.8); vec3 color_diffuse = vec3(0.0);
vec3 color_specular = vec3(0.5); vec3 color_specular = vec3(0.0);
vec3 attenuation = vec3(1.0, 0.0, 0.001); // 1 / (x + y*l + z*l*l) 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 float spot_cuttof_angle = glm::radians(1.5); // radians
SceneNode* targeted_by = nullptr; // spot will follow this node SceneNode* targeted_by = nullptr; // spot will follow this node
@ -93,6 +97,7 @@ struct SceneNode {
// textures // textures
float shinyness = 10.0; // specular power float shinyness = 10.0; // specular power
vec2 uvOffset = vec2(0.0, 0.0); // specular power
uint diffuseTextureID; uint diffuseTextureID;
uint normalTextureID; uint normalTextureID;
uint displacementTextureID; uint displacementTextureID;
@ -111,10 +116,6 @@ struct SceneNode {
mat4 MV; // MV mat4 MV; // MV
mat4 MVnormal; // transpose(inverse(MV)) mat4 MVnormal; // transpose(inverse(MV))
}; };
// Struct for keeping track of 2D coordinates // Struct for keeping track of 2D coordinates