How to do geometric projection shadows?
- by John Murdoch
I have decided that since my game world is mostly flat I don't need better shadows than geometric projections - at least for now.
The only problem is I don't even know how to do those properly - that is to produce a 4x4 matrix which would render shadows for my objects (that is, I guess, project them on a horizontal XZ plane).
I would like a light source at infinity (e.g., the sun at some point in the sky) and thus parallel projection.
My current code does something that looks almost right for small flying objects, but actually is a very rude approximation, as it doesn't project the objects onto the ground, but simply moves them there (I think). Also it always wrongly assumes the sun is always on the zenith (projecting straight down).
Gdx.gl20.glEnable(GL10.GL_BLEND);
Gdx.gl20.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
//shells
shellTexture.bind();
shader.begin();
for (ShellState state : shellStates.values()) {
transform.set(camera.combined);
transform.mul(state.transform);
shader.setUniformMatrix("u_worldView", transform);
shader.setUniformi("u_texture", 0);
shellMesh.render(shader, GL10.GL_TRIANGLES);
}
shader.end();
// shadows
shader.begin();
for (ShellState state : shellStates.values()) {
transform.set(camera.combined);
m4.set(state.transform);
state.transform.getTranslation(v3);
m4.translate(0, -v3.y + 0.5f, 0); // TODO HACK: + 0.5f is a hack to ensure the shadow appears above the ground; this is overall a hack as we are just moving the shell to the surface instead of projecting it on the surface!
transform.mul(m4);
shader.setUniformMatrix("u_worldView", transform);
shader.setUniformi("u_texture", 0); // TODO: make shadow black somehow
shellMesh.render(shader, GL10.GL_TRIANGLES);
}
shader.end();
Gdx.gl.glDisable(GL10.GL_BLEND);
So my questions are:
a) What is the proper way to produce a Matrix4 to pass to openGL which would render the shadows for my objects?
b) I am supposed to use another fragment shader for the shadows which would paint them in semi-transparent grey, correct?
c) The limitation of this simplistic approach is that whenever there is some object on the ground (it is not flat) the shadows will not be drawn, correct?
d) Do I need to add something very small to the y (up) coordinate to avoid z-fighting with ground textures? Or is the fact they will be semi-transparent enough to resolve that problem?