I’m a noob regarding shaders, so I’d like to make sure I’m getting the right conclusions out of my learning. Is this a correct glsl shader for simple lighting? And for normal mapping?
Are there any mistakes? Or obvious improvements?
Thanks.
vertex shader
#version 460
uniform mat4 u_MVPMatrix;
uniform mat3 u_NormalMatrix;
in vec3 a_VertexPosition;
in vec2 a_VertexTextureCoordinates;
in vec3 a_VertexNormal;
out vec3 v_FragPosition;
out vec2 v_TextureCoordinates;
out vec3 v_Normal;
void main()
{
gl_Position = u_MVPMatrix * vec4 ( a_VertexPosition, 1.0 );
v_FragPosition = a_VertexPosition;
v_TextureCoordinates = a_VertexTextureCoordinates;
v_Normal = u_NormalMatrix * normalize ( a_VertexNormal );
}
Fragment shader
#version 460
out vec4 FragOutput;
uniform vec3 u_ViewPosition;
in vec3 v_Normal;
in vec3 v_FragPosition;
in vec2 v_TextureCoordinates;
uniform sampler2D u_DiffuseTexture;
struct AmbientLightData
{
vec3 Color;
float Intensity;
};
struct PointLightData
{
vec4 Position;
vec4 Diffuse, Specular;
float Intensity;
float ConstantAttenuation;
float LinearAttenuation;
float ExponentialAttenuation;
};
layout ( std140 ) uniform u_LightData
{
AmbientLightData AmbientLight;
PointLightData PointLights[8];
int PointLightCount;
} LightData;
void main()
{
vec4 InputDiffuse = texture (u_DiffuseTexture, v_TextureCoordinates);
vec4 InputSpecular = InputDiffuse;
float InputShininess = 0.8;
vec3 InputNormal = v_Normal;
vec3 ViewPosToFrag = u_ViewPosition - v_FragPosition;
vec3 TotalPointLightContribution = vec3(0);
for ( int PointLightIndex = 0; PointLightIndex < LightData.PointLightCount; ++PointLightIndex )
{
vec3 LightPosToFrag = LightData.PointLights[PointLightIndex].Position.xyz - v_FragPosition;
// attenuation
float Distance = length ( LightPosToFrag ); // Light to fragment vector
float Attenuation = LightData.PointLights[PointLightIndex].ConstantAttenuation + LightData.PointLights[PointLightIndex].LinearAttenuation * Distance + LightData.PointLights[PointLightIndex].ExponentialAttenuation * pow ( Distance, 2.0f );
// diffuse
vec3 NormalizedLightPosToFrag = normalize ( LightPosToFrag );// normalize, and use just the direction
float DiffuseComponent = max ( dot ( InputNormal, NormalizedLightPosToFrag ), 0.0 ); // Calculate dot product on the angle between the two vectors, and make it positive
// specular
vec3 NormalizedViewPosToFrag = normalize ( ViewPosToFrag );
vec3 HalfwayDir = normalize ( NormalizedLightPosToFrag + NormalizedViewPosToFrag );
float SpecularComponent = pow ( max ( dot ( InputNormal, HalfwayDir ), 0.0 ), InputShininess );
// add it all together
vec3 DiffuseContribution = DiffuseComponent * LightData.PointLights[PointLightIndex].Diffuse.xyz * InputDiffuse.xyz * LightData.PointLights[PointLightIndex].Intensity;
vec3 SpecularContribution = SpecularComponent * LightData.PointLights[PointLightIndex].Specular.xyz * InputSpecular.xyz * LightData.PointLights[PointLightIndex].Intensity;
DiffuseContribution /= Attenuation;
SpecularContribution /= Attenuation;
TotalPointLightContribution += DiffuseContribution + SpecularContribution;
}
// Ambient light is calculated here, so it only adds once to the fragment, instead of once every light
vec3 AmbientLightContribution = LightData.AmbientLight.Color * LightData.AmbientLight.Intensity * InputDiffuse.xyz;
FragOutput = vec4 ( TotalPointLightContribution + AmbientLightContribution, InputDiffuse.a);
}
and then, for normal mapping…
vertex shader
#version 460
uniform mat4 u_MVPMatrix;
uniform mat4 u_ModelMatrix;
uniform mat3 u_NormalMatrix;
in vec3 a_VertexPosition;
in vec2 a_VertexTextureCoordinates;
in vec3 a_VertexNormal;
in vec3 a_VertexTangent;
out vec3 v_FragPosition;
out vec2 v_TextureCoordinates;
out vec3 v_Normal;
out mat3 v_TBN;
void main()
{
gl_Position = u_MVPMatrix * vec4 ( a_VertexPosition, 1.0 );
vec3 T = normalize(u_NormalMatrix * a_VertexTangent);
vec3 N = normalize(u_NormalMatrix * a_VertexNormal);
T = normalize(T - dot(T, N) * N);
vec3 B = cross(N, T);
v_TBN = transpose(mat3(T, B, N));
v_FragPosition = a_VertexPosition;
v_TextureCoordinates = a_VertexTextureCoordinates;
v_Normal = normalize ( a_VertexNormal );
}
and fragment shader
#version 460
out vec4 FragOutput;
uniform vec3 u_ViewPosition;
in vec3 v_FragPosition;
in vec2 v_TextureCoordinates;
in vec3 v_Normal;
in mat3 v_TBN;
uniform sampler2D u_DiffuseTexture, u_NormalTexture;
struct AmbientLightData
{
vec3 Color;
float Intensity;
};
struct PointLightData
{
vec4 Position;
vec4 Diffuse, Specular;
float Intensity;
float ConstantAttenuation;
float LinearAttenuation;
float ExponentialAttenuation;
};
layout ( std140 ) uniform u_LightData
{
AmbientLightData AmbientLight;
PointLightData PointLights[8];
int PointLightCount;
} LightData;
void main()
{
vec4 InputDiffuse = texture (u_DiffuseTexture, v_TextureCoordinates);
vec4 InputSpecular = InputDiffuse;
float InputShininess = 0.8;
vec3 InputNormal = texture ( u_NormalTexture, v_TextureCoordinates ).rgb;
// transform normal vector to range [-1,1]
InputNormal = normalize(InputNormal * 2.0 - 1.0);
vec3 TangentFragPos = v_TBN * v_FragPosition;
vec3 TangentViewToFrag = (v_TBN * u_ViewPosition) - TangentFragPos;
vec3 TotalPointLightContribution = vec3(0);
for ( int PointLightIndex = 0; PointLightIndex < LightData.PointLightCount; ++PointLightIndex )
{
vec3 TangentLightPos = v_TBN * LightData.PointLights[PointLightIndex].Position.xyz;
vec3 TangentLightPosToFrag = TangentLightPos - TangentFragPos;
// attenuation
float Distance = length ( TangentLightPosToFrag ); // Light to fragment vector
float Attenuation = LightData.PointLights[PointLightIndex].ConstantAttenuation + LightData.PointLights[PointLightIndex].LinearAttenuation * Distance + LightData.PointLights[PointLightIndex].ExponentialAttenuation * pow ( Distance, 2.0f );
// diffuse
vec3 NormalizedTangentLightPosToFrag = normalize ( TangentLightPosToFrag );// normalize, and use just the direction
float DiffuseComponent = max ( dot ( InputNormal, NormalizedTangentLightPosToFrag ), 0.0 ); // Calculate dot product on the angle between the two vectors, and make it positive
// specular
vec3 NormalizedTangentViewToFrag = normalize ( TangentViewToFrag );
vec3 HalfwayDir = normalize ( NormalizedTangentLightPosToFrag + NormalizedTangentViewToFrag );
float SpecularComponent = pow ( max ( dot ( InputNormal, HalfwayDir ), 0.0 ), InputShininess );
// add it all together
vec3 DiffuseContribution = DiffuseComponent * LightData.PointLights[PointLightIndex].Diffuse.xyz * InputDiffuse.xyz * LightData.PointLights[PointLightIndex].Intensity;
vec3 SpecularContribution = SpecularComponent * LightData.PointLights[PointLightIndex].Specular.xyz * InputSpecular.xyz * LightData.PointLights[PointLightIndex].Intensity;
DiffuseContribution /= Attenuation;
SpecularContribution /= Attenuation;
TotalPointLightContribution += DiffuseContribution + SpecularContribution;
}
// Ambient light is calculated here, so it only adds once to the fragment, instead of once every light
vec3 AmbientLightContribution = LightData.AmbientLight.Color * LightData.AmbientLight.Intensity * InputDiffuse.xyz;
FragOutput = vec4 ( TotalPointLightContribution + AmbientLightContribution, InputDiffuse.a);
}