best shadows ever PSLiPVSM

Announce new projects or updates of Irrlicht Engine related tools, games, and applications.
Also check the Wiki
Post Reply
devsh
Competition winner
Posts: 2049
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

best shadows ever PSLiPVSM

Post by devsh »

EDIT NEW POST:
I am really sorry as my work is not going to be open source, I will leave clues behind on how to get PSSM and LiPSM working so you can do it yourself but no code (cause I'm getting paid)

For the shadow camera:
1)Well first you need a view matrix
2)and crop it with an orthogonal projection matrix so it tightly bounds your REAL view frustum
3)pull the Depth back a bit so objects between the camera frustum and the light can cast shadows
Read up on unit cube clipping (imagine you shorten the camera frustum if its outside of level bounds so you get better shadows when looking out of the level)
You have a special shader which writes to your shadow map (which must be R16G16F or R32G32F) with linear (0,1 range) depth where red=depth and green=depth*depth
Depending on your implementation of lighting and shadowing (forward or deferred) the vsm shader is going to be different, its important to knock down the number of matrix transforms, you should only need one matrix transform to get a position on the shadowmap. NOTE: in opengl you need to inverse (*-1.f) the 12th float in the projection matrix when you pass to a GLSL shader (you will need to invert Y sometimes)
Remember matrix transformed coords will be in range 1 to -1 and texcoords are 1 to 0

The equation for splits was very complicated to come up with and attempt to solve... it took into account the FoV, aspect ratio, resolution of the screen and shadow map but it turned out they cancel each other out if you want a definite amount of splits in your view frustum
FOR 2 SPLITS:
(d*e_x-m_x*n)*(d*e_y-m_y*n)/n^2 = (f*e_x-m_x*d)*(f*e_y-m_y*d)/d^2
Ok so what do these stand for?
d = the split position we want to find
n = near value of the rendering camera
f = far value
Now for the next you need to actually transform the camera frustum into shadowspace and get the vectors from the camera to each far frustum corner. Then divide by the far value (because we want an progression/expansion of the size of the shadowmap as the depth of the split increases)
e_x = extent in X direction (largest vector take smallest)
e_y = extent in Y
NOTE: the max in X is 0 if all vectors are negative in X and min is 0 if all vectors positive
same for the Y axis. This is as if you max'ed and min'ed the vector from the camera to the camera itself
m_x = the smallest absolute vector in X (absolute value for the min comparisons but later restored the sign)
m_y = similar thing for Y

All this simplifies into a quartic
(e_x*e_y)*d^4-(e_x*m_y+e_y*m_x)*d^3+f*(m_x*e_y+m_y*e_x)*d-f*e_x*e_y=0
which I am trying to solve as we speak
This is how far I've got
Image

OLD CODE:
hi all I need a simple one file model that has a LoT of geometry detail or transparent stuff like fences, sharp points etc. anything that would require a very good shadowing technique to show all the detail.

If you donate a suitable model, you get full source code before I post it here (you can request seeing it at any moment).

It is going to be Parallel Split Light Space Variance Shadow Maps, a shadowing technique that updates every frame, splitting the camera frustum into 2 to 4 smaller ones taking into account projected pixel sizes so the over and under sampling distribution in each frustum is the same. Then each of these frustums is rotated, scaled and sheared to turn into a cube, the objects closer to the camera will be bigger on the shadow map. LiPSM is an improvement over PSM and here the frustum transforming into a cube is interpolated, by a variable. This leads to finer control over how much "perspective" is put on the shadow map, this variable would correspond to the over&&under sampling distribution to try and even it out. Variance Shadow Mapping is used to achieve very soft shadows using the difference of squares, this requires sampling and blurring so adding perspective will force me to adjust the bluring.

The equations I have so far:

VSM = (squareDepth-Depth^2)/(squareDepth+shadowVertPosition.z-2*Depth*shadowVertPosition.z)

This equation only works for the duelling frusta and if the light looks the same way as the camera (angle between light and camera == 0) and camera angle 90 degrees
(shadowmapRes/ScreenResX)^n=CameraFarValue
n/numberOfSplits = x
then the depth at which the split takes place is (shadowmapRes/ScreenResX)^(x*splitNumber)

for screen resolution of 800 and shadowmap of 2k with 4 splits (4k shadowmap overall) the X constant is 1.837154775

we calculate over sampling like this
beginning of frustum[smaller end] (x^splitNumber/2048)/(x^(splitNumber-1)/800)
end of frustum[bigger end] (x^splitNumber/2048)/(x^(splitNumber-1)/800)

you get under sampling if value is above 1 and over sampling when below 1, if the splits are perfectly calculated the beginning and end values should be the same for each frustum as they are in my case (0.39 and 2. something, dont remember now)

I can produce a graph describing that distribution, next part is to get my equation to accept different camera angles and then light to camera angles. But now in this perfect situation I will search to apply LiPSM with an equation that bring the over and undersampling closer to 1.
Last edited by devsh on Sun Jan 30, 2011 6:59 pm, edited 3 times in total.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

ok

Post by REDDemon »

Here is the first test file.

There is one B3D model that uses several textures (all included in the zip file).

