I try port Parallel split shadow map (PSSM) to irrLicht engine. This PSSM method have 5 states below.
1.) Calculate camera far plane from PSSM_AdjustCameraPlanes() then return newFar.
2.) Calulate split distance use newFar from 1.) use function PSSM_CalculateSplitDistances() then return array of splits part.
3.) Loop each split area for calculate frustum corners from PSSM_CalculateFrustumCorners() pass new Near and Far value then return 8 points corners.
4.) Use frustum corners from 3.) to calculate a new light frustum use function PSSM_CalculateLightForFrustum() then return new light crop projection matrix.
5.) Render depth map with depth shader and pass new light view and projection as parameter.
I don't know where i miss process. Could u please suggest me about this problem ? I need help to fix it. :'-(
Result is:
Split 3 parts.
Split 1 part.
best regards,
sourcecode&binary:
http://www.easy-share.com/1903741199/PSSM.zip
mirror:
http://www.upload-thai.com/download.php ... bab0c0dc75
http://www.geocities.com/zaros64/PSSM.zip
PSSM_AdjustCameraPlanes()
Code: Select all
float PSSM_AdjustCameraPlanes( const matrix4 &cameraView, float cameraNear, aabbox3df &scenebox )
{
matrix4 cameraview = cameraView;
vector3df _vSceneAABB[8];
_vSceneAABB[0]=vector3df(scenebox.MinEdge.X,scenebox.MinEdge.Y,scenebox.MinEdge.Z);
_vSceneAABB[1]=vector3df(scenebox.MaxEdge.X,scenebox.MinEdge.Y,scenebox.MinEdge.Z);
_vSceneAABB[2]=vector3df(scenebox.MinEdge.X,scenebox.MinEdge.Y,scenebox.MaxEdge.Z);
_vSceneAABB[3]=vector3df(scenebox.MaxEdge.X,scenebox.MinEdge.Y,scenebox.MaxEdge.Z);
_vSceneAABB[4]=vector3df(scenebox.MinEdge.X,scenebox.MaxEdge.Y,scenebox.MinEdge.Z);
_vSceneAABB[5]=vector3df(scenebox.MaxEdge.X,scenebox.MaxEdge.Y,scenebox.MinEdge.Z);
_vSceneAABB[6]=vector3df(scenebox.MinEdge.X,scenebox.MaxEdge.Y,scenebox.MaxEdge.Z);
_vSceneAABB[7]=vector3df(scenebox.MaxEdge.X,scenebox.MaxEdge.Y,scenebox.MaxEdge.Z);
// Find the most distant point of AABB
//
float fMaxZ=0;
float fZ = 0;
for(int i=0;i<8;i++)
{
// transform z coordinate with view matrix
vector3df SceneAABox;
cameraview.transformVect( SceneAABox, _vSceneAABB[i] );
//fZ=_vSceneAABB[i].X*cameraview[2] + _vSceneAABB[i].Y*cameraview[6]+_vSceneAABB[i].Z*cameraview[10]+1*cameraview[14];
fZ = SceneAABox.Z;
// check if its largest
if(fZ>fMaxZ)
fMaxZ=fZ;
}
// use largest Z coordinate as new far plane
return (fMaxZ+cameraNear);
}
Code: Select all
float* PSSM_CalculateSplitDistances( float fNear, float fFar, int iSplit, float fLamda )
{
// Reallocate array in case the split count has changed
//
int _iNumSplits = iSplit;
float _fCameraFar = fFar;
float _fCameraNear = fNear;
float* _pSplitDistances = NULL;
float _fSplitSchemeLambda=clamp(fLamda,0.0f,1.0f);
_pSplitDistances=new float[_iNumSplits+1];
// Practical split scheme:
//
// CLi = n*(f/n)^(i/numsplits)
// CUi = n + (f-n)*(i/numsplits)
// Ci = CLi*(lambda) + CUi*(1-lambda)
//
// lambda scales between logarithmic and uniform
//
for(int i=0;i<_iNumSplits;i++)
{
float fIDM=i/(float)_iNumSplits;
float fLog=_fCameraNear*powf((_fCameraFar/_fCameraNear),fIDM);
float fUniform=_fCameraNear+(_fCameraFar-_fCameraNear)*fIDM;
_pSplitDistances[i]=fLog*_fSplitSchemeLambda+fUniform*(1-_fSplitSchemeLambda);
}
// make sure border values are right
_pSplitDistances[0]=_fCameraNear;
_pSplitDistances[_iNumSplits]=_fCameraFar;
return _pSplitDistances;
}
Code: Select all
void PSSM_CalculateFrustumCorners(vector3df *pPoints, // --> vector3df pPoints[8];
const vector3df &cameraSource,
const vector3df &cameraTarget,
const vector3df &cameraUp,
float fNear, float fFar,
float cameraFOV, float cameraAspect, float fScale )
{
vector3df vSource = cameraSource;
vector3df vTarget = cameraTarget;
vector3df vUp = cameraUp;
float fFOV = cameraFOV;
float fAspect = cameraAspect;
vector3df vZ=vTarget-vSource;
vZ.normalize( );
vector3df vX;
vX = vUp.crossProduct( vZ );
vX.normalize( );
vector3df vY;
vY = vZ.crossProduct( vX );
float fNearPlaneHeight = tanf((fFOV) * 0.5f) * fNear;
float fNearPlaneWidth = fNearPlaneHeight * fAspect;
float fFarPlaneHeight = tanf((fFOV) * 0.5f) * fFar;
float fFarPlaneWidth = fFarPlaneHeight * fAspect;
vector3df vNearPlaneCenter = vSource + vZ * fNear;
vector3df vFarPlaneCenter = vSource + vZ * fFar;
pPoints[0]=vector3df(vNearPlaneCenter - vX*fNearPlaneWidth - vY*fNearPlaneHeight);
pPoints[1]=vector3df(vNearPlaneCenter - vX*fNearPlaneWidth + vY*fNearPlaneHeight);
pPoints[2]=vector3df(vNearPlaneCenter + vX*fNearPlaneWidth + vY*fNearPlaneHeight);
pPoints[3]=vector3df(vNearPlaneCenter + vX*fNearPlaneWidth - vY*fNearPlaneHeight);
pPoints[4]=vector3df(vFarPlaneCenter - vX*fFarPlaneWidth - vY*fFarPlaneHeight);
pPoints[5]=vector3df(vFarPlaneCenter - vX*fFarPlaneWidth + vY*fFarPlaneHeight);
pPoints[6]=vector3df(vFarPlaneCenter + vX*fFarPlaneWidth + vY*fFarPlaneHeight);
pPoints[7]=vector3df(vFarPlaneCenter + vX*fFarPlaneWidth - vY*fFarPlaneHeight);
// calculate center of points
vector3df vCenter(0,0,0);
for(int i=0;i<8;i++)
vCenter+=pPoints[i];
vCenter/=8;
// for each point
for(int i=0;i<8;i++)
// scale by adding offset from center
pPoints[i]+=(pPoints[i]-vCenter)*(fScale-1);
}
Code: Select all
void PSSM_CalculateLightForFrustum( matrix4 *out_lightProj, vector3df *pCorners, SShadowLight& shadow_light )
{
// Next we will find the min and max values of the current
// frustum split in lights post-projection space
// (where coordinate range is from -1.0 to 1.0)
//
float fMaxX=-FLT_MAX;
float fMaxY=-FLT_MAX;
float fMinX=FLT_MAX;
float fMinY=FLT_MAX;
float fMaxZ=0;
matrix4 _mLightView = shadow_light.getViewMatrix() ;
matrix4 _mLightProj = shadow_light.getProjectionMatrix();
matrix4 mLightViewProj=_mLightProj;
mLightViewProj *=_mLightView;
// for each corner point
for(int i=0;i<8;i++)
{
// transform point
vector3df vTransformed;
mLightViewProj.transformVect( vTransformed, pCorners[i] );
float w = pCorners[i].X*mLightViewProj[3] + pCorners[i].Y*mLightViewProj[7] + pCorners[i].Z*mLightViewProj[11] + mLightViewProj[15];
// project x and y
vTransformed.X/=w;
vTransformed.Y/=w;
// find min and max values
if(vTransformed.X>fMaxX) fMaxX=vTransformed.X;
if(vTransformed.Y>fMaxY) fMaxY=vTransformed.Y;
if(vTransformed.Y<fMinY) fMinY=vTransformed.Y;
if(vTransformed.X<fMinX) fMinX=vTransformed.X;
// find largest z distance
if(vTransformed.Z>fMaxZ) fMaxZ=vTransformed.Z;
}
// set values to valid range (post-projection)
fMaxX=clamp(fMaxX,-1.0f,1.0f);
fMaxY=clamp(fMaxY,-1.0f,1.0f);
fMinX=clamp(fMinX,-1.0f,1.0f);
fMinY=clamp(fMinY,-1.0f,1.0f);
// Adjust the far plane of the light to be at the farthest
// point of the frustum split. Some bias may be necessary.
//
float _fLightNear = shadow_light.getNearValue( );
float _fLightFar=fMaxZ+_fLightNear+1.25f;
// Next we build a special matrix for cropping the lights view
// to only contain points of the current frustum split
//
float fScaleX=2.0f/(fMaxX-fMinX);
float fScaleY=2.0f/(fMaxY-fMinY);
float fOffsetX=-0.5f*(fMaxX+fMinX)*fScaleX;
float fOffsetY=-0.5f*(fMaxY+fMinY)*fScaleY;
float mCropView[] = { fScaleX, 0.0f, 0.0f, 0.0f,
0.0f, fScaleY, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
fOffsetX, fOffsetY, 0.0f, 1.0f };
matrix4 mCrop;
mCrop.makeIdentity( );
mCrop.setM( mCropView );
// re-calculate lights matrices with the new far plane
matrix4 newm;
newm.buildProjectionMatrixPerspectiveFovLH( shadow_light.getFov(), 1, _fLightNear, _fLightFar );
// multiply the projection matrix with it
//_mLightProj = mCrop * _mLightProj;
_mLightProj = mCrop;
_mLightProj *= newm;
// finally modify projection matrix for linearized depth
_mLightProj[10]/=_fLightFar;
_mLightProj[14]/=_fLightFar;
// return value
*out_lightProj = _mLightProj;
}
Code: Select all
matrix mWorldViewProj;
struct VSOUTPUT_SHADOW
{
float4 vPosition : POSITION;
float fDepth : TEXCOORD0;
};
VSOUTPUT_SHADOW vertexMain( float4 inPosition : POSITION )
{
// Output struct
VSOUTPUT_SHADOW OUT = (VSOUTPUT_SHADOW)0;
// Output the transformed position
OUT.vPosition = mul( inPosition, mWorldViewProj );
// Output the scene depth
OUT.fDepth = OUT.vPosition.z/OUT.vPosition.w;
return OUT;
}
Code: Select all
struct VSOUTPUT_SHADOW
{
float4 vPosition : POSITION;
float fDepth : TEXCOORD0;
};
float4 pixelMain( VSOUTPUT_SHADOW IN ) : COLOR0
{
// Output the scene depth
return float4( IN.fDepth, IN.fDepth, IN.fDepth, 1.0 );
}