Projected Textures Vs Shadow Maps

Hi everyone! :slight_smile:

Guys… I am so lost with shadows.
I don’t know yet where to point to, and that makes it very frustrating. Could you please point me in the right direction?

I know I want:

  1. Shadows that respond to Alpha Channel since I use trees with alpha maps for their leaves (so Volume Shadows is discarded)
  2. Soft Shadows with medium opacity (not solid black and no hard edges)
  3. My scenes have only Directional lighting caused by sunlight (no interior lighting).
  4. Performance: don’t care if shadows are not updated (if shadows are kept static that would be fine for me as long as FPS are kept high).

Do you recommend me using Projected Texture Shadows approach or Shadowmapping? Or another technique?

I find information and examples on this topic so lacking!

Thanks so much everyone!
Cheers!
Rod

  1. Yes, shadow volumes are out. You need shadow maps.
  2. Hold on a sec! This is the part where most beginners make their major error: shadow does not have opacity - it is not blended to scene. I’m explaining this below.
  3. Good for you - shadowmaps from directional light are simplest to implement. Later you will probably want perspective shadow maps or something similar to achieve better quality and area of shadows.
  4. Not much performance difference between shadow maps and projected textues. I suggest shadowmaps then (actually they are sort of projected textures).

Ok, now about that opacity thing.
The whole idea is that all objects receive ambient lighting and only objects not in shadow receive lighting from light source. So, objects inside a shadow receive ambient, and objects outside shadow receive ambient+light. For outdoor scenery ambient can be a dark blue-grey color, and sunlight can be bright yellow (nearly white).
Rendering is done in two passes:

  1. Render all scene with no lighting enabled, modulate textures with constant ambient color (actually some kind of ambient occlusion would be better but for now just use constant color)
  2. Render scene again - render scene with lighting from sun, but with no ambient lighting. Multiply pixels by shadowmap comparison result (pixels in shadow will be perfctly black) and add to existing scene.

Ok, now about that opacity thing.
The whole idea is that all objects receive ambient lighting and only objects not in shadow receive lighting from light source. So, objects inside a shadow receive ambient, and objects outside shadow receive ambient+light. For outdoor scenery ambient can be a dark blue-grey color, and sunlight can be bright yellow (nearly white).
Rendering is done in two passes:

  1. Render all scene with no lighting enabled, modulate textures with constant ambient color (actually some kind of ambient occlusion would be better but for now just use constant color)
  2. Render scene again - render scene with lighting from sun, but with no ambient lighting. Multiply pixels by shadowmap comparison result (pixels in shadow will be perfctly black) and add to existing scene. [/QB]
    Thanks!!! this makes it much more clearer :slight_smile:

About the implementation, is this a good path?:
1)Implementing Shadowmaps with FBO instead of glCopyImage2D, and using GLSL Shaders to do the pixel comparison with the depth texture instead of doing it directly in OpenGL (I read all this in other sites).

Is that a good idea? Or will using shaders slow performance?

2)About soft edges: Will I need to code a blur filter that is applied to the depth texture after it is created with FBO? (Is that done with shaders too?)

Thanks so much for everything! :slight_smile:
Cheers
Rod

It depends on what hardware you are targeting.

If your project will be on any older cards that may not support shaders you want a method that either avoids shaders or has a scalable fall back path that doesn’t use them (based on a run time check of the available extensions).

If you are only targeting recent (last couple years) graphics cards then I’d recommend using the shaders approach.

Remember this shadow approach requires at least three render passes. One from the light’s viewpoint and then two from the camera. (possibly more if you are using any multipass shader materials in your scene on objects receiving shadows)

Once you have it working… a neat optimization trick that may work for you is to only update the shadow map texture (render from light’s viewpoint) every two or three frames on a dynamic scene, or only when something changes if you have a static scene.

Well, you can do it in two passes if you have one light source. You can combine ambient pass with lighting pass - shader will always take ambient into account and add lighting from light source only in unshadowed areas. So that’s one pass from camera’s point of view.

Excellent optimization for the shader based approach. (as I run away to rewrite my shadow map shader :slight_smile: )

Just remember that with multiple lights you only add ambient in first pass (with first light).
On other passes you can discard fragments completely in shadow.

2)About soft edges: Will I need to code a blur filter that is applied to the depth texture after it is created with FBO? (Is that done with shaders too?)
Good blurring is sensitive to distance from shadow caster (more blur when shadow is casted by object far away).
That means you shouldn’t blur the shadowmap, but you should apply blur filter when rendering objects that receive shadow.

There is one important step you forgot to mention - 4). So the simpliest and fastest solution is to use some program (e.g. Maya) to generate lightmaps and use them as multitextures :-).

:slight_smile:
No, I haven’t forgot that. I intentionally didn’t mention such possibility. Rodrix seems to be in a perfect state to implement something cool. I just didn’t want to waste that potential. Performance will be nearly identical if he don’t update shadowmaps, since he’s interested in one light source. He would also get less memory consumption since unrolled lightmaps usually take more space than shadowmap, assuming texels have identical sizes.
And having static shadowmaps is a good starting point to make dynamic shadowmaps with multiple light sources.
I think nowadays it’s a good approach to use lightmaps for ambient lighting (calculate radiosity offline) and shadowmaps for light sources. Further combined with ambient occlusion for dynamic objects and light sources can produce very convincing results.

