🔒 Locked
shadow maps question
Advertisement
Original Post
Yes, you need a separate depth map for each lightsource. When rendering the shadowed geometry, you perform as many tests as there are lights, and somehow combine the results. I said "somehow", because different people use different methods, it's more often than not an artistic decision. The physically most correct way is to add the light contribution of all sources together, each one multiplied with the shadow comparison factor of its depth map.
1) Start by rendering each light to its individual depth surface
2) Bind each surface to a separate texture (imaging) unit.
3) Set up a depth compare for each unit, making sure that the generated projected texture coordinates for each unit match the one of the respective lightsource.
4) Use the following equation per pixel:
c(final_light) = c(light0) * depthCompareResult(0) + c(light1) * depthCompareResult(1) + ...
5) Multiply the c(final_light) with whatever diffuse texture or colour you might need.
1) Start by rendering each light to its individual depth surface
2) Bind each surface to a separate texture (imaging) unit.
3) Set up a depth compare for each unit, making sure that the generated projected texture coordinates for each unit match the one of the respective lightsource.
4) Use the following equation per pixel:
c(final_light) = c(light0) * depthCompareResult(0) + c(light1) * depthCompareResult(1) + ...
5) Multiply the c(final_light) with whatever diffuse texture or colour you might need.
I have a question relating to Shadow maps.. I think I sort of understand how the process of setting up the depth map works, but what I dont understand is the rendering process.. (basically) how does the texture create these shadows on the screen, and do you use a textured quad in front of the camera? I know a quad is involved somehow, but.. I just don't see how it all fits together at the moment. Maybe someone could direct me to a nice explanation of shadow mapping.
A couple of shadow map links:
nVidia paper
Paul's Projects tutorial
To provide a bit of answer to your question Mikey, shadow mapping makes use of projective texturing, to project the shadow map onto the geometry into the scene. Using this you can easily figure out which texel in the shadow map applies to the particular part of the geometry you are rendering, and thus know if it is in shadow or not WRT the light source.
-Mezz
nVidia paper
Paul's Projects tutorial
To provide a bit of answer to your question Mikey, shadow mapping makes use of projective texturing, to project the shadow map onto the geometry into the scene. Using this you can easily figure out which texel in the shadow map applies to the particular part of the geometry you are rendering, and thus know if it is in shadow or not WRT the light source.
-Mezz
Quote:
Original post by McZ
I can't really understand how the shadow maps can be valid at the same time..
I'm not sure I understand this question. If you have one shadow map for each light, then render the scene from each light's POV into their shadow maps, then all the shadow maps contain valid information. After you've done this, you can use these shadow maps when drawing your actual scene from the viewer's perspective, to tell whether certain objects are in shadow or not.
Quote:
Original post by McZ
this will cost alot of texunits?
It will if you do multiple lights in one pass, but you can do a pass per light and only bind one of your shadow map textures at a time, hence only using one texture unit.
Quote:
Original post by McZ
or do I create an extra pass that project all of them into one big depthmap and use that one only?
I've never heard of this as a technique, so I couldn't recommend it.
-Mezz
If you don't have enough texture units to do one light in a single pass... well, that's some complex lighting equation you have going on there :)
If you were able to split one light into multiple passes, then yes you'd still need a shadow test for each pass, remember that in the end all your shadow test does is effectively multiply the light's value either by 1.0 (i.e. full brightness) if it's not in shadow, or 0.0 (i.e. no brightness at all) if it is. Sometimes you might multiply it somewhere in between if it's on a boundary but that's a more advanced case.
If you have more depth maps than texture units... well, like has been said previously, you need to do a pass per light, or whatever you can afford. You only need the depth map for the light you are rendering, so if you do a single pass per light, you would use at most 1 texture unit with the depth map.
Hope that clears some stuff up.
-Mezz
If you were able to split one light into multiple passes, then yes you'd still need a shadow test for each pass, remember that in the end all your shadow test does is effectively multiply the light's value either by 1.0 (i.e. full brightness) if it's not in shadow, or 0.0 (i.e. no brightness at all) if it is. Sometimes you might multiply it somewhere in between if it's on a boundary but that's a more advanced case.
If you have more depth maps than texture units... well, like has been said previously, you need to do a pass per light, or whatever you can afford. You only need the depth map for the light you are rendering, so if you do a single pass per light, you would use at most 1 texture unit with the depth map.
Hope that clears some stuff up.
-Mezz
I tried to implement Nvidia's HardwareShadowMap sample, but I am definitely not seeing the right results.
(http://download.nvidia.com/developer/SDK/Individual_Samples/DEMOS/Direct3D9/HardwareShadowMap.zip)
-set the render target to the color surface
-set the depth stencil surface to the new one
-clear the target & depth buffer
-set the new viewport
-set up matrices from lights POV.
-draw each mesh with the 2nd technique (GenHardwareShadowMap)
-reset the viewport
-reset the render target/depth buffers
-clear the target/depthbuffer
-set up texScaleBias Matrix
-set "ShadowMap" to the depth texture
-set "spotlight" texture
-set view's worldviewproj and worldIT for each mesh
-Draw each mesh with 1st technique (UseHardwareShadowMap)
-Rinse, lather, repeat
And this is what it looks like: (Top in wireframe, bottom solid, gray = color render target rendered to a sprite)
So anybody know what many things I might be doing wrong?
(http://download.nvidia.com/developer/SDK/Individual_Samples/DEMOS/Direct3D9/HardwareShadowMap.zip)
-set the render target to the color surface
-set the depth stencil surface to the new one
-clear the target & depth buffer
-set the new viewport
-set up matrices from lights POV.
-draw each mesh with the 2nd technique (GenHardwareShadowMap)
-reset the viewport
-reset the render target/depth buffers
-clear the target/depthbuffer
-set up texScaleBias Matrix
-set "ShadowMap" to the depth texture
-set "spotlight" texture
-set view's worldviewproj and worldIT for each mesh
-Draw each mesh with 1st technique (UseHardwareShadowMap)
-Rinse, lather, repeat
And this is what it looks like: (Top in wireframe, bottom solid, gray = color render target rendered to a sprite)
So anybody know what many things I might be doing wrong?
Well there isn't really anything wrong with the algorithm you've written there MikeyO, but I can't tell what the problem is just from those shots. Are you sure you're doing the texture projection correctly in the UseHardWareShadowMap phase?
I assume you're just using nVidia's shaders, in which case they will be correct.
Hmm... dunno.
-Mezz
I assume you're just using nVidia's shaders, in which case they will be correct.
Hmm... dunno.
-Mezz
Ok, here's the relevent source code... I'm sure it's either some fundamental error, something I'm doing completely wrong, or its a few small things I'm forgetting. - Captain Obvious
The shader can be found here: http://pk.dras.us/users/Orion/ShadowMap.fx
Anything that is just glare-in-your-face obvious? subtle errors? Help thus far has been greatly appreciated.
///////INITIALIZATION CODE//////shadowFX.SetValue("LightVec", Vector4.Scale(Vector4.Normalize(new Vector4(lightVector.X, lightVector.Y, lightVector.Z, 1.0f)), 100));backBuffer = device.GetRenderTarget(0); //I assume this is a reference..zBuffer = device.DepthStencilSurface;colShadowTex = new Texture(device, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, Usage.RenderTarget, Format.A8R8G8B8, Pool.Default); //Color texturezShadowTex = new Texture(device, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, Usage.DepthStencil, Format.D24S8, Pool.Default); //Z depth textureshadowColSurface = colShadowTex.GetSurfaceLevel(0); //Color surfaceshadowZSurface = zShadowTex.GetSurfaceLevel(0); //Z depth surfacelightPosition = new Vector3(1000, 1000, 0);///////MAKE SHADOW CODE//////////Matrix World;Vector3 lookAt = Vector3.Subtract(lightPosition, lightVector);Matrix lightView, lightProj;lightView = Matrix.LookAtLH(lightPosition, lookAt, new Vector3(0, 1, 0));lightProj = Matrix.PerspectiveFovLH((float)Math.PI / 3, 1, 1, 1000);lightViewProj = lightView * lightProj;device.SetRenderTarget(0, shadowColSurface);device.DepthStencilSurface = shadowZSurface; Viewport oldViewport = device.Viewport;Viewport newViewport = new Viewport();newViewport.X = 0; newViewport.Y = 0;newViewport.Width = SHADOW_MAP_SIZE;newViewport.Height = SHADOW_MAP_SIZE;newViewport.MinZ = 0.0f;newViewport.MaxZ = 1.0f;device.Viewport = newViewport;shadowFX.Technique = shadowFX.GetTechnique(1);device.RenderState.DepthBias = 0.0002f;device.RenderState.SlopeScaleDepthBias = 2.0f;device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Gray/*0x00FFFFFF*/, 1.0f, 0);device.VertexDeclaration = defDeclare;Matrix tempIdent = Matrix.Identity;int passes;for(int i = 0; i < balls.Count; i++){ Ball b = (Ball)balls; ///////RENDER CODE HERE ///// World = device.Transform.World = Matrix.Scaling(1, 1, 1) * Matrix.RotationYawPitchRoll(0,0,0) * Matrix.Translation(b.position); device.Transform.World = World; //Set up matrices Matrix WorldViewProj = World * lightViewProj; Matrix WorldITMat = Matrix.TransposeMatrix(Matrix.Invert(World)); shadowFX.SetValue("WorldViewProj", WorldViewProj); shadowFX.SetValue("WorldIT", WorldITMat); shadowFX.SetValue("TexTransform", tempIdent); passes = shadowFX.Begin(0); for(int j = 0; j < passes; j++) { shadowFX.BeginPass(j); ballMesh.DrawSubset(0); shadowFX.EndPass(); } shadowFX.End();}device.Transform.World = World = Matrix.Translation(0, -4, 0);shadowFX.SetValue("WorldViewProj", World * lightViewProj);shadowFX.SetValue("WorldIT", Matrix.TransposeMatrix(Matrix.Invert(World)));passes = shadowFX.Begin(0);for(int j = 0; j < passes; j++){ shadowFX.BeginPass(j); plane.DrawSubset(0); shadowFX.EndPass();}shadowFX.End();//Reset render settingsdevice.Viewport = oldViewport;device.RenderState.DepthBias = 0.0f;device.RenderState.SlopeScaleDepthBias = 0.0f;//////////USE SHADOW CODE///////////////////Generate Shadow MapRenderShadowMap(device, View, Proj); //Calls above code (MAKE SHADOW CODE)//Render SceneshadowFX.Technique = shadowFX.GetTechnique(0); //Use shadow techniquedevice.SetRenderTarget(0, backBuffer); //reset to original render targetdevice.DepthStencilSurface = zBuffer;device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Blue, 1.0f, 0);shadowFX.SetValue("ShadowMap", zShadowTex);shadowFX.SetValue("SpotLight", decalShadowModel);float fOffset = 0.5f + (0.5f / (float)SHADOW_MAP_SIZE);int range = 1;float fbias = 0f;Matrix texScaleBiasMat = new Matrix();texScaleBiasMat.M11 = 0.5f;texScaleBiasMat.M22 = -0.5f;texScaleBiasMat.M33 = (float)range;texScaleBiasMat.M12 = texScaleBiasMat.M13 = texScaleBiasMat.M14 = texScaleBiasMat.M21 = texScaleBiasMat.M23 = texScaleBiasMat.M24 = texScaleBiasMat.M31 = texScaleBiasMat.M32 = texScaleBiasMat.M34 = 0.0f;texScaleBiasMat.M41 = texScaleBiasMat.M42 = fOffset;texScaleBiasMat.M43 = fbias;texScaleBiasMat.M44 = 1.0f;int passes;for(int i = 0; i < balls.Count; i++){ Ball b = (Ball)balls; ///////RENDER CODE HERE ///// World = device.Transform.World = Matrix.Scaling(1, 1, 1) * Matrix.RotationYawPitchRoll(0,0,0) * Matrix.Translation(b.position); device.Transform.World = World; //Set up Matrices Matrix WorldViewProj = World * View * Proj; Matrix WorldIT = Matrix.TransposeMatrix(Matrix.Invert(World)); shadowFX.SetValue("WorldViewProj", WorldViewProj); shadowFX.SetValue("WorldIT", WorldIT); shadowFX.SetValue("TexTransform", World * lightViewProj * texScaleBiasMat); passes = shadowFX.Begin(0); for(int j = 0; j < passes; j++) { shadowFX.BeginPass(j); ballMesh.DrawSubset(0); shadowFX.EndPass(); } shadowFX.End();}shadowFX.SetValue("SpotLight", decalShadowSurf);device.Transform.World = World = Matrix.Translation(0, -4, 0);shadowFX.SetValue("WorldViewProj", World * View * Proj);shadowFX.SetValue("WorldIT", Matrix.TransposeMatrix(Matrix.Invert(World)));passes = shadowFX.Begin(0);for(int j = 0; j < passes; j++){ shadowFX.BeginPass(j); plane.DrawSubset(0); shadowFX.EndPass();}shadowFX.End();The shader can be found here: http://pk.dras.us/users/Orion/ShadowMap.fx
Anything that is just glare-in-your-face obvious? subtle errors? Help thus far has been greatly appreciated.
Quote:
Original post by Mezz
If you don't have enough texture units to do one light in a single pass... well, that's some complex lighting equation you have going on there :)
If you were able to split one light into multiple passes, then yes you'd still need a shadow test for each pass, remember that in the end all your shadow test does is effectively multiply the light's value either by 1.0 (i.e. full brightness) if it's not in shadow, or 0.0 (i.e. no brightness at all) if it is. Sometimes you might multiply it somewhere in between if it's on a boundary but that's a more advanced case.
If you have more depth maps than texture units... well, like has been said previously, you need to do a pass per light, or whatever you can afford. You only need the depth map for the light you are rendering, so if you do a single pass per light, you would use at most 1 texture unit with the depth map.
Hope that clears some stuff up.
-Mezz
lets say I have 4 texture units and 2 of them is texture but I have 4 shadowcasting lights(depthmaps) so then I need to do it in 2 passes?
first make sure the depthmaps is updated.
bind the textures for the mesh
bind the first 2 depthmaps
draw
blend scene with the new pass
bind the last 2 depthmaps
draw
or is it some other way?
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement