PDA

View Full Version : LWJGL - Shadow Mapping



Alphaomega86
03-29-2013, 09:02 AM
Hallo!

I have writte a shadow mapping class in LWJGL (without shaders) and now i have a problem with texturing the scene. If i render my scene without textures and just with colors, then my shadow mapping code works fine but if i use textures in my scene, all textures become gray.

I really hope, that someone can help me!

MfG, Daniel!

Alphaomega86
03-29-2013, 09:13 AM
Code for initializing the FBO and Renderbuffer:

private void initialize() {
final int mrb = GL11.glGetInteger(GL30.GL_MAX_RENDERBUFFER_SIZE);
final int mts = GL11.glGetInteger(GL11.GL_MAX_TEXTURE_SIZE);

if (mts > quality.resolution) {
if (mrb < mts) {
glShadowMapDimension = mrb;
} else {
glShadowMapDimension = quality.resolution;
}
} else {
glShadowMapDimension = mts;
}

fBuffer = GL30.glGenFramebuffers();
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fBuffer);

rBuffer = GL30.glGenRenderbuffers();
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, rBuffer);

GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL14.GL_DEPTH_COMPONENT32, glShadowMapDimension, glShadowMapDimension);
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER , GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER, rBuffer);

GL11.glDrawBuffer(GL11.GL_NONE);
GL11.glReadBuffer(GL11.GL_NONE);

int status = GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER) ;
if (status != GL30.GL_FRAMEBUFFER_COMPLETE) {
throw new OpenGLException("Framebuffer error: " + GLU.gluErrorString(GL11.glGetError()));
}

GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
}

Code for shadow texture coordinate generation:

public void genTexCoords() {
GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, GL14.GL_COMPARE_R_TO_TEXTURE);

GL11.glEnable(GL11.GL_TEXTURE_GEN_S);
GL11.glEnable(GL11.GL_TEXTURE_GEN_T);
GL11.glEnable(GL11.GL_TEXTURE_GEN_R);
GL11.glEnable(GL11.GL_TEXTURE_GEN_Q);

tBuffer.clear();

tBuffer.put(0, glModelViewProjectionMatrix.m00);
tBuffer.put(1, glModelViewProjectionMatrix.m01);
tBuffer.put(2, glModelViewProjectionMatrix.m02);
tBuffer.put(3, glModelViewProjectionMatrix.m03);

GL11.glTexGen(GL11.GL_S, GL11.GL_EYE_PLANE, tBuffer);

tBuffer.put(0, glModelViewProjectionMatrix.m10);
tBuffer.put(1, glModelViewProjectionMatrix.m11);
tBuffer.put(2, glModelViewProjectionMatrix.m12);
tBuffer.put(3, glModelViewProjectionMatrix.m13);

GL11.glTexGen(GL11.GL_T, GL11.GL_EYE_PLANE, tBuffer);

tBuffer.put(0, glModelViewProjectionMatrix.m20);
tBuffer.put(1, glModelViewProjectionMatrix.m21);
tBuffer.put(2, glModelViewProjectionMatrix.m22);
tBuffer.put(3, glModelViewProjectionMatrix.m23);

GL11.glTexGen(GL11.GL_R, GL11.GL_EYE_PLANE, tBuffer);

tBuffer.put(0, glModelViewProjectionMatrix.m30);
tBuffer.put(1, glModelViewProjectionMatrix.m31);
tBuffer.put(2, glModelViewProjectionMatrix.m32);
tBuffer.put(3, glModelViewProjectionMatrix.m33);

GL11.glTexGen(GL11.GL_Q, GL11.GL_EYE_PLANE, tBuffer);
}

Code for shadow map rendering:

public void render(Renderable scene) {
FloatBuffer glLightModelView = BufferUtils.createFloatBuffer(16);
FloatBuffer glLightProjection = BufferUtils.createFloatBuffer(16);

Matrix4f glLightModelViewTemp = new Matrix4f();
Matrix4f glLightProjectionTemp = new Matrix4f();

float sceneBoundingRadius = 50;
float lightToSceneDistance = (float) FastMath.sqrt(lPosition.get(0) * lPosition.get(0) + lPosition.get(1) * lPosition.get(1) + lPosition.get(2) * lPosition.get(2));
float nearPlane = lightToSceneDistance - sceneBoundingRadius;

if (nearPlane < 0) {
throw new OpenGLException("Camera is too close to scene. A valid shadow map cannot be generated!");
}

float fov = (float) FastMath.toDegrees(2.0f * FastMath.atan(sceneBoundingRadius / lightToSceneDistance));

GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPushMatrix();
GL11.glLoadIdentity();

GLU.gluPerspective(fov, 1, nearPlane, nearPlane + sceneBoundingRadius * 2);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, glLightProjection);

GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPushMatrix();
GL11.glLoadIdentity();

GLU.gluLookAt(lPosition.get(0), lPosition.get(1), lPosition.get(2), 0, 0, 0, 0, 1, 0);
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, glLightModelView);
GL11.glViewport(0, 0, glShadowMapDimension, glShadowMapDimension);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fBuffer);

GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);

GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
{
GL11.glShadeModel(GL11.GL_FLAT);

GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_NORMALIZE);
GL11.glDisable(GL11.GL_COLOR_MATERIAL);

GL11.glColorMask(false, false, false, false);

GL11.glEnable(GL11.GL_POLYGON_OFFSET_FILL);

scene.render();

GL11.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, 0, 0, glShadowMapDimension, glShadowMapDimension, 0);

GL11.glPopMatrix();
GL11.glMatrixMode(GL11.GL_PROJECTION);

GL11.glPopMatrix();
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
}
GL11.glPopAttrib();

GL11.glViewport(0, 0, Display.getWidth(), Display.getHeight());
glLightProjectionTemp.load(glLightProjection);
glLightModelViewTemp.load(glLightModelView);

glLightProjection.flip();
glLightModelView.flip();

glModelViewProjectionMatrix.setIdentity();
glModelViewProjectionMatrix.translate(new Vector3f(0.5f, 0.5f, 0.5f));
glModelViewProjectionMatrix.scale(new Vector3f(0.5f, 0.5f, 0.5f));

Matrix4f.mul(glModelViewProjectionMatrix, glLightProjectionTemp, glModelViewProjectionMatrix);
Matrix4f.mul(glModelViewProjectionMatrix, glLightModelViewTemp, glModelViewProjectionMatrix);

Matrix4f.transpose(glModelViewProjectionMatrix, glModelViewProjectionMatrix);
}

Alphaomega86
03-29-2013, 09:15 AM
This is my rendering core, where all objects are rendered:

package org.j3d.rendering;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import org.j3d.boundings.BoundingBox;
import org.j3d.boundings.BoundingSphere;
import org.j3d.boundings.BoundingVolume;
import org.j3d.culling.ViewFrustum;
import org.j3d.filter.ShadowFilter;
import org.j3d.interfaces.Renderable;
import org.j3d.rendering.scene.Mesh;
import org.lwjgl.opengl.ARBShadowAmbient;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL14;
import org.lwjgl.util.vector.Vector3f;

/**
* All rendering stuff will be done here.
*
* @author Daniel
*/
public class Renderer implements Renderable {

/**
* Class logger.
*/
private static final Logger LOG = Logger.getLogger(Renderer.class.getName());
/**
* View frustum for all objects for testing, if the rendered object is in
* the frustum of the camera.
*/
private ViewFrustum frustum = new ViewFrustum();
/**
* Every object, which should be rendered, must be added to this list.In
* this list, all objects from type Mesh will be saved.
*/
protected List<Mesh> objects = Collections.synchronizedList(new ArrayList<Mesh>());
/**
* The shadow filter if shadows are enabled.
*/
private ShadowFilter shadow;
/**
* The shadow quality.
*/
private ShadowFilter.ShadowQuality shadowQuality;
/**
* Light position for shadow mapping.
*/
private Vector3f lightPosition;
/**
* True if the shadows are enabled for this scene, otherwise false.
*/
private boolean shadowEnabled = false;

@Override
public void render() {
if (objects.isEmpty()) {
return;
}

if (shadowEnabled && shadow == null) {
shadow = new ShadowFilter(lightPosition.x, lightPosition.y, lightPosition.z, shadowQuality);
}
if (shadowEnabled) {
shadow.genTexCoords();
}

frustum.update(); //Updates the view frustum of the camera

//Boundings for frustum tests
BoundingVolume volume;
BoundingBox aabb;
BoundingSphere sphere;


for (int i = 0; i < objects.size(); i++) {
volume = objects.get(i).getBounding();

if (volume == null) {
continue;
}

//Tests if BoundingVolume is in the view frustum and render it
GL11.glPushMatrix();
GL11.glPushAttrib(GL11.GL_TEXTURE_BIT);
{
if (shadowEnabled) {
useTexParameters();
}
if (volume instanceof BoundingBox) {
aabb = (BoundingBox) volume;

if (frustum.isCuboidInFrustum(aabb.getCenter(), aabb.getDefaultSize())) {
objects.get(i).render();
}
} else if (volume instanceof BoundingSphere) {
sphere = (BoundingSphere) volume;

if (frustum.isSphereInFrustum(sphere.getCenter(), sphere.getRadius())) {
objects.get(i).render();
}
}
}
GL11.glPopAttrib();
GL11.glPopMatrix();
}

if (shadowEnabled) {
shadowEnabled = false;

shadow.render(this);

shadowEnabled = true;
}
}

/**
* Attach a Mesh 3D object to the renderer.
*
* @param mesh Additional 3D object.
*/
public void addMesh(Mesh mesh) {
objects.add(mesh);
}

/**
* With this method, the shadows can be enabled fo this scene.
*
* @param bool true if the shadows should be enabled, otherwise false.
* @param quality The shadow qulity.
* @param lightPosition Light position for shadow mapping.
*/
public void setShadowEnabled(boolean bool, ShadowFilter.ShadowQuality quality, Vector3f lightPosition) {
shadowEnabled = bool;
shadowQuality = quality;
this.lightPosition = lightPosition;
}

public void setMainLightSourcePosition(Vector3f pos) {
if (shadow != null) {
shadow.setLightPosition(pos.x, pos.y, pos.z);
lightPosition = pos;
}
}

/**
* Returns true if the shadows in this scene are enabled, otherwise false.
*
* @return true if the shadows in this scene are enabled, otherwise false.
*/
public boolean isShadowEnabled() {
return shadowEnabled;
}

/**
* Uses all texture parameters for shadow mapping.
*/
private void useTexParameters() {
GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);

GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);

GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);

GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_DEPTH_TEXTURE_MODE, GL11.GL_INTENSITY);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, ARBShadowAmbient.GL_TEXTURE_COMPARE_FAIL_VALUE_ARB , 0.5f);
}
}


And this is my init method for OpenGL:

public static void glInitialize3D(int fov, float aspect, float zFar) {
GluUtilities.fov = fov;
GluUtilities.aspect = aspect;
GluUtilities.zFar = zFar;

GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GluUtilities.gluPerspective(fov, 0.001f, zFar, aspect);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glEnable(GL11.GL_TEXTURE_2D);
// GL11.glEnable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_NORMALIZE);
GL11.glEnable(GL11.GL_COLOR_MATERIAL);

GL11.glPolygonOffset(1.1f, 4.0f);

GL11.glDepthFunc(GL11.GL_LEQUAL);
GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);

//For shadow mapping
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);

GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);

GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_DEPTH_TEXTURE_MODE, GL11.GL_INTENSITY);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, ARBShadowAmbient.GL_TEXTURE_COMPARE_FAIL_VALUE_ARB , 0.5f);

GL11.glTexGeni(GL11.GL_S, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_EYE_LINEAR);
GL11.glTexGeni(GL11.GL_T, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_EYE_LINEAR);
GL11.glTexGeni(GL11.GL_R, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_EYE_LINEAR);
GL11.glTexGeni(GL11.GL_Q, GL11.GL_TEXTURE_GEN_MODE, GL11.GL_EYE_LINEAR);

// GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glCullFace(GL11.GL_BACK);
}

Alphaomega86
03-29-2013, 09:20 AM
Scene with color and shadow mapping:
996

Scene with textures and shadow mapping:
997

Scene with textures and without shadow mapping:
999

I hope this all is enough information to find my bug :D

Dark Photon
03-29-2013, 02:03 PM
glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_DEPTH_TEXTURE_MODE, GL11.GL_INTENSITY);

Wow! It's been a long time since I've done texturing without shaders. Hmm. Let's see.

The above looks fishy. Seems to say that you're setting the albedo MODULATE and the depth texture compare state on the same texture unit. That's not right. You need some glActiveTexture calls in there to switch texture units. Along with glBindTexture to attach the textures to the texture units. Along with the above, split across the correct texture units.

Alphaomega86
03-30-2013, 10:06 AM
Thank you for your answer Dark Photon!

I put glActiveTexture(GL_TEXTURE0) every time, before i call glBindTexture, and i put glActiveTexture(GL_TEXTURE1) every time, when i manipulate/render the shadows. And the initialize code looks like that:

glActiveTexture(GL_TEXTURE0)
glTexEnvi(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
glActiveTexture(GL_TEXTURE1)
glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_DEPTH_TEXTURE_MODE, GL11.GL_INTENSITY);

And now i got that:
1000

Now, the texture is just on the ground and not on the airplane anymore, but the shadows are removed.
I don't know, if i miss understand something, or if it just did not solve my problem.

Oh, and for the glActiveTexture calls, i have removed the glPushAttrib(GL_ALL_ATTRIB_BITS) and glPopAttrib calls from my render class.

If i remove all glActiveTexture calls and if i remove the glPushAttrib(GL_ALL_ATTRIB_BITS) and glPopAttrib calls from my render class, i got that result:
1001

No shadows, but these strange black stripes on the ground.

Dark Photon
03-31-2013, 02:02 PM
For each texture unit you need to say which texture you're operating on, that that unit is enabled, how to sample from that texture, and how to combine what you get with the accumulated result(s) from previous texture stage(s).

I don't see any enabling of texture units here (e.g. glEnable( GL_TEXTURE_2D)). I also don't see you saying how you're going to combine your depth texture lookup/comparison with the previous stage's output (e.g. GL_MODULATE).

You should just find a working example of fixed-function shadow mapping and use that as a guide. Here's one:

* http://www.paulsprojects.net/tutorials/smt/smt.html

For simplicity, he renders the ambient in one pass, and then renders the diffuse/specular (with shadowing applied) using a second pass. But he does acknowledge that you can do this in one pass. Doing so with shaders is pretty simple (once you're familiar with shaders). Doing so with fixed-function is a bit more involved.

An NVidia presentation on the old fixed-function shadow mapping that might be useful:

* Shadow Mapping (Kilgard, 2001) (https://developer.nvidia.com/sites/default/files/akamai/gamedev/docs/GDC01_Shadows.pdf)