• Create Account

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

9 replies to this topic

#1mv348  Members

263
Like
0Likes
Like

Posted 01 September 2012 - 12:54 AM

So I believe the next step in m engine is to add shadows. After doing some research, shadow mapping seems to be a popular and fast method.

The theory makes sense to me, but I find it slightly surprising that it uses a full scene render per light-source. I've noticed that modern games seem to use a pretty high number of light sources! Is this technique advisible for a large number of lights?

Moreover, the method works by rendering from the lamps point of view, so the light is limited to a frustum pointing in one specific direction. I presume you would have to do multiple renders for a light spreading out in all directions?

I read some hardware offers 'shadow mapping support'. What kind of support is available? I'm using OpenGL/GLSL

#2Hodgman  Moderators

49386
Like
1Likes
Like

Posted 01 September 2012 - 01:12 AM

I find it slightly surprising that it uses a full scene render per light-source. I've noticed that modern games seem to use a pretty high number of light sources

Yes, some new games do use as many as a thousand dynamic lights, however, only a small number of them will actually be shadow-casting lights.

Also, in specific scenes / specific scenarios, you don't need a "full scene" render per light.
e.g. I once worked on a racing game where all of the environment shadows used static light-map techniques, so only the dynamic cars themselves needed shadow mapping. We also used "deferred shadow maps" where you accumulate the shadow information into a full-screen texture. We would render each car individually into it's own shadow map (which makes good use of low resolution shadow textures), and then composited each single shadow into the full-screen texture. This meant we had to render (at most) an extra numCars * numLights for shadows -- not wholeScene * numLights.
You should also perform frustum culling (and full visibility culling if your scene supports it) on the light, so that you're only rendering objects that are visible from it's viewpoint. If no cars were visible from a particular light, then no extra rendering was performed for it.

Moreover, the method works by rendering from the lamps point of view, so the light is limited to a frustum pointing in one specific direction. I presume you would have to do multiple renders for a light spreading out in all directions?

Yes, the most obvious solution is 6 different 90º frustums rendered to a "cube-shadow-map". There's also hemisphere-based solutions that use fewer frustums (Dual-Paraboloid SM or Dual Sphere-Unfolding SM), or complex distortion methods like CSSM, but these alternatives generally exhibit more distortion than the basic solution.

Edited by Hodgman, 01 September 2012 - 01:20 AM.

#3MJP  Moderators

18192
Like
1Likes
Like

Posted 01 September 2012 - 12:35 PM

The "hardware support" for shadow maps amounts to "free" depth comparison and 2x2 PCF filtering when sampling the shadow map. Usually it's implemented by rendering your shadow map depth to a depth buffer, then sampling that depth buffer with a special instruction and/or sampler state in the shader. Unfortunately I'm not familiar with how it's done in GLSL so I couldn't tell you offhand.

#4Ignifex  Members

507
Like
1Likes
Like

Posted 01 September 2012 - 03:07 PM

For OpenGL / GLSL, you need to set up your depth texture to do a comparison upon lookup using for instance:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

Then, in your shader, you should give your shadowmap uniform the type sampler2DShadow. This will allow you to call the regular texture function, or one of its variants, with a 3 dimensional texture coordinate. The third coordinate is the depth value used for comparison.

#5mv348  Members

263
Like
1Likes
Like

Posted 15 September 2012 - 11:12 PM

Thanks for all the input guys! I just got shadow-mapping workingwith a single light, for a single model. So now I am moving towards multiple lights, and multiple models.

To avoid excessive extra-rendering, I am planning on enclosing each lamp in a bounding volume (i.e. an Axis Aligned Bounding Box) and checking for intersections with each models bounding volume. I admit I haven't read up much on this just yet, there's something called 'Cascaded Shadows' that I need to look into, but I wanted to get your input on the algorithm I came up with today.

Here's the psuedo-code. Should be pretty self explanatory:


Algorithm:

PositionModels()
PositionsLights()
/////////////////
/////////////////

for  light in AllLights
{
// determine which models are hit by the light
for model in AllModels:
{
if (collision(light.volume, model.volume)
{
}
}

// if any models were hit by the light
if (light.modelsInView.Count > 0)
{

// render all models in this light's view to the light's shadowmap
for model in light.modelsInView
{
model.render();
}

}

}

//////////////////
// FINAL RENDER //
//////////////////

for model in models:
{
{
}
model.render();

}



Obviously the relevant lists need to be cleared after each rendered. Further optimizations can obviously be made, such as caching shadows for stable objects. But I think the general structure is captured here, wouldn't you say?

Any input/feedback would be appreciated.

Edited by mv348, 15 September 2012 - 11:23 PM.

#6RetroIP  Members

405
Like
0Likes
Like

Posted 16 September 2012 - 12:36 PM

Your approach seems correct form my view, I have something similar, but not in OpenGL.

//Generating shadows
{
foreach light
{
foreach object
{
if(distance(object,light)<30
{
render object to shadowmap for this light
}
}
}
}
foreach light
{
{
}
else
{
render light
}
}


Edited by RetroIP, 16 September 2012 - 12:38 PM.

Small gate to retron element on [http://retron.sk] | ProjectNN - Experimental AI project which will cover Survival, Social and Battle simulation of various lifeforms.

#7mv348  Members

263
Like
0Likes
Like

Posted 17 September 2012 - 08:25 PM

Thanks! Glad I'm on the right track!

I have a question though. The algorithm I outlined should work fine provided I am using spot-lamps with a relatively small area of effect. However, using directional lights, such as sunlight, poses a bit of a problem. I would have to render the entire scene from a sufficient distance to capture everything. A single shadow-map spread out over an entire scene is going to look awful pixelated for large, outdoor environments.

How can I address this issue?

#8MJP  Moderators

18192
Like
1Likes
Like

Posted 17 September 2012 - 11:09 PM

Cascaded shadow maps is the most common solution for directional lights, and I'd recommend it as a starting point.

#9mv348  Members

263
Like
0Likes
Like

Posted 18 September 2012 - 11:19 PM

Thanks so much, MJP!

So I started reading through this article by Nvidia. I'm making some headway with it, but its a bit difficult to follow at times. Some of the details are posted in the references, but require a subscription to read.

Any particular tutorial or paper suggestions would be welcome.

#10L. Spiro  Members

24826
Like
1Likes
Like

Posted 19 September 2012 - 05:01 AM

To avoid excessive extra-rendering, I am planning on enclosing each lamp in a bounding volume (i.e. an Axis Aligned Bounding Box) and checking for intersections with each models bounding volume.

For directional lights, I have written a tutorial on how to “capture” only objects that are inside the camera frustum or could cast shadows into the camera’s frustum, tightly excluding all other objects.

Tutorial: Tightly Culling Shadow Casters for Directional Lights (Part 1)
Tutorial: Tightly Culling Shadow Casters for Directional Lights (Part 2)

L. Spiro

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.