Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Ady

Member Since 11 Jun 2008
Offline Last Active Mar 09 2015 06:27 AM

#5210839 Can't fix shadow acne with bias

Posted by Ady on 15 February 2015 - 09:19 AM

Omg it works, thank you all so much !!!

 

// Generate projective tex-coords to project shadow map onto scene.
float4x4 worldShadowTransform = mul(world, gShadowTransform); 
vout.ShadowPosH = mul(float4(vin.PosL + (vin.NormalL*0.1f), 1.0f), worldShadowTransform);

yu2zeXg.png




#5210826 Can't fix shadow acne with bias

Posted by Ady on 15 February 2015 - 08:40 AM

Thanks for all your suggestions !

 

I'll try Aardvajk's approach 1st.

I tried to implement your method, but it doesn't give me the expected result.

The shader i build the shadow map with, is actually a very simple vertex shader where i just draw the scene on the deph buffer :

 

VertexOut VS(VertexIn vin)
{
VertexOut vout;

float4x4 world = GetIdentity();
world[3][0] =  vin.World.x;
world[3][1] =  vin.World.y;
world[3][2] =  vin.World.z;

float4x4 worldViewProj = mul(world, gViewProj);
vout.PosH = mul(float4(vin.PosL, 1.0f), worldViewProj);
vout.Tex  = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;

return vout;
}

My first attempt was to slightly "push" vertices away from their position in the direction of their normal vector :

 

VertexOut VS(VertexIn vin)
{
VertexOut vout;

float4x4 world = GetIdentity();
world[3][0] =  vin.World.x;
world[3][1] =  vin.World.y;
world[3][2] =  vin.World.z;

float4x4 worldViewProj = mul(world, gViewProj);
vout.PosH = mul(float4(vin.PosL + vin.NormalL * 0.2f, 1.0f), worldViewProj);
vout.Tex  = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;

return vout;
}

This made things worse :

 

5YctwWK.png

 

I think i probably did this wrong, but i am not exactly sure what i missed here. Just to be sure, i increased the factor by 2 :

VertexOut VS(VertexIn vin)
{
VertexOut vout;

float4x4 world = GetIdentity();
world[3][0] =  vin.World.x;
world[3][1] =  vin.World.y;
world[3][2] =  vin.World.z;

float4x4 worldViewProj = mul(world, gViewProj);
vout.PosH = mul(float4(vin.PosL + vin.NormalL * 2.0f, 1.0f), worldViewProj);
vout.Tex  = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;

return vout;
}

XAdk55L.png

 

We can see on the depth buffer faces of cubes going away from each others in the direction of normals, i i think that's the point of this technique.

 

Then i tried a similar approach by trying to scale the scene up by 5% just for the shadow map, and this was also a failure : 

VertexOut VS(VertexIn vin)
{
VertexOut vout;

float4x4 world = GetIdentity();
world[3][0] =  vin.World.x;
world[3][1] =  vin.World.y;
world[3][2] =  vin.World.z;

float4x4 worldViewProj = mul(world, gViewProj);
vout.PosH = mul(float4(vin.PosL * 1.05f, 1.0f), worldViewProj);
vout.Tex  = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;

return vout;
}

9ifS6FR.png

 

I'll keep experimenting though :-)




#5210700 Can't fix shadow acne with bias

Posted by Ady on 14 February 2015 - 11:21 AM

Hi there,
 
Lately i decided to dig up an old project of mine i stopped working on because shadows was giving me a hard time.
Well, my shadow issue is still there, and i need help to figure this thing out.
 
My problem :
 
I have shadow acne :
 
 
I am learning D3D programming with Franck Luna's book which comes with code sample i used in my engine.
The book says that acne is a common issue when working with shadow mapping, and is usually fixed by increasing the bias.
I did, and predictably the acne was gone, but then i had the "peter pan" issue where the shadow would look detached from it's source :
 
 
According to the book, you have to make lots of experiment with your scene to find the sweet spot (perfect bias i presume).
Well i tried a lot of different values, but instead of finding the perfect bias, i ended up having both peter pan AND acne.
 
When i start digging on the internet how to fix shadows, i often find articles about PCF filtering which and other advanced techniques which, if i am not mistaken, will not help me fix my acne issue but improve shadow edges quality.
 
