会员: 密码:  免费注册 | 忘记密码 | 会员登录 网页功能: 加入收藏 设为首页 网站搜索  
游戏开发 > 程序设计 > 3D图形
Trapezoidal Shadow Map
发表日期:2007-03-27 13:07:10作者: 出处:  

 


  在light’s post perspective space中根据视锥构建的梯形,为了方便表示,贴了一张贴图表示.贴图中的Top表示靠近视锥前截面的梯形的上底,Bottom表示靠近视锥后截面的梯形的下底。



梯形转换到trapezoidal space后的显示情况

light’s post perspective space->trapezoidal space的距阵计算:

HRESULT CTrapezoidalShadowMap::ComputeTrapezoidalMatrix(D3DXMATRIX& matrix,D3DXVECTOR3& topl,D3DXVECTOR3& topr,D3DXVECTOR3& bottoml,D3DXVECTOR3& bottomr,D3DXVECTOR3& intersection)
{
    // 平移TopLine的中点到Light's Post-Perspective Space的中点
    D3DXMatrixTranslation(&matrix,-(topl.x+topr.x)/2.0f,-(topl.y+topr.y)/2.0f,0);

    // 旋转梯形使得TopLine和Light's Post-Perspective Space的x轴重合
    D3DXVECTOR3 t_topline=(topl-topr);
    D3DXVec3Normalize(&t_topline,&t_topline);

    float t_angle=D3DXVec3Dot(&t_topline,&D3DXVECTOR3(1,0,0));

    D3DXMATRIX t_matrix;
    D3DXMatrixRotationZ(&t_matrix,-acosf(t_angle));

    matrix*=t_matrix;

    // 平移梯形使得两侧边交点到Light's Post-Perspective Space的中点
    D3DXVECTOR3 t_intersection;

    D3DXVec3TransformCoord(&t_intersection,&intersection,&matrix);

    D3DXMatrixTranslation(&t_matrix,-t_intersection.x,-t_intersection.y,0);

    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=t_matrix._24=t_matrix._42=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;

    matrix*=t_matrix;

    // 平移使得矩形的中心到Light's Post-Perspective Space的中点
    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方向,使得充满整个Light's Post-Perspective Space
    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;
};

参加讨论




  中间的红色框包起来的是在light's post−perspective space中的视锥,红色框是构造出的trapezoidal,外围的是在trapezoidal space中的视锥.其中蓝色的表示视锥的Near Plane,绿色的表示Far Plane和边.

通过视锥计算梯形的代码:

HRESULT CTrapezoidalShadowMap::ComplteLightPostPerspectiveTrapezoidal(SFrustum& frustum,D3DXMATRIX& lightviewproj,D3DXVECTOR3& topl,D3DXVECTOR3& topr,D3DXVECTOR3& bottoml,D3DXVECTOR3& bottomr,D3DXVECTOR3& intersection)
{
    D3DXVECTOR3 t_frustumvertex[9];

    // 转换到Light's Post-Perspective Space
    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);

    // 平移和旋转使得中轴线的中点在Light's Post-Perspective Space中点,方向指向Light's Post-Perspective Space的Y轴
    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) );

    // 求出2D AABB
    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_topl.y=frustumAABB2D.maxPt.y;
    t_topl.x=-(t_frustumvertex[8].y-frustumAABB2D.maxPt.y)*tanf(acosf(t_value[t_no]));
    t_bottoml.y=frustumAABB2D.minPt.y;
    t_bottoml.x=-(t_frustumvertex[8].y-frustumAABB2D.minPt.y)*tanf(acosf(t_value[t_no]));

    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_topr.y=frustumAABB2D.maxPt.y;
    t_topr.x=(t_frustumvertex[8].y-frustumAABB2D.maxPt.y)*tanf(acosf(t_value[t_no]));
    t_bottomr.y=frustumAABB2D.minPt.y;
    t_bottomr.x=(t_frustumvertex[8].y-frustumAABB2D.minPt.y)*tanf(acosf(t_value[t_no]));

    // 将梯形四个顶点和两边的交点变换回Light's Post-Perspective Space
    D3DXMATRIX t_invtrans;
    D3DXMatrixInverse(&t_invtrans,NULL,&t_trans);

    D3DXVec3TransformCoord(&topl,&t_topl,&t_trans);
    D3DXVec3TransformCoord(&topr,&t_topr,&t_trans);
    D3DXVec3TransformCoord(&bottoml,&t_bottoml,&t_trans);
    D3DXVec3TransformCoord(&bottomr,&t_bottomr,&t_trans);
    D3DXVec3TransformCoord(&intersection,&t_frustumvertex[8],&t_trans);

    //
    return S_OK;
};

参加讨论








上面图中右上角为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;
};
 
返回顶部】 【打印本页】 【关闭窗口

关于我们 / 给我留言 / 版权举报 / 意见建议 / 网站编程QQ群   
Copyright ©2003- 2024 Lihuasoft.net webmaster(at)lihuasoft.net 加载时间 0.00258