PDA

View Full Version : Problem getting shadow mapping to work correctly



reaktor24
03-12-2017, 06:31 PM
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.\n");
}
else {
printf("Framebuffer is not complete.\n");
}

// 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...

reaktor24
03-12-2017, 07:07 PM
OK, I've managed to record a short clip using nVidia GeForce Experience recording facility. It seemed to work OK so I'm now uploading to YouTube.

Here is the direct link:

https://youtu.be/GEZZALOfYuQ

Really hope someone can help as I'm totally stumped. :(

GClements
03-12-2017, 10:52 PM
The fragment shader has two subroutine uniforms (RenderType and RenderPass) but each call to glUniformSubroutinesuiv() has a count of one. That should result in the call failing with GL_INVALID_VALUE.

Are you checking for errors?

reaktor24
03-13-2017, 04:59 AM
The fragment shader has two subroutine uniforms (RenderType and RenderPass) but each call to glUniformSubroutinesuiv() has a count of one. That should result in the call failing with GL_INVALID_VALUE.

Are you checking for errors?

You're right I forgot to enable error checking. I have it turned off by default. I get this error:

API:Undefined Behavior [Medium Warning] (131222) : Program undefined behavior warning: Sampler object 0 is bound to non-depth texture 1, yet it is used with a program that uses a shadow sampler. This is undefined behavior.

I'm not too clear on how glUniformSubroutinesuiv actually works? So should my calls to this be a count of 2? I tried that and most of the geometry just disappeared.

GClements
03-13-2017, 12:15 PM
I get this error:

API:Undefined Behavior [Medium Warning] (131222) : Program undefined behavior warning: Sampler object 0 is bound to non-depth texture 1, yet it is used with a program that uses a shadow sampler. This is undefined behavior.

That's a warning; it's unrelated to the issue with subroutine uniforms, but probably relevant to shadow mapping.

It's related to this:




glUniform1i(uTexture0Location, 0);
glUniform1i(uShadowMapLocation, 0);



You're setting both sampler uniforms to refer to texture unit 0. It's an error to execute a program where sampler uniforms of different types refer to the same texture unit. If you use more than one texture, you have to bind them to different texture units (even if they're bound to different targets).

Actual GL errors are queried by calling glGetError(). This isn't particularly convenient as a means to identify the source of errors; it's useful mostly to confirm that no errors have occurred (which should be the case; a correct program shouldn't generate any errors).



I'm not too clear on how glUniformSubroutinesuiv actually works? So should my calls to this be a count of 2? I tried that and most of the geometry just disappeared.

The count parameter should be equal to the number of active subroutine uniforms, which can be queried with glGetProgramStageiv() with pname equal to GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS.

glUniformSubroutinesuiv() sets the values of all subroutine uniforms at once; each element in the array sets the value for one subroutine uniform.

glGetSubroutineIndex() returns the index of a subroutine given its name. glGetSubroutineUniformLocation() returns the location of a subroutine uniform given its name. But you can use the location layout qualifier on the subroutine uniforms and the index layout qualifier on subroutine functions to avoid the need to query these values in the client code.

Alternatively, you could just avoid the use of subroutines altogether, and just use different programs for generating the depth map and for rendering.

reaktor24
03-13-2017, 01:08 PM
Yes it looks like you're right. I changed them all (count values) to 2 and I am getting this error message in my debug log file:

API:OpenGL Error [MAJOR PROBLEM] (1282) : GL_INVALID_OPERATION error generated. Wrong component type or count.

I just need to track down which function is calling the error. Maybe I will put them in different shader files as this is starting to be a pain.

Dark Photon
03-13-2017, 06:29 PM
I just need to track down which function is calling the error.

From the warnings and errors you're reporting, it looks like you're using NVidia drivers. In that case, you can just enable a debug context, register a debug message callback function (https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDebugMessageCallback.xhtml), and then put a breakpoint on that callback function. It'll get called whenever the any GL error or warning is triggered, with the entire callstack of functions down to the GL call that triggered it on the stack.

This makes tracking down the cause of GL errors really easy.

Alternatively, inside your GL debug message callback, you can just put some code that dumps not only the warning/error but also the call stack.

NOTE: You can access this functionality through ARB_debug_output (https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_debug_output.txt), which has been supported by NVidia drivers for many years. It's also part of core OpenGL 4.3+.

reaktor24
03-15-2017, 09:30 AM
From the warnings and errors you're reporting, it looks like you're using NVidia drivers. In that case, you can just enable a debug context, register a debug message callback function (https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glDebugMessageCallback.xhtml), and then put a breakpoint on that callback function. It'll get called whenever the any GL error or warning is triggered, with the entire callstack of functions down to the GL call that triggered it on the stack.

This makes tracking down the cause of GL errors really easy.

Alternatively, inside your GL debug message callback, you can just put some code that dumps not only the warning/error but also the call stack.

NOTE: You can access this functionality through ARB_debug_output (https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_debug_output.txt), which has been supported by NVidia drivers for many years. It's also part of core OpenGL 4.3+.

Hi Dark Photon. Thanks for the response. I am using NVidia Geforce GTX980 so you are correct. Plus I am also using a debug callback function which creates a log file. How do you detect the function that caused the error though? I've tried skipping through the code but it just ends up giving me a 'nvoglv64.pdb no loaded' error message. I've tried to get this working by downloading files from the Microsoft symbol servers but it didn't work.

EDIT:

I've just fixed a small error with my debug callback function. I hadn't included an append option so it was only writing one error at a time.

The errors are mainly 'Invalid shader subroutine uniform' and 'wrong component type or count' errors. There is one that stands out but it says its only a warning:

API:Undefined Behavior [Medium Warning] (131222) : Program undefined behavior warning: Sampler object 0 has depth compare enabled. It is being used with depth texture 6, by a program that samples it with a regular sampler. This is undefined beahvior.

Dark Photon
03-15-2017, 01:14 PM
How do you detect the function that caused the error though?

1) Put a breakpoint on your debug callback
2) Run your program
3) When the breakpoint triggers, look at the call stack.

That at least used to work last time I tried it.


The errors are mainly 'Invalid shader subroutine uniform' and 'wrong component type or count' errors. There is one that stands out but it says its only a warning:

API:Undefined Behavior [Medium Warning] (131222) : Program undefined behavior warning: Sampler object 0 has depth compare enabled. It is being used with depth texture 6, by a program that samples it with a regular sampler. This is undefined beahvior.


I'd fix this. I recall talking to someone that tracked down a nasty crash or screen corruption problem on NVidia drivers that was being triggered by mismatching either depth compare state or texture type with a shader that was expecting a depth texture with depth compare set (or vice versa). It was caused by an app bug, but the resulting problem wasn't easy to track back to the instigating code.

reaktor24
03-17-2017, 05:58 AM
I have never used the call stack before so I'm a bit of a beginner in that respect.

It doesn't appear to be telling me much. Once inside the debug callback function all I see in the callstack is this:

> ShaderProject.exe!debugCallback(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char * message, void * param) Line 1261 C++


Maybe I have it setup wrong? I'm not sure. I'm using Visual Studio 2015 Community Edition.

Dark Photon
03-17-2017, 06:56 AM
I have never used the call stack before so I'm a bit of a beginner in that respect.

It doesn't appear to be telling me much. Once inside the debug callback function all I see in the callstack is this:

> ShaderProject.exe!debugCallback(...) Line 1261 C++

Maybe I have it setup wrong? I'm not sure. I'm using Visual Studio 2015 Community Edition.

Run your program. Bring up the callstack window (https://msdn.microsoft.com/en-us/library/a3694ts5.aspx). Omitting the line numbers and the "C++" mentions, you should see something like this:



ShaderProject.exe!debugCallback(...)
nvoglv64.dll!0000000069450b3b()
[Frames below may be incorrect and/or missing, no symbols loaded for nvoglv64.dll]
nvoglv64.dll!000000006921c53f()
nvoglv64.dll!000000006921c62c()
nvoglv64.dll!000000006921c5d5()
nvoglv64.dll!000000006957d298()
nvoglv64.dll!000000006957f859()
nvoglv64.dll!000000006957c69b()
nvoglv64.dll!00000000691ee012()
nvoglv64.dll!00000000691f9053()
ShaderProject.exe!func6(...)
ShaderProject.exe!func5(...)
ShaderProject.exe!func4(...)
ShaderProject.exe!func3(...)
ShaderProject.exe!func2(...)
ShaderProject.exe!func1(...)
ShaderProject.exe!func0(...)
...
ShaderProject.exe!main(int argc, char * * argv)
ShaderProject.exe!__tmainCRTStartup()
ShaderProject.exe!mainCRTStartup()
kernel32.dll!00000000772959cd()
ntdll.dll!00000000774ca561()


This is where you are currently in your code. Skip past all the frames that are in the NVidia GL library ("nvoglv64.dll...") as there's not much you can do with those. Double-click on the first stack frame that is inside of your code (i.e. ShaderProject.exe) -- In the example above, I've named it func6(). This is the bottom-most frame in your code and should put you right on a line where you've made a GL call. This GL call is likely the one that triggered the error, warning, or info message that the callback was called for.

reaktor24
03-17-2017, 07:17 AM
Thanks for that clear explanation. Seems simple enough.

Unfortunately I don't get any ShaderProject.exe stack frames. All I can see is a list of 12 DLL frames.

I've just tried it from a couple of other points in my code and it does work correctly as you explained. It just doesn't work in my callback function. Damn.

Silence
03-17-2017, 07:56 AM
Thanks for that clear explanation. Seems simple enough.

Unfortunately I don't get any ShaderProject.exe stack frames. All I can see is a list of 12 DLL frames.

I've just tried it from a couple of other points in my code and it does work correctly as you explained. It just doesn't work in my callback function. Damn.

Not sure if this is your case but you could try to switch to another thread in your debugger. If the debugger is not in the same thread, it cannot see the matching callstack.

reaktor24
03-17-2017, 01:52 PM
I keep getting errors about missing .pdb files if I try to step out of the callback function so I assume it must be something to do with that.

EDIT:

So anyway I've given up with the callstack and decided on a new (maybe unconventional) tactic. Basically I've created a new global variable called error_count which is a GLuint. It equals zero. Every time the debugCallback is called this value increases by one. Now by strategically inserting breakpoints around the program I have narrowed down exactly which calls are making the errors. Now I just have to fix the problems.

Will keep you updated on my progress. :)

