This topic is 4793 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I have been reading alot of different tutorials and stuff here on this forum, but one thing I havn't understand yet is if I need one depthmap for each light that cast shadows? but then I need to activate all of them at the same time when doing the test against the depthmap?

##### Share on other sites
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.

##### Share on other sites
EDIT Beaten by Yann

-Mezz

##### Share on other sites
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.

##### Share on other sites

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

##### Share on other sites
Do shadow casters/reciever meshes need to have UV coordinates?

##### Share on other sites
The depth map is projected onto the shadow receivers, so the uv coords are generated. The nVidia paper that Mezz posted is a very good reference, especially when you first start to learn about shadow maps.

##### Share on other sites
ok, I'll look into the nVidia paper... but so far I can't really understand how the shadow maps can be valid at the same time.. this will cost alot of texunits? or do I create an extra pass that project all of them into one big depthmap and use that one only?

##### Share on other sites
Quote:
 Original post by McZI 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 McZthis 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 McZor 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

##### Share on other sites
ahh thank you! now I understand :)

I use up all tex units I have free for a pass.. but what if my texunits isn't enough for one pass? how do I split it into several passes? do the extra passes also need depthmap testing?

and what to do if I have more depthmaps then tex units?

##### Share on other sites
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

##### Share on other sites
I tried to implement Nvidia's HardwareShadowMap sample, but I am definitely not seeing the right results.

-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?

##### Share on other sites
Heres what it should look like (this is with stencil volumes though):

##### Share on other sites

I know a quad is involved somehow
[\quote]
I think you were meaning a volume shadows bad version, in wich you use a black quad over the whole screen to create the shadows, using the stencil generated mask to render it.

##### Share on other sites
No, I mean shadow mapping.. I realized some time ago that the quad they(nvidia) are creating in their sample is only used for the shadow casting object's shadow to be projected onto (:D).

##### Share on other sites
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

##### Share on other sites
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

///////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();

Anything that is just glare-in-your-face obvious? subtle errors? Help thus far has been greatly appreciated.

##### Share on other sites
I finally got it working by removing the new viewport code.

##### Share on other sites
Quote:
 Original post by MezzIf 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?

##### Share on other sites
Not that I'm aware of (well, you could split it into 4 passes if you wanted) but that 2-pass approach looks fine McZ.

-Mezz

##### Share on other sites
just another thing, do I need the textures for the mesh in all passes? or can I blend it someway so that I only need to draw the textures for the mesh in one pass and skip them in the others?

##### Share on other sites
You need the textures for you mesh in each pass, in every case I can currently think of.

-Mezz

##### Share on other sites
Yes, I would - what you have to understand is that the shadow map is simply part of your lighting equation. Everything you do with normal maps, diffuse textures, specular highlights etc. is all part of the lighting equation - so is the shadow map, it just tells you what to multiply your final light result by - either a 1 or a 0 in simple terms (although with some PCF it can change to a fractional value for something partially in shadow).

-Mezz

##### Share on other sites
so for all passes I do I will need all textures and stuff as if it was the first pass? but with some blending I guess so I add it to the pass before..

like this?

pass 1
bind textures/normal maps etc.
bind the depthmaps for this pass
draw mesh

pass 2...n
enable blending
bind textures/normal maps etc.
bind depthmaps that didn't fit in pass 1
draw mesh

how do I know which depthmap to use? do I add some kind of range on the lights so I can check if the object is in the lights range, if so then it will be affected by the lights depthmap else it will not?