[2.2] Self Shadowing errors

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

[2.2] Self Shadowing errors

Post by SolarPortal »

Hi, just wondering if there is a solution to fix the self shadowing artefacts that run on the pcf based shadows.
When an object casts a shadow onto another, the shadows are black and correct.
However, when an object self shadows it produces a really acne'd shadow which doesn't look good in worlds.
I believe the acne is caused by the depth issues on casting onto itself, but adjusting the shadow depth bias improves the acne with depth issues either coming forwards on an object or you get the peter panning effect and is not ideal.

I have a couple screenshots taken of the PBS materials sample with only the directional light in the scene.
In the shader i am simply outputting fShadow to the outPs_colour variable.
Here is what i get.

Image
Image

Is there anyway of improving the self shadows to be full black on the shadowed side of a self shadow as they should be rather than the ugly acne and light bleed it causes on the backsides of objects in the world.
Acne is of course affected by the PCF filtering, blurring the acne makes the shadow lighter and more noticeable that something is not shadowed.

I would use ESM as it looks great, but it doesn't cast shadows on point lights and i'm getting some issues running shadow nodes with more complex setups and larger textures( ESM second PSSM split 1 has projection issues). and also receiving curves at the edge of buildings... but still trying to work these issues out myself in case there is an implementation issue.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 241
Joined: Wed Apr 23, 2014 3:49 pm
x 45

Re: [2.2] Self Shadowing errors

Post by TaaTT4 »

Welcome back! :D

Don't know if you've seen it (or if is in some way useful to your specific case), but there's has been some work concerning shadows (see: viewtopic.php?p=547572#p547572).
In addition, @xrgo and some other users also have discovered some bugs (see here and here).

I'm super-interested in this topic since it's a problem quite noticeable which I have (since forever I guess :|) on some particular objects (e.g. flags and guard rails).
Senior game programmer at Vae Victis
Working on Racecraft

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

Thanks :) i have tried most of those settings, but im looking for a more unified approach if thats even possible with shadows.. adjusting biases per material is simply a complicated way of managing the shadows.

Why would the other engines be able to not bother with this, surely they would experience the same problems as the rest of gfx development regarding shadows, unless they know something we don't :P
Possibly going to look into CSSM instead of PSSM as those shadows are more used across the engine board.
Im possibly looking at adding a compute shader at the end of the compositor node for the shadows to attempt a sort of denoise or de acne based on reading blocks of data and finding if the texel should be shadow or light. This way in theory you would not have to use a bias as you could sort of post process the shadow image data to make it either black or white rather than a plane of acne.
This would only work though if the acne is in the shadow texture otherwise its in the pixel shader and my approach would not work.
Just a thought anyway.

Will continue to look into this to see if there is any improvements that can be made :)

Edit: Turning Off the backface culling for shadows did improve the quality and adding a slight constant bias in the shadowmapping piece for the depth does get rid of most of the lit area acne and get strong shadows/non acne shadows in the self shadow. Of course having a thin object though is not going to get self shadows because of the bias and the way it works. Better than no shadows and just acne though.
Downside is that backface culling is also faster.

Edit2: Yeah, this is much better than it was.. (Screenshot from inside our engine rather than ogre demo.)
Image

As you can see self shadowing is working quite well, the odd bit of acne. The white box is not emissive, its just to thin to get the shadow on it with the bias.
Speaking of bias, probably the wrong place but at the moment i have added a hardcoded bias into the shader at:
ShadowMapping_piece_ps.any
Line 155:
instead of:

Code: Select all

float fDepth = psPosLN.z / psPosLN.w;
add this:

Code: Select all

float fDepth = psPosLN.z+0.0007 / psPosLN.w;
and i getter a better image than i did previously.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

SolarPortal wrote:
Tue Jun 09, 2020 2:02 pm
I would use ESM as it looks great, but it doesn't cast shadows on point lights
Please note ESM does work with point lights.
float fDepth = psPosLN.z+0.0007 / psPosLN.w;
Please note it should be (psPosLN.z+0.0007) / psPosLN.w
It's missing a parenthesis, otherwise it won't work with spot and point lights.

Btw there's one more thing to try I didn't invest time into: slope bias.
The slope bias must be set from a macroblock level via HlmsMacroblock::mDepthBiasSlopeScale and should only be set to the shadow caster's macroblock.
We currently don't touch this value in HlmsDatablock::setMacroblock, but it is worth looking into this (a lot).

SlopeScale bias is known to alleviate self shadowing issues as it allows large values that only affect triangles nearly parallel to the light direction, while applying 0 or near-0 bias to triangles perpendicular to the light direction.

Update: We don't implement "normal offset bias", PRs are welcomed:
https://mynameismjp.wordpress.com/2013/ ... adow-maps/ (look for "The normal-based offset, called Offset Scale...")
http://c0de517e.blogspot.com/2011/05/sh ... notes.html
https://ndotl.wordpress.com/2014/12/19/ ... adow-bias/

There are two ways:
1. Displace during the caster pass
```
triangle.xyz += normal.xyz * ( 1.0f - abs( dot( normal, lightdir ) ) ) * normal_bias;
```
I'm not sure if that's the exact formula, MJP has a demo with code.

Requires access to normals in the vertex shader for the caster pass, thus make sure that the shadow map optimization is turned off (because it strips everything except position data). msOptimizeForShadowMapping should be set to false and hasIndependentShadowMappingVaos should be returning false.

Once the PR is done we can modify VertexShadowMapHelper::optimizeForShadowMapping to keep normals in a lightweight manner (probably 8bpp per component is enough?, adding only 4 bytes per vertex)

2. Displace during the normal rendering pass by the geometric normal, before sampling the shadow map. This should be more accurate.

This is what MJP demo does:

Code: Select all

float3 GetShadowPosOffset(in float nDotL, in float3 normal)
{
    float2 shadowMapSize;
    float numSlices;
    ShadowMap.GetDimensions(shadowMapSize.x, shadowMapSize.y, numSlices);
    float texelSize = 2.0f / shadowMapSize.x;
    float nmlOffsetScale = saturate(1.0f - nDotL);
    return texelSize * OffsetScale * nmlOffsetScale * normal;
}

float3 offset = GetShadowPosOffset(nDotL, normal) / abs(CascadeScales[cascadeIdx].z);

// Project into shadow space
float3 samplePos = positionWS + offset;
...
It seems MJP uses saturate() instead of abs()

It divides the offset by the shadow map size in order to apply the offset in texels, making this effect account shadow map resolution.

Also: made a Github ticket.

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

ahh, so normal offset shadow mapping is like baking high poly to low poly where you create a cage, but instead of using it to raycast normals, in shadowmapping it would be used to create a fake depth from the surface. Sounds interesting, i will take a look into it and see what i come up with as it does sound like the right approach.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

That's one way of looking at it.

Btw looking at the problem, it appears normal offset depth is only a couple lines of code to change (specially option 2, in the pixel shader) so it looks like it's way easier to implement than I originally thought so.

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

@dark_sylinc, do you have a compiled version of that MJP demo as mine does not seem to compile and would be useful while testing to see what it happening.

You may say its easy, but the shadow code in ogre is quite complex to other sources out there and having to work out which variables are which and where to put this normal offset. I think i have a location in the ShadowMapper_os file under the getShadow function.

So making a little bit of progress but not much so far :P will keep working on it.. but the extra bit of information could help :)
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

SolarPortal wrote:
Wed Jun 10, 2020 12:17 am
@dark_sylinc, do you have a compiled version of that MJP demo as mine does not seem to compile and would be useful while testing to see what it happening.
The releases page has it already compiled.
SolarPortal wrote:
Wed Jun 10, 2020 12:17 am
You may say its easy, but the shadow code in ogre is quite complex to other sources out there and having to work out which variables are which and where to put this normal offset. I think i have a location in the ShadowMapper_os file under the getShadow function.
Oops sorry.

You can modify psPosLN.xyz by the offset normal in getShadow/getShadowPoint around line 151 from ShadowMapping_piece_ps.any

You have the geometric normal in pixelData.geomNormal (you will have to modify getShadow so that it accepts PixelData as input argument)

I wonder if this can be done at vertex shader level, in ShadowMapping_piece_vs.any by offsetting outVs.posL@n, but I'm not sure if that's correct.

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

Thanks, even there demo when you display the shadows only has issues on planes casting shadows. Biasing not so much but the normal offset doesnt seem to be a total fix. It seems that everyone uses the ambience of an object to hide any shadow problems but these cause problems when you have strong normals that create a light bleed effect which the shadows can hide producing a much better result.. catch 22

However, the one thing i do notice is that self shadows on thicker objects even with back face culling are producing a solid black shadow whereas in ogre it does not. So i will have to compare the shadow casters also i think.

As for the normal offset, i need to get hold of the light direction, what is the best way of grabbing this information for use in the getshadow() that you would recommend. or even getting NDOTL

Edit: It also appears in the demo that shadows are rendered with no culling:

Code: Select all

    D3D11_RASTERIZER_DESC rsDesc = RasterizerStates::NoCullDesc();
    rsDesc.DepthClipEnable = FALSE;
    DXCall(device->CreateRasterizerState(&rsDesc, &shadowRSState));
But that cant be performance effective

Edit2: Sort of have the normal offset working but doesnt take the light into account yet.
placed in top the get shadow function (not the full code.)

Code: Select all

	@property( hlms_normal || hlms_qtangent )
		//normal = normalize(normal);
		//float3 lightDir = lightPos.xyz - posVS;
		//float nDotL = saturate(dot(normal, lightPos));
		float3 normalBias = GetShadowPosOffset(shadowMap, 0, pixelData.geomNormal.xyz, 1.8);
		//float3 samplePos =  posVS.xyz + normalBias;
		//float3 shadowoffset = mul(float4(normalBias, 1.0f), passBuf.shadowRcv[0].texViewProj).xyz;
		//uv += shadowoffset.xy;
		//uv += normalBias;
		//uv = lightPos.xy;
		
		@property( @m == 0 || @m == 1 )psPosLN.xyz -= normalBias;@end
	@end
	
New shadow function.

Code: Select all

INLINE float3 GetShadowPosOffset(@insertpiece( TEXTURE2DSHADOW ) shadowMap, float nDotL, float3 normal, float offsetScale)
{
    float2 shadowMapSize;
    shadowMap.GetDimensions(shadowMapSize.x, shadowMapSize.y);
    float texelSize = 2.0f / shadowMapSize.x;
	float nmlOffsetScale = saturate(1.0f - nDotL);
    return texelSize * offsetScale * nmlOffsetScale * normal;
}
However, depending on camera angle it changes, perhaps its one of things that needs to be world space like the other bits, but to get world space on the light direction, i will need to pass in an inverse view matrix as ogre does all the lightpos * view in c++.
Still just working things through, but wanted to keep you all updated in case someone has an "ahh.. if you did this" moment :P
I wonder if this can be done at vertex shader level, in ShadowMapping_piece_vs.any by offsetting outVs.posL@n, but I'm not sure if that's correct.
Still have yet to try this
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

posting seperately as this is potentially it working.
In the getShadow() code at the top of the function i have this:

Code: Select all

float3 lightPos = light.position.xyz;
float2 uv;
	
@property( @m < 2 ) -- the other side of the condition is the point light
	@property( hlms_normal || hlms_qtangent )
		float3 lightDir = mul(light.position, (float3x3)passBuf.invView);
		float nDotL = saturate(dot(pixelData.worldNorm, lightDir));
		float3 offset = GetShadowPosOffset(shadowMap, nDotL, pixelData.worldNorm, 4) / passBuf.pssmSplitPoints0;//abs(CascadeScales[cascadeIdx].z);
		float4 shadowPosition = mul(float4(pixelData.worldPos+offset, 1.0f), passBuf.shadowRcv[shadowMapIdx].texViewProj);
		@property( !hlms_shadowmap@n_is_directional_light && hlms_no_reverse_depth )
		shadowPosition.z = shadowPosition.z * passBuf.shadowRcv[shadowMapIdx].shadowDepthRange.y;@end
			
		@property( hlms_no_reverse_depth && (syntax == glsl || syntax == glsles) )shadowPosition.z = (shadowPosition.z * 0.5) + 0.5;@end
		psPosLN = shadowPosition;
			
		float constantBias = 0.0002;
		//psPosLN.z -= constantBias;
	@end
Now to get this working, i set about it in world space.
It seems to function and works for both front face and back face culling. Both have their own little artifacts that need adjustments for.
There is a constant bias but currently commented out.
I can get black shadows on both thick and thin objects in either culling mode and it does do a nice job at removing acne but the backface culling adds a gap of light where the offset is. I would say it works better with front face, but it does an alright job with backface culling.
Also with complete bias'ing turned off.

You may also notice that I redid the shadow map position in the pixel shader

BACK FACE EXAMPLES - Normal offset value: 4
Image This is the error i was talking about with the light gap
Image Thin object from front with shadow recieve
Image Really thin object from behind first split
Image Note the lines in the edges
Image This is a PCF6x6 on second split on the really thin object

FRONT FACE EXAMPLES - Normal offset value: 7
Image Note the line under the square box
Image Thin object split 1 all black
Image The sphere shadows comes out front a bit
Image Thick objects with correct rendering.

Note: The ground plane in front face culling has depth issues, simply turning off cast shadows on the plane works, not necessary in backface.
Note2: Applying a slight constant bias in the front face helps remove more acne but in these shots it is not used.

All that is rendered is the variable fShadow only. It only proceeds to look better with proper shading and ambience.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

I couldn't resist. The math is supposed to be done in image space, and I saw some conversion to world space you were doing so I started looking into it.

After some experimentation I arrived to this experimental tweaks:

Code: Select all

diff --git a/OgreMain/src/OgreHlmsDatablock.cpp b/OgreMain/src/OgreHlmsDatablock.cpp
index ae5e73810..6e41076dd 100644
--- a/OgreMain/src/OgreHlmsDatablock.cpp
+++ b/OgreMain/src/OgreHlmsDatablock.cpp
@@ -115,7 +115,7 @@ namespace Ogre
         mAlphaTestCmp( CMPF_ALWAYS_PASS ),
         mAlphaTestShadowCasterOnly( false ),
         mAlphaTestThreshold( 0.5f ),
-        mShadowConstantBias( 0.01f )
+        mShadowConstantBias( 0.05f )
     {
         mMacroblockHash[0] = mMacroblockHash[1] = 0;
         mMacroblock[0] = mMacroblock[1] = 0;
diff --git a/OgreMain/src/OgreHlmsManager.cpp b/OgreMain/src/OgreHlmsManager.cpp
index 4292409f0..99c3787ff 100644
--- a/OgreMain/src/OgreHlmsManager.cpp
+++ b/OgreMain/src/OgreHlmsManager.cpp
@@ -44,7 +44,7 @@ namespace Ogre
     HlmsManager::HlmsManager() :
         mComputeHlms( 0 ),
         mRenderSystem( 0 ),
-        mShadowMappingUseBackFaces( true ),
+        mShadowMappingUseBackFaces( false ),
         mDefaultHlmsType( HLMS_PBS )
   #if !OGRE_NO_JSON
     ,   mJsonListener( 0 )
diff --git a/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp b/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp
index a2415e108..057d414b9 100644
--- a/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp
+++ b/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp
@@ -97,7 +97,7 @@ namespace Demo
                         createChildSceneNode( Ogre::SCENE_DYNAMIC );
 
                 mSceneNode[idx]->setPosition( (i - 1.5f) * armsLength,
-                                              2.0f,
+                                              0.0f,
                                               (j - 1.5f) * armsLength );
                 mSceneNode[idx]->setScale( 0.65f, 0.65f, 0.65f );
 
@@ -123,7 +123,7 @@ namespace Demo
         lightNode->attachObject( light );
         light->setDiffuseColour( 0.8f, 0.4f, 0.2f ); //Warm
         light->setSpecularColour( 0.8f, 0.4f, 0.2f );
-        light->setPowerScale( Ogre::Math::PI );
+        light->setPowerScale( Ogre::Math::PI * 0 );
         light->setType( Ogre::Light::LT_SPOTLIGHT );
         lightNode->setPosition( -10.0f, 10.0f, 10.0f );
         light->setDirection( Ogre::Vector3( 1, -1, -1 ).normalisedCopy() );
@@ -136,7 +136,7 @@ namespace Demo
         lightNode->attachObject( light );
         light->setDiffuseColour( 0.2f, 0.4f, 0.8f ); //Cold
         light->setSpecularColour( 0.2f, 0.4f, 0.8f );
-        light->setPowerScale( Ogre::Math::PI );
+        light->setPowerScale( Ogre::Math::PI * 0 );
         light->setType( Ogre::Light::LT_SPOTLIGHT );
         lightNode->setPosition( 10.0f, 10.0f, -10.0f );
         light->setDirection( Ogre::Vector3( -1, -1, 1 ).normalisedCopy() );
@@ -175,6 +175,14 @@ namespace Demo
                                                gaussianDeviationFactor, K );
 #endif
 
+        {
+            Ogre::Root *root = mGraphicsSystem->getRoot();
+            Ogre::Hlms *hlms = root->getHlmsManager()->getHlms( Ogre::HLMS_PBS );
+            assert( dynamic_cast<Ogre::HlmsPbs*>( hlms ) );
+            Ogre::HlmsPbs *pbs = static_cast<Ogre::HlmsPbs*>( hlms );
+            pbs->getHlmsManager()->setShadowMappingUseBackFaces( false );
+        }
+
         TutorialGameState::createScene01();
     }
     //-----------------------------------------------------------------------------------
@@ -450,10 +458,10 @@ namespace Demo
             }
 #endif
 
-            if( nextFilter == Ogre::HlmsPbs::ExponentialShadowMaps )
+            //if( nextFilter == Ogre::HlmsPbs::ExponentialShadowMaps )
                 pbs->getHlmsManager()->setShadowMappingUseBackFaces( false );
-            else
-                pbs->getHlmsManager()->setShadowMappingUseBackFaces( true );
+//            else
+//                pbs->getHlmsManager()->setShadowMappingUseBackFaces( true );
 
             pbs->setShadowSettings( nextFilter );
 
diff --git a/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any b/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any
index d4e0a668a..7a66574f5 100644
--- a/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any
+++ b/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any
@@ -3,14 +3,22 @@
 
 @property( hlms_shadowcaster )
 	@piece( DoShadowCasterVS )
-		float shadowConstantBias = uintBitsToFloat( worldMaterialIdx[inVs_drawId].y );
+        @property( hlms_no_reverse_depth )
+            float shadowConstantBias = uintBitsToFloat( worldMaterialIdx[inVs_drawId].y );
+        @else
+            //float shadowConstantBias = -uintBitsToFloat( worldMaterialIdx[inVs_drawId].y );
+            //float shadowConstantBias = -0.5 / passBuf.depthRange.y * 0.1f;
+            //float shadowConstantBias = -4.5 / passBuf.depthRange.y * 0.1f;
+            float shadowConstantBias = -0.015 / passBuf.depthRange.y /passBuf.depthRange.y * 0.1f;
+            //float shadowConstantBias = 0.65 / passBuf.depthRange.y * 0.1f;
+        @end
 
 		@property( !hlms_shadow_uses_depth_texture && !hlms_shadowcaster_point && !exponential_shadow_maps )
 			//Linear depth
 			@property( hlms_shadowcaster_directional || !hlms_no_reverse_depth )
-				outVs.depth	= outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y;
+                outVs.depth	= outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y;
 			@else
-				outVs.depth	= (outVs_Position.z + shadowConstantBias * passBuf.depthRange.y) * passBuf.depthRange.y;
+                outVs.depth	= (outVs_Position.z + shadowConstantBias * passBuf.depthRange.y) * passBuf.depthRange.y;
 			@end
 			@property( hlms_no_reverse_depth && (syntax == glsl || syntax == glsles) )outVs.depth = (outVs.depth * 0.5) + 0.5;@end
 		@end
@@ -27,7 +35,7 @@
 			//however we can use a cheap approximation ("pseudo linear depth")
 			//see http://www.yosoygames.com.ar/wp/2014/01/linear-depth-buffer-my-ass/
 			@property( hlms_shadowcaster_directional || !hlms_no_reverse_depth )
-				outVs_Position.z = outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y;
+                outVs_Position.z = outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y;
 			@else
 				outVs_Position.z = (outVs_Position.z + shadowConstantBias * passBuf.depthRange.y) * passBuf.depthRange.y * outVs_Position.w;
 			@end
diff --git a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any
index 58b8b7e01..89c59b438 100644
--- a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any
+++ b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any
@@ -1,4 +1,4 @@
-
+
 //#include "SyntaxHighlightingMisc.h"
 
 @property( hlms_num_shadow_map_lights )
@@ -134,10 +134,10 @@
 @foreach( 4, m )
 	@property( @m == 0 )
 		INLINE float getShadow( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow )
-								float4 psPosLN, float4 invShadowMapSize )
+                                float4 psPosLN, float4 invShadowMapSize, float2 invDepthRange, PixelData pixelData, float f )
 	@end @property( @m == 1 )
 		INLINE float getShadow( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow )
-								float4 psPosLN, float4 invShadowMapSize, float2 minUV, float2 maxUV )
+                                float4 psPosLN, float4 invShadowMapSize, float2 invDepthRange, PixelData pixelData, float f, float2 minUV, float2 maxUV )
 	@end @property( @m == 2 )
 		INLINE float getShadowPoint( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow )
 									 float3 posVS, float3 lightPos, float4 invShadowMapSize, float2 invDepthRange
