Revamp the shader and lighting system

This commit is contained in:
Peder Bergebakken Sundt 2019-03-16 20:12:35 +01:00
parent 74d65ee092
commit 7135ebab6b
5 changed files with 145 additions and 108 deletions

View File

@ -1,102 +1,95 @@
#version 430 core #version 430 core
in layout(location = 0) vec3 normal; in layout(location = 0) vec3 vertex;
in layout(location = 1) vec3 vertex; 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) mat3 TBN;
layout(binding = 0) uniform sampler2D diffuseTexture; layout(binding = 0) uniform sampler2D diffuseTexture;
layout(binding = 1) uniform sampler2D normalTexture; layout(binding = 1) uniform sampler2D normalTexture;
layout(binding = 2) uniform sampler2D displacementTexture;
uniform float displacementCoefficient;
uniform mat4 MVP; uniform mat4 MVP;
uniform mat4 MV; uniform mat4 MV;
uniform mat4 MVnormal; uniform mat4 MVnormal;
uniform float shininess;
uniform bool isIlluminated; uniform bool isIlluminated;
uniform bool isTextured; uniform bool isTextured;
uniform bool isNormalMapped; uniform bool isNormalMapped;
uniform bool isDisplacementMapped;
uniform bool isInverted; uniform bool isInverted;
// lights // lights
struct Light { // coordinates in MV space struct Light { // point lights, coordinates in MV space
vec3 position; 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 bool is_spot; // false means point light
vec3 spot_target;
float spot_cuttof_angle;
}; };
//named #define N_LIGHTS 1
#define N_LIGHTS 3
uniform Light light[N_LIGHTS]; uniform Light light[N_LIGHTS];
out vec4 color; 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); vec4 phong(vec4 basecolor) {
vec3 nnormal; // normalized normal
void main_(vec4 basecolor) {
vec3 nnormal;
if (isNormalMapped) { if (isNormalMapped) {
vec3 tangential = texture(normalTexture, UV).rgb * 2.0 - 1.0; vec3 tangential = texture(normalTexture, UV).rgb * 2.0 - 1.0;
nnormal = TBN * -normalize(tangential); nnormal = TBN * normalize(tangential);
} else { }
else {
nnormal = normalize(normal); nnormal = normalize(normal);
} }
float diffuse_intensity = 0.0; vec3 emmissive_component = vec3(0.0);
float specular_intensity = 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<N_LIGHTS; i++) {
vec3 L = light[i].position - vertex; vec3 L = light[i].position - vertex;
float l = length(L); float l = length(L);
float attenuation = clamp(2000/(1 + 1*l + 0.1*l*l), 0.0, 1.25);
L = normalize(L); L = normalize(L);
if (light[i].is_spot) { if (light[i].is_spot) {
vec3 L2 = normalize(light[i].position - light[i].spot_target); if (dot(normalize(light[i].position - light[i].spot_target), L) < light[i].spot_cuttof_angle) {
if (dot(L2, L) < spot_cuttof_angle) {
continue; continue;
} }
attenuation *= 30;
} }
float attenuation = clamp(1 / (
light[i].attenuation.x +
light[i].attenuation.y * l +
light[i].attenuation.z * l * l
), 0.0, 1.25);
float diffuse_i = dot(nnormal, L); float diffuse_i = dot(nnormal, L);
float specular_i = pow(dot(reflect(-L, nnormal), normalize(-vertex)), shininess);
float specular_i = pow(dot(reflect(-L, nnormal), normalize(vec3(0,0,0) - vertex)), shininess); 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;
if (diffuse_i > 0) diffuse_intensity += attenuation*diffuse_i;
if (specular_i > 0) specular_intensity += attenuation*specular_i;
} }
//diffuse_intensity *= 1.0 / N_LIGHTS; return vec4(basecolor.rgb * (emmissive_component + diffuse_component) + specular_component, basecolor.a);
//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);
} }
void main() { void main() {
if(isIlluminated) { if(isIlluminated) {
if (isTextured) { if (isTextured) {
c_diffuse = vec3(0.9); color = phong(texture(diffuseTexture, UV));
c_emissive = vec3(0.2);
main_(texture(diffuseTexture, UV));
} else { } else {
main_(vec4(1.0)); color = phong(vec4(1.0));
} }
} else { } else {
color = texture(diffuseTexture, UV); color = texture(diffuseTexture, UV);

View File

@ -6,6 +6,9 @@ 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;
layout(binding = 2) uniform sampler2D displacementTexture;
uniform float displacementCoefficient;
uniform mat4 MVP; uniform mat4 MVP;
uniform mat4 MV; uniform mat4 MV;
uniform mat4 MVnormal; uniform mat4 MVnormal;
@ -13,8 +16,8 @@ uniform bool isIlluminated;
uniform bool isTextured; uniform bool isTextured;
uniform bool isNormalMapped; uniform bool isNormalMapped;
out layout(location = 0) vec3 normal_out; out layout(location = 0) vec3 vertex_out;
out layout(location = 1) vec3 vertex_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) mat3 TBN;

View File

@ -39,7 +39,8 @@ SceneNode* padNode;
SceneNode* hudNode; SceneNode* hudNode;
SceneNode* textNode; 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 // These are heap allocated, because they should not be initialised at the start of the program
sf::Sound* sound; sf::Sound* sound;
@ -122,7 +123,7 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) {
plainNode->setTexture(&t_plain_diff, &t_plain_normal); plainNode->setTexture(&t_plain_diff, &t_plain_normal);
// add lights // add lights
for (int i = 0; i<3; i++) { for (uint i = 0; i<N_LIGHTS; i++) {
lightNode[i] = createSceneNode(POINT_LIGHT); lightNode[i] = createSceneNode(POINT_LIGHT);
lightNode[i]->lightID = i; lightNode[i]->lightID = i;
} }
@ -151,8 +152,6 @@ void updateNodeTransformations(SceneNode* node, mat4 transformationThusFar, mat4
mat4 transformationMatrix(1.0); mat4 transformationMatrix(1.0);
switch(node->nodeType) { switch(node->nodeType) {
case NORMAL_TEXTURED_GEOMETRY:
case TEXTURED_GEOMETRY:
case GEOMETRY: case GEOMETRY:
transformationMatrix = transformationMatrix =
glm::translate(mat4(1.0), node->position) 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) { 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;
vec3 spot_target; vec3 spot_target;
bool is_spot; 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) { 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)
glUniform3fv (l(position) , 1, glm::value_ptr(position)); glUniform1i (l(is_spot) , is_spot);
glUniform3fv (l(spot_target), 1, glm::value_ptr(spot_target)); glUniform1f (l(spot_cuttof_angle), spot_cuttof_angle);
glUniform1i (l(is_spot) , is_spot); 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 #undef l
} }
}; };
static Light lights[3]; static Light lights[N_LIGHTS];
static Gloom::Shader* s = nullptr; // The currently active shader static Gloom::Shader* s = nullptr; // The currently active shader
// activate the correct 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++); 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) { 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: case GEOMETRY:
if(node->vertexArrayObjectID != -1) { if(node->vertexArrayObjectID != -1) {
glUniform1ui(s->location("isIlluminated"), node->isIlluminated); // load uniforms
glUniform1ui(s->location("isInverted"), node->isInverted); 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); glBindVertexArray(node->vertexArrayObjectID);
glDrawElements(GL_TRIANGLES, node->VAOIndexCount, GL_UNSIGNED_INT, nullptr); 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 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 * glm::vec4(node->position, 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;
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); lights[id].push_to_shader(s, id);
break; break;
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <assert.h>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@ -22,7 +23,9 @@ using std::vector;
typedef unsigned int uint; typedef unsigned int uint;
enum SceneNodeType { enum SceneNodeType {
GEOMETRY, POINT_LIGHT, SPOT_LIGHT, TEXTURED_GEOMETRY, NORMAL_TEXTURED_GEOMETRY GEOMETRY,
POINT_LIGHT,
SPOT_LIGHT,
}; };
struct SceneNode { struct SceneNode {
@ -34,58 +37,84 @@ struct SceneNode {
static map<Mesh*, int> cache; static map<Mesh*, int> cache;
if (cache.find(mesh) == cache.end()) if (cache.find(mesh) == cache.end())
cache[mesh] = generateBuffer(*mesh, nodeType==NORMAL_TEXTURED_GEOMETRY); cache[mesh] = generateBuffer(*mesh, isNormalMapped || isDisplacementMapped);
vertexArrayObjectID = cache[mesh]; vertexArrayObjectID = cache[mesh];
VAOIndexCount = mesh->indices.size(); VAOIndexCount = mesh->indices.size();
} }
void setTexture(PNGImage* diffuse, PNGImage* normal = nullptr) { void setTexture(PNGImage* diffuse, PNGImage* normal=nullptr, PNGImage* displacement=nullptr) {
static map<PNGImage*, int> cache; static map<PNGImage*, int> cache;
assert(vertexArrayObjectID==-1);
if (cache.find(diffuse) == cache.end()) cache[diffuse] = generateTexture(*diffuse); if (diffuse) {
diffuseTextureID = cache[diffuse]; if (cache.find(diffuse) == cache.end())
cache[diffuse] = generateTexture(*diffuse);
diffuseTextureID = cache[diffuse];
isTextured = true;
}
if (!normal) return; if (normal) {
if (cache.find(normal) == cache.end()) cache[normal] = generateTexture(*normal); if (cache.find(normal) == cache.end())
normalTextureID = cache[normal]; 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<SceneNode*> children; vector<SceneNode*> 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 // The node's position and rotation relative to its parent
vec3 position = vec3(0, 0, 0); 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); vec3 scale = vec3(1, 1, 1);
vec3 referencePoint = vec3(0, 0, 0); // center of rotation, in model space
// 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);
// VAO IDs refering to a loaded Mesh and its length // VAO IDs refering to a loaded Mesh and its length
int vertexArrayObjectID = -1; int vertexArrayObjectID = -1;
uint VAOIndexCount = 0; uint VAOIndexCount = 0;
// textures // textures
float shinyness = 10.0; // specular power
uint diffuseTextureID; uint diffuseTextureID;
uint normalTextureID; uint normalTextureID;
uint displacementTextureID;
float displacementCoefficient = 0.1; // in units
// shader flags // shader flags
bool isTextured = false;
bool isNormalMapped = false;
bool isDisplacementMapped = false;
bool isIlluminated = true; bool isIlluminated = true;
bool isInverted = false; bool isInverted = false;
// Node type is used to determine how to handle the contents of a node // rendering
SceneNodeType nodeType; 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 // Struct for keeping track of 2D coordinates

View File

@ -64,7 +64,7 @@ void addTangents(uint vaoID, Mesh& mesh) {
vec2 deltaUV1 = uv2 - uv1; vec2 deltaUV1 = uv2 - uv1;
vec2 deltaUV2 = uv3 - 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{ vec3 tangent{
f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x), f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x),