Pocketmoon's Soft Shadow Cg Demo

I have finally gotten a chance to implement the soft shadow algorithm which I have been blathering on about. I used Pocketmoon’s soft shadow Cg contest entry and simply rewrote the fragment shader.

Here is the code:
EDIT: Code seems to be really hard to copy and paste out of a browser. You can get the code from here: http://www.io.com/~fenix/cg_shimmerFP.cg

// ***** *** *** * * * * ****** ***
// * * * * ** * * * * * *
// * * * * * * * * * * *
// * * * * * * * * * * *
// * * * * * * * * * * *
// * * * * * * * * * * *
// * * * * * * * * * * *
// * * * * ** * * * * *
// ***** * * * * ****** ***
//

//Copyright (c) 2002 Rob James - see license.txt for details

//A lot of additional work by Jason Wilkins
//(Nakoruru, fenix AT io DOT com). This
//code is almost completely rewritten, but
//I would not feel comfortable taking
//copyright unless Rob told me I could.

struct v2f
{
float4 HPosition : POSITION;
float4 Color0 : COLOR0;
float4 Color1 : COLOR1;
float4 TC0 : TEXCOORD0;
float4 TC1 : TEXCOORD1;
float4 TC2 : TEXCOORD2; // normal
float4 TC3 : TEXCOORD3; // world space light vec
};

fragout main (v2f IN, uniform samplerRECT tex0 : texunit0)
{
const float surf = (length(IN.TC1.xyz) / 6.5);

float shadow;

#define SHADOW_SMOOTHSTEP smoothstep(-0.005, -0.001, surf - occl)

//Sample 1
float occl = f1texRECTproj(tex0, IN.TC0.xyw);
shadow = SHADOW_SMOOTHSTEP;

float scale = 200.0 * sqrt(1 - (occl / surf));

#define SAMPLE(x, y) (IN.TC0.xyw + float3((x), (y), 0))

//sample 2
occl = f1texRECTproj(tex0, SAMPLE(scale, scale));
shadow += SHADOW_SMOOTHSTEP;

//sample 3
occl = f1texRECTproj(tex0, SAMPLE(-scale, -scale));
shadow += SHADOW_SMOOTHSTEP;

//sample 4
occl = f1texRECTproj(tex0, SAMPLE(-scale, scale));
shadow += SHADOW_SMOOTHSTEP;

//sample 5
occl = f1texRECTproj(tex0, SAMPLE(scale, -scale));
shadow += SHADOW_SMOOTHSTEP;

shadow /= 5.0;

fragout OUT;
OUT.col.xyz = IN.Color0.xyz * (1.0 - shadow);
return OUT;
}

It takes 5 shadow samples in a quincunx pattern.

I ended up using a square root in the pattern scaling function when I realized that linear scaling resulted in a prenumbra that was the same size no matter how far away from the light the occluder and surface are. It looks right, but I am too tired to figure out why :slight_smile:

Thanks to Pocketmoon, it was not too hard for me to just jump in and modify the shader, except I would appreciate it more if your program reported compiler errors :slight_smile:

The code is kinda sloppy. I wanna change it to make adding additional samples easier, but I am only half way there.

The smoothstep is an attempt to smooth out the shadow acne, but it doesn’t work

I have not spent enough time trying to understand how Pocketmoon’s anti-acne cream works.

I took out the specular lighting because I thought it was distracting.

EDIT: More details…

I removed the ddx, ddy stuff. It was completely screwing up the shape of the shadows. I wonder why it was there to begin with.

To use this code you should get the soft shadow contest entry from the www.cgshaders.com sight and replace the fragment shader with this code.

Make sure the gamma is high on your monitor. I did not want to fool the eye too much so I have no ambient light (it would soften the shadows unfairly).

I’ll make some screen shots later. Cannot wait to see how fast this will run on NV30!

MORE EDIT:

The reason the shadows do not seem as soft as they should is that even though the shadows are soft, they are not any bigger they seem to be ‘stenciled’ inside what would be the hard shadow if there was only one sample. I have some ideas as to why that is the case… (by stenciled I do not mean stencil buffer, just that for some reasons the shadows are the same shape as a hardshadow, which is wrong).

EVEN MORE EDIT:

Changed the code to make the light size more managable. The 200.0 is the light size. MAke it bigger to make shadows softer.

Figured out why the shadows do not seem to get bigger like they should. It is because the center point is the point used to determine how big the sample pattern is. Because of this, if the center sample does not hit an occluder then the sample pattern will be reduced to a point sample (5 samples from the same point). The code probably needs to be changed to determine sample size by some heuristic that would allow it to catch occluder edges that are not straight towards the light.

[This message has been edited by Nakoruru (edited 10-11-2002).]

[This message has been edited by Nakoruru (edited 10-11-2002).]

Nakoruru,

The entry was very rushed. The ddx/ddy shouldn’t have been in there. In fact there are LOTS of problems with the code, both the shader and the C you grabbed. I hope to have a page up soon with a complete and correct implementation as well as screenshots. I’m not sure how your idea differs much from what was already there? My current version uses correct screen space sampling (using ddx/ddy) which gives much better shadows. Although I’ve taken out the variable sample area size for now. I’ve also fixed the shadow achne