@@ -150,6 +150,17 @@
 	@end
 	{
 	@property( @m < 2 )
+        float tmpNDotL = saturate( dot( passBuf.lights[0].position.xyz, pixelData.geomNormal.xyz ) );
+        @property( @m == 0 )
+            psPosLN.xy -= ((1.0f - tmpNDotL) * 3.5f * pixelData.geomNormal.xy * 0.000488281f * invDepthRange.y) * psPosLN.w;
+        @else
+            float regionSize = (maxUV.x - minUV.x) / invShadowMapSize.x;
+            regionSize = 1.0f / regionSize;
+            psPosLN.xyz -= ((1.0f - tmpNDotL) * 0.75f * pixelData.geomNormal.xyz *
+                            float3(regionSize,regionSize, -1.0f * invDepthRange.y)) * psPosLN.w;
+//            psPosLN.xyz -= ((1.0f - tmpNDotL) * 0.5f * pixelData.geomNormal.xyz * regionSize * (f+1)) * psPosLN.w;
+//            psPosLN.z += (f) * psPosLN.w * 0.005f;
+        @end
 		//Spot and directional lights
 		@property( !exponential_shadow_maps && !hlms_no_reverse_depth )
 			float fDepth = psPosLN.z / psPosLN.w;
@@ -328,14 +339,18 @@
 		{
 			fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 								 inPs.posL0,
-								 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+                    passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+                                 pixelData, @value(CurrentShadowMap)
 								 hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
 			@property( hlms_pssm_blend )
 				if( inPs.depth > passBuf.pssmBlendPoints@value(CurrentShadowMapBlend) )
 				{
 					fShadowBlend = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 											  inPs.posL1,
-											  passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                              passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+                            passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+                                              pixelData, @value(CurrentShadowMap)
 											  hlms_shadowmap@value(CurrentShadowMap)_uv_param );
 					fShadow = lerp( fShadow, fShadowBlend,
 									(inPs.depth - passBuf.pssmBlendPoints@value(CurrentShadowMapBlend)) /
@@ -351,14 +366,18 @@
 		{
 			fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 								 inPs.posL@n,
-								 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+                    passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+                    pixelData, @value(CurrentShadowMap)
 								 hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
 			@property( hlms_pssm_blend && @n < hlms_pssm_splits_minus_one )
 				if( inPs.depth > passBuf.pssmBlendPoints@value(CurrentShadowMapBlend) )
 				{
 					fShadowBlend = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 											  inPs.posL@value(CurrentShadowMap),
-											  passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                              passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+                            passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+                            pixelData, @value(CurrentShadowMap)
 											  hlms_shadowmap@value(CurrentShadowMap)_uv_param );
 					fShadow = lerp( fShadow, fShadowBlend,
 									(inPs.depth - passBuf.pssmBlendPoints@value(CurrentShadowMapBlend)) /
@@ -387,7 +406,9 @@
 	@property( receive_shadows )
 		float fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 								   inPs.posL0,
-								   passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                   passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+    passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+    pixelData, @value(CurrentShadowMap)
 								   hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
 	@end @property( !receive_shadows )
 		float fShadow = 1.0;
@@ -400,7 +421,9 @@
 	@piece( DarkenWithShadow )
 		* getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 					 inPs.posL@value(CurrentShadowMap),
-					 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                     passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+    passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+    pixelData, @value(CurrentShadowMap)
 					 hlms_shadowmap@counter(CurrentShadowMap)_uv_param )
 	@end
Note that I only worked on Directional and spotlights. Not everything may work as expected.
This looks almost perfect (minor artifacts here and there) with some exceptions.

A couple things to notice:
  1. The "0.75f" in "(1.0f - tmpNDotL) * 0.75f * pixelData.geomNormal.xyz..." is the arbitrary normal offset
    • The spheres from PbsMaterial benefit from a value much smaller than 0.75, else they show artifacts
  2. The -0.015 in "float shadowConstantBias = -0.015 / passBuf.depthRange.y /passBuf.depthRange.y * 0.1f;" is the arbitrary constant offset. The value from HlmsDatablock is not being respected in this patch
  3. The caster "/ passBuf.depthRange.y /passBuf.depthRange.y" can be done much more efficiently (mostly because a few lines later we multiply against passBuf.depthRange.y; this was a quick way of undoing that from the root)
  4. I tested Forward3D sample (which has a large scene), a modified version of ShadowMapDebugging, and PbsMaterials
  5. ESM could be broken
  6. It's quite clear with this technique that two factors are needed: One global (per scene) and one per object. I'm not sure yet if we can identify what element from a scene can be used to automatically calculate that global factor

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

Thanks, will try your implementation of it tomorrow. So far i'm having very good results with mine in both front and back face culling. Much better than what it was previously. My teammate is finally looking a bit happier with the shadows haha :P

Heres some comparison shots:

First with some ambience, notice all the white streaks because of the broken self shadowing. without(left) and normal offset(right)
ImageImage
No ambience to show what it looks like without(left) and normal offset(right)
ImageImage
Brighter comparison: before(left) and new normal offset(right)
ImageImage
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

New version:

Code: Select all

diff --git a/OgreMain/src/OgreHlmsDatablock.cpp b/OgreMain/src/OgreHlmsDatablock.cpp
index ae5e73810..6e41076dd 100644
--- a/OgreMain/src/OgreHlmsDatablock.cpp
+++ b/OgreMain/src/OgreHlmsDatablock.cpp
@@ -115,7 +115,7 @@ namespace Ogre
         mAlphaTestCmp( CMPF_ALWAYS_PASS ),
         mAlphaTestShadowCasterOnly( false ),
         mAlphaTestThreshold( 0.5f ),
-        mShadowConstantBias( 0.01f )
+        mShadowConstantBias( 0.05f )
     {
         mMacroblockHash[0] = mMacroblockHash[1] = 0;
         mMacroblock[0] = mMacroblock[1] = 0;
diff --git a/OgreMain/src/OgreHlmsManager.cpp b/OgreMain/src/OgreHlmsManager.cpp
index 4292409f0..99c3787ff 100644
--- a/OgreMain/src/OgreHlmsManager.cpp
+++ b/OgreMain/src/OgreHlmsManager.cpp
@@ -44,7 +44,7 @@ namespace Ogre
     HlmsManager::HlmsManager() :
         mComputeHlms( 0 ),
         mRenderSystem( 0 ),
-        mShadowMappingUseBackFaces( true ),
+        mShadowMappingUseBackFaces( false ),
         mDefaultHlmsType( HLMS_PBS )
   #if !OGRE_NO_JSON
     ,   mJsonListener( 0 )
diff --git a/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp b/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp
index a2415e108..057d414b9 100644
--- a/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp
+++ b/Samples/2.0/ApiUsage/ShadowMapDebugging/ShadowMapDebuggingGameState.cpp
@@ -97,7 +97,7 @@ namespace Demo
                         createChildSceneNode( Ogre::SCENE_DYNAMIC );
 
                 mSceneNode[idx]->setPosition( (i - 1.5f) * armsLength,
-                                              2.0f,
+                                              0.0f,
                                               (j - 1.5f) * armsLength );
                 mSceneNode[idx]->setScale( 0.65f, 0.65f, 0.65f );
 
@@ -123,7 +123,7 @@ namespace Demo
         lightNode->attachObject( light );
         light->setDiffuseColour( 0.8f, 0.4f, 0.2f ); //Warm
         light->setSpecularColour( 0.8f, 0.4f, 0.2f );
-        light->setPowerScale( Ogre::Math::PI );
+        light->setPowerScale( Ogre::Math::PI * 0 );
         light->setType( Ogre::Light::LT_SPOTLIGHT );
         lightNode->setPosition( -10.0f, 10.0f, 10.0f );
         light->setDirection( Ogre::Vector3( 1, -1, -1 ).normalisedCopy() );
@@ -136,7 +136,7 @@ namespace Demo
         lightNode->attachObject( light );
         light->setDiffuseColour( 0.2f, 0.4f, 0.8f ); //Cold
         light->setSpecularColour( 0.2f, 0.4f, 0.8f );
-        light->setPowerScale( Ogre::Math::PI );
+        light->setPowerScale( Ogre::Math::PI * 0 );
         light->setType( Ogre::Light::LT_SPOTLIGHT );
         lightNode->setPosition( 10.0f, 10.0f, -10.0f );
         light->setDirection( Ogre::Vector3( -1, -1, 1 ).normalisedCopy() );
@@ -175,6 +175,14 @@ namespace Demo
                                                gaussianDeviationFactor, K );
 #endif
 
+        {
+            Ogre::Root *root = mGraphicsSystem->getRoot();
+            Ogre::Hlms *hlms = root->getHlmsManager()->getHlms( Ogre::HLMS_PBS );
+            assert( dynamic_cast<Ogre::HlmsPbs*>( hlms ) );
+            Ogre::HlmsPbs *pbs = static_cast<Ogre::HlmsPbs*>( hlms );
+            pbs->getHlmsManager()->setShadowMappingUseBackFaces( false );
+        }
+
         TutorialGameState::createScene01();
     }
     //-----------------------------------------------------------------------------------
@@ -450,10 +458,10 @@ namespace Demo
             }
 #endif
 
-            if( nextFilter == Ogre::HlmsPbs::ExponentialShadowMaps )
+            //if( nextFilter == Ogre::HlmsPbs::ExponentialShadowMaps )
                 pbs->getHlmsManager()->setShadowMappingUseBackFaces( false );
-            else
-                pbs->getHlmsManager()->setShadowMappingUseBackFaces( true );
+//            else
+//                pbs->getHlmsManager()->setShadowMappingUseBackFaces( true );
 
             pbs->setShadowSettings( nextFilter );
 
diff --git a/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any b/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any
index d4e0a668a..7a66574f5 100644
--- a/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any
+++ b/Samples/Media/Hlms/Common/Any/ShadowCaster_piece_vs.any
@@ -3,14 +3,22 @@
 
 @property( hlms_shadowcaster )
 	@piece( DoShadowCasterVS )
-		float shadowConstantBias = uintBitsToFloat( worldMaterialIdx[inVs_drawId].y );
+        @property( hlms_no_reverse_depth )
+            float shadowConstantBias = uintBitsToFloat( worldMaterialIdx[inVs_drawId].y );
+        @else
+            //float shadowConstantBias = -uintBitsToFloat( worldMaterialIdx[inVs_drawId].y );
+            //float shadowConstantBias = -0.5 / passBuf.depthRange.y * 0.1f;
+            //float shadowConstantBias = -4.5 / passBuf.depthRange.y * 0.1f;
+            float shadowConstantBias = -0.015 / passBuf.depthRange.y /passBuf.depthRange.y * 0.1f;
+            //float shadowConstantBias = 0.65 / passBuf.depthRange.y * 0.1f;
+        @end
 
 		@property( !hlms_shadow_uses_depth_texture && !hlms_shadowcaster_point && !exponential_shadow_maps )
 			//Linear depth
 			@property( hlms_shadowcaster_directional || !hlms_no_reverse_depth )
-				outVs.depth	= outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y;
+                outVs.depth	= outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y;
 			@else
-				outVs.depth	= (outVs_Position.z + shadowConstantBias * passBuf.depthRange.y) * passBuf.depthRange.y;
+                outVs.depth	= (outVs_Position.z + shadowConstantBias * passBuf.depthRange.y) * passBuf.depthRange.y;
 			@end
 			@property( hlms_no_reverse_depth && (syntax == glsl || syntax == glsles) )outVs.depth = (outVs.depth * 0.5) + 0.5;@end
 		@end
@@ -27,7 +35,7 @@
 			//however we can use a cheap approximation ("pseudo linear depth")
 			//see http://www.yosoygames.com.ar/wp/2014/01/linear-depth-buffer-my-ass/
 			@property( hlms_shadowcaster_directional || !hlms_no_reverse_depth )
-				outVs_Position.z = outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y;
+                outVs_Position.z = outVs_Position.z + shadowConstantBias * passBuf.depthRange.y * passBuf.depthRange.y;
 			@else
 				outVs_Position.z = (outVs_Position.z + shadowConstantBias * passBuf.depthRange.y) * passBuf.depthRange.y * outVs_Position.w;
 			@end
diff --git a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any
index 58b8b7e01..8b843eeb5 100644
--- a/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any
+++ b/Samples/Media/Hlms/Pbs/Any/ShadowMapping_piece_ps.any
@@ -1,4 +1,4 @@
-
+
 //#include "SyntaxHighlightingMisc.h"
 
 @property( hlms_num_shadow_map_lights )
@@ -134,10 +134,10 @@
 @foreach( 4, m )
 	@property( @m == 0 )
 		INLINE float getShadow( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow )
-								float4 psPosLN, float4 invShadowMapSize )
+                                float4 psPosLN, float4 invShadowMapSize, float2 invDepthRange, PixelData pixelData, float f )
 	@end @property( @m == 1 )
 		INLINE float getShadow( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow )
-								float4 psPosLN, float4 invShadowMapSize, float2 minUV, float2 maxUV )
+                                float4 psPosLN, float4 invShadowMapSize, float2 invDepthRange, PixelData pixelData, float f, float2 minUV, float2 maxUV )
 	@end @property( @m == 2 )
 		INLINE float getShadowPoint( @insertpiece( TEXTURE2DSHADOW ) shadowMap, @insertpiece( SamplerShadow )
 									 float3 posVS, float3 lightPos, float4 invShadowMapSize, float2 invDepthRange
@@ -150,6 +150,21 @@
 	@end
 	{
 	@property( @m < 2 )
+        float tmpNDotL = saturate( dot( passBuf.lights[0].position.xyz, pixelData.geomNormal.xyz ) );
+        @property( @m == 0 )
+            psPosLN.xy -= ((1.0f - tmpNDotL) * 3.5f * pixelData.geomNormal.xy * 0.000488281f * invDepthRange.y) * psPosLN.w;
+        @else
+            float regionSize = (maxUV.x - minUV.x) / invShadowMapSize.x;
+            regionSize = 1.0f / regionSize;
+            float dff = max( abs(OGRE_ddx( psPosLN.z )), abs(OGRE_ddy( psPosLN.z )) );
+            dff = 1.0f + pow( dff, 0.1 ) * 16.0;
+            //float dff = max( 1.0f - 4.0 * pow( max( abs(OGRE_ddx( psPosLN.z )), abs(OGRE_ddy( psPosLN.z )) ), 0.05 ), 0 );
+            //float dff = 1.0;
+            psPosLN.xyz -= ((1.0f - tmpNDotL) * (0.75f) * pixelData.geomNormal.xyz *
+                            float3(regionSize,regionSize, -1.0f * invDepthRange.y / dff)) * psPosLN.w;
+//            psPosLN.xyz -= ((1.0f - tmpNDotL) * 0.5f * pixelData.geomNormal.xyz * regionSize * (f+1)) * psPosLN.w;
+//            psPosLN.z += (f) * psPosLN.w * 0.005f;
+        @end
 		//Spot and directional lights
 		@property( !exponential_shadow_maps && !hlms_no_reverse_depth )
 			float fDepth = psPosLN.z / psPosLN.w;
@@ -328,14 +343,18 @@
 		{
 			fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 								 inPs.posL0,
-								 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+                    passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+                                 pixelData, @value(CurrentShadowMap)
 								 hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
 			@property( hlms_pssm_blend )
 				if( inPs.depth > passBuf.pssmBlendPoints@value(CurrentShadowMapBlend) )
 				{
 					fShadowBlend = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 											  inPs.posL1,
-											  passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                              passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+                            passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+                                              pixelData, @value(CurrentShadowMap)
 											  hlms_shadowmap@value(CurrentShadowMap)_uv_param );
 					fShadow = lerp( fShadow, fShadowBlend,
 									(inPs.depth - passBuf.pssmBlendPoints@value(CurrentShadowMapBlend)) /
@@ -351,14 +370,18 @@
 		{
 			fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 								 inPs.posL@n,
-								 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+                    passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+                    pixelData, @value(CurrentShadowMap)
 								 hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
 			@property( hlms_pssm_blend && @n < hlms_pssm_splits_minus_one )
 				if( inPs.depth > passBuf.pssmBlendPoints@value(CurrentShadowMapBlend) )
 				{
 					fShadowBlend = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 											  inPs.posL@value(CurrentShadowMap),
-											  passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                              passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+                            passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+                            pixelData, @value(CurrentShadowMap)
 											  hlms_shadowmap@value(CurrentShadowMap)_uv_param );
 					fShadow = lerp( fShadow, fShadowBlend,
 									(inPs.depth - passBuf.pssmBlendPoints@value(CurrentShadowMapBlend)) /
@@ -387,7 +410,9 @@
 	@property( receive_shadows )
 		float fShadow = getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 								   inPs.posL0,
-								   passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                                   passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+    passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+    pixelData, @value(CurrentShadowMap)
 								   hlms_shadowmap@counter(CurrentShadowMap)_uv_param );
 	@end @property( !receive_shadows )
 		float fShadow = 1.0;
@@ -400,7 +425,9 @@
 	@piece( DarkenWithShadow )
 		* getShadow( hlms_shadowmap@value(CurrentShadowMap), @insertpiece( UseSamplerShadow )
 					 inPs.posL@value(CurrentShadowMap),
-					 passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize
+                     passBuf.shadowRcv[@value(CurrentShadowMap)].invShadowMapSize,
+    passBuf.shadowRcv[@value(CurrentShadowMap)].shadowDepthRange.xy,
+    pixelData, @value(CurrentShadowMap)
 					 hlms_shadowmap@counter(CurrentShadowMap)_uv_param )
 	@end
 
It's the same as the one before, but also uses DDX & DDY to mitigate some of the artifacts

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

I found a major bug in my code. I'll be uploading a fixed one soon.

Also I found the original paper in Godot's github. The technique works from vertex shader too!

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

Ok, I shall wait for the new fixed version before trying yours.

How would the light affect the offset in the vertex shader, would it have the same quality.

And yeah that original paper was useful for me too, I should have posted a link to it. sorry :P

Edit: Be careful with front face culling and point lights: (as my version does not support point lights and normal offsets yet)
The point lights need a bias at all times from what it seems.
Clipboard Image (3).jpg
Its also good that we are solving this as having blacker areas with no light bleed or acne means the GI solutions will have better quality.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

Nickak2003
Gremlin
Posts: 192
Joined: Thu Jun 10, 2004 4:19 am
x 11
Contact:

Re: [2.2] Self Shadowing errors

Post by Nickak2003 »

you guys are my heroes.

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

@dark_sylinc, if you have the patch with the bug fix, i will have time tomorrow to test it out :)
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

Pushed the changes to a new branch 'shadow_bias_improve'.

I didn't want to risk breaking master, it needs more testing (but so far it looks damn good!).
The commit explains the changes.

I removed the back face method. This method is far superior.
This version supports all light types: directional, spot & point lights.

Cheers!

Lax
Orc
Posts: 476
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 30

Re: [2.2] Self Shadowing errors

Post by Lax »

Hi dark_sylinc,

thanks! I will test it.

Best Regards
Lax
Image
http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62
Image

Lax
Orc
Posts: 476
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 30

Re: [2.2] Self Shadowing errors

Post by Lax »

Hi,

I cannot load a scene anymore using the 'shadow_bias_improve'. I updated all hlms/compositor resource and cleared also the shader cache.

But I'm getting the following shader compile errors:

Code: Select all

13:56:49: OGRE EXCEPTION(-2147467259:RenderingAPIException): Cannot compile D3D11 high-level shader 700000000VertexShader_vs Errors:
(438,45-53): error X3004: undeclared identifier 'worldNorm'
 in D3D11HLSLProgram::compileMicrocode at ..\Ogre2.2SDK\RenderSystems\Direct3D11\src\OgreD3D11HLSLProgram.cpp (line 549)
13:56:49: High-level program 700000000VertexShader_vs encountered an error during loading and is thus not supported.
Best Regards
Lax
Image
http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62
Image

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

I have now just merged my ogre sources ( we use a custom ogre source ) and am currently compiling so hopefully it all works. But will keep you informed of progress :)

@Lax, i shall see if i get this too and let you know.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

@Lax, my code doesnt throw that error your seeing, have you added the PBS HLMS shaders(Any, hlsl,etc...) and the Hlms/Common/Any which contains the caster_vs

I am also running in DX11.

However, so far i am experiencing the odd strange shadow artefact that i didn't get with mine happening at the moment which i am investigating.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

Lax wrote:
Fri Jun 12, 2020 12:58 pm
Hi,

I cannot load a scene anymore using the 'shadow_bias_improve'. I updated all hlms/compositor resource and cleared also the shader cache.

But I'm getting the following shader compile errors:

Code: Select all

13:56:49: OGRE EXCEPTION(-2147467259:RenderingAPIException): Cannot compile D3D11 high-level shader 700000000VertexShader_vs Errors:
(438,45-53): error X3004: undeclared identifier 'worldNorm'
 in D3D11HLSLProgram::compileMicrocode at ..\Ogre2.2SDK\RenderSystems\Direct3D11\src\OgreD3D11HLSLProgram.cpp (line 549)
13:56:49: High-level program 700000000VertexShader_vs encountered an error during loading and is thus not supported.
Best Regards
Lax
Thanks for the report. Fixed it.

Gosh, I really should work on that "unit test mode" for the samples so that these bugs can be spot immediately and automatically.

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: [2.2] Self Shadowing errors

Post by SolarPortal »

Good catch!

Quick question and not sure if i'm wrong, but is the worldnormal of the object multiplied by the transform of the node? Or does the normal that comes into the vertex already have the multiplication against the node transform. Could be having a ditsy moment haha

Because i'm just looking at the animated boxes in the ShadowmapDebugging and keep getting black on top of the boxes at certain rotations.

Also some shadow acne on the stable splits in that demo too.
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4501
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 936
Contact:

Re: [2.2] Self Shadowing errors

Post by dark_sylinc »

SolarPortal wrote:
Fri Jun 12, 2020 7:24 pm
Quick question and not sure if i'm wrong, but is the worldnormal of the object multiplied by the transform of the node? Or does the normal that comes into the vertex already have the multiplication against the node transform. Could be having a ditsy moment haha
The normals are in object space, hence need to be multiplied against the worldMatrix to be in world space.
Because i'm just looking at the animated boxes in the ShadowmapDebugging and keep getting black on top of the boxes at certain rotations.
I can't see such thing, perhaps GL3+ vs D3D11 thing? (I only tried GL).
Also I tried to apply the lowest bias as possible
SolarPortal wrote:
Fri Jun 12, 2020 7:24 pm
Also some shadow acne on the stable splits in that demo too.
I see it too once stable splits > 1; which is why I added the ability to globally control the bias per cascade.
Once stable splits > 2, the quality degradation on the higher splits is rather big; thus it's no longer just a matter of a "small bias issue" (but it can be solved with larger biases).

I agree the shadow map debugging sample should automatically adjust these biases to show how it's done.

Post Reply