From e4d425a9153fa8e6f5c5f5852a5b440bfc661fa4 Mon Sep 17 00:00:00 2001 From: Eikthyrnir Date: Fri, 12 Jan 2024 14:49:53 +0100 Subject: [PATCH] tangent space light for all objects --- cw 7/shaders/shader_5_1_tex.frag | 1 - cw 7/shaders/shader_5_1_tex.vert | 1 + cw 7/shaders/shader_earth.frag | 56 +++++++++++++---------- cw 7/shaders/shader_earth.vert | 41 ++++++++++++++--- cw 7/shaders/shader_proc_tex.frag | 75 ++++++++++++++++++------------- cw 7/shaders/shader_proc_tex.vert | 41 ++++++++++++++--- cw 7/src/ex_7_1.hpp | 18 ++++++-- 7 files changed, 163 insertions(+), 70 deletions(-) diff --git a/cw 7/shaders/shader_5_1_tex.frag b/cw 7/shaders/shader_5_1_tex.frag index ed5ec4f..07e79a9 100644 --- a/cw 7/shaders/shader_5_1_tex.frag +++ b/cw 7/shaders/shader_5_1_tex.frag @@ -18,7 +18,6 @@ uniform float reflectorAngle; uniform float reflectorLightExp; vec3 normalizedVertexNormal; -mat3 TBN; in vec3 vertexPosWld; in vec2 vertexTexCoordOut; diff --git a/cw 7/shaders/shader_5_1_tex.vert b/cw 7/shaders/shader_5_1_tex.vert index 8f42751..54d646a 100644 --- a/cw 7/shaders/shader_5_1_tex.vert +++ b/cw 7/shaders/shader_5_1_tex.vert @@ -32,6 +32,7 @@ void main() //`lightPos - vertexPos` from tutorial is wrong? //TODO why should we normalize here if we would normalize Tangent Space vectors later? + // and why do it here, mb fragment shader? vec3 sunLightDir = normalize(vertexPosWld - sunPos); vec3 reflectorLightDir = normalize(vertexPosWld - reflectorPos); vec3 viewDir = normalize(cameraPos - vertexPosWld); diff --git a/cw 7/shaders/shader_earth.frag b/cw 7/shaders/shader_earth.frag index d3d96fc..0016977 100644 --- a/cw 7/shaders/shader_earth.frag +++ b/cw 7/shaders/shader_earth.frag @@ -2,6 +2,7 @@ uniform sampler2D colorTexture; uniform sampler2D clouds; +uniform sampler2D normalSampler; uniform vec3 sunPos; uniform vec3 sunColor; @@ -18,40 +19,40 @@ uniform float reflectorLightExp; vec3 normalizedVertexNormal; -in vec3 vertexNormalOut; -in vec3 vertexPosOut; +in vec3 vertexPosWld; in vec2 vertexTexCoordOut; +in vec3 viewDirTS; +in vec3 sunLightDirTS; +in vec3 reflectorLightDirTS; out vec4 outColor; -vec4 calcPointLight(vec3 fragColor, vec3 lightPos, vec3 lightColor, float lightExp) { - vec3 lightDir = normalize(vertexPosOut - lightPos); - float lightDistance = length(vertexPosOut - lightPos); +vec4 calcPointLight(vec3 fragColor, vec3 lightPos, vec3 lightDirTS, vec3 lightColor, float lightExp) { + float lightDistance = length(vertexPosWld - lightPos); vec3 newLightColor = lightColor / pow(lightDistance, 2); - float intensity = dot(normalizedVertexNormal, -lightDir); + float intensity = dot(normalizedVertexNormal, -lightDirTS); intensity = max(intensity, 0.0); - vec3 viewDir = normalize(cameraPos - vertexPosOut); - vec3 reflectDir = reflect(lightDir, normalizedVertexNormal); - + vec3 reflectDir = reflect(lightDirTS, normalizedVertexNormal); + float glossPow = 8; - float specular = pow(max(dot(viewDir, reflectDir), 0.0), glossPow); + float specular = pow(max(dot(viewDirTS, reflectDir), 0.0), glossPow); float diffuse = intensity; vec3 resultColor = newLightColor * (fragColor * diffuse + specular ); return vec4(1 - exp(-resultColor * lightExp), 1.0); } -vec4 calcSpotLight(vec3 fragColor, vec3 lightPos, vec3 lightColor, vec3 lightDir, - float innerCutOff, float outerCutOff, float lightExp) { - vec3 lightToFragDir = normalize(vertexPosOut - lightPos); - float angleCos = dot(lightToFragDir, lightDir); - float epsilon = cos(innerCutOff) - cos(outerCutOff); +vec4 calcSpotLight(vec3 fragColor, vec3 lightPos, vec3 lightDirTS, vec3 lightColor, float lightExp) { + vec3 reflectorLightDir = normalize(vertexPosWld - lightPos); + float angleCos = dot(reflectorLightDir, reflectorDir); + float reflectorOutAngle = reflectorAngle + radians(10); + float epsilon = cos(reflectorAngle) - cos(reflectorOutAngle); vec4 res = vec4(0, 0, 0, 1); - if (angleCos > cos(outerCutOff)) { - float intensity = clamp((angleCos - cos(outerCutOff)) / epsilon, 0.0, 1.0); - res = calcPointLight(fragColor, lightPos, lightColor, reflectorLightExp * intensity); + if (angleCos > cos(reflectorOutAngle)) { + float intensity = clamp((angleCos - cos(reflectorOutAngle)) / epsilon, 0.0, 1.0); + res = calcPointLight(fragColor, lightPos, lightDirTS, lightColor, lightExp * intensity); } return res; } @@ -62,13 +63,22 @@ void main() vec3 textureColor = texture2D(colorTexture, vertexTexCoordOut).rgb; vec3 cloudColor = texture2D(clouds, vertexTexCoordOut).rgb; - textureColor = mix(vec3(1), textureColor, cloudColor.r); + //disabled to prevent riffled clouds + //textureColor = mix(vec3(1), textureColor, cloudColor.r); - normalizedVertexNormal = normalize(vertexNormalOut); + //get normal from normal sampler + vec3 samplerNormal = texture2D(normalSampler, vertexTexCoordOut).xyz; + samplerNormal = 2 * samplerNormal - 1;//since sampler has values from [0, 1], but we want [-1, 1] + normalizedVertexNormal = normalize(samplerNormal);// to avoid potential precision problems in sampler texture - outColor = calcPointLight(textureColor, sunPos, sunColor, sunLightExp); + //Debug + //normalizedVertexNormal = vec3(0, 0, 1); - outColor += calcSpotLight(textureColor, reflectorPos, reflectorColor, reflectorDir, - reflectorAngle, reflectorAngle + radians(10), reflectorLightExp); + outColor = calcPointLight(textureColor, sunPos, sunLightDirTS, sunColor, sunLightExp); + + outColor += calcSpotLight(textureColor, reflectorPos, reflectorLightDirTS, reflectorColor, reflectorLightExp); + + //Debug + //outColor = vec4(textureColor, 1); } \ No newline at end of file diff --git a/cw 7/shaders/shader_earth.vert b/cw 7/shaders/shader_earth.vert index 954b887..f989df1 100644 --- a/cw 7/shaders/shader_earth.vert +++ b/cw 7/shaders/shader_earth.vert @@ -3,20 +3,49 @@ layout(location = 0) in vec3 vertexPosition; layout(location = 1) in vec3 vertexNormal; layout(location = 2) in vec2 vertexTexCoord; +layout(location = 3) in vec3 vertexTangent; +layout(location = 4) in vec3 vertexBitangent; uniform mat4 transformation; uniform mat4 modelMat; -out vec3 vertexNormalOut; -out vec3 vertexPosOut; +uniform vec3 cameraPos; +uniform vec3 sunPos; +uniform vec3 reflectorPos; + +out vec3 vertexPosWld; out vec2 vertexTexCoordOut; +out vec3 viewDirTS; +out vec3 sunLightDirTS; +out vec3 reflectorLightDirTS; void main() { gl_Position = transformation * vec4(vertexPosition, 1.0); - vec4 worldNormal = modelMat * vec4(vertexNormal, 0.0); - vertexNormalOut = worldNormal.xyz; - vertexPosOut = (modelMat * vec4(vertexPosition, 1.0)).xyz; + vec3 normal = (modelMat * vec4(vertexNormal, 0.0)).xyz; + vec3 tangent = (modelMat * vec4(vertexTangent, 0.0)).xyz; + vec3 bitangent = (modelMat * vec4(vertexBitangent, 0.0)).xyz; + vertexPosWld = (modelMat * vec4(vertexPosition, 1.0)).xyz; vertexTexCoordOut = vertexTexCoord; vertexTexCoordOut.y = 1 - vertexTexCoord.y;// corrects inversion (bottom at top) of the earth -} \ No newline at end of file + + mat3 TBN = transpose(mat3(tangent, bitangent, normal)); + + //`lightPos - vertexPos` from tutorial is wrong? + //TODO why should we normalize here if we would normalize Tangent Space vectors later? + // and why do it here, mb fragment shader? + vec3 sunLightDir = normalize(vertexPosWld - sunPos); + vec3 reflectorLightDir = normalize(vertexPosWld - reflectorPos); + vec3 viewDir = normalize(cameraPos - vertexPosWld); + + // tangent space + viewDirTS = TBN * viewDir; + sunLightDirTS = TBN * sunLightDir; + reflectorLightDirTS = TBN * reflectorLightDir; + + //TODO should normilize here or in the fragment shader? + viewDirTS = normalize(viewDirTS); + sunLightDirTS = normalize(sunLightDirTS); + reflectorLightDirTS = normalize(reflectorLightDirTS); +} + diff --git a/cw 7/shaders/shader_proc_tex.frag b/cw 7/shaders/shader_proc_tex.frag index 09634a6..4d550ef 100644 --- a/cw 7/shaders/shader_proc_tex.frag +++ b/cw 7/shaders/shader_proc_tex.frag @@ -3,6 +3,8 @@ uniform sampler2D colorTexture; uniform sampler2D rust; uniform sampler2D scratches; +uniform sampler2D shipNormalSampler; +uniform sampler2D rustNormalSampler; uniform vec3 sunPos; uniform vec3 sunColor; @@ -18,69 +20,82 @@ uniform float reflectorAngle; uniform float reflectorLightExp; vec3 normalizedVertexNormal; +vec3 scratchesColor; -in vec3 vertexNormalOut; -in vec3 vertexPosOut; +in vec3 vertexPosWld; in vec2 vertexTexCoordOut; +in vec3 viewDirTS; +in vec3 sunLightDirTS; +in vec3 reflectorLightDirTS; in vec3 vertexLocPos; out vec4 outColor; -vec4 calcPointLight(vec3 fragColor, vec3 lightPos, vec3 lightColor, float lightExp) { - vec3 lightDir = normalize(vertexPosOut - lightPos); - float lightDistance = length(vertexPosOut - lightPos); +vec4 calcPointLight(vec3 fragColor, vec3 lightPos, vec3 lightDirTS, vec3 lightColor, float lightExp) { + float lightDistance = length(vertexPosWld - lightPos); vec3 newLightColor = lightColor / pow(lightDistance, 2); - float intensity = dot(normalizedVertexNormal, -lightDir); + float intensity = dot(normalizedVertexNormal, -lightDirTS); intensity = max(intensity, 0.0); - vec3 viewDir = normalize(cameraPos - vertexPosOut); - vec3 reflectDir = reflect(lightDir, normalizedVertexNormal); - + vec3 reflectDir = reflect(lightDirTS, normalizedVertexNormal); + float glossPow = 8; - float specular = pow(max(dot(viewDir, reflectDir), 0.0), glossPow); + float specular = pow(max(dot(viewDirTS, reflectDir), 0.0), glossPow); float diffuse = intensity; vec3 resultColor = newLightColor * (fragColor * diffuse + specular ); return vec4(1 - exp(-resultColor * lightExp), 1.0); } -vec4 calcSpotLight(vec3 fragColor, vec3 lightPos, vec3 lightColor, vec3 lightDir, float lightExp) { - vec3 reflectorLightDir = normalize(vertexPosOut - reflectorPos); +vec4 calcSpotLight(vec3 fragColor, vec3 lightPos, vec3 lightDirTS, vec3 lightColor, float lightExp) { + vec3 reflectorLightDir = normalize(vertexPosWld - lightPos); float angleCos = dot(reflectorLightDir, reflectorDir); float reflectorOutAngle = reflectorAngle + radians(10); float epsilon = cos(reflectorAngle) - cos(reflectorOutAngle); vec4 res = vec4(0, 0, 0, 1); if (angleCos > cos(reflectorOutAngle)) { float intensity = clamp((angleCos - cos(reflectorOutAngle)) / epsilon, 0.0, 1.0); - res = calcPointLight(fragColor, reflectorPos, reflectorColor, reflectorLightExp * intensity); + res = calcPointLight(fragColor, lightPos, lightDirTS, lightColor, lightExp * intensity); } return res; } - -void main() -{ +vec3 calcShipColor() { vec3 shipColor = texture2D(colorTexture, vertexTexCoordOut).rgb; vec3 rustColor = texture2D(rust, vertexTexCoordOut).rgb; - vec3 scratchesColor = texture2D(scratches, vertexTexCoordOut).rgb; - vec3 textureColor = mix(rustColor, shipColor, scratchesColor .r); + vec3 textureColor = mix(rustColor, shipColor, scratchesColor.r); if (sin(vertexLocPos.y * vertexLocPos.x * vertexLocPos.z) > 0) { textureColor = vec3(1, 0, 0); } - - normalizedVertexNormal = normalize(vertexNormalOut); - outColor = calcPointLight(textureColor, sunPos, sunColor, sunLightExp); - - vec3 reflectorLightDir = normalize(vertexPosOut - reflectorPos); - float angleCos = dot(reflectorLightDir, reflectorDir); - float reflectorOutAngle = reflectorAngle + radians(10); - float epsilon = cos(reflectorAngle) - cos(reflectorOutAngle); - if (angleCos > cos(reflectorOutAngle)) { - float intensity = clamp((angleCos - cos(reflectorOutAngle)) / epsilon, 0.0, 1.0); - outColor += calcSpotLight(textureColor, reflectorPos, reflectorColor, reflectorLightDir, reflectorLightExp * intensity); - } + return textureColor; +} + +vec3 calcShipNormal() { + vec3 shipNormal = texture2D(shipNormalSampler, vertexTexCoordOut).xyz; + shipNormal = 2 * shipNormal - 1;//since sampler has values from [0, 1], but we want [-1, 1] + vec3 rustNormal = texture2D(rustNormalSampler, vertexTexCoordOut).xyz; + rustNormal = 2 * rustNormal - 1;//since sampler has values from [0, 1], but we want [-1, 1] + //normalize to avoid potential precision problems in sampler texture + return normalize(mix(rustNormal, shipNormal, scratchesColor.r)); +} + +void main() +{ + scratchesColor = texture2D(scratches, vertexTexCoordOut).rgb; + vec3 textureColor = calcShipColor(); + + normalizedVertexNormal = calcShipNormal(); + //Debug + //normalizedVertexNormal = vec3(0, 0, 1); + + outColor = calcPointLight(textureColor, sunPos, sunLightDirTS, sunColor, sunLightExp); + + outColor += calcSpotLight(textureColor, reflectorPos, reflectorLightDirTS, reflectorColor, reflectorLightExp); + + //Debug + //outColor = vec4(textureColor, 1); } diff --git a/cw 7/shaders/shader_proc_tex.vert b/cw 7/shaders/shader_proc_tex.vert index f42775b..22707f4 100644 --- a/cw 7/shaders/shader_proc_tex.vert +++ b/cw 7/shaders/shader_proc_tex.vert @@ -3,21 +3,50 @@ layout(location = 0) in vec3 vertexPosition; layout(location = 1) in vec3 vertexNormal; layout(location = 2) in vec2 vertexTexCoord; +layout(location = 3) in vec3 vertexTangent; +layout(location = 4) in vec3 vertexBitangent; uniform mat4 transformation; uniform mat4 modelMat; -out vec3 vertexNormalOut; -out vec3 vertexPosOut; -out vec2 vertexTexCoordOut; +uniform vec3 cameraPos; +uniform vec3 sunPos; +uniform vec3 reflectorPos; + +out vec3 vertexPosWld; out vec3 vertexLocPos; +out vec2 vertexTexCoordOut; +out vec3 viewDirTS; +out vec3 sunLightDirTS; +out vec3 reflectorLightDirTS; void main() { gl_Position = transformation * vec4(vertexPosition, 1.0); - vec4 worldNormal = modelMat * vec4(vertexNormal, 0.0); - vertexNormalOut = worldNormal.xyz; - vertexPosOut = (modelMat * vec4(vertexPosition, 1.0)).xyz; + vec3 normal = (modelMat * vec4(vertexNormal, 0.0)).xyz; + vec3 tangent = (modelMat * vec4(vertexTangent, 0.0)).xyz; + vec3 bitangent = (modelMat * vec4(vertexBitangent, 0.0)).xyz; + vertexPosWld = (modelMat * vec4(vertexPosition, 1.0)).xyz; vertexTexCoordOut = vertexTexCoord; + vertexLocPos = vertexPosition; + + mat3 TBN = transpose(mat3(tangent, bitangent, normal)); + + //`lightPos - vertexPos` from tutorial is wrong? + //TODO why should we normalize here if we would normalize Tangent Space vectors later? + // and why do it here, mb fragment shader? + vec3 sunLightDir = normalize(vertexPosWld - sunPos); + vec3 reflectorLightDir = normalize(vertexPosWld - reflectorPos); + vec3 viewDir = normalize(cameraPos - vertexPosWld); + + // tangent space + viewDirTS = TBN * viewDir; + sunLightDirTS = TBN * sunLightDir; + reflectorLightDirTS = TBN * reflectorLightDir; + + //TODO should normilize here or in the fragment shader? + viewDirTS = normalize(viewDirTS); + sunLightDirTS = normalize(sunLightDirTS); + reflectorLightDirTS = normalize(reflectorLightDirTS); } diff --git a/cw 7/src/ex_7_1.hpp b/cw 7/src/ex_7_1.hpp index 0b73c62..dda43ab 100644 --- a/cw 7/src/ex_7_1.hpp +++ b/cw 7/src/ex_7_1.hpp @@ -25,8 +25,10 @@ namespace texture { GLuint grid; GLuint earthNormal; + GLuint moonNormal; GLuint asteroidNormal; GLuint shipNormal; + GLuint rustNormal; GLuint cubemap; } @@ -143,12 +145,15 @@ void drawObjectColor(GLuint program, Core::RenderContext& context, glm::mat4 mod } void drawObjectProc(Core::RenderContext& context, glm::mat4 modelMatrix, glm::vec3 color) { - program = programProcTex; - + GLuint program = programProcTex; glUseProgram(program); + Core::SetActiveTexture(texture::ship, "colorTexture", program, 0); Core::SetActiveTexture(texture::rust, "rust", program, 1); Core::SetActiveTexture(texture::scratches, "scratches", program, 2); + Core::SetActiveTexture(texture::shipNormal, "shipNormalSampler", program, 3); + Core::SetActiveTexture(texture::rustNormal, "rustNormalSampler", program, 4); + glm::mat4 viewProjectionMatrix = createPerspectiveMatrix() * createCameraMatrix(); glm::mat4 transformation = viewProjectionMatrix * modelMatrix; glUniformMatrix4fv(glGetUniformLocation(program, "transformation"), 1, GL_FALSE, (float*)&transformation); @@ -173,9 +178,11 @@ void drawObjectProc(Core::RenderContext& context, glm::mat4 modelMatrix, glm::ve } -void drawObjectTexture(GLuint program, Core::RenderContext& context, glm::mat4 modelMatrix, GLuint textureId) { +void drawObjectTexture(GLuint program, Core::RenderContext& context, glm::mat4 modelMatrix, + GLuint textureId, GLuint normalsTextureId) { glUseProgram(program); Core::SetActiveTexture(textureId, "colorTexture", program, 0); + Core::SetActiveTexture(normalsTextureId, "normalSampler", program, 1); glm::mat4 viewProjectionMatrix = createPerspectiveMatrix() * createCameraMatrix(); glm::mat4 transformation = viewProjectionMatrix * modelMatrix; glUniformMatrix4fv(glGetUniformLocation(program, "transformation"), 1, GL_FALSE, (float*)&transformation); @@ -205,6 +212,7 @@ void drawEarth(Core::RenderContext& context, glm::mat4 modelMatrix) { glUseProgram(program); Core::SetActiveTexture(texture::earth, "colorTexture", program, 0); Core::SetActiveTexture(texture::clouds, "clouds", program, 1); + Core::SetActiveTexture(texture::earthNormal, "normalSampler", program, 2); glm::mat4 viewProjectionMatrix = createPerspectiveMatrix() * createCameraMatrix(); glm::mat4 transformation = viewProjectionMatrix * modelMatrix; glUniformMatrix4fv(glGetUniformLocation(program, "transformation"), 1, GL_FALSE, (float*)&transformation); @@ -266,7 +274,7 @@ void renderScene(GLFWwindow* window) drawObjectTexture(programTex, sphereContext, glm::eulerAngleY(time / 3) * glm::translate(glm::vec3(4.f, 0, 0)) * glm::eulerAngleY(time) * glm::translate(glm::vec3(1.f, 0, 0)) * glm::scale(glm::vec3(0.1f)), - texture::grid); + texture::grid, texture::moonNormal); glm::vec3 spaceshipSide = glm::normalize(glm::cross(spaceshipDir, glm::vec3(0.f, 1.f, 0.f))); glm::vec3 spaceshipUp = glm::normalize(glm::cross(spaceshipSide, spaceshipDir)); @@ -370,8 +378,10 @@ void init(GLFWwindow* window) texture::grid = Core::LoadTexture("./textures/grid_color.png"); texture::earthNormal = Core::LoadTexture("./textures/earth_normalmap.png"); + texture::moonNormal = Core::LoadTexture("./textures/moon_normal.jpg"); texture::asteroidNormal = Core::LoadTexture("./textures/rust_normal.jpg"); texture::shipNormal = Core::LoadTexture("./textures/spaceship_normalmap.jpg"); + texture::rustNormal = Core::LoadTexture("./textures/rust_normal.jpg"); init_cubemap(); }