Thanks robosport, glAren, and k_szczech for all your comments! They are really very helpful. :slight_smile:

Originally posted by k_szczech:
No, I haven’t forgot that. I intentionally didn’t mention such possibility. Rodrix seems to be in a perfect state to implement something cool. I just didn’t want to waste that potential.
k_szczech your words are most valuable to me. There are moments in a man-only project where, after so much time working, obstacles seem really difficult to surpass. You really give me strength to continue. I was about to give up and go for lightmapping as shadowmapping seems to become a complex topic. Thanks to your post, you give me the strength to try implementing Shadow maps. Thanks, really. :slight_smile:

Now about GLSL:

As robosport said:
“If your project will be on any older cards that may not support shaders you want a method that either avoids shaders or has a scalable fall back path that doesn’t use them (based on a run time check of the available extensions).”

Reading through webpages I got the impression that
implementing Shadowmaps with GLSL was much straight foward than without GLSL (I even found some sample simple shadowmapping shaders). Given what you mention, I’ll probably code both solutions (shaders and non-shaders approach; although I am deciding which to start with).

Will shaders solution (if supported) be faster than extension’s solution or is that hardware dependent too?

Thanks so much everyone! :slight_smile:
Cheers,
Rod

Will shaders solution (if supported) be faster than extension’s solution or is that hardware dependent too?
On everything starting from GeForce 6 it makes no difference. These GPU’s don’t have fixed functionality pipeline - they use shaders anyway to emulate fixed functionality.
GLSL will be slow on GeForce FX, but simply focus on those GPU’s that can handle GLSL properly first. Then you can add fallback functionality that will use vertex shaders only, or no shaders at all if you prefer.

I was about to give up and go for lightmapping as shadowmapping seems to become a complex topic.
Shadowmaps evolved a lot during last years. When you look at perspective shadow maps or variance shadow maps you can get really confused at first. But when you look at very basic tutorials on shadowmapping on GeForce 3 it’s not that difficult. Furthermore, shadowmaps from directional light source (outdoor) are the simplest ones:

  1. Render scene from light’s point of view using glOrtho projection
  2. Copy depth to texture (don’t use FBO - just copy)
  3. Render scene with shadowmap projected using linear texgens and proper texture env mode

These linear texgens are nothing more than 3 axes pointing right, up, and forward when looking from light source’s point of view. They start at one corner of light source’s view frustum and end at the opposite one.
With point light there is some matrix math required, but with directional you only need texgens.

Then I wish you everlasting strength Rodrix. I guess we all know how difficult and long can be the jurney of the graphic engine developer. You are going to be more far in developement than me, because I still didn’t start with realtime shadow implementation having more important work around. But I look forward to it :wink: .

I remember I stayed away from shaders for a long time. I had GeForce 4Ti but didn’t write a single shader back then.
When I started experimenting with GLSL 2 years ago (under software emulation) I got so sucked in that I ran and bought GeForce 6600GT. I started with some distortion shader which evolved into water shader you can see in my game.
I actually learnt to write GeForce 3/Radeon 8500 shaders much later.
After that I began to advance very quickly. Not only I’ve learned new techniques and developed some on my own. My software runs 2 times faster and will be even faster in future as I’m still advancing and allready found new improvement opportunities for my applications.
I think you are where I was 2 years ago - if you make step forward now it will certainly not be your last.

I learn something new on this forum every day.

Why do you say GLSL is slower? I’m not disagreeing I’m just curious why.

Thanks!

Why do you say GLSL is slower?
It’s not. Except for GeForce FX I mentioned earlier.
First fragment shaders used 16-bit floating point numbers for calculations. This is how it was done on Radeon 8500 for example.
GeForce 3 and 4 did not have actual fragment shaders but they had advanced register combiners.

GLSL works on 32-bit floats and requires real programmable shaders. Such shaders are available in all Shader Model 2.0 cards. That means minimum Radeon 9500 or GeForce FX.
All Radeons could handle 32-bit floats quite nicely. GeForce FX supports 16-bit floats at good speed, but 32-bit floats are supported with performance penalty.
Since GeForce 6 there is no speed difference between 16 and 32-bit floats.

That’s of course true for fragment shaders. Vertex shaders run on 32-bit floats from very beginning.

glAren thanks so much for your supportive words! :slight_smile:

Originally posted by k_szczech:
I think you are where I was 2 years ago - if you make step forward now it will certainly not be your last.
k_szczech, your words really mean to me. I guess my next step will be implementing GLSL (it seems like fun too!). Thanks for everything, really.

I’ll post any important progress on this post and see if I can get working Shadowmapping with GLSL :slight_smile: !

Cheers!
Rod

Shadowmapping with GLSL is simple. In my project is an example for 8 point light sources included: http://sourceforge.net/projects/lumina/

Some important things:

The depthbuffer comparison should be done by the texture unit and not via shader.
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB );
Without this, it’s not possible to use the hardware PCF filter on nvidia cards (enable linear filter)

Use the same projection matrix to generate and read the shadowmap, but the render buffer has a range from -1;-1 to 1;1 The texture from 0;0 to 1;1

Use a FBO to setup a 16 or 24 bit depth component, remember that the 24 bit version needs the double bandwith.