Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics

[DirectX 11] Sudden Saturday Shadow Sadness Syndrome


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
4 replies to this topic

#1 L. Spiro   Crossbones+   -  Reputation: 5172

Like
0Likes
Like

Posted 27 July 2012 - 10:07 AM

I just got out of rehab from my previous shadow problem.
I was able to change the type so that I could view it in PIX and then I was able to see that the values had too much range.
The way to fix it follows.
Old Code:
float shadow2dDepth( Texture2D _tTexture, float2 _vCoord ){ return _tTexture.Sample( lsg_SamplerShadow, _vCoord ).x; }
New Code:
float shadow2dDepth( Texture2D _tTexture, float2 _vCoord ){ return _tTexture.Sample( lsg_SamplerShadow, _vCoord ).x * 0.5 + 0.5; }
  • This works but obviously I prefer a more efficient shader. In DirectX 9 there is no way to read from a depth surface so I have to create a colored surface and output depth to that manually, which is where I perform this conversion, however in OpenGL and OpenGL ES 2 the depth surface can be read directly. But it works without having to perform this conversion anywhere. I don’t set up a special viewport depth range or do the conversion in the shader. Isn’t this X * 0.5 + 0.5 conversion supposed to be done by the rasterizer of Direct3D 11? What do I need to do to make it do this instead of me doing it in my shader?


The second issue is that my PCSSM shader fails to compile with the following:

e:\Blah\x64\DirectX11 Debug\Shader@0x00000000036A1CC0(105,16): error X4014: cannot have gradient operations inside loops with divergent flow control

Here are the relevant parts of the shader:
float PCSSShadowMap( in vec4 _vShadowCoord ) {
	float fSum = (LSE_PCF_STEPS * 2.0 + 1.0);
	float fTotal = fSum * fSum;
	if ( _vShadowCoord.w > 0.0 && _vShadowCoord.x >= 0.0 && _vShadowCoord.x <= 1.0 && _vShadowCoord.y >= 0.0 && _vShadowCoord.y <= 1.0 ) {
		float fAvgDepth = 0.0;
		float fTotalBlockers = 0.0;
		vec4 vShadowCoordWDivide = _vShadowCoord / _vShadowCoord.w;
		//vShadowCoordWDivide.z -= 0.000625 * 0.125;
		FindBlockers( vShadowCoordWDivide.xy, vShadowCoordWDivide.z, g_vShadowMapUvDepth.xy * 1.25,
			fTotalBlockers, fAvgDepth );
		if ( fTotalBlockers != 0.0 ) {
			fTotal = 0.0;
			vec2 vSize = g_vShadowMapUvDepth.xy * g_fShadowMapCasterSize * fAvgDepth * g_vShadowMapUvDepth.z;
			// Get the distance within the shadow we are.
			vec2 vThis;
			vec2 fStepUv = vSize / LSE_PCF_STEPS;
			for ( float y = -LSE_PCF_STEPS; y <= LSE_PCF_STEPS; y++ ) {
				for ( float x = -LSE_PCF_STEPS; x <= LSE_PCF_STEPS; x++ ) {
					vec2 vOffset = vec2( x, y ) * fStepUv; // **************** LINE 105 **************** //
					float fDepth = shadow2dDepth( g_sShadowTex, vShadowCoordWDivide.xy + vOffset );
					fTotal += (fDepth == 1.0 || fDepth > vShadowCoordWDivide.z) ? 1.0 : 0.0;
				}
			}
		}
	}
	return fTotal / (fSum * fSum);
}
  • Why is it barking at that line and how can I rewrite it to work?
If you need shader code that actually compiles, the actual shader that is sent to Direct3D 11 follows. Yes, it is ugly. If you have heart conditions or are pregnant, viewer discretion is advised.
Spoiler



L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

Sponsor:

#2 ATEFred   Members   -  Reputation: 499

Like
0Likes
Like

Posted 27 July 2012 - 10:27 AM

In DirectX 9 there is no way to read from a depth surface


