FloatBuffer lightModelView = BufferUtils.createFloatBuffer(16);
/**
* The projection matrix of the light.
*/
FloatBuffer lightProjection = BufferUtils.createFloatBuffer(16);
Matrix4f lightProjectionTemp = new Matrix4f();
Matrix4f lightModelViewTemp = new Matrix4f();
/**
* The radius that encompasses all the objects that cast shadows in the scene. There should
* be no object farther away than 50 units from [0, 0, 0] in any direction.
* If an object exceeds the radius, the object may cast shadows wrongly.
*/
float sceneBoundingRadius = 50;
/**
* The distance from the light to the scene, assuming that the scene is located
* at [0, 0, 0]. Using the Pythagorean theorem, the distance is calculated by taking the square-root of the
* sum of each of the components of the light position squared.
*/
float lightToSceneDistance = (float) Math.sqrt(lightPosition.get(0) * lightPosition.get(0) +
lightPosition.get(1) * lightPosition.get(1) +
lightPosition.get(2) * lightPosition.get(2));
/**
* The distance to the object that is nearest to the camera. This excludes objects that do not cast shadows.
* This will be used as the zNear parameter in gluPerspective.
*/
float nearPlane = lightToSceneDistance - sceneBoundingRadius;
if (nearPlane < 0) {
System.err.println("Camera is too close to scene. A valid shadow map cannot be generated.");
}
/**
* The field-of-view of the shadow frustum in degrees. Formula taken from the OpenGL SuperBible.
*/
float fieldOfView = (float) Math.toDegrees(2.0F * Math.atan(sceneBoundingRadius / lightToSceneDistance));
glMatrixMode(GL_PROJECTION);
// Store the current projection matrix.
glPushMatrix();
glLoadIdentity();
// Generate the 'shadow frustum', a perspective projection matrix that shows all the objects in the scene.
gluPerspective(fieldOfView, 1, nearPlane, nearPlane + sceneBoundingRadius * 2);
// Store the shadow frustum in 'lightProjection'.
glGetFloat(GL_PROJECTION_MATRIX, lightProjection);
glMatrixMode(GL_MODELVIEW);
// Store the current model-view matrix.
glPushMatrix();
glLoadIdentity();
// Have the 'shadow camera' look toward [0, 0, 0] and be location at the light's position.
gluLookAt(lightPosition.get(0), lightPosition.get(1), lightPosition.get(2), 0, 0, 0, 0, 1, 0);
glGetFloat(GL_MODELVIEW_MATRIX, lightModelView);
// Set the view port to the shadow map dimensions so no part of the shadow is cut off.
glViewport(0, 0, shadowMapWidth, shadowMapHeight);
// Bind the extra frame buffer in which to store the shadow map in the form a depth texture.
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
// Clear only the depth buffer bit. Clearing the colour buffer is unnecessary, because it is disabled (we
// only need depth components).
glClear(GL_DEPTH_BUFFER_BIT);
// Store the current attribute state.
glPushAttrib(GL_ALL_ATTRIB_BITS);
{
// Disable smooth shading, because the shading in a shadow map is irrelevant. It only matters where the
// shape
// vertices are positioned, and not what colour they have.
glShadeModel(GL_FLAT);
// Enabling all these lighting states is unnecessary for reasons listed above.
glDisable(GL_LIGHTING);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_NORMALIZE);
// Disable the writing of the red, green, blue, and alpha colour components,
// because we only need the depth component.
glColorMask(false, false, false, false);
// An offset is given to every depth value of every polygon fragment to prevent a visual quirk called
// 'shadow
// acne'.
glEnable(GL_POLYGON_OFFSET_FILL);
// Draw the objects that cast shadows.
drawScene();
/**
* Copy the pixels of the shadow map to the frame buffer object depth attachment.
* int target -> GL_TEXTURE_2D
* int level -> 0, has to do with mip-mapping, which is not applicable to shadow maps
* int internalformat -> GL_DEPTH_COMPONENT
* int x, y -> 0, 0
* int width, height -> shadowMapWidth, shadowMapHeight
* int border -> 0
*/
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, shadowMapWidth, shadowMapHeight, 0);
// Restore the previous model-view matrix.
glPopMatrix();
glMatrixMode(GL_PROJECTION);
// Restore the previous projection matrix.
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}// Restore the previous attribute state.
glPopAttrib();
// Restore the view port.
glViewport(0, 0, Display.getWidth(), Display.getHeight());
lightProjectionTemp.load(lightProjection);
lightModelViewTemp.load(lightModelView);
lightProjection.flip();
lightModelView.flip();
depthModelViewProjection.setIdentity();
// [-1,1] -> [-0.5,0.5] -> [0,1]
depthModelViewProjection.translate(new Vector3f(0.5F, 0.5F, 0.5F));