Ecumene
|
 |
«
Posted
2015-01-09 16:24:09 » |
|
I'm slowly making progress with my game engine, but I can't seem to get omni-directional shadow maps to work. The shading for each point light is done in two passes: It renders the depth component 6 times in each direction (for the cube that is). One framebuffer is used to draw to a cube map. Then it passes the scene again with the light's calculation, sampling the cube-map texture. Here's what I understand & have so far, To initialize the OpenGL cubemap, there's 6 enums for 6 textures with one binding: 1 2 3 4 5 6 7
| GL13.GL_TEXTURE_CUBE_MAP GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_X GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Y GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Z GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z |
And the per-cubemap-face constants: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private final static int[] GL_CUBEMAP_ENUM = { GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, };
private final static Vector3f[] DIRECTIONS = new Vector3f[] { new Vector3f( 1.0f, 0.0f, 0.0f), new Vector3f(-1.0f, 0.0f, 0.0f), new Vector3f( 0.0f, 1.0f, 0.0f), new Vector3f( 0.0f,-1.0f, 0.0f), new Vector3f( 0.0f, 0.0f, 1.0f), new Vector3f( 0.0f, 0.0f,-1.0f), };
private final static Vector3f[] DIRECTIONS_UP = new Vector3f[]{ new Vector3f(0.0f,-1.0f, 0.0f), new Vector3f(0.0f,-1.0f, 0.0f), new Vector3f(0.0f, 0.0f,-1.0f), new Vector3f(0.0f, 0.0f, 1.0f), new Vector3f(0.0f,-1.0f, 0.0f), new Vector3f(0.0f,-1.0f, 0.0f), }; |
And were I loop through the cubemap to initialize it: 1 2 3 4 5 6
| depthCubeMap = new Texture(GL13.GL_TEXTURE_CUBE_MAP, WorldLightBatchObject.SHADOW_MAP_TMUNIT, GL11.GL_NEAREST, GL11.GL_REPEAT); depthCubeMap.bind(); for(int i = 0; i < 6; i++){ GL13.glActiveTexture(GL13.GL_TEXTURE0 + WorldLightBatchObject.SHADOW_MAP_TMUNIT); GL11.glTexImage2D(GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL14.GL_DEPTH_COMPONENT24, (int) (WorldGameContext.SHADOW_MAP_MUL * 1024), (int) (WorldGameContext.SHADOW_MAP_MUL * 1024), 0, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (ByteBuffer) null); } |
Initializing the framebuffer & the perspecive matrix 1 2 3 4
| depthFrame = new Frame(GL30.GL_FRAMEBUFFER); depthFrame.bind();
depthProjection = Projection.createPerspective(90f, 1.f, 0.01f, 100f); |
And to render to the depth-map: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| GL11.glPushAttrib(GL11.GL_VIEWPORT_BIT | GL11.GL_ENABLE_BIT); GL11.glViewport(0, 0, (int) (WorldGameContext.SHADOW_MAP_MUL * 1024), (int) (WorldGameContext.SHADOW_MAP_MUL * 1024)); for(int i = 0; i < 6; i++){ GL11.glColorMask(false, false, false, false); GL11.glEnable(GL11.GL_DEPTH_TEST); GL11.glClearColor(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE); depthFrame.bind(); GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL_CUBEMAP_ENUM[i], depthCubeMap.getID(), 0); GL11.glDrawBuffer(GL11.GL_NONE); GL11.glReadBuffer(GL11.GL_NONE); GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); Matrix4f depthTransform = getLightMatrix(i); depthProgram.use(); depthProgram.setUniformM4("u_tLight", false, depthTransform); depthProgram.setUniformf("u_lPosition", position.x, position.y, position.z); rootObject.render(null, depthProgram); GL11.glColorMask(true, true, true, true); } GL11.glPopAttrib(); GL11.glClearDepth(1.0d); |
And to find the light projection/view matrix per-face, (I'm certain this one's right, worked with the spotlight...) 1 2 3 4 5 6 7 8
| private Matrix4f getLightMatrix(int index){ Vector3f direction = DIRECTIONS[index]; Vector3f up = DIRECTIONS_UP[index]; Matrix4f out = ViewTransformComponent.lookat(position, direction, up); out.mul(depthProjection); return out; } |
Here's what I use in the light pass, to multiply with the light fragment v_position is in world space (object matrix * vertex) and l_position is traditionally in world space 1 2 3 4 5 6 7 8 9 10 11
| uniform samplerCube u_sDepthMap;
float shadowVisibility(vec3 l_position, vec3 v_position){ vec3 l_direction = l_position - v_position; float depth = length(l_direction); float sample = textureCube(u_sDepthMap, normalize(l_direction)).z; if(sample <= depth + 0.00005) return 1; else return 0; }; |
And the fragment shader for the 'depth' pass, same world space calculation as before just with the light's matrix. 1 2 3 4 5 6 7 8 9
| #include "./asset/shader/global.fsh"
varying vec3 v_lPosition_ws; varying vec3 v_vPosition_ws;
vec4 calcPixel() { return vec4(length(v_vPosition_ws - v_lPosition_ws)); } |
Vertex shader for the 'depth' pass 1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include "./asset/shader/global.vsh"
uniform mat4 u_tLight; uniform vec3 u_lPosition;
varying vec3 v_lPosition_ws; varying vec3 v_vPosition_ws;
void main(void) { v_lPosition_ws = u_lPosition; v_vPosition_ws = vec3(u_tObject * gl_Vertex); gl_Position = u_tLight * vec4(v_vPosition_ws, gl_Vertex.w); } |
Stack overflow doesn't know what's up, but here's the output:  As you can see in the small circle is an error I noticed happening. But in the large circle the shadows not projecting. More code will be provided on request. Thanks in advance!
|