reaktor24
03-21-2017, 10:10 AM
I keep getting errors about missing .pdb files if I try to step out of the callback function so I assume it must be something to do with that.

EDIT:

So anyway I've given up with the callstack and decided on a new (maybe unconventional) tactic. Basically I've created a new global variable called error_count which is a GLuint. It equals zero. Every time the debugCallback is called this value increases by one. Now by strategically inserting breakpoints around the program I have narrowed down exactly which calls are making the errors. Now I just have to fix the problems.

Will keep you updated on my progress. :)

Quick Update:

First the good news. I have managed to fix all OpenGL errors! So that is quite good news.

More good news. I have a shadow on the screen!

I managed to get it to this state by reading this thread: https://www.opengl.org/discussion_boards/showthread.php/176958-Drawing-depth-texture-bound-to-a-FBO

I had made the same mistake as this guy but nobody here seemed to notice. The bind to the framebuffer has to occur BEFORE the glClear(GL_DEPTH_BUFFER_BIT) function.

OK now the bad news. The shadow is actually rotating with respect to the light orientation but it is also positioned incorrectly in the scene. i.e its not attached to the objects its meant to be shadowing. It must be something super obvious that I'm overlooking.

See this video to see the effect in action: https://www.youtube.com/watch?v=awKaZEOBy9Y

reaktor24
03-22-2017, 04:19 AM
OK I think it is close to being finished. I have modified my transformation code on my cube object like this:


First the main rendering code


void RenderScene()
{
glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO); // Select the framebuffer object first
glClear(GL_DEPTH_BUFFER_BIT); // Clear the depth buffer second
light_frustum.UpdateCamera(&M_Viewing);
glViewport(0, 0, 512, 512);
UpdateProjection(60.0f, 512.0f, 512.0f, 1.0f, 1000.0f);
M_LightPV = shadow_bias * M_Projection * M_Viewing; // NEW CREATION OF LIGHT POV MATRIX!
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
CreateShadowMap();

// SECOND RENDERING PASS...
glBindFramebuffer(GL_FRAMEBUFFER, 0); // Revert to the default framebuffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
camera.UpdateCamera(&M_Viewing);
glViewport(0, 0, 1920, 1080);
UpdateProjection(45.0f, 1920.0f, 1080.0f, 0.5f, 1000.0f);
glDisable(GL_CULL_FACE);
UpdateLightPosition();
Draw3D();



Then the shadow matrix is constructed before each individual object is rendered in the second pass. Is this correct?



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);

mat4 shadowMatrix = lightPVMatrix * mModelMatrix;
shadowMatrix.GetMatrix(shadow_Matrix); // NEW TEST!!

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);

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);



The reason I ask is because the shadow appears to be at the correct 'side' of the object but is actually attached to the object and isn't being projected onto the floor. I made another short video showing the program in action with the odd behaviour.

https://www.youtube.com/watch?v=Tqd4VlU0Xa0&t=26s


I'm almost there. If someone could help with this final problem that would be a massive help. Thanks.

reaktor24
03-23-2017, 09:26 AM
OK I think I'm narrowing this down now but I still need a bit of help with this.

I'm pretty sure the problem lies in the creation of the depth map. i.e it's not getting created properly.

I have tried texturing my world objects with the depth map just to see if it was created and there is no textured image in the depth map.

I am learning from the OpenGL 4 Shading Language Cookbook and it says just to pass through fragment shader and do nothing with it. So thats what I do.

vertex shader


#version 450 core

uniform mat4 mvp_Matrix; // ModelViewProjection Matrix

in vec4 in_position;


void main()
{
// Convert position to clip coordinates and pass to fragment shader
gl_Position = mvp_Matrix * in_position;
}


fragment shader


#version 450 core

out vec4 frag_colour;


void main()
{
// Do nothing, depth will be written automatically
}



Having looked at code on this tutorial I'm wondering now if I'm doing it wrong: http://ogldev.atspace.co.uk/www/tutorial23/tutorial23.html


He does this in his fragment shader


#version 330

in vec2 TexCoordOut;
uniform sampler2D gShadowMap;

out vec4 FragColor;

void main()
{
float Depth = texture(gShadowMap, TexCoordOut).x;
Depth = 1.0 - (1.0 - Depth) * 25.0;
FragColor = vec4(Depth);
}