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