Randomly Rotated PCF Shadows

Started by
4 comments, last by Schrompf 15 years, 10 months ago
Hello all [smile] EDIT: Changed topic title from "Poisson Disk Random Rotation Texture" to the above since I also have a question about randomly rotated PCF, as in my second post. Question: how do I generate a poisson disk random rotation texture? Pretty much any PCF shadow mapping paper mentions rotating the kernel randomly based on a "randomly rotated poisson disk". Googling for "poisson disk [texture]" or similar does not reveal any obvious results. Some papers include an example image of what this texture might look like, but obviously copy & paste from the PDF won't really help [grin]. So, how do I generate a texture like this? Currently I managed to generate some basic RGB noise in a 30-minute tweaking session, only to figure out RGB noise was two clicks away in the gimp [lol]. But I want to generate a "random rotation poisson disk" [smile]. [Edited by - agi_shi on June 23, 2008 3:10:15 PM]
Advertisement
I think one of the ATI presentations cover how they create this texture. It is in here:

http://developer.amd.com/media/gpu_assets/Isidoro-ShadowMapping.pdf

check out slide 16.
Quote:Original post by wolf
I think one of the ATI presentations cover how they create this texture. It is in here:

http://developer.amd.com/media/gpu_assets/Isidoro-ShadowMapping.pdf

check out slide 16.


Yeah, that's the exact paper (and slide [wink]) I was talking about. They mention about red being cos(x) and green being cos(y). But that produces, very obviously, a predictable pattern.

Current I have the random tap shadows working by reflecting some constant offsets over a normal from a screen-aligned texture, much like SSAO works. Except, I don't think this is what everyone is referring to in their papers, since they are talking about some kind of rotation along with cosine... I just feel like I'm missing some key fundamental here [grin]
hmm I used it about two years ago to implement a filter kernel like this and it was fine. When you say predictable pattern do you see this pattern in ATI's example screenshots?
Quote:Original post by agi_shi
Current I have the random tap shadows working by reflecting some constant offsets over a normal from a screen-aligned texture, much like SSAO works. Except, I don't think this is what everyone is referring to in their papers, since they are talking about some kind of rotation along with cosine... I just feel like I'm missing some key fundamental here

When you say "a screen-aligned texture" do you mean a texture in the same dimensions as the screen or a smaller texture, tiled or stretched over the screen?

AFAIK the algorithm in Isidoro's presentation (and as it's used by Crytek) uses a small (e.g. 64x64) texture, tiled over the screen so many times, in order to get 1:1 pixel / texel ratio. Every texel keeps the cos and sin of a random 2D angle, in its RG channels and these are used in order to create a 2D rotation matrix (remember that your offsets are 2D in shadowmap space). What you have to do is read the rotation texture using the current fragment's screen position and use the cos and sin values (normalization may be necessary before use) in order to rotate the fixed kernel (which can be a poisson disc).

For getting a fixed poisson disc, you can use the little app nVidia suggest in their paper on PCSS (Integrating Realistic Soft Shadows into Your Game Engine).

HellRaiZer
HellRaiZer
We do a simple mirror on the sample pattern according to a pseudy-random value calculated from the shadow map texture coords. At screen this is perceived as some sort of dithering the shadow borders... it looks quite convincing. Performance-wise it is rather cheap, maybe five arithmetic instructions per fragment. Random calculations look like this:

float2 jitterFactor = frac( inp.mShadowTexCoords.xy * float2( 18428.4f, 23614.3f)) * 2.0f - 1.0f;


This produces a simple 2d (or 3D, if you need it) pseudo-random value in the range -1..+1. We than scale this value by the size of the sample disc and use it as a simple vector multiplicator to scale the actual sample offset values.

float2 offsetFactor = jitterFactor * gSizeOfYourSampleDisc;float shadowDepth0 = tex2D( TexShadow, input.mShadowTexCoords + gShadowSampleOffset[0] * offsetFactor);float shadowDepth1 = tex2D( TexShadow, input.mShadowTexCoords + gShadowSampleOffset[1] * offsetFactor);float shadowDepth2 = tex2D( TexShadow, input.mShadowTexCoords + gShadowSampleOffset[2] * offsetFactor);// and so on


It works quite nice here, even with only 4 samples and at standard non-antialiased screen resolutions. And it has close to no impact on performance compared to regular PCF shadow maps. The only problem is that the pseudo random function is derived from the shadow map texture coords. This leads to optically unstable appearance of the shadow borders when the camera moves. A better idea might be to use the screen space fragment position to derive the pseudo-random value instead, but I'm not informed if it is readily available in all shader models.

[edit] Just checked it, starting from Shader Model 3.0 there is a vPos register containing the fragment's screen space position. You could use this instead, making the shadow borders appear more stable. To bad we're focusing on SM2.0 hardware at min.
----------
Gonna try that "Indie" stuff I keep hearing about. Let's start with Splatter.

This topic is closed to new replies.

Advertisement