There are 3 textures in jpg format used for making the mesh a little nicer (not to much)

and Alpha channeled PNG image i used for the glass above a door.

If you need to split the mesh into more file just ask(or if you need more geometries). I attached the .blend file also

There are some low poly meshes and a terrain mesh.

http://www.2shared.com/file/mTFHnezd/Te ... le_01.html
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
devsh
Competition winner
Posts: 2049
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Post by devsh »

Thx a lot that is great, could use a fence though
devsh
Competition winner
Posts: 2049
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Post by devsh »

ok I made the fence myself... so...

I found out that it really boosts to have a world bounding box, (bbox for the whole level) and clip your far value to that...
this way the shadows get better near the limits of the level
stefbuet
Competition winner
Posts: 495
Joined: Sun Dec 09, 2007 4:13 pm
Location: france

Post by stefbuet »

Will u use cubemap or another kind of mapping?
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

devsh wrote:ok I made the fence myself... so...
ah you was meaning a "separated fence" i was asking why didn't you noticed the fence i putted in the file gived to you :)
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
devsh
Competition winner
Posts: 2049
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Post by devsh »

I compiled some kinda equation that takes care of rotation

first construct a shadow lookAt matrix
then a projection matrix to crop the frustum
sum the rotations and transform the entire frustum
then get the vectors from the rotated camera position to corresponding corners of the far plane
next divide these vectors by your far value
(you get a so called perZ unit which tells you how much the vector progresses in the shadow space per 1 increase in far value)
now find the max and the min value of X axis among these 4 vectors
same for the Y
no need for Z as we are not dealing with perspective shadows
these are your perZshadowRanges

get the distance between the corners of your view frustum at exactly 1 far unit away from camera - distance in IN WORLD SPACE please
get the distances along the horizontal line of the screen plane and vertical we refer to them as distanceX and Y
(now notice we are getting precise distances with world space but not in shadow space only ranges)

now distanceX/resolutionX and same for Y should tell you how big a pixel has to be in world space to appear on screen if it is located exactly 1 unit away from the camera plane (not near plane)

and perZshadowRangeX/shadowmapResolution (same for perZshadowRangeY) should tell how big a pixel has to be to appear on the shadowmap

Now what we are looking for is the Z value at which the size that something has to be to appear on the shadow map is equal to the size something has to be to appear on the screen at 1 unit away from camera

we need to cross check everything with everything and we are looking for Z

(perZshadowRangeX*Z/shadowmapResolution) = distanceX/resolutionX
(perZshadowRangeX*Z/shadowmapResolution) = distanceY/resolutionY
(perZshadowRangeY*Z/shadowmapResolution) = distanceX/resolutionX
(perZshadowRangeY*Z/shadowmapResolution) = distanceY/resolutionY
p*z/s=d/r
z=ds/rp
Z=distanceX*shadowmapRes/(resolution*perZshadowRangeX)
and so on

So wait? why did Z=shadowmapRes/resolution before??
well the answear is simple when camera and shadow look same way or the opposite the worldspace increase in xy in each corner is the same as the range vectors after rotating to shadowmap space

example 1:1 aspect, with 90 degree cam angle and resolution 800*600 (really bad aspect) and shadowmap size 2048^2 per split
-1,1 per 1 Z and distance is 2
1,1
1,-1
-1,-1
no rotation applied because looking same way
min x in any of the vectors is -1 and so is Y
same for max (except its 1 ofcourse)
ranges in effect same as distances
so the equations are
Z=2*2048/2*800
which in effect reduces to smapsize/resolution

however the ranges and distances get different when rotation is applied

so anyway, there will be 4 answers and you need to pick the smallest one (worst case) ofcourse certain combinations of angles of 90,270 and so on will cause the perZshadowRange in X or Y to equal 0, so its important that you check for NaNs in your code which occur when there has been a division by 0 and dismiss them
so if previously z=s/r and (s/r)^n=cameraFar=z^n and n/noOfSplitsAKACascades= theMagicXconstant
Then (ds/rp)^n=f and n/c = x
where c is noOfSplitsAKACascades

Which all simplifies to
log(f)/log(ds/rp)/c=x


P.S. BlindSide, FuzzySpo0n or Sudi please check this
devsh
Competition winner
Posts: 2049
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Post by devsh »

Right so first step in the implementation has failed, the current code I use for clipping the far value of the camera to the world boundaries has failed so i rewrite that part soon. This is very important as it will increase shadow quality a lot when looking to the outside of the level. Pixel perfect shadows will be achieved(no aliasing) under two circumstaNces, you are sh
(shadowmapresolution/screenresolution)^4 or less away from the edge of the map and you are looking away from the map. To give an example, your x resolution is 800 and shadow map split size 2048 than the distance to boundaries can be 43 units. This gives perfect pixels ratio andthe undersampling equation is always less thn 1
devsh
Competition winner
Posts: 2049
Joined: Tue Dec 09, 2008 6:00 pm
Location: UK
Contact:

Post by devsh »

So a bit of a bump.. read the main post after the EDIT
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

great snippets. that's why i'm getting strange shadows( square corners instead of smooth lines)XD

I will take an attempt with your suggestions.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
Post Reply