|
||||||||||||||||||
Add Forum to Favorites | Send Topic To a Friend | View Forum FAQ | Track this topic Page: 1 2 »» |
Last Thread Next Thread ![]() |
| Soft-Edged Shadows |
|
![]() Ysaneya GDNet+ Member since: 1/7/2000 From: Brussels, Belgium |
||||
|
|
||||
| Nice. It's very close to what i described in ShaderX2 two years ago, in the chapter about rendering Soft Shadows, except that i did it with shadow volumes instead of shadow mapping. I'm a bit disapointed that you didn't even mention (unless i misread it) the biggest drawback of this technique IMO: the "halo" effect around the silhouette of the objects. This might or not be acceptable, but because everything is done in screen space, increasing the amount of blur (to get "smoother" shadows) makes this problem more and more noticeable, up to the point where it becomes a real problem. In my article i tried to fight against it by only blurring the areas in the penumbra, using a custom kind of stenciling. It improved it a bit but there was still some glitches. Y. |
||||
|
||||
![]() [deleted 66475] Member since: 9/2/2004 From: Chicago, United States |
||||
|
|
||||
| I'm still too much of a newbie in this area, but the article is a good read. I do have one question... The effect looks great but given the example, shouldn't the blurring of the shadow increase along it's length? The diffracted light from the head of the statue has farther to travel than of the feet. At least I that's what I've noticed in real life. Is it difficult to add to the effect? -A clueless Noob [Edited by - Matthew Chastain on January 18, 2005 6:38:37 PM] |
||||
|
||||
![]() CraZeE Member since: 2/28/2001 From: Malaysia |
||||
|
|
||||
| i have to agree on the query of Matthew, above. i like the blurred shadows.. looks nice as they are, but since we're on the topic of believable shadows.. the blur shudn't be uniform, right? how could we enhance the blur mechanism to support this? |
||||
|
||||
![]() SirKnight Member since: 1/7/2001 |
||||
|
|
||||
| To do that you would need to correctly calculate the shadow's penumbra and go from there. This is just a simple "dumb" blur so obviously it's forcing every shadow to have a constant sized penumbra area. Like he says on the first page, this technique does not do that (calculate penumbra) and the ones that do are very slow for complex scenes. One thing that you can do for a speed up is to only blur on the shadow's edge. But to detect this and only blur on the edge would require dynamic branching in the fragment processor. NVIDIA has a demo that does this very thing (as do I, hehe). -SirKnight |
||||
|
||||
![]() frostburn Member since: 6/27/2000 From: Sogndalsfjora, Norway |
||||
|
|
||||
| I (think I've) made an improvement on the example that could be used to expand it to "real" soft shadows (penumbra) I've changed the GetGaussianDestrobution method to only take one "axis" as input. I did this because either x or y is 0 and is therefore not needed in this example anyway. It didn't really matter, but KISS. Another distrobution of sample points (blur kernel) could be used instead to trade visual quality for better efficiency (I think). In that case the original GetGaussinDistrobution method would have to be used. I changed GetGaussianOffset to eliminate the offset entirely. This is moved to the .fx file instead. In retrospect I think I've done this in an extremely complicated way. I'll explain later. I've also changed the method to output the weights in a more linear way. It now goes from -8 to +7. C++ float GetGaussianDistribution( float amount, float rho ) { float g = 1.0f / sqrt( 2.0f * 3.141592654f * rho * rho ); return g * exp( -( amount * amount ) / (2 * rho * rho) ); } void GetGaussianOffsets( bool bHorizontal, D3DXVECTOR2 vViewportTexelSize, D3DXVECTOR2* vSampleOffsets, float* fSampleWeights ) { // Get the weights for the remaining taps for( int i = 0; i < 15; i += 2 ) { fSampleWeights[i] = 2.0f * GetGaussianDistribution( 0.0f, float(i - 8 ), 3.0f ); } // Get the center texel offset and weight fSampleWeights[8] = 1.0f * GetGaussianDistribution( 0, 0, 2.0f ); } I've made several changes in the .fx file. First I added the vViewportTexelSize's as properties(?). I then changed the accumulators to calculate the texture coordinates on the fly. It's also possible to add a scalar to increase the size of the blur. The mistake I think I've made is that it would probably have been as easy as multiplying the g_vSampleOffsets[i] by the scalar instead, and thus get the same effect without making the changes I did at all. In my defense this is about the first time I've read shader code, and I couldn't understand anything of the code the first couple of times I read it. I didn't think of it until after I started to write on this post. Anyway, the changed code should produce exactly the same result as the original (I hope), though it adds a couple of mults in place of a lookup :( Also, I just changed the spots that I could see in the code on the web. There are probably some other spots in the source that would have to be changed to make it compile (notably to assign vViewportSize) The scalar could be put in place of "2.0f" in my code vAccum += tex2D( ScreenSampler, IN.vTexCoord + float2( 2.0f * (i-8) * g_viewPortSizeX, 0.0f ) * g_fSampleWeights[i]; ..or at the marked spot in the original code. vAccum += tex2D( ScreenSampler, IN.vTexCoord + g_vSampleOffsets[i] HERE) * g_fSampleWeights[i]; .fx file float g_viewPortTexelSizeX; // vViewportTexelSize.x float g_viewPortTexelSizeY; // vViewportTexelSize.y // Gaussian filter vertex shader struct VSOUTPUT_BLUR { float4 vPosition : POSITION; float2 vTexCoord : TEXCOORD0; }; VSOUTPUT_BLUR VS_Blur( float4 inPosition : POSITION, float2 inTexCoord : TEXCOORD0 ) { // Output struct VSOUTPUT_BLUR OUT = (VSOUTPUT_BLUR)0; // Output the position OUT.vPosition = inPosition; // Output the texture coordinates OUT.vTexCoord = inTexCoord; return OUT; } // Horizontal blur pixel shader float4 PS_BlurH( VSOUTPUT_BLUR IN ): COLOR0 { // Accumulated color float4 vAccum = float4( 0.0f, 0.0f, 0.0f, 0.0f ); // Sample the taps (g_vSampleOffsets holds the texel offsets // and g_fSampleWeights holds the texel weights) for(int i = 0; i < 15; i++ ) { // vAccum += tex2D( ScreenSampler, IN.vTexCoord + g_vSampleOffsets[i] ) * g_fSampleWeights[i]; vAccum += tex2D( ScreenSampler, IN.vTexCoord + float2( 2.0f* (i-8) * g_viewPortSizeX, 0.0f ) * g_fSampleWeights[i]; } return vAccum; } // Vertical blur pixel shader float4 PS_BlurV( VSOUTPUT_BLUR IN ): COLOR0 { // Accumulated color float4 vAccum = float4( 0.0f, 0.0f, 0.0f, 0.0f ); // Sample the taps (g_vSampleOffsets holds the texel offsets and // g_fSampleWeights holds the texel weights) for( int i = 0; i < 15; i++ ) { // vAccum += tex2D( BlurHSampler, IN.vTexCoord + g_vSampleOffsets[i] ) * g_fSampleWeights[i]; vAccum += tex2D( BlurHSampler, IN.vTexCoord + float2( 0.0f, 2.0f * (i-8) * g_viewPortSizeX ) * g_fSampleWeights[i]; } return vAccum; } To create a natural looking soft shadow the we must create another texture map with values from 0.0f to perhaps about 10.0f (150 pixels) for the distance from the shadow caster to reciever. I don't know enough about shadow mapping to know how this can be done, but I imagine it would be possible since the way it currently works IIRC is to transform the light perspective to the camera perspective and compare z-maps. If this is done in pixel shader then I believe it is possible to calculate the distance. This texture map would then be used to calculate change the size of the blur using the scalar I mentioned before. I hope that it's possible to do it without having to change the weights as well. PS as a final option, it would be possible to use a 2d lookup map for offsets and weights, so it should work no matter what. I think scalars are better though, since they take less space and it's possible to get a much smoother transition from min blur to max blur. With a 2d lookup map we'd get steps for each blur size change. It does work as a last resort though. |
||||
|
||||
![]() Guimo Member since: 5/17/2000 From: Lima, Peru |
||||
|
|
||||
| Why does it run at 3FPS in my FX5200? After switching to tiger.x model it went to 12fps. Is that th standar performance? Guimo |
||||
|
||||
![]() Wavewash Member since: 8/19/2000 |
||||
|
|
||||
Quote: Does the article do anything to fight this? I did not see anything in the screenshots. ~Wave |
||||
|
||||
![]() Enrico Member since: 4/5/2004 From: Stuttgart, Germany |
||||
|
|
||||
| Hi, I dont know why, but when I start the demo, it just shows black :-? I have a Radeon 9800Pro with 5.1 Drivers. Bye Enrico |
||||
|
||||
![]() nuvem Member since: 1/17/2004 From: Ottawa, Canada |
||||
|
|
||||
Quote:Haven't been able to play with shaders for a while now after my computer fried, but the first thing that came to mind after reading the article and this thread was if it was possible to simply encode that information in the shadow map. Rather than simply duplicating the depth across xyz, storing it only in one, and using the remainder for perhaps some 2D vectors to modify the strength of the blur. |
||||
|
||||
![]() mrbastard Member since: 10/9/2000 From: Nottingham, United Kingdom |
||||
|
|
||||
Quote: Works fine on mine with 6.14.10.6497 and 6.14.10.6505 catalyst 5.1 drivers (I upgraded them today). |
||||
|
||||
![]() Ainokea Member since: 3/15/2004 From: Keaau, HI, United States |
||||
|
|
||||
Quote: Same here and the same setup. It is probally because FX5200s are crappy. I would like to know how this works on a higher end card so if anyone is getting decent performance please tell me. ______________________________________________________________________________________ With the flesh of a cow. |
||||
|
||||
![]() Guimo Member since: 5/17/2000 From: Lima, Peru |
||||
|
|
||||
| GFX5200 are slow but n0ot THAT slow. The demo its just rendering one object of 30000 polys and making a blur... get 3FPS just for that???? No way... The offsceen texture is 512*512 so no problem there. Its a small RT. I even changed the rendering mode so it uses other model and does no blurring but no use... if this is the real performance then I guess this effect cant be used for a real game. Luck! Guimo |
||||
|
||||
![]() Ysaneya GDNet+ Member since: 1/7/2000 From: Brussels, Belgium |
||||
|
|
||||
| Look into the blur pixel shader - FX5200 are crappy, but they are particularly crappy at doing pixel shaders 2.0 ! |
||||
|
||||
![]() Koen Member since: 1/11/2002 From: Leuven, Belgium |
||||
|
|
||||
Quote: I had the same problem with an X800Pro. What fixed it for me was switching to release d3d-runtime. |
||||
|
||||
![]() _MrC_ Member since: 8/15/2003 From: England |
||||
|
|
||||
| Switching to the retail version of d3d also fixed the black screen problem on my GeForce 6800GT, latest drivers, December sdk. |
||||
|
||||
![]() JonnyQuest Member since: 5/14/2000 From: Kew, United Kingdom |
||||
|
|
||||
| I'm wondering, could this method be improved such that the amount of blurring is not constant? One hacky way of doing this could be that when rendering to the screen-sized buffer, the distance of the light is recorded. If you're rendering to the RGB channels, the Alpha channel is a good choice. The distance value will then modify the grain of the blurring filter. Really close objects will therefore have very sharp shadows, and since they're so close, the shadow mapping aliasing won't be very strong.
Of course, this isn't the correct way of doing things, as the sharpness depends on the distance from the shadow-casting object rather than the light, but it's still going to look better, surely?
~phil |
||||
|
||||
![]() Anonymous Poster |
||||
|
||||
Quote: What about making the variance (or standerd deviation (rho˛), can't rememer which) in the normal (Gaussian) distribution proportional to the distance between the occluder to the recieving surface divided by the distance between the light and the occluder. In the pass that renders the shadowed to the screen (Step 2) both the distance from the light to the occluder (A) and the distance from the light to recieving surface (A) are known. The distance between the occluder and the recieving surface is then B-A so the amount of blurring should be proportional to (B-A)/A. That value can be stored in one of the components of the out value of the pixel shader. |
||||
|
||||
![]() Moe Member since: 1/24/2000 From: Calgary, Canada |
||||
|
|
||||
| I thought the article was quite interesting. Does anyone know any other good links for more of the theory beind lighting and shadowing techniques? I think I would like to learn more of the theory before I delve too far into it. |
||||
|
||||
![]() JonnyQuest Member since: 5/14/2000 From: Kew, United Kingdom |
||||
|
|
||||
Quote: Well, that's going to be a lot more involved. For one, you need to divide by A, and since it's a texture lookup and not a coordinate like B, you can't even do it outside the pixel shader. Secondly, using a per-sample weighting of the blur function isn't going to be straightforward, especially as the weights still have to add to 1. It probably can be done, but it's not going to be easy/fast. ~phil |
||||
|
||||
![]() DrGUI Member since: 10/20/2003 From: Sunningdale, United Kingdom |
||||
|
|
||||
| Well done! However: The light seemed to flicker on my computer (800Mhz, NVidia GeForce FX 5200), but it was only running at about 8 fps so perhaps it is not usually noticable. In your pshader code I noticed: // Sample each of them checking whether the pixel under test is shadowed or not float fShadowTerms[9]; float fShadowTerm = 0.0f; for( int i = 0; i < 9; i++ ) { float A = tex2Dproj( ShadowSampler, vTexCoords[i] ).r; float B = (IN.fDepth – 0.1f); // Texel is shadowed fShadowTerms[i] = A < B ? 0.0f : 1.0f; fShadowTerm += fShadowTerms[i]; } // Get the average fShadowTerm /= 9.0f; return fShadowTerm; fShadowTerms is only used as a temporary variable but why when fShadowTerm += A < B ? 0.0f : 1.0f would suffice? ------------------------------------ Development of Rock, Paper, Scissors - The Third Dimension |
||||
|
||||
![]() jbstjohn Member since: 6/22/2005 From: Munich, Germany |
||||
|
|
||||
| Thanks for the article! I'm fairly new to shadows, but not so new to lighting, and I have a few efficiency notes. First, in the comment from DrGUI, he recommends getting rid of the fShadowTerm temporary array. Good idea, but simpler and better is (in the inner loop) if (A < B) . fShadowTerm += (1.0f / 9.0f); and get rid of the divide at the end of the loop. Probably most importantly, in your PS_scene function, you're always calculating the specular component, which is pretty expensive. You want to put this off until you know you need it. E.g. // NB!! I use "p=" for plus equals, since the plus sign wasn't showing up // in my previews float4 result = ambient * vColor; float nDotL = dot( IN.vNormal, IN.vLightVec ) float diffuse = 0.0f; if (nDotL > 0.0f) { // Grab the shadow term float fShadowTerm = tex2Dproj( BlurVSampler, IN.vScreenCoord ); // Grab the spot term float fSpotTerm = tex2Dproj( SpotSampler, IN.vProjCoord ); float intensity = fShadowTerm * fSpotTerm; if (intensity > (1.0f / 255.0f)) // minimum to effect 8-bit color { // add the diffuse term we know exists result += diffuse * intensity * g_vLightColor.a * vColor; float theta = dot (2 * nDotL * IN.vNormal - IN.vLightVec, IN.vEyeVec); if (theta > 0.0f) { float specular = pow(theta, 8); // add the specular term we know exists result += specular * intensity * g_vLightColor.a * vColor; } } } return result; There are other ways to improve this, e.g., if you know the shininess has a minimum value you can increase the threshold for theta, it's possible the intensity branch isn't worth it (although I doubt it), it's possible you could factor out vColor (don't know my way around a shader well enough to say), you've fixed the ambient intensity to zero.... Still it should boost the speed considerably. The power function is quite expensive. It would be interesting to know where the bottlenecks are in this -- of course it will vary depending on the hardware, but I imagine there are some general trends. Cheers, Ben |
||||
|
||||
![]() dnaxx Member since: 3/4/2005 From: Austria |
||||
|
|
||||
| has anyone tried to implement the sample in OpenGL/ GLSL? |
||||
|
||||
![]() jzpijiang Member since: 11/12/2006 From: Guangzhou, China |
||||
|
|
||||
| Has anyone use GLSL and opengl turned out that programme? |
||||
|
||||
![]() GDW Member since: 4/14/2007 |
||||
|
|
||||
| Can anyone explain this matrix for me: // Generate the texture matrix float fTexOffs = 0.5 + (0.5 / (float)SHADOW_MAP_SIZE); D3DXMATRIX matTexAdj( 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, fTexOffs, fTexOffs, 0.0f, 1.0f ); What I understood so far is that this matrix takes a vertex from it's local (mesh) coordinates system to the texture coordinates system of the light. But can someone explain briefly the math behind it, because I believe my demo isn't working correctly because of this matrix. Thanks |
||||
|
||||
|
Page: 1 2 »» All times are ET (US) ![]() |
Last Thread Next Thread ![]() |
|