LWJGL Shadow mapping

Hello guys,

Im working at an 3d strategy game at the moment, where i would like to add shadows.
Im trying to implement this for the third time now, but i keep getting nothing.
Could anyone please help me?

I already have tryed to create some kind of buffer texture:


    public FrameBufferObject3D(int texturew, int textureh){
        width = texturew;
        height = textureh;
        
        FBOId = glGenFramebuffers();
        biasMatrix.load(bM);
                
        createTexture();     
        glBindFramebuffer(GL_FRAMEBUFFER, FBOId);
        glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textId, 0);
        glDrawBuffer(GL_NONE);
	glReadBuffer(GL_NONE);
        
        int framebuffer = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        switch ( framebuffer ) {
                case GL_FRAMEBUFFER_COMPLETE:
                        break;
                case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
                        throw new RuntimeException( "FrameBuffer: " + FBOId
                                        + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT exception" );
                case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
                        throw new RuntimeException( "FrameBuffer: " + FBOId
                                        + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT exception" );
                case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
                        throw new RuntimeException( "FrameBuffer: " + FBOId
                                        + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT exception" );
                case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
                        throw new RuntimeException( "FrameBuffer: " + FBOId
                                        + ", has caused a GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT exception" );
                default:
                        throw new RuntimeException( "Unexpected reply from glCheckFramebufferStatusEXT: " + framebuffer );
        }
        
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
    
    private void createTexture(){
        textId = TextureLoader.createTextureID();
        
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textId);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, (ByteBuffer)null);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    }

    public void Bind(){
        if(updatelight){
            glLoadIdentity();
            glPushMatrix();
                Vector3f l = (Vector3f)new Vector3f(Panel.getLightPos()).negate();

                glLoadIdentity(); 
                glOrtho(-10,10,-10,10,-10,20);
                lightbuffer.position(0);
                glGetFloat(GL_PROJECTION_MATRIX, lightbuffer);
                projectionMatrix.load(lightbuffer);
                
                GLU.gluLookAt(l.x, l.y, l.z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
                lightbuffer.position(0);
                glGetFloat(GL_MODELVIEW_MATRIX, lightbuffer);
                lightMatrix.load(lightbuffer);

                shadowMatrix.load(Panel.getProjection());
                shadowMatrix.mul(lightMatrix);

                biasshadowMatrix.load(Panel.getProjection());
                biasshadowMatrix.mul(lightMatrix);
            glPopMatrix();
            updatelight = false;
        }      
        
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBOId);
       
        glPushAttrib(GL_VIEWPORT_BIT);
        glViewport( 0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }

Im sure this is a mess, as i understand only little about it.
My problems are starting with generating the correct matrices:


                shadowMatrix.load(Panel.getProjection());
                shadowMatrix.mul(lightMatrix);

                biasshadowMatrix.load(Panel.getProjection());
                biasshadowMatrix.mul(lightMatrix);

I need one matrix to transform the models to the light view (a vec3 with position).
Second, i would need a matrix to map the buffer on the model.

Im sorry for the mess, thanks in advance.

Please, does noone have a idea?

When rendering the shadow map
Object space --model matrix–> World space --light view/eye matrix–> Light eye space --light projection matrix–> Light Normalized Device Coordinates (NDC)

When rendering the scene
Object space --model matrix–> World space --view/eye matrix–> Eye space --projection matrix–> Normalized Device Coordinates (NDC)

The idea is to first render a shadow map by transforming your coordinates using the light’s view matrix and projection matrix. Then when you render your scene, you transform your vertices into both Light NDC and NDC. Your NDC coordinates are simply passed into gl_Position as usual, but the Light NDC coordinates should be passed into the fragment shader. In the fragment shader, you use the Light NDC coordinates as texture coordinates into your shadow map. The problem here is that NDC coordinates range from -1 to +1 while texture coordinates range from 0 to 1. This is where the bias matrix comes in. Its job is to take Light NDC and turn them into texture coordinates, but this can be done easily without a matrix:

vec3 shadowTexCoords = lightNDC.xyz * 0.5 + 0.5;

Note that this is only necessary when reading the shadow map, not when rendering it.

Thank you for your information.

I think i am calculating the light matrix wrong, do you want to elaborate this?
Also, i how do i build the matrix to project the (depth) texture on the scene?

There are 3 (main) types of lights: cone/spot lights, point lights and directional lights. Not everyone uses the same names though, so be careful when Googling.

  • Cone/spot lights are lights which originate from a point but also have a direction which they shine in. Examples include a flashlight or a car’s headlight.
  • Point lights are lights which originate from a point in all directions, for example a candle.
  • Directional lights are lights where the light comes from a point infinitely far away. It’s often used for sun light since the sun is so far away that all the incoming light has essentially the same direction.

The basics are the same for all 3. You wish to create an view matrix the same way you create a view matrix for your camera, but instead create it with the parameters of your light, not your camera.

Shadows are implemented pretty differently for each one of these.

  • Cone lights are the easiest thanks to their shape. You can easily set up a view matrix using gluLookAt():
    • Eye position = light position.
    • Center position = light position + light direction.
    • Up vector = Anything as long as it isn’t parallel to the light direction. (0, 1, 0) works for everything except when the light is pointing exactly up or down.
      The perspective matrix is also easy to set up. The cone light has an angle which works exactly like the camera’s field-of-view angle. You can therefore create a projection matrix the same way as you do for your camera.

  • Point lights are much more complicated since they shine in all directions, but our shadow map is flat. You therefore need to have 6 shadow maps to form a cube around the light (can also be done using 2 shadow maps and some math magic). Needless to say, this gets complicated quickly so I’ll just ignore them for now.

  • Directional lights are as simple as cone lights to implement but it’s much harder to get them to look right. You basically want the light’s “position” to be the camera’s position here so the shadows “follow” the camera. With that you have a position and a direction so you can easily set up a view matrix just like you did for cone lights. The perspective matrix is also pretty easy. Instead of using a projection matrix like your camera, you’ll use an orthographic matrix. This essentially creates a huge box centered at the camera and oriented along the direction of the ligth. The problem here is that the shadow map cannot stretched over an infinitely large area since that would also require a shadow map of infinite resolution. Hence we need to limit the “range” of the directional light. This is done using the parameters to glOrtho(). The smaller you limit your area to, the sharper and better your shadows will look since the resolution of the shadow map will be distributed over a smaller area. A solution here is Cascaded Shadow Maps.