Implementation :
 
I tried to implement Frank Luna's shadow mapping sample the best i could in my engine:
 
Main draw call :
 
void LightGame::DrawScene()
{
mGameComponents[GameComponent::Id::Land]->BuildShadowMap(); 
ResetRenderTarget();
mGameComponents[GameComponent::Id::Land]->Draw(); 


// ...


HR(mSwapChain->Present(0, 0));
}
 
1- I first build the Land's shadow map by rendering the land on the depth buffer only.
2- Then i reset the render target back to the backbuffer.
3- Then render the land normaly now that it has the shadow map.
 
This is how i build the shadow map. Note that the "Chunk" class represents the "Land" component.
 
void Chunk::BuildShadowMap()
{
// Prepare drawing on depth buffer only.


GetShadowMap()->SetRenderTargetToDepthBuffer();


// I build the transform matrix i'll use to transform the shadow map from light, to player perspective. 
// I also initialize mLightView, and mLightProj in there.


BuildShadowTransform();


// Draw the land from the light perspective.


XMMATRIX view     = XMLoadFloat4x4(&mLightView);
XMMATRIX proj     = XMLoadFloat4x4(&mLightProj);
XMMATRIX viewProj = XMMatrixMultiply(view, proj);
mBuildShadowMapFX->SetViewProj(viewProj);


ID3DX11EffectTechnique* tessSmapTech = mBuildShadowMapFX->BuildShadowMapTech;
ID3D11DeviceContext* deviceContext = Graphics::GetInstance().GetImmediateContext();
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
deviceContext->IASetInputLayout(mBuildShadowMapFX->GetInputLayout()); 


UINT stride[] = {sizeof(Vertex::Basic32), sizeof(InstanceData)};
UINT offset[] = {0, 0};
ID3D11Buffer* bufferPointers[2] = {mVB, mInstanceBuffer};


    D3DX11_TECHNIQUE_DESC techDesc;
tessSmapTech->GetDesc( &techDesc );


    deviceContext->IASetVertexBuffers(0, 2, bufferPointers, stride, offset);
deviceContext->IASetIndexBuffer(mIB, DXGI_FORMAT_R32_UINT, 0); 


for(UINT p = 0; p < techDesc.Passes; ++p)
    {
mBuildShadowMapFX->SetViewProj(viewProj);
mBuildShadowMapFX->SetTexTransform(XMMatrixScaling(2.0f, 1.0f, 1.0f));
tessSmapTech->GetPassByIndex(p)->Apply(0, deviceContext);
deviceContext->DrawIndexedInstanced(36, mNumberOfActiveCubes, 0, 0, 0);
    }
}


This is how i build the transform matrix for the shadow map.


void Chunk::BuildShadowTransform(void)
{
DirectionalLight* sunLight = World::GetInstance().GetSunlight();


XMFLOAT3 lightPosFloat3;
XMVECTOR lightDir = XMLoadFloat3(&sunLight->Direction);
XMVECTOR lightPos = mBoundingSphere->Radius*(lightDir * -1.0f) * 2;
XMStoreFloat3(&lightPosFloat3, lightPos);
lightPosFloat3.x += mBoundingSphere->Center.x;
lightPosFloat3.z += mBoundingSphere->Center.z;
lightPos = XMLoadFloat3(&lightPosFloat3);


XMVECTOR targetPos = XMLoadFloat3(&mBoundingSphere->Center);
XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
XMMATRIX V = XMMatrixLookAtLH(lightPos, targetPos, up);


// Transform bounding sphere to light space.
XMFLOAT3 sphereCenterLS;
XMStoreFloat3(&sphereCenterLS, XMVector3TransformCoord(targetPos, V));


// Ortho frustum in light space encloses scene.
float l = sphereCenterLS.x - mBoundingSphere->Radius;
float b = sphereCenterLS.y - mBoundingSphere->Radius;
float n = sphereCenterLS.z - mBoundingSphere->Radius;
float r = sphereCenterLS.x + mBoundingSphere->Radius;
float t = sphereCenterLS.y + mBoundingSphere->Radius;
float f = sphereCenterLS.z + mBoundingSphere->Radius;
XMMATRIX P = XMMatrixOrthographicOffCenterLH(l, r, b, t, n, f);


// Transform NDC space [-1,+1]^2 to texture space [0,1]^2
XMMATRIX T(
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f);


XMMATRIX S = V*P*T;


XMStoreFloat4x4(&mLightView, V);
XMStoreFloat4x4(&mLightProj, P);
XMStoreFloat4x4(&mShadowTransform, S);
}
 
mBuildShadowMapFX shader :
 
#include "utility.fx"


cbuffer cbPerObject
{
float4x4 gViewProj;
float4x4 gTexTransform;
}; 


struct VertexIn
{
float3 PosL     : POSITION0;
float3 NormalL  : NORMAL;
float2 Tex      : TEXCOORD;
float2 IsSelected : TEXCOORD1;
float3 World    : POSITION1;
};


struct VertexOut
{
float4 PosH : SV_POSITION;
float2 Tex  : TEXCOORD;
};


VertexOut VS(VertexIn vin)
{
VertexOut vout;


float4x4 world = GetIdentity();
world[3][0] =  vin.World.x;
world[3][1] =  vin.World.y;
world[3][2] =  vin.World.z;


float4x4 worldViewProj = mul(world, gViewProj);


vout.PosH = mul(float4(vin.PosL, 1.0f), worldViewProj);
vout.Tex  = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;


return vout;
}


RasterizerState Depth
{
DepthBias = 1000; // <- This is where i play with the bias !!!
    DepthBiasClamp = 0.0f;
SlopeScaledDepthBias = 1.0f;
};


technique11 BuildShadowMapTech
{
    pass P0
    {
SetVertexShader( CompileShader( vs_5_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( NULL );


SetRasterizerState(Depth);
    }
}
 
And now the main shader rendering the land using the shadow map :
 
#include "light.fx"
#include "utility.fx"


float oneThird = 0.3334f;
float twoThird = 0.6667f;
float borderYThickness = 0.007f;
float borderXThickness = 0.007f / 3.0f;
float4 borderColor = float4(0.1f, 0.1f, 0.1f, 1.0f);


struct VertexIn
{
float3 PosL    : POSITION0;
float3 NormalL : NORMAL;
float2 Tex     : TEXCOORD0;
float2 IsSelected : TEXCOORD1;
float3 World    : POSITION1;
float2 CubeType : TEXCOORD2;
};


struct VertexOut
{
float4 PosH    : SV_POSITION;
    float3 PosW    : POSITION;
float3 PosVS   : POSITION1;
float3 ViewRay   : POSITION2;
    float3 NormalW : NORMAL;
float2 Tex     : TEXCOORD;
float IsSelected : DEPTH;
float4 ShadowPosH : TEXCOORD1; 
float CubeType : DEPTH1;
};


cbuffer cbPerObject
{
float4x4 gWorld;
float4x4 gView;
float4x4 gWorldInvTranspose;
float4x4 gViewProj;
float4x4 gProjInvTranspose;
float4x4 gTexTransform;
float4x4 gShadowTransform;
Material gMaterial;
};


cbuffer cbPerFrame
{
DirectionalLight gDirLight;
float3 gEyePosW;
};


// Nonnumeric values cannot be added to a cbuffer.
Texture2DArray gBlockMapArray;


SamplerState Aniso
{
Filter = ANISOTROPIC;
MaxAnisotropy = 4; 
AddressU = WRAP;
AddressV = WRAP;
};


SamplerComparisonState samShadow
{
Filter   = COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
AddressU = BORDER;
AddressV = BORDER;
AddressW = BORDER;
BorderColor = float4(0.0f, 0.0f, 0.0f, 0.0f);


    ComparisonFunc = LESS_EQUAL;
};


RasterizerState DisableCulling
{
CullMode = BACK;
};


SamplerState samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};


Texture2D gShadowMap;


VertexOut VS(VertexIn vin)
{
VertexOut vout; 
float4x4 world = GetIdentity();
world[3][0] =  vin.World.x;
world[3][1] =  vin.World.y;
world[3][2] =  vin.World.z;


float4x4 WorldViewMatrix = mul(world, gView);


// Transform to world space.
vout.PosW    = mul(float4(vin.PosL, 1.0f), world).xyz;


// Find transformed normals.
vout.NormalW = mul(vin.NormalL, (float3x3)world);


// Transform to homogeneous clip space.
vout.PosH = mul(float4(vout.PosW, 1.0f), gViewProj);


    vout.Tex = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;
vout.IsSelected = vin.IsSelected.x;


// Generate projective tex-coords to project shadow map onto scene.
float4x4 worldShadowTransform = mul(world, gShadowTransform); 
vout.ShadowPosH = mul(float4(vin.PosL, 1.0f), worldShadowTransform);


float3 positionVS = mul(vin.PosL, gProjInvTranspose);
vout.ViewRay = float3(positionVS.xy / positionVS.z, 1.0f);


vout.PosVS = mul(float4(vin.PosL, 1.0f), WorldViewMatrix);
vout.CubeType = vin.CubeType.x;
    
    return vout;
}


float GetPercentLit(SamplerComparisonState samShadow, Texture2D shadowMap, float4 shadowPosH)
{
// Complete projection by doing division by w.
shadowPosH.xyz /= shadowPosH.w;


// Depth in NDC space (from light source).
float depth = shadowPosH.z;


return shadowMap.SampleCmpLevelZero(samShadow, shadowPosH.xy, depth).r;
}


float4 PS(VertexOut pin) : SV_Target
{
// Highlighting edges of the block if it's selected.
if(pin.IsSelected == 1.0f)
{
if(pin.Tex.x  > oneThird && pin.Tex.x  < oneThird + borderXThickness)
{
return borderColor;
}


if(pin.Tex.x  > twoThird - borderXThickness && pin.Tex.x  < twoThird)
{
return borderColor;
}


if(pin.Tex.y  > 0.0 && pin.Tex.y  < borderYThickness)
{
return borderColor;
}


if(pin.Tex.y  > 1.0 - borderYThickness)
{
return borderColor;
}
}


    // Interpolating normal can unnormalize it, so normalize it.
    pin.NormalW = normalize(pin.NormalW);  


// Start with a sum of zero. 
float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
float3 uvw = float3(pin.Tex, pin.CubeType);
float4 texColor = gBlockMapArray.Sample(Aniso, uvw);


ambient = gMaterial.Ambient * gDirLight.Ambient;


// The light vector aims opposite the direction the light rays travel.
float3 lightVec = -gDirLight.Direction;


// Add diffuse and specular term, provided the surface is in 
// the line of site of the light. 
float diffuseFactor = dot(lightVec, pin.NormalW);


// Flatten to avoid dynamic branching.
[flatten]
if( diffuseFactor > 0.0f )
{
diffuse = diffuseFactor * gMaterial.Diffuse * gDirLight.Diffuse;
}


float percentLit = GetPercentLit(samShadow, gShadowMap, pin.ShadowPosH);
diffuse = diffuse * percentLit;
float4 litColor = texColor * (diffuse + ambient);


// Common to take alpha from diffuse material.
litColor.a = gMaterial.Diffuse.a;


return litColor;
}


technique11 BlockTech
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_5_0, PS() ) );
SetRasterizerState(DisableCulling);
    }
}
 
 
I think this is it. I tried all kind of things, but i still do not understand where the issue is.
Any help or suggestion would be greatly appreciated :-)
 
BTW, the full source is available here if you're interested : https://www.dropbox.com/s/0rmiln0bua3pshk/source.zip?dl=0
I have a dependency on Effect11.lib i compiled with VS2013, so you might need to rebuild it if you have and older version of VS.



#5141522 Help with Smooth Gradient on Skydome

Posted by Ady on 23 March 2014 - 02:34 PM

Have you thought about sampling a sky gradient texture instead ?

Something like this




#5093298 Instancing : Different textures for instances

Posted by Ady on 11 September 2013 - 10:00 AM

Hi eppo !

Actually i implemented you 1st approach yesterday night and it works fine (but with artefects on edges as you mentionned).

A friend just told me 5 minutes ago about texture arrays which is EXACTLY what i need as you also suggested, so i'll implement that tonight, thank you so much !




PARTNERS