From 32b480b2264c353f7554cfd50733b6880fcdf5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= <tomaszkax86@gmail.com> Date: Wed, 10 Feb 2016 23:38:49 +0100 Subject: [PATCH] Rewritten lighting in OpenGL 2.1 engine --- src/graphics/opengl/gl21device.cpp | 88 +++++++++++-------- src/graphics/opengl/gl21device.h | 28 +++++- .../shaders/fragment_shader_21_perpixel.glsl | 65 ++++++++------ .../shaders/fragment_shader_21_pervertex.glsl | 5 +- .../shaders/vertex_shader_21_pervertex.glsl | 64 ++++++++------ 5 files changed, 153 insertions(+), 97 deletions(-) diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index cf10607c..8a4fcd90 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -273,7 +273,11 @@ bool CGL21Device::Create() sprintf(filename, "shaders/vertex_shader_21_pervertex.glsl"); shaders[0] = LoadShader(GL_VERTEX_SHADER, filename); - if (shaders[0] == 0) return false; + if (shaders[0] == 0) + { + m_errorMessage = GetLastShaderError(); + return false; + } if (m_perPixelLighting) sprintf(filename, "shaders/fragment_shader_21_perpixel.glsl"); @@ -281,10 +285,18 @@ bool CGL21Device::Create() sprintf(filename, "shaders/fragment_shader_21_pervertex.glsl"); shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename); - if (shaders[1] == 0) return false; + if (shaders[1] == 0) + { + m_errorMessage = GetLastShaderError(); + return false; + } m_program = LinkProgram(2, shaders); - if (m_program == 0) return false; + if (m_program == 0) + { + m_errorMessage = GetLastShaderError(); + return false; + } glDeleteShader(shaders[0]); glDeleteShader(shaders[1]); @@ -318,11 +330,30 @@ bool CGL21Device::Create() uni_ShadowColor = glGetUniformLocation(m_program, "uni_ShadowColor"); uni_LightingEnabled = glGetUniformLocation(m_program, "uni_LightingEnabled"); + uni_AmbientColor = glGetUniformLocation(m_program, "uni_AmbientColor"); + uni_DiffuseColor = glGetUniformLocation(m_program, "uni_DiffuseColor"); + uni_SpecularColor = glGetUniformLocation(m_program, "uni_SpecularColor"); + + GLchar name[64]; for (int i = 0; i < 8; i++) { - char name[64]; - sprintf(name, "uni_LightEnabled[%d]", i); - uni_LightEnabled[i] = glGetUniformLocation(m_program, name); + sprintf(name, "uni_Light[%d].Enabled", i); + uni_Light[i].Enabled = glGetUniformLocation(m_program, name); + + sprintf(name, "uni_Light[%d].Position", i); + uni_Light[i].Position = glGetUniformLocation(m_program, name); + + sprintf(name, "uni_Light[%d].Ambient", i); + uni_Light[i].Ambient = glGetUniformLocation(m_program, name); + + sprintf(name, "uni_Light[%d].Diffuse", i); + uni_Light[i].Diffuse = glGetUniformLocation(m_program, name); + + sprintf(name, "uni_Light[%d].Specular", i); + uni_Light[i].Specular = glGetUniformLocation(m_program, name); + + sprintf(name, "uni_Light[%d].Attenuation", i); + uni_Light[i].Attenuation = glGetUniformLocation(m_program, name); } // Set default uniform values @@ -355,7 +386,7 @@ bool CGL21Device::Create() glUniform1i(uni_LightingEnabled, 0); for (int i = 0; i < 8; i++) - glUniform1i(uni_LightEnabled[i], 0); + glUniform1i(uni_Light[i].Enabled, 0); // create default framebuffer object FramebufferParams framebufferParams; @@ -485,9 +516,9 @@ void CGL21Device::SetMaterial(const Material &material) { m_material = material; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m_material.ambient.Array()); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m_material.diffuse.Array()); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m_material.specular.Array()); + glUniform4fv(uni_AmbientColor, 1, m_material.ambient.Array()); + glUniform4fv(uni_DiffuseColor, 1, m_material.diffuse.Array()); + glUniform4fv(uni_SpecularColor, 1, m_material.specular.Array()); } int CGL21Device::GetMaxLightCount() @@ -502,40 +533,21 @@ void CGL21Device::SetLight(int index, const Light &light) m_lights[index] = light; - // Indexing from GL_LIGHT0 should always work - glLightfv(GL_LIGHT0 + index, GL_AMBIENT, const_cast<GLfloat*>(light.ambient.Array())); - glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, const_cast<GLfloat*>(light.diffuse.Array())); - glLightfv(GL_LIGHT0 + index, GL_SPECULAR, const_cast<GLfloat*>(light.specular.Array())); + glUniform4fv(uni_Light[index].Ambient, 1, light.ambient.Array()); + glUniform4fv(uni_Light[index].Diffuse, 1, light.diffuse.Array()); + glUniform4fv(uni_Light[index].Specular, 1, light.specular.Array()); + glUniform3f(uni_Light[index].Attenuation, light.attenuation0, light.attenuation1, light.attenuation2); - glLightf(GL_LIGHT0 + index, GL_CONSTANT_ATTENUATION, light.attenuation0); - glLightf(GL_LIGHT0 + index, GL_LINEAR_ATTENUATION, light.attenuation1); - glLightf(GL_LIGHT0 + index, GL_QUADRATIC_ATTENUATION, light.attenuation2); - - if (light.type == LIGHT_SPOT) + if (light.type == LIGHT_DIRECTIONAL) { - glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, light.spotAngle * Math::RAD_TO_DEG); - glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, light.spotIntensity); + glUniform4f(uni_Light[index].Position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f); } else { - glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 180.0f); + glUniform4f(uni_Light[index].Position, light.position.x, light.position.y, light.position.z, 1.0f); } - if (light.type == LIGHT_SPOT) - { - GLfloat direction[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 1.0f }; - glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction); - } - else if (light.type == LIGHT_DIRECTIONAL) - { - GLfloat position[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 0.0f }; - glLightfv(GL_LIGHT0 + index, GL_POSITION, position); - } - else - { - GLfloat position[4] = { light.position.x, light.position.y, light.position.z, 1.0f }; - glLightfv(GL_LIGHT0 + index, GL_POSITION, position); - } + // TODO: add spotlight params } void CGL21Device::SetLightEnabled(int index, bool enabled) @@ -545,7 +557,7 @@ void CGL21Device::SetLightEnabled(int index, bool enabled) m_lightsEnabled[index] = enabled; - glUniform1i(uni_LightEnabled[index], enabled ? 1 : 0); + glUniform1i(uni_Light[index].Enabled, enabled ? 1 : 0); } /** If image is invalid, returns invalid texture. diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h index 5be94a5f..f2b3bc42 100644 --- a/src/graphics/opengl/gl21device.h +++ b/src/graphics/opengl/gl21device.h @@ -299,8 +299,32 @@ private: //! true enables lighting GLint uni_LightingEnabled = 0; - //! true enables light source - GLint uni_LightEnabled[8] = {}; + //! Ambient color + GLint uni_AmbientColor = 0; + //! Diffuse color + GLint uni_DiffuseColor = 0; + //! Specular color + GLint uni_SpecularColor = 0; + + struct LightUniforms + { + //! true enables light + GLint Enabled = 0; + //! Light type + GLint Type = 0; + //! Position or direction vector + GLint Position = 0; + //! Ambient color + GLint Ambient = 0; + //! Diffuse color + GLint Diffuse = 0; + //! Specular color + GLint Specular = 0; + //! Attenuation + GLint Attenuation = 0; + }; + + LightUniforms uni_Light[8]; }; diff --git a/src/graphics/opengl/shaders/fragment_shader_21_perpixel.glsl b/src/graphics/opengl/shaders/fragment_shader_21_perpixel.glsl index 8f1213a2..723fe055 100644 --- a/src/graphics/opengl/shaders/fragment_shader_21_perpixel.glsl +++ b/src/graphics/opengl/shaders/fragment_shader_21_perpixel.glsl @@ -34,8 +34,23 @@ uniform vec4 uni_FogColor; uniform float uni_ShadowColor; +struct LightParams +{ + bool Enabled; + vec4 Position; + vec4 Ambient; + vec4 Diffuse; + vec4 Specular; + float Shininess; + vec3 Attenuation; +}; + +uniform vec4 uni_AmbientColor; +uniform vec4 uni_DiffuseColor; +uniform vec4 uni_SpecularColor; + uniform bool uni_LightingEnabled; -uniform bool uni_LightEnabled[8]; +uniform LightParams uni_Light[8]; varying vec3 pass_Normal; varying vec3 pass_Position; @@ -51,46 +66,41 @@ void main() vec4 diffuse = vec4(0.0f); vec4 specular = vec4(0.0f); - vec3 normal = pass_Normal; + vec3 normal = (gl_FrontFacing ? pass_Normal : -pass_Normal); - for(int i=0; i<8; i++) + for (int i = 0; i < 8; i++) { - if(uni_LightEnabled[i]) + if (uni_Light[i].Enabled) { - vec3 lightDirection = vec3(0.0f); - float atten; + vec3 lightDirection = uni_Light[i].Position.xyz; + float atten = 1.0f; - // Directional light - if(gl_LightSource[i].position.w == 0.0f) - { - lightDirection = gl_LightSource[i].position.xyz; - atten = 1.0f; - } // Point light - else + if (abs(uni_Light[i].Position.w) > 1e-3f) { - vec3 lightDirection = normalize(gl_LightSource[i].position.xyz - pass_Position); - float dist = distance(gl_LightSource[i].position.xyz, pass_Position); + vec3 lightDirection = normalize(uni_Light[i].Position.xyz - pass_Position.xyz); + float dist = distance(uni_Light[i].Position.xyz, pass_Position.xyz); - atten = 1.0f / (gl_LightSource[i].constantAttenuation - + gl_LightSource[i].linearAttenuation * dist - + gl_LightSource[i].quadraticAttenuation * dist * dist); + vec3 lightAtten = uni_Light[i].Attenuation; + + atten = 1.0f / (lightAtten.x + + lightAtten.y * dist + + lightAtten.z * dist * dist); } vec3 reflectDirection = -reflect(lightDirection, normal); - ambient += gl_LightSource[i].ambient; - diffuse += atten * clamp(dot(normal, lightDirection), 0.0f, 1.0f) * gl_LightSource[i].diffuse; - specular += atten * clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) * gl_LightSource[i].specular; + ambient += uni_Light[i].Ambient; + diffuse += atten * clamp(dot(normal, lightDirection), 0.0f, 1.0f) * uni_Light[i].Diffuse; + specular += atten * clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) * uni_Light[i].Specular; } } - vec4 result = gl_FrontMaterial.ambient * ambient - + gl_FrontMaterial.diffuse * diffuse - + gl_FrontMaterial.specular * specular; + vec4 result = uni_AmbientColor * ambient + + uni_DiffuseColor * diffuse + + uni_SpecularColor * specular; - color.rgb = min(vec3(1.0f), result.rgb); - color.a = 1.0f; //min(1.0f, 1.0f); + color = vec4(min(vec3(1.0f), result.rgb), 1.0f); } if (uni_TextureEnabled[0]) @@ -105,7 +115,8 @@ void main() if (uni_TextureEnabled[2]) { - color = color * mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, gl_TexCoord[2].xyz).x); + if (gl_FrontFacing) + color.rgb *= mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, gl_TexCoord[2].xyz).x); } if (uni_FogEnabled) diff --git a/src/graphics/opengl/shaders/fragment_shader_21_pervertex.glsl b/src/graphics/opengl/shaders/fragment_shader_21_pervertex.glsl index 340fa862..7d965553 100644 --- a/src/graphics/opengl/shaders/fragment_shader_21_pervertex.glsl +++ b/src/graphics/opengl/shaders/fragment_shader_21_pervertex.glsl @@ -52,7 +52,10 @@ void main() if (uni_TextureEnabled[2]) { - color = color * mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, gl_TexCoord[2].xyz).x); + if (gl_FrontFacing) + color.rgb *= mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, gl_TexCoord[2].xyz).x); + else + color.rgb *= uni_ShadowColor; } if (uni_FogEnabled) diff --git a/src/graphics/opengl/shaders/vertex_shader_21_pervertex.glsl b/src/graphics/opengl/shaders/vertex_shader_21_pervertex.glsl index eee0c1eb..e2b93157 100644 --- a/src/graphics/opengl/shaders/vertex_shader_21_pervertex.glsl +++ b/src/graphics/opengl/shaders/vertex_shader_21_pervertex.glsl @@ -25,8 +25,23 @@ uniform mat4 uni_ModelMatrix; uniform mat4 uni_ShadowMatrix; uniform mat4 uni_NormalMatrix; +struct LightParams +{ + bool Enabled; + vec4 Position; + vec4 Ambient; + vec4 Diffuse; + vec4 Specular; + float Shininess; + vec3 Attenuation; +}; + +uniform vec4 uni_AmbientColor; +uniform vec4 uni_DiffuseColor; +uniform vec4 uni_SpecularColor; + uniform bool uni_LightingEnabled; -uniform bool uni_LightEnabled[8]; +uniform LightParams uni_Light[8]; varying float pass_Distance; @@ -44,53 +59,44 @@ void main() if (uni_LightingEnabled) { - vec4 color; vec4 ambient = vec4(0.0f); vec4 diffuse = vec4(0.0f); vec4 specular = vec4(0.0f); vec3 normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz); - for(int i=0; i<8; i++) + for (int i = 0; i < 8; i++) { - if(uni_LightEnabled[i]) + if (uni_Light[i].Enabled) { - vec3 lightDirection = vec3(0.0f); - float atten; + vec3 lightDirection = uni_Light[i].Position.xyz; + float atten = 1.0f; - // Directional light - if(gl_LightSource[i].position.w == 0.0f) - { - lightDirection = gl_LightSource[i].position.xyz; - atten = 1.0f; - } // Point light - else + if (abs(uni_Light[i].Position.w) > 1e-3f) { - vec3 lightDirection = normalize(gl_LightSource[i].position.xyz - position.xyz); - float dist = distance(gl_LightSource[i].position.xyz, position.xyz); + vec3 lightDirection = normalize(uni_Light[i].Position.xyz - position.xyz); + float dist = distance(uni_Light[i].Position.xyz, position.xyz); - atten = 1.0f / (gl_LightSource[i].constantAttenuation - + gl_LightSource[i].linearAttenuation * dist - + gl_LightSource[i].quadraticAttenuation * dist * dist); + vec3 lightAtten = uni_Light[i].Attenuation; + + atten = 1.0f / (lightAtten.x + + lightAtten.y * dist + + lightAtten.z * dist * dist); } vec3 reflectDirection = -reflect(lightDirection, normal); - ambient += gl_LightSource[i].ambient; - diffuse += atten * clamp(dot(normal, lightDirection), 0.0f, 1.0f) * gl_LightSource[i].diffuse; - specular += atten * clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) * gl_LightSource[i].specular; + ambient += uni_Light[i].Ambient; + diffuse += atten * clamp(dot(normal, lightDirection), 0.0f, 1.0f) * uni_Light[i].Diffuse; + specular += atten * clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f) * uni_Light[i].Specular; } } - vec4 result = gl_FrontMaterial.ambient * ambient - + gl_FrontMaterial.diffuse * diffuse - + gl_FrontMaterial.specular * specular; + vec4 result = uni_AmbientColor * ambient + + uni_DiffuseColor * diffuse + + uni_SpecularColor * specular; - color.rgb = min(vec3(1.0f), result.rgb); - color.a = 1.0f; //min(1.0f, 1.0f); - - gl_FrontColor = color; + gl_FrontColor = vec4(min(vec3(1.0f), result.rgb), 1.0f); } } -