I know this is not what you were asking about, but you can sample from a depth texture in dx9, through vendor specific extensions.
INTZ works on pretty much all non ancient ati and nv hw (http://aras-p.info/texts/D3D9GPUHacks.html).

#3 MJP   Moderators   -  Reputation: 5444

Like
1Likes
Like

Posted 27 July 2012 - 12:11 PM

"Gradient operations" refer to anything that computes partial derivatives in the pixel shader, and in this particular case it's referring to the "Sample" function. You can't compute derivatives inside of dynamic flow control, since they're undefined if one of the pixels in the quad doesn't take the same path. So you need to either...

A. Use a sampling function that doesn't compute gradients, such as SampleLevel or SampleCmpLevelZero

or

B. Flatten all branches and unroll all loops in which you need to compute gradients

Edited by MJP, 27 July 2012 - 12:12 PM.


#4 L. Spiro   Crossbones+   -  Reputation: 5172

Like
0Likes
Like

Posted 27 July 2012 - 12:43 PM

SampleLevel worked; thank you. My DirectX 11 side is now fully caught up to my DirectX 9, OpenGL 3.2, and OpenGL ES 2 sides. Now I can get serious about new graphics features.

What about the first issue?


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#5 Tsus   Members   -  Reputation: 789

Like
1Likes
Like

Posted 29 July 2012 - 03:32 AM

Hi!

What about the first issue?

As you know, one of the many (meticulously hidden) differences between GL and D3D is that the range of the z-coordinate in clipping space differs. In GL the clipping space z goes from [-1…1] and in D3D it goes from [0…1]. GL and GL ES give direct access to the [-1…1] coordinate, which happens to be correct, since the clipping space coordinate you want to compare to is also in [-1…1] as well. Very convenient. In D3D (9 and 11) it is – surprise, surprise – the same, but the clipping space z-coordinate is in [0…1]. If you store the coordinate unaltered, you can just read from it and directly use it without conversions, e.g. render to depth texture, fetch the depth later and compare it to the depth in clipping space from the light’s point of view.

But now, you confuse me a little. How can it be that the values had “too much range” in D3D (i.e. ended up in [-1…1])? What puzzles me even more is that you convert it to [0…1] to compare it to a depth value in [0…1]. How can it be that one coordinate ended up in [-1…1] needing a conversion and the other one is in [0…1]? It appears to me that there is an inconsistency at some point.

I have the feeling that you currently store the depth in [-1…1]. This means, you’re converting it at writing to the render target and when reading from it. (Note that you invert the operation at reading that you have done at writing. --> You can avoid that entirely.) The depth value you compare to is coming out from a projection matrix, thus is still in [0…1], right?

I’m quite sure you don’t, but: Do you use the exact same projection matrix in D3D as you use in GL? (That would cause the depth to be in D3D in [-1…1].) That would be a problem, since in D3D the projection matrix returns something with depth in [0...1] and in GL in [-1…1]. The D3D rasterizer would happily clip away half of your frustum, since in D3D-country things are not getting negative. So… using a proper projection matrix that returns values in the correct range would be the easiest fix, as it would render all needs for conversions void.

Also, storing the depth consistently over all platforms in [-1…1] is rather impossible to achieve (isn't it?), since the D3D depth buffer just happens to store in [0…1]. You may change the coordinate in D3D9, when writing to the render target (needing a conversion at reading), but it won’t help you much in D3D10+, if you use the real depth buffer.
Or can you persuade D3D to work in [-1...1] too by messing with the viewport? Hm...

Is there a reason, you need to have explicitly the depth values in [-1…1] on all platforms? I see that you would like to have consistency, but wouldn't it be just fine if the range is in the "correct" space of the respective platform? If the projection matrix leads you to the correct space (GL: [-1...1], D3D: [0...1], there shouldn't be much to worry about, right?

Best regards!

Acagamics e.V. – IGDA Student Game Development Club (University of Magdeburg, Germany)





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS