hi ,
i am start to implement pssm a few days ago, but i have some problems on it, when camera look the same direction of light,
the pssm works very well as the image below
[attachment=22290:1.png]
but when camera look opposite of the light ,all shadow disappeared
[attachment=22291:3.png]
when turn camer to left a bit , the shadow became obscured
[attachment=22292:2.png]
if i turn the camera to right, i got this image
[attachment=22293:4.png]
this is the hlsl code for depth map
struct VS_OUTPUT
{
float4 posH : POSITION;
float4 depth : TEXCOORD0;
};
VS_OUTPUT vs_depth(
float3 posL : POSITION0)
{
VS_OUTPUT o = (VS_OUTPUT) 0;
o.posH = mul(float4(posL, 1.0f), gWLightVP);
o.tex = tex;
o.depth = o.posH;
}
float4 ps_depth(VS_OUTPUT i) : COLOR
{
float z = i.depth.z / i.depth.w;
}
this is the hlsl code of scene
VS_OUTPUT vs(
float3 posL : POSITION0,
float3 Normal : NORMAL,
float2 TexCoord : TEXCOORD0)
{
VS_OUTPUT o = (VS_OUTPUT) 0;
o.Position = mul(float4(posL, 1.0f), gWorldViewProj);
o.TexCoord = TexCoord;
o.Normal = Normal;
float4 posW = mul(posL, gWorld);
float4 posV = mul(posW, gView);
o.zV = posV.z;
for (int i = 0; i < 4; ++i)
{
o.ScreenPos[i] = mul(float4(posL, 1.0f), gWLightVPs[i]);
}
return o;
}
float4 ps(VS_OUTPUT i) : COLOR
{
float shadow = 0.0f;
for (int j = 0; j < 4; ++j)
{
if (i.zV >= PSSMDistances[j] && i.zV < PSSMDistances[j + 1])
{
shadow = process_shadow(j, i.ScreenPos[j]);
}
}
}
process_shadow function
float process_shadow(sampler sam, float4 projTex)
{
// Compute pixel depth for shadowing.
float depth = projTex.z;
// Transform to texel space
float2 texelpos = ShadowMapSize * projTex.xy;
// Determine the lerp amounts.
float2 lerps = frac( texelpos );
// 2x2 percentage closest filter.
float dx = 1.0f / ShadowMapSize;
float s0 = (tex2D(sam, projTex.xy).r + SHADOW_EPSILON < depth) ? 0 : 1;
float s1 = (tex2D(sam, projTex.xy + float2(dx, 0.0f)).r + SHADOW_EPSILON < depth) ? 0 : 1;
float s2 = (tex2D(sam, projTex.xy + float2(0.0f, dx)).r + SHADOW_EPSILON < depth) ? 0 : 1;
float s3 = (tex2D(sam, projTex.xy + float2(dx, dx)).r + SHADOW_EPSILON < depth) ? 0 : 1;
return lerp( lerp(s0, s1, lerps.x), lerp(s2, s3, lerps.x), lerps.y );
}
float process_shadow(int partition, float4 screenPos)
{
float4 projTex = screenPos;
projTex.xyz /= projTex.w;
projTex.x = 0.5f*projTex.x + 0.5f;
projTex.y = -0.5f*projTex.y + 0.5f;
float shadow = 1.0f;
if (partition == 0)
{
shadow = process_shadow(shadowmapsam0, projTex);
}
if (partition == 1)
{
shadow = process_shadow(shadowmapsam1, projTex);
}
if (partition == 2)
{
shadow = process_shadow(shadowmapsam2, projTex);
}
if (partition == 3)
{
shadow = process_shadow(shadowmapsam3, projTex);
}
return shadow;
}
PSSMUtils.cpp this code is come from https://code.google.com/p/irrcg/
CPSSMUtils::CPSSMUtils(WSCamera* vLightCamera, int vSplitsCount, float vSplitLambda) : SplitLambda(vSplitLambda), LightCamera(0),
SplitsCount(0), Near(0), Far(0), Current(0)
{
for(int i = 0; i < 4; i++)
{
FrustumCorner[i] = D3DXVECTOR3(0,0,0);
//mP[i] = 0;
//mV[i] = 0;
D3DXMatrixIdentity(&mP[i]);
D3DXMatrixIdentity(&mV[i]);
}
setLightCamera(vLightCamera);
if(vSplitsCount > 0)
{
if(vSplitsCount > 4)
SplitsCount = 4;
else
SplitsCount = vSplitsCount;
}
else
SplitsCount = 1;
}
void CPSSMUtils::CalculateSplitDistances(WSCamera* vCamera)
{
//delete[] SplitDistance;
//SplitDistance = new float[SplitsCount + 1];
float vNear = vCamera->getNearValue();
float vFar = vCamera->getFarValue();
SplitLambda = Clamp(SplitLambda, 0.0f, 1.0f);
for(int i = 0; i < SplitsCount; i++)
{
float Param = i / (float)SplitsCount;
float Log = vNear * powf((vFar / vNear), Param);
float Uniform = vNear + (vFar - vNear) * Param;
int dist = Log * SplitLambda + Uniform * (1.0 - SplitLambda);
SplitDistance[i] = dist;
}
SplitDistance[0] = vNear;
SplitDistance[SplitsCount] = vFar;
}
void CPSSMUtils::CalculateFrustumCorners(WSCamera* vCamera, int vCurrent, float vScale)
{
if(vCurrent < 0 || vCurrent > 3)
vCurrent = 0;
Current = vCurrent;
D3DXVECTOR3 vSource = vCamera->pos();
D3DXVECTOR3 vTarget = vCamera->look();
D3DXVECTOR3 vUp = vCamera->up();
float vFOV = vCamera->getFOV();
float vAspect = vCamera->getAspectRatio();
float vNear = SplitDistance[Current];
float vFar = SplitDistance[Current + 1];
D3DXVECTOR3 vZ = vTarget - vSource;
//vZ.normalize();
D3DXVec3Normalize(&vZ, &vZ);
//D3DXVECTOR3 vX = vUp.crossProduct(vZ);
//vX.normalize();
D3DXVECTOR3 vX;
D3DXVec3Cross(&vX, &vUp, &vZ);
D3DXVec3Normalize(&vX, &vX);
//D3DXVECTOR3 vY = vZ.crossProduct(vX);
D3DXVECTOR3 vY;
D3DXVec3Cross(&vY, &vZ, &vX);
float NearPlaneHeight = tanf(vFOV * 0.5f) * vNear;
float NearPlaneWidth = NearPlaneHeight * vAspect;
float FarPlaneHeight = tanf(vFOV * 0.5f) * vFar;
float FarPlaneWidth = FarPlaneHeight * vAspect;
D3DXVECTOR3 NearPlaneCenter = vSource + vZ * vNear;
D3DXVECTOR3 FarPlaneCenter = vSource + vZ * vFar;
FrustumCorner[0] = D3DXVECTOR3(NearPlaneCenter - vX*NearPlaneWidth - vY*NearPlaneHeight);
FrustumCorner[1] = D3DXVECTOR3(NearPlaneCenter - vX*NearPlaneWidth + vY*NearPlaneHeight);
FrustumCorner[2] = D3DXVECTOR3(NearPlaneCenter + vX*NearPlaneWidth + vY*NearPlaneHeight);
FrustumCorner[3] = D3DXVECTOR3(NearPlaneCenter + vX*NearPlaneWidth - vY*NearPlaneHeight);
FrustumCorner[4] = D3DXVECTOR3(FarPlaneCenter - vX*FarPlaneWidth - vY*FarPlaneHeight);
FrustumCorner[5] = D3DXVECTOR3(FarPlaneCenter - vX*FarPlaneWidth + vY*FarPlaneHeight);
FrustumCorner[6] = D3DXVECTOR3(FarPlaneCenter + vX*FarPlaneWidth + vY*FarPlaneHeight);
FrustumCorner[7] = D3DXVECTOR3(FarPlaneCenter + vX*FarPlaneWidth - vY*FarPlaneHeight);
D3DXVECTOR3 vCenter(0,0,0);
for(int i = 0; i < 8; i++)
vCenter += FrustumCorner[i];
vCenter/=8;
for(int i = 0; i < 8; i++)
FrustumCorner[i] += (FrustumCorner[i] - vCenter) * (vScale - 1.0);
}
void CPSSMUtils::CalculateLightForFrustum(int vCurrent)
{
if(vCurrent < 0 || vCurrent > 3)
vCurrent = 0;
Current = vCurrent;
float MaxX = -FLT_MAX;
float MaxY = -FLT_MAX;
float MinX = FLT_MAX;
float MinY = FLT_MAX;
float MaxZ = 0;
LightCamera->setNearValue(Near);
LightCamera->setFarValue(Far);
//mP[Current].buildProjectionMatrixPerspectiveFovLH(LightCamera->getFOV(),1.0,LightCamera->getNearValue(),LightCamera->getFarValue());
D3DXMatrixPerspectiveFovLH(&mP[Current], LightCamera->getFOV(), 1.0f, LightCamera->getNearValue(),LightCamera->getFarValue());
mV[Current] = LightCamera->view();
//D3DXMATRIX mLVP = mP[Current];
//mLVP *= mV[Current];
D3DXMATRIX mLVP = mV[Current] * mP[Current];
for(int i = 0; i < 8; i++)
{
float X = FrustumCorner[i].x * mLVP[0] + FrustumCorner[i].y * mLVP[4] + FrustumCorner[i].z * mLVP[8] + mLVP[12];
float Y = FrustumCorner[i].x * mLVP[1] + FrustumCorner[i].y * mLVP[5] + FrustumCorner[i].z * mLVP[9] + mLVP[13];
float Z = FrustumCorner[i].x * mLVP[2] + FrustumCorner[i].y * mLVP[6] + FrustumCorner[i].z * mLVP[10] + mLVP[14];
float W = FrustumCorner[i].x * mLVP[3] + FrustumCorner[i].y * mLVP[7] + FrustumCorner[i].z * mLVP[11] + mLVP[15];
X /= W;
Y /= W;
if(X > MaxX)
MaxX = X;
if(Y > MaxY)
MaxY = Y;
if(X < MinX)
MinX = X;
if(Y < MinY)
MinY = Y;
if(Z > MaxZ)
MaxZ = Z;
}
MaxX = Clamp(MaxX, -1.0f, 1.0f);
MaxY = Clamp(MaxY, -1.0f, 1.0f);
MinX = Clamp(MinX, -1.0f, 1.0f);
MinY = Clamp(MinY, -1.0f, 1.0f);
float nFar = MaxZ + Near + 1.5f;
LightCamera->setNearValue(Near);
LightCamera->setFarValue(Far);
//LightCamera->setNearValue(SplitDistance[Current]);
//LightCamera->setFarValue(SplitDistance[Current + 1]);
//mP[Current].buildProjectionMatrixPerspectiveFovLH(LightCamera->getFOV(),1.0,LightCamera->getNearValue(),LightCamera->getFarValue());
D3DXMatrixPerspectiveFovLH(&mP[Current], LightCamera->getFOV(), 1.0f, LightCamera->getNearValue(),LightCamera->getFarValue());
mV[Current] = LightCamera->view();
float ScaleX = 2.0f / (MaxX - MinX);
float ScaleY = 2.0f / (MaxY - MinY);
float OffsetX = -0.5f * (MaxX + MinX) * ScaleX;
float OffsetY = -0.5f * (MaxY + MinY) * ScaleY;
D3DXMATRIX cropMatrix = D3DXMATRIX(
ScaleX, 0, 0, 0,
0, ScaleY, 0, 0,
0, 0, 1, 0,
OffsetX, OffsetY, 0, 1);
mP[Current] = mP[Current] * cropMatrix;
//mP[Current][10] /= nFar;
//mP[Current][14] /= nFar;
}
WSCamera* CPSSMUtils::getLightCamera()
{
return LightCamera;
}
void CPSSMUtils::setLightCamera(WSCamera* vLightCamera)
{
if(vLightCamera)
{
LightCamera = vLightCamera;
Near = LightCamera->getNearValue();
Far = LightCamera->getFarValue();
}
}
D3DXMATRIX & CPSSMUtils::getProjectionMatrix(int vCurrent)
{
return mP[vCurrent];
}
D3DXMATRIX & CPSSMUtils::getViewMatrix(int vCurrent)
{
return mV[vCurrent];
}
int CPSSMUtils::getSplitsCount()
{
return SplitsCount;
}
void CPSSMUtils::setSplitsCount(int vSplitsCount)
{
if(vSplitsCount > 0)
{
if(vSplitsCount > 4)
SplitsCount = 4;
else
SplitsCount = vSplitsCount;
}
}
float CPSSMUtils::getSplitLambda()
{
return SplitLambda;
}
void CPSSMUtils::setSplitLambda(float vSplitLambda)
{
SplitLambda = vSplitLambda;
}
float CPSSMUtils::getSplitDistance(int vCurrent)
{
return SplitDistance[vCurrent];
}
int CPSSMUtils::getCurrentPass()
{
return Current;
}
float CPSSMUtils::Clamp(float A, float Min, float Max)
{
if(A < Min)
return Min;
if(A > Max)
return Max;
return A;
}
render the scene
mPSSMUtils->CalculateSplitDistances(&mCamera);
for (int i = 0; i < 4; ++i)
{
mShadowMapRTT[i].beginScene();
{
WSShader *shader = WSResourceManager::inst()->getShader(EShaderDepth);
mPSSMUtils->CalculateFrustumCorners(&mCamera, i, 1.1f);
mPSSMUtils->CalculateLightForFrustum(i);
mRootNode->render(shader, mPSSMUtils->getViewMatrix(i) * mPSSMUtils->getProjectionMatrix(i))
}
mShadowMapRTT[i].endScene();
}
this werid of pssm drive me crazy, i can't find which part is wrong, is any one can help me , any reply will be appreciated!