Sign in to follow this  

OpenGL GLSL shadows not working

Recommended Posts

polyfrag    2502
I copied this code from the tutorial at and this is what I see in my game:


Here is the code:

void RenderWorld()

inline void RenderPlayScene()
// Set the current viewport to our texture size
glViewport(0, 0, (int)SHADOW_WIDTH, (int)SHADOW_HEIGHT);
// Now we just need to set the matrices for the light before we render

// Push on a matrix to make sure we can restore to the old matrix easily
// Set the current projection matrix to our light's projection matrix
// Load modelview mode to set our light's modelview matrix
// Load the light's modelview matrix before we render to a texture
// Since we don't care about color when rendering the depth values to
// the shadow-map texture, we disable color writing to increase speed.
// Eliminate artifacts caused by shadow mapping
glPolygonOffset(8.0f, 4.0f);

// This turns of the polygon offset functionality to fix artifacts.
// Comment this out and run the program to see what artifacts I mean.
// Render the world according to the light's view
// Now that the world is rendered, save the depth values to a texture
glBindTexture(GL_TEXTURE_2D, g_renderTexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, (int)SHADOW_WIDTH, (int)SHADOW_HEIGHT);
// We can turn color writing back on since we already stored the depth values
// Turn off polygon offsetting
// Restore our normal viewport size to our screen width and height
glViewport(0, 0, (int)g_width, (int)g_height);
// Go back to the projection mode and restore the original matrix
// Restore the original projection matrix
// Go back to modelview model to start drawing like normal
// Clear the color and depth bits and start over from the camera's view
// After we have switched backed to our camera's view, we need to
// grab the inverse of the modelview's matrix. If you are unfamiliar
// with what an inverse of a matrix does, let's review. If you
// multiply a matrix by it's inverse, it basically zeros it out.
// We need the inverse because in the vertex shader we will have a
// vertex that is multiplied by the camera's view matrix (modelview),
// and we need to bring that back down to world space and project
// it into the light's clip space. Since we are working in the light's
// clip space and not the camera's clip space this needs to happen.
// For this to work, we need to make sure we have called the Look()
// function from the camera object before calling GetInverseMatrix().
// Pass in the global matrix that will store our modelview inverse matrix.
// This function grabs the current modelview matrix and returns the inverse.
// Render the world and apply the shadow map texture to it
glLightfv( GL_LIGHT0, GL_POSITION, g_LightPosition );

void RenderScene()
if(g_mode == PLAY)
if(g_mode == PLAY)

void StoreLightMatrices()
// Reset our current light matrices
memset(g_mModelView, 0, sizeof(float)*16);
memset(g_mProjection, 0, sizeof(float)*16);
// Let's push on a new matrix so we don't change the rest of the world
// Push on a new matrix to keep our view changes isolated
// Reset the current modelview matrix
// This is where we set the light's position and view.
gluLookAt(g_LightPosition[0], g_LightPosition[1], g_LightPosition[2],
g_LightView[0], g_LightView[1], g_LightView[2], 0, 1, 0);
// Now that we have the light's view, let's save the current modelview matrix.
glGetFloatv(GL_MODELVIEW_MATRIX, g_mModelView);
// Now pop off the current light view's matrix
// Reset the current matrix
// Set our FOV, aspect ratio, then near and far planes for the light's view
gluPerspective(60.0f, 1.0f, 0.5f, 25.0f);
// Grab the current matrix that will be used for the light's projection matrix
glGetFloatv(GL_MODELVIEW_MATRIX, g_mProjection);
// Go back to the original matrix
void CreateRenderTexture(int sizeX, int sizeY, int channels, int type)
// Create a pointer to store the blank image data
unsigned int *pTexture = NULL;
// Store the current channels to be allocated by default
int channelsTrue = channels;
// If the channels are greater than 4 there must be a special flag like
// GL_DEPTH_COMPONENT, so make sure we only allocate 1 bit per pixel.
if(channels > 4)
channelsTrue = 1;
// Allocate and init memory for the image array and point to it from pTexture
pTexture = new unsigned int [sizeX * sizeY * channelsTrue];
memset(pTexture, 0, sizeX * sizeY * channelsTrue * sizeof(unsigned int));
// Register the texture with OpenGL and bind it to the texture ID
glGenTextures(1, &g_renderTexture);
glBindTexture(GL_TEXTURE_2D, g_renderTexture);

// Create the texture and store it on the video card
glTexImage2D(GL_TEXTURE_2D, 0, channels, sizeX, sizeY, 0, type, GL_UNSIGNED_INT, pTexture);

// Set the texture quality
// Since we stored the texture space with OpenGL, we can delete the image data
delete [] pTexture;
void RenderWorld();
void ApplyShadowMap()

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

// This function is the main function that needs to be changed from the
// previous tutorial. We needed to take out the texture generation code
// so a couple things will change. This means we will need to turn our
// shadow on, as well as multiply the inverse of our camera matrix by
// the light's projection and modelview matrix. We still include the
// bias matrix to convert the clip space to a 0 to 1 ratio instead of
// a -1 to 1 ratio.
// Let's turn our shaders on for doing shadow mapping on our world
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

// Turn on our texture unit for shadow mapping and bind our depth texture
glBindTexture(GL_TEXTURE_2D, g_renderTexture);

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
// In order for the shader to have access to our light's texture of depth
// values, we need to tell our fragment shader the texture unit that our
// texture is being bound to. Since we use GL_TEXTURE0_ARB we pass in 0.
GLuint uniform = glGetUniformLocationARB(g_Shader.GetProgram(), "shadowMap");
glUniform1iARB(uniform, 0);
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

// Here is where we set the mode and function for shadow mapping with shadow2DProj().
// Create our bias matrix to have a 0 to 1 ratio after clip space
const float mBias[] = {0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0};
glLoadMatrixf(mBias); // The bias matrix to convert to a 0 to 1 ratio
glMultMatrixf(g_mProjection); // The light's projection matrix
glMultMatrixf(g_mModelView); // The light's modelview matrix

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
// Instead of using texture generation functions that handle the inverse
// camera matrix for us, we calculated this ourselves and need to multiply
// it by the preceding matrices. Remember the equation for projection:
// mProjectedTexture = mLightProjection * mLightModelview * mCameraInverse;
// We need to use this because we are projecting the shadow map onto the
// world from the light's position. A bit tricky to wrap your head around?
// Keep in mind, the camera's inverse matrix is really the modelview matrix
// inverted with the camera already applied to it.
// Following the above equation, multiply our camera's inverse by the matrices.
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

glMatrixMode(GL_MODELVIEW); // Switch back to normal modelview mode
RenderWorld(); // Render the world that needs to be shadowed
// Now that the world is shadowed and we are done with the texture generation,
// let's set everything back to normal by resetting the texture matrix.
// Turn the first multi-texture pass off

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
// Light expected, we need to turn our shader off since we are done
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

uniform sampler2DShadow shadowMap;
varying vec4 projCoord;
void main ()
const float kTransparency = 0.3;
vec4 color = gl_Color;
float rValue = shadow2DProj(shadowMap, projCoord).r + kTransparency;
rValue = clamp(rValue, 0.0, 1.0);
vec3 coordPos = / projCoord.w;
if(coordPos.x >= 0.0 && coordPos.y >= 0.0 && coordPos.x <= 1.0 && coordPos.y <= 1.0 )
gl_FragColor = color * rValue;
gl_FragColor = color;

varying vec4 projCoord;
void main()
vec4 realPos = gl_ModelViewMatrix * gl_Vertex;

projCoord = gl_TextureMatrix[0] * realPos;
gl_FrontColor = gl_Color;
gl_Position = ftransform();

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By Zaphyk
      I am developing my engine using the OpenGL 3.3 compatibility profile. It runs as expected on my NVIDIA card and on my Intel Card however when I tried it on an AMD setup it ran 3 times worse than on the other setups. Could this be a AMD driver thing or is this probably a problem with my OGL code? Could a different code standard create such bad performance?
    • By Kjell Andersson
      I'm trying to get some legacy OpenGL code to run with a shader pipeline,
      The legacy code uses glVertexPointer(), glColorPointer(), glNormalPointer() and glTexCoordPointer() to supply the vertex information.
      I know that it should be using setVertexAttribPointer() etc to clearly define the layout but that is not an option right now since the legacy code can't be modified to that extent.
      I've got a version 330 vertex shader to somewhat work:
      #version 330 uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewMatrix; layout(location = 0) in vec4 Vertex; layout(location = 2) in vec4 Normal; // Velocity layout(location = 3) in vec3 TexCoord; // TODO: is this the right layout location? out VertexData { vec4 color; vec3 velocity; float size; } VertexOut; void main(void) { vec4 p0 = Vertex; vec4 p1 = Vertex + vec4(Normal.x, Normal.y, Normal.z, 0.0f); vec3 velocity = (osg_ModelViewProjectionMatrix * p1 - osg_ModelViewProjectionMatrix * p0).xyz; VertexOut.velocity = velocity; VertexOut.size = TexCoord.y; gl_Position = osg_ModelViewMatrix * Vertex; } What works is the Vertex and Normal information that the legacy C++ OpenGL code seem to provide in layout location 0 and 2. This is fine.
      What I'm not getting to work is the TexCoord information that is supplied by a glTexCoordPointer() call in C++.
      What layout location is the old standard pipeline using for glTexCoordPointer()? Or is this undefined?
      Side note: I'm trying to get an OpenSceneGraph 3.4.0 particle system to use custom vertex, geometry and fragment shaders for rendering the particles.
    • By markshaw001
      Hi i am new to this forum  i wanted to ask for help from all of you i want to generate real time terrain using a 32 bit heightmap i am good at c++ and have started learning Opengl as i am very interested in making landscapes in opengl i have looked around the internet for help about this topic but i am not getting the hang of the concepts and what they are doing can some here suggests me some good resources for making terrain engine please for example like tutorials,books etc so that i can understand the whole concept of terrain generation.
    • By KarimIO
      Hey guys. I'm trying to get my application to work on my Nvidia GTX 970 desktop. It currently works on my Intel HD 3000 laptop, but on the desktop, every bind textures specifically from framebuffers, I get half a second of lag. This is done 4 times as I have three RGBA textures and one depth 32F buffer. I tried to use debugging software for the first time - RenderDoc only shows SwapBuffers() and no OGL calls, while Nvidia Nsight crashes upon execution, so neither are helpful. Without binding it runs regularly. This does not happen with non-framebuffer binds.
      GLFramebuffer::GLFramebuffer(FramebufferCreateInfo createInfo) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); textures = new GLuint[createInfo.numColorTargets]; glGenTextures(createInfo.numColorTargets, textures); GLenum *DrawBuffers = new GLenum[createInfo.numColorTargets]; for (uint32_t i = 0; i < createInfo.numColorTargets; i++) { glBindTexture(GL_TEXTURE_2D, textures[i]); GLint internalFormat; GLenum format; TranslateFormats(createInfo.colorFormats[i], format, internalFormat); // returns GL_RGBA and GL_RGBA glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, createInfo.width, createInfo.height, 0, format, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); DrawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; glBindTexture(GL_TEXTURE_2D, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, textures[i], 0); } if (createInfo.depthFormat != FORMAT_DEPTH_NONE) { GLenum depthFormat; switch (createInfo.depthFormat) { case FORMAT_DEPTH_16: depthFormat = GL_DEPTH_COMPONENT16; break; case FORMAT_DEPTH_24: depthFormat = GL_DEPTH_COMPONENT24; break; case FORMAT_DEPTH_32: depthFormat = GL_DEPTH_COMPONENT32; break; case FORMAT_DEPTH_24_STENCIL_8: depthFormat = GL_DEPTH24_STENCIL8; break; case FORMAT_DEPTH_32_STENCIL_8: depthFormat = GL_DEPTH32F_STENCIL8; break; } glGenTextures(1, &depthrenderbuffer); glBindTexture(GL_TEXTURE_2D, depthrenderbuffer); glTexImage2D(GL_TEXTURE_2D, 0, depthFormat, createInfo.width, createInfo.height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0); glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthrenderbuffer, 0); } if (createInfo.numColorTargets > 0) glDrawBuffers(createInfo.numColorTargets, DrawBuffers); else glDrawBuffer(GL_NONE); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cout << "Framebuffer Incomplete\n"; glBindFramebuffer(GL_FRAMEBUFFER, 0); width = createInfo.width; height = createInfo.height; } // ... // FBO Creation FramebufferCreateInfo gbufferCI; gbufferCI.colorFormats =; gbufferCI.depthFormat = FORMAT_DEPTH_32; gbufferCI.numColorTargets = gbufferCFs.size(); gbufferCI.width = engine.settings.resolutionX; gbufferCI.height = engine.settings.resolutionY; gbufferCI.renderPass = nullptr; gbuffer = graphicsWrapper->CreateFramebuffer(gbufferCI); // Bind glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); // Draw here... // Bind to textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textures[0]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textures[1]); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textures[2]); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, depthrenderbuffer); Here is an extract of my code. I can't think of anything else to include. I've really been butting my head into a wall trying to think of a reason but I can think of none and all my research yields nothing. Thanks in advance!
    • By Adrianensis
      Hi everyone, I've shared my 2D Game Engine source code. It's the result of 4 years working on it (and I still continue improving features ) and I want to share with the community. You can see some videos on youtube and some demo gifs on my twitter account.
      This Engine has been developed as End-of-Degree Project and it is coded in Javascript, WebGL and GLSL. The engine is written from scratch.
      This is not a professional engine but it's for learning purposes, so anyone can review the code an learn basis about graphics, physics or game engine architecture. Source code on this GitHub repository.
      I'm available for a good conversation about Game Engine / Graphics Programming
  • Popular Now