You’re also finding out, as I have, that the general idea isn’t as straightforward as it sounds. One thing you could try,I have already , is doing a pre-sample (in texture space) over a wider area and pick the furthest occluder distance for those samples in shadow. This would then determine you actual sample area. But as the number of samples goes up, the time per frame goes up as well and my patients goes down. Also, there is still the issue of multiple occluders - you only get the occluder nearest the light which gives bad results when shadows overlap. I indent to solve this (to some extent) using a deep shadow map to store multiple occluder depths IF ONLY NVIDIA WOULD RELEASE A CG COMPILER WITH DEPTH REPLACE OR DISCARD WORKING. Ahem.

I think there is still value in occluder distance effects. One thing my demo shows well (IMO!) is the very dark shadows very close to the occluding surface.

Anyway, good luck!

Rob

I do not believe that the method you where using to to calculate your sample scale (you called it ‘of’) was correct. The method I used in the code eventually ended up using a sqrt in order to make the prenumbre increase in size as the occluder distance from the surface increases.

How exactly were you distributing your samples? Mine are arranged like this:

4 2
1
3 5

My shadows also fade with distance, but it is a side effect of the samples being spread out further, not something that is directly injected. One big motivation for creating a new shadow shader for your demo is that I think that your distance fading looks really wrong. I think that the distance fade in my code, on the cone for example, is much more compelling.

I think that the sample pattern scaling is the most important component of soft shadows. I could hardly believe that your shadows look like soft shadows if you removed that from your code. One reason why I removed ambient light, distance fade, and specular lighting is that they all distract from seeing if your shadows really are soft, or just lightened.

I removed diffuse lighting from the vertex shader as well, because it was hiding the shadow acne I failed to fix. How exactly did you fix it. I am really having trouble understanding why smoothstep does not work.

EDIT: I just figured out that a very large part of the shadow acne I see could be fixed by putting the backface test back in. But, I’m still cannot figure out how to put those very smooth self-shadow edges back into the code. I assume that is implemented by what you called the ‘close occluder factor’, but if I put that back into the code it has no effect.

[This message has been edited by Nakoruru (edited 10-11-2002).]

Nakoruru,

Please remember that I’m not aiming for realism yet, just an understanding of the shadow dynamics. I can tweak my parameters later when I have the method just right

Originally posted by Nakoruru:
How exactly were you distributing your samples? Mine are arranged like this:

[quote]

4 2
1
3 5

[/QUOTE]

I’ve tried 5 samples both on the diagonals and up/down/left/right. At the moment I’m do full 9 samples.

My shadows also fade with distance, but it is a side effect of the samples being spread out further, not something that is directly injected.

I wanted to get a feeling for how the additional ambient light effected the shadowed area. As you move further from the occluder more of the ‘world’ becomes visible so the ambient light increases, even along the center-line of the shadow.

One big motivation for creating a new shadow shader for your demo is that I think that your distance fading looks really wrong. I think that the distance fade in my code, on the cone for example, is much more compelling.

Well here’s a link to some screenshots, including one of yours.
http://www.baddoggames.com/cg/shadow.jpg

These are all screengrabs zoomedx3.

Top left - 256x256 depth map with no filtering YUK!
Top Middle - screen based sampling 0.5 pixel offset
Top Right - 1.4 pixel offset
Bottom Left - Yours.
Bottom Right - Mine with 1Kx1K depth map, slight variable offset (occluder distance)

EDIT: I just figured out that a very large part of the shadow acne I see could be fixed by putting the backface test back in.

Yes, with 2nd depth shadow mapping (as we are doing here) you MUST have the backface test in there.

I found to get really soft (penumbra like) edges, the sample area had to be big, and that doesn’t always look nice. I’m almost willing to conceed that anything approaching a decent looking penumbra is not going to be achievable using these methods without a complex fragment shader with an expensive number of samples. But then again… give me a bit longer

Rob.

I can see that you have improved your methods quite a bit! Although, somehow it seems that the light size is way too big in the screenshot for my shader. I seem to remember mine looking a lot more comparable to the one on the lower right.

I had banding, which you seem to have taken care of by having more samples, but it still looked a lot better than that screen shot.

Hmm, maybe I messed up when I edited the code I posted.

Maybe you changed your scene or program a little? Moved the light?

EDIT: Indeed, after finding a computer here at work to test it on, it looks 2 million times better using the version of your program available at cgshaders.org

[This message has been edited by Nakoruru (edited 10-11-2002).]

[This message has been edited by Nakoruru (edited 10-11-2002).]

just wanted to say, nice shadows on the blue ground. but the shadows on the spheres are terrible

Yeah, I am currently looking into correcting the shadow acne. I am eschewing the backfacing test for now in favor of trying to come up with a good offset method. You can tell in Pocketmoon’s screen shots where the shadow just suddenly switches from cast shadow to backfacing shadow.

Originally posted by davepermen:
just wanted to say, nice shadows on the blue ground. but the shadows on the spheres are terrible

Tweakable I have the ‘close occluder’ shadow deepening too high.

You can tell in Pocketmoon’s screen shots where the shadow just suddenly switches from cast shadow to backfacing shadow.

Tweakable - I hope