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 = 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);

View File

@ -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)));
}

View File

@ -19,6 +19,7 @@
#include <utilities/timeutils.h>
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;

View File

@ -16,6 +16,7 @@
#include <utilities/shader.hpp>
#include <vector>
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<PNGImage*, int> 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