pssm problems

Started by
-1 comments, last by dreamjourney 9 years, 10 months ago

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!

This topic is closed to new replies.

Advertisement