上面图中右上角为Shadow Map.
使用TSM做Self-Shadow时需要注意ShadowMap保存和第二步用于比较的Depth不要转换到trapezoidal space中,只转换x和y就行了.
计算trapezoidal和LPPS->trapezoidal space的代码修正后为:
HRESULT CTrapezoidalShadowMap::ComputeTrapezoidalMatrix(D3DXMATRIX& matrix,D3DXVECTOR3& topl,D3DXVECTOR3& topr,D3DXVECTOR3& bottoml,D3DXVECTOR3& bottomr,D3DXVECTOR3& intersection)
{
// 平移梯形使得两侧边交点到LightProjectSpace的中点
D3DXMatrixTranslation(&matrix,-intersection.x,-intersection.y,0);
// 旋转梯形使得TopLine和LightProjectSpace的x轴重合
D3DXVECTOR3 t_topline=(topl-topr);
D3DXVec3Normalize(&t_topline,&t_topline);
float t_angle=D3DXVec3Dot(&t_topline,&D3DXVECTOR3(1,0,0));
D3DXMATRIX t_matrix;
if (t_topline.y>0)
D3DXMatrixRotationZ(&t_matrix,-acosf(t_angle));
else
D3DXMatrixRotationZ(&t_matrix,+acosf(t_angle));
matrix*=t_matrix;
// 变换使得成为等边梯形
D3DXVECTOR3 t_point1,t_point2;
D3DXVec3TransformCoord(&t_point1,&topl,&matrix);
D3DXVec3TransformCoord(&t_point2,&topr,&matrix);
t_point1+=t_point2;
D3DXMatrixIdentity(&t_matrix);
t_matrix._21=-t_point1.x/t_point1.y;
matrix*=t_matrix;
// 变换使得两侧边成90度,TopLine的两点在[-1,1]和[1,1]上
D3DXVec3TransformCoord(&t_point1,&topr,&matrix);
D3DXMatrixScaling(&t_matrix,1.0f/t_point1.x,1.0f/t_point1.y,1.0f);
matrix*=t_matrix;
// 变换使得梯形变成矩形
t_matrix._11=t_matrix._22=t_matrix._33=1.0f;
t_matrix._12=t_matrix._13=t_matrix._14=t_matrix._21=t_matrix._23=0.0f;
t_matrix._31=t_matrix._32=t_matrix._34=t_matrix._41=t_matrix._43=t_matrix._44=0.0f;
t_matrix._42=1.0f;
t_matrix._24=1.0f;
matrix*=t_matrix;
// 平移使得矩形的中心到LightProjectSpace的中点
D3DXVec3TransformCoord(&t_point1,&topl,&matrix);
D3DXVec3TransformCoord(&t_point2,&bottomr,&matrix);
D3DXMatrixTranslation(&t_matrix,0,-(t_point1.y+t_point2.y)/2.0f,0);
matrix*=t_matrix;
// 拉伸矩形的Y方向,使得充满整个LightProjectSpace
D3DXVECTOR4 t_point3;
D3DXVec3Transform(&t_point3,&topl,&matrix);
D3DXMatrixIdentity(&t_matrix);
t_matrix._22=-t_point3.w/t_point3.y;
matrix*=t_matrix;
//
return S_OK;
};
HRESULT CTrapezoidalShadowMap::ComplteLightPostPerspectiveTrapezoidal(SFrustum& frustum,D3DXMATRIX& lightviewproj,D3DXVECTOR3& topl,D3DXVECTOR3& topr,D3DXVECTOR3& bottoml,D3DXVECTOR3& bottomr,D3DXVECTOR3& intersection)
{
D3DXVECTOR3 t_frustumvertex[9];
D3DXVec3TransformCoordArray( t_frustumvertex, sizeof(D3DXVECTOR3), frustum.m_Vertexs, sizeof(D3DXVECTOR3), &lightviewproj, sizeof(t_frustumvertex)/sizeof(D3DXVECTOR3) );
for (int i=0;i<9;++i)
{
t_frustumvertex[i].z=0.0f;
}
D3DXVECTOR3 t_topcenter =0.25*(t_frustumvertex[0]+t_frustumvertex[1]+t_frustumvertex[2]+t_frustumvertex[3]);
D3DXVECTOR3 t_bottomcenter =0.25*(t_frustumvertex[4]+t_frustumvertex[5]+t_frustumvertex[6]+t_frustumvertex[7]);
D3DXVECTOR3 t_centerline = t_topcenter - t_bottomcenter;
D3DXVec3Normalize(&t_centerline,&t_centerline);
D3DXMATRIX t_trans;
D3DXMatrixTranslation(&t_trans,-0.5f*(t_topcenter.x+t_bottomcenter.x),-0.5f*(t_topcenter.y+t_bottomcenter.y),0);
D3DXMATRIX t_rotation;
float t_angle=acosf(D3DXVec3Dot(&t_centerline,&D3DXVECTOR3(0,1,0)));
if (t_centerline.x>0)
D3DXMatrixRotationZ(&t_rotation,+t_angle);
else
D3DXMatrixRotationZ(&t_rotation,-t_angle);
t_trans*=t_rotation;
D3DXVec3TransformCoordArray( t_frustumvertex, sizeof(D3DXVECTOR3), t_frustumvertex, sizeof(D3DXVECTOR3), &t_trans, sizeof(t_frustumvertex)/sizeof(D3DXVECTOR3) );
BoundingBox frustumAABB2D( t_frustumvertex, (sizeof(t_frustumvertex)/sizeof(D3DXVECTOR3)-1) );
D3DXVECTOR3 t_topl,t_topr,t_bottoml,t_bottomr;
D3DXVECTOR3 t_side[4];
float t_value[4];
for (int i=0;i<4;++i)
{
t_side[i]=t_frustumvertex[i]-t_frustumvertex[i+4];
D3DXVec3Normalize(&t_side[i],&t_side[i]);
t_value[i]=D3DXVec3Dot(&t_side[i],&D3DXVECTOR3(0,1,0));
}
float t_min=1.0f;
int t_no;
for (int i=0;i<4;++i)
{
if (t_side[i].x>0)
continue;
if (t_value[i]<t_min)
{
t_min=t_value[i];
t_no=i;
}
}
t_topr.y=frustumAABB2D.maxPt.y;
t_topr.x=(t_frustumvertex[8].y-frustumAABB2D.maxPt.y)*tanf(acosf(t_value[t_no]));
t_topr.z=0.0f;
t_bottomr.y=frustumAABB2D.minPt.y;
t_bottomr.x=(t_frustumvertex[8].y-frustumAABB2D.minPt.y)*tanf(acosf(t_value[t_no]));
t_bottomr.z=0.0f;
t_min=1.0f;
for (int i=0;i<4;++i)
{
if (t_side[i].x<0)
continue;
if (t_value[i]<t_min)
{
t_min=t_value[i];
t_no=i;
}
}
t_topl.y=frustumAABB2D.maxPt.y;
t_topl.x=-(t_frustumvertex[8].y-frustumAABB2D.maxPt.y)*tanf(acosf(t_value[t_no]));
t_topl.z=0.0f;
t_bottoml.y=frustumAABB2D.minPt.y;
t_bottoml.x=-(t_frustumvertex[8].y-frustumAABB2D.minPt.y)*tanf(acosf(t_value[t_no]));
t_bottoml.z=0.0f;
D3DXMATRIX t_invtrans;
D3DXMatrixInverse(&t_invtrans,NULL,&t_trans);
D3DXVec3TransformCoord(&topl,&t_topl,&t_invtrans);
D3DXVec3TransformCoord(&topr,&t_topr,&t_invtrans);
D3DXVec3TransformCoord(&bottoml,&t_bottoml,&t_invtrans);
D3DXVec3TransformCoord(&bottomr,&t_bottomr,&t_invtrans);
D3DXVec3TransformCoord(&intersection,&t_frustumvertex[8],&t_invtrans);
//
return S_OK;
};