So I have spent the last few days trying and failing to get this shadow mapping working. Basically all I am getting is a rendering of a mostly white scene albeit shaded via lighting so you can see all the objects, however there is no colour, no textures and most importantly no shadows. Colour and textures was working correctly before I started to implement this shadow mapping code. I suspect the problem lies in my shader code so I’ll post them here:
First is the vertex shader:
#version 450 core
uniform mat4 mv_Matrix; // ModelView Matrix
uniform mat4 mvp_Matrix; // ModelViewProjection Matrix
uniform mat3 normal_Matrix; // Normal Matrix
uniform mat4 shadow_Matrix; // *** NEW **** Shadow Matrix
in vec4 in_position;
in vec3 in_colour;
in vec3 in_normal;
in vec2 in_texcoord;
out vec4 out_position;
out vec3 out_colour;
out vec3 out_normal;
out vec2 out_texcoord;
out vec4 out_shadowcoord;
void main()
{
// Convert normal and vertex into eye-space coordinates
out_normal = normalize(normal_Matrix * in_normal);
out_position = mv_Matrix * in_position;
// Send the texture coordinates to the fragment shader
out_texcoord = in_texcoord;
// Send the input colour to the fragment shader
out_colour = in_colour;
// **** NEW **** Shadow Matrix converts from modelling coordinates to shadow map coordinates
out_shadowcoord = shadow_Matrix * in_position;
// Convert position to clip coordinates and pass to fragment shader
gl_Position = mvp_Matrix * in_position;
}
Fragment shader:
#version 450 core
struct LightInfo {
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec4 position;
vec4 halfVector;
};
struct MaterialInfo {
vec3 Ka; // Ambient reflectivity
vec3 Kd; // Diffuse reflectivity
vec3 Ks; // Specular reflectivity
float Shininess; // Specular shininess factor
};
struct FogInfo {
vec3 fog_colour; // Fog colour
float min_dist; // Minimum distance to fog start
float max_dist; // Maximum distance to fog end
};
uniform LightInfo Light; // Light properties
uniform MaterialInfo Material; // Material properties
uniform FogInfo Fog; // Fog properties
subroutine vec4 renderModelType();
subroutine uniform renderModelType RenderType;
subroutine void RenderPassType();
subroutine uniform RenderPassType RenderPass;
uniform sampler2D s_texture;
uniform sampler2DShadow Shadow_Map;
in vec4 out_position;
in vec3 out_colour;
in vec3 out_normal;
in vec2 out_texcoord;
in vec4 out_shadowcoord;
out vec4 frag_colour;
vec4 phongModel()
{
vec3 S;
if(Light.position.w == 0.0) {
S = normalize(vec3(Light.position)); // Directional light source
}
else {
S = normalize(vec3(Light.position - out_position)); // Positional light source
}
vec3 V = normalize(-out_position.xyz);
vec3 R = reflect(-S, out_normal);
//vec3 ambient = vec3(0.0, 1.0, 0.0) * Material.Ka;
vec3 ambient = Light.ambient * Material.Ka;
float sDotN = max(dot(S, out_normal), 0.0);
vec3 diffuse = Light.diffuse * Material.Kd * sDotN;
vec3 specular = vec3(0.0);
if(sDotN > 0.0) {
specular = Light.specular * Material.Ks * pow(max(dot(R,V), 0.0), Material.Shininess);
}
return vec4(ambient + diffuse + specular, 1.0);
}
vec4 GetLightColour()
{
if(gl_FrontFacing){ return phongModel(); }
else return vec4(0.0, 0.0, 0.0, 1.0);
}
subroutine(renderModelType)
vec4 ReturnObjectColour()
{
vec4 light_colour = GetLightColour();
return vec4(light_colour.rgb, 1.0);
}
subroutine(renderModelType)
vec4 ReturnTextureColour()
{
vec4 texture_colour = texture2D(s_texture, out_texcoord);
vec4 light_colour = GetLightColour();
// return vec4(out_colour * texture_colour.rgb, texture_colour.a); // Lighting disabled
return vec4(light_colour.rgb * out_colour * texture_colour.rgb, texture_colour.a); // Lighting enabled
}
subroutine(RenderPassType)
void shadeWithShadow()
{
vec4 ambient = vec4(Light.ambient,1.0); // compute ambient component
vec4 pixel_colour = RenderType();
// Do the shadow-map look-up
float shadow = textureProj(Shadow_Map, out_shadowcoord);
// If the fragment is in shadow, use ambient light only
frag_colour = vec4(pixel_colour * shadow + ambient);
}
subroutine(RenderPassType)
void recordDepth()
{
// Do nothing, depth will be written automatically
}
void main()
{
RenderPass();
// vec4 final_colour = RenderType();
// frag_colour = final_colour;
}
Here is my main rendering code:
void RenderScene()
{
glClear(GL_DEPTH_BUFFER_BIT);
// FIRST RENDERING PASS...
light_frustum.UpdateCamera(&M_Viewing);
glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
glViewport(0, 0, 512, 512);
UpdateProjection(60.0f, 512.0f, 512.0f, 1.0f, 1000.0f);
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &pass1Index); // Select the subroutine to use in the shader
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
Draw3D(); // Draws the various objects in the scene inc. DrawHouse()
// SECOND RENDERING PASS...
camera.UpdateCamera(&M_Viewing);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, 1920, 1080);
UpdateProjection(45.0f, 1920.0f, 1080.0f, 0.5f, 1000.0f);
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &pass2Index); // Selected the second subroutine in the shader
glDisable(GL_CULL_FACE);
UpdateLightPosition();
Draw3D();
}
Creation of the framebuffer object should be OK…
void SetupFBO(void)
{
GLsizei shadowMapWidth = 512;
GLsizei shadowMapHeight = 512;
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT24, shadowMapWidth, shadowMapHeight);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
// Assign the shadow map to texture unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthTexture);
// Create and setup the FBO
glGenFramebuffers(1, &shadowFBO);
glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
GLenum drawBuffers[] = { GL_NONE };
glDrawBuffers(1, drawBuffers);
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (result == GL_FRAMEBUFFER_COMPLETE) {
printf("Framebuffer is complete.
");
}
else {
printf("Framebuffer is not complete.
");
}
// Revert to the default framebuffer for now
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
What else? My object rendering code looks like this:
void DrawHouse(void)
{
if (textures_enabled) { glUseProgram(phong_program); }
else { glUseProgram(flatshade_program); }
house.Translate(vec3(-6.0f, -5.0f, 15.0f)); // Position the house object in world space
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &textureIndex);
if (textures_enabled) { house.TransformTest(M_Viewing, M_Projection, light_eye_space, ambient_light, diffuse_light, specular_light); }
else { house.TransformRT(M_Viewing, M_Projection); }
house.ActivateTexture(GL_TEXTURE0, 0); // Activate texture 0
house.Draw();
}
Transform test where number crunching happens…
void Mesh3D::TransformTest(mat4 viewMatrix, mat4 projectionMatrix, vec4 light_position, vec4 light_ambient, vec4 diffuse_light, vec4 specular_light)
{
mModelMatrix = mTranslationMatrix * mRotationMatrix;
mModelViewMatrix = viewMatrix * mModelMatrix;
mModelViewMatrix.GetMatrix(mv_Matrix);
mModelViewMatrix.GetNormalMatrix(normal_Matrix);
// Now we calculate the modelview-projection matrix
mMVPMatrix = projectionMatrix * mModelViewMatrix;
mMVPMatrix.GetMatrix(mvp_Matrix);
// Calculate the normal matrix by taking the inverse-transpose of the modelview matrix
// mNormalMatrix = mModelViewMatrix;
// mNormalMatrix.InvertM();
// mNormalMatrix.TransposeM();
// mNormalMatrix.GetNormalMatrix(normal_Matrix);
// TEST
mLightPV = mShadowBias * projectionMatrix * viewMatrix;
mShadowMatrix = mLightPV * mModelMatrix;
mShadowMatrix.GetMatrix(shadow_Matrix);
glUniform3f(uLightAmbientLocation, light_ambient.x, light_ambient.y, light_ambient.z);
glUniform3f(uLightDiffuseLocation, diffuse_light.x, diffuse_light.y, diffuse_light.z);
glUniform3f(uLightSpecularLocation, specular_light.x, specular_light.y, specular_light.z);
glUniform4f(uLightPositionLocation, light_position.x, light_position.y, light_position.z, light_position.w);
glUniform3f(uMatAmbientLocation, mat.ambient.x, mat.ambient.y, mat.ambient.z);
glUniform3f(uMatDiffuseLocation, mat.diffuse.x, mat.diffuse.y, mat.diffuse.z);
glUniform3f(uMatSpecularLocation, mat.specular.x, mat.specular.y, mat.specular.z);
glUniform1f(uMatShininessLocation, mat.shininess);
glUniformMatrix4fv(uMVMatrixLocation, 1, GL_FALSE, mv_Matrix);
glUniformMatrix4fv(uMVPMatrixLocation, 1, GL_FALSE, mvp_Matrix);
glUniformMatrix3fv(uNormalMatrixLocation, 1, GL_FALSE, normal_Matrix);
glUniformMatrix4fv(uShadowMatrixLocation, 1, GL_FALSE, shadow_Matrix);
glUniform1i(uTexture0Location, 0);
glUniform1i(uShadowMapLocation, 0);
}
My shader loading code looks like this:
if (!s.LoadShader("Shaders/phong.vert", "Shaders/phong.frag")) { return FALSE; }
else
{
phong_program = s.CreateProgram();
if (phong_program == 0) { return FALSE; }
glBindAttribLocation(phong_program, 0, "in_position");
glBindAttribLocation(phong_program, 1, "in_colour");
glBindAttribLocation(phong_program, 2, "in_normal");
glBindAttribLocation(phong_program, 3, "in_texcoord");
glBindFragDataLocation(phong_program, 0, "frag_colour");
if (!s.LinkProgram(phong_program)) { return FALSE; }
}
All uniforms etc are correctly initialised. I have tested the light transformations and the view is correctly being rendered from the lights position and correct direction in the first pass. I just have no idea why the textures aren’t appearing and no shadows either. I must be doing something wrong.
I’ve tried to post a screenshot of what the scene looks like but the ‘Manage Attachments’ doesn’t allow you to attach anything. Bizarre.
EDIT: OK I just changed this line in TransformTest from 3fv to 4fv:
glUniformMatrix4fv(uShadowMatrixLocation, 1, GL_FALSE, shadow_Matrix);
I realised from posting here that I had made a mistake there. Now I see some texturing swimming across the objects. Looks super strange. Wish I could make a short video of this effect. Still no shadow effect though. This just gets wierder…