迈克老狼2012 发表于 2012-12-30 11:50:40

Directx11教程(64) tessellation学习(6)-PN Triangles

Directx11教程(64) tessellation学习(6)-PN Triangles

<div class="postbody"><div id="cnblogs_post_body">      前面我们用tessellation细分三角形或者四边形,产生的细分点都是在三角形或四边形平面内。本教程我们学习一下PN triangles(point normal triangles)的方法,把一个三角形细分为一个曲面。PN triangles的详细介绍请参考:2001 paper by Vlachos et al ,下面我们简单介绍一下PN triangles:
     大家都知道,通常我们用贝塞尔函数表示光滑的曲面,贝塞尔函数是多项式函数,它表示的曲面通常也称作贝塞尔曲面,贝塞尔曲面的详细介绍,可以到wiki上看看Bezier Surface。
     PN triangle是一个特殊的贝塞尔曲面,它的表示形式为:  
http://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210704472088.png
      u,v, w是重心坐标,bxyz就是控制点,其中u+v+w=1,控制点的位置如下,看以看出来,b003, b030,b300就是三角形的三个顶点控制点,根据这三个控制点位置和法向,我们就可以计算出其它控制点的位置。
http://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/20120821070452721.png
http://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210704579113.png
      
http://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210705001225.png
         PN triangles的法向通过下面的方法计算得到:
http://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/20120821070504862.png
http://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210705073040.png
     下面我们在myTutorialD3D_54的基础上,增加PN triangle支持,用三角形生成曲面。首先修改MeshClass类,为三角形patch顶点结构增加normal属性,因为计算控制点时候需要它。
struct VertexType   
    {      
    D3DXVECTOR3 position;      
    D3DXVECTOR3 normal;      
    D3DXVECTOR4 color;      
    };   


//创建顺时针方向的三角形,左手规则      
// 设置顶点数据      
vertices.position = D3DXVECTOR3(4.0f, 0.0f, -2.0f);  // 左下      
vertices.normal = D3DXVECTOR3(-1.0f, 1.0f, 0.0f);      
vertices.color = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f);
vertices.position = D3DXVECTOR3(6.0f, 0.0f, 4.0f);  // 中上.      
vertices.normal = D3DXVECTOR3(0.0f, 1.0f, 1.0f);      
vertices.color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);
vertices.position = D3DXVECTOR3(8.0f, 0.0f, -2.0f);  // 底右      
vertices.normal = D3DXVECTOR3(1.0f, 1.0f, 0.0f);      
vertices.color = D3DXVECTOR4(0.0f, 1.0f, 1.0f, 1.0f);   

       接下来,修改TessShaderClass类,修改顶点布局,增加normal支持:
polygonLayout.SemanticName = "NORMAL";      
polygonLayout.SemanticIndex = 0;      
polygonLayout.Format = DXGI_FORMAT_R32G32B32_FLOAT;      
polygonLayout.InputSlot = 0;      
polygonLayout.AlignedByteOffset = 12;      
polygonLayout.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;      
polygonLayout.InstanceDataStepRate = 0;      


       接着就是shader 文件的修改,这也是最关键的部分,下面看看各个shader文件,vs中基本就是pass through,把顶点属性传到hs,和以前比没有太多的变化,hs中增加了生成新控制点的代码:
ConstantOutputType ColorPatchConstantFunction(InputPatch<HullInputType, 3> inputPatch, uint patchId : SV_PrimitiveID)   
{   
    ConstantOutputType output;
   
    //设置三条边的细分因子.      
    output.edges = tessellationAmount;      
    output.edges = tessellationAmount;      
    output.edges = tessellationAmount;
    //设置三角形内的细分因子      
    output.inside = tessellationAmount;
   // PN triangle三个控制顶点的位置,和三角形patch的原始控制点是一样的      
    float3 f3B003 = inputPatch.position;      
    float3 f3B030 = inputPatch.position;      
    float3 f3B300 = inputPatch.position;
   
    // 法向      
    float3 f3N002 = inputPatch.normal;      
    float3 f3N020 = inputPatch.normal;      
    float3 f3N200 = inputPatch.normal;
       
    // 根据公式计算边控制点和中心控制点      
    output.f3B210 = ( ( 2.0f * f3B003 ) + f3B030 - ( dot( ( f3B030 - f3B003 ), f3N002 ) * f3N002 ) ) / 3.0f;      
    output.f3B120 = ( ( 2.0f * f3B030 ) + f3B003 - ( dot( ( f3B003 - f3B030 ), f3N020 ) * f3N020 ) ) / 3.0f;      
    output.f3B021 = ( ( 2.0f * f3B030 ) + f3B300 - ( dot( ( f3B300 - f3B030 ), f3N020 ) * f3N020 ) ) / 3.0f;      
    output.f3B012 = ( ( 2.0f * f3B300 ) + f3B030 - ( dot( ( f3B030 - f3B300 ), f3N200 ) * f3N200 ) ) / 3.0f;      
    output.f3B102 = ( ( 2.0f * f3B300 ) + f3B003 - ( dot( ( f3B003 - f3B300 ), f3N200 ) * f3N200 ) ) / 3.0f;      
    output.f3B201 = ( ( 2.0f * f3B003 ) + f3B300 - ( dot( ( f3B300 - f3B003 ), f3N002 ) * f3N002 ) ) / 3.0f;
    float3 f3E = ( output.f3B210 + output.f3B120 + output.f3B021 + output.f3B012 + output.f3B102 + output.f3B201 ) / 6.0f;   
    float3 f3V = ( f3B003 + f3B030 + f3B300 ) / 3.0f;      
    output.f3B111 = f3E + ( ( f3E - f3V ) / 2.0f );
   // 计算法向控制点      
    float fV12 = 2.0f * dot( f3B030 - f3B003, f3N002 + f3N020 ) / dot( f3B030 - f3B003, f3B030 - f3B003 );      
    output.f3N110 = normalize( f3N002 + f3N020 - fV12 * ( f3B030 - f3B003 ) );      
    float fV23 = 2.0f * dot( f3B300 - f3B030, f3N020 + f3N200 ) / dot( f3B300 - f3B030, f3B300 - f3B030 );      
    output.f3N011 = normalize( f3N020 + f3N200 - fV23 * ( f3B300 - f3B030 ) );      
    float fV31 = 2.0f * dot( f3B003 - f3B300, f3N200 + f3N002 ) / dot( f3B003 - f3B300, f3B003 - f3B300 );      
    output.f3N101 = normalize( f3N200 + f3N002 - fV31 * ( f3B003 - f3B300 ) );
    return output;   
}

    在ds中,我们根据PN triangle公式生成新的控制点:

    //重心坐标      
    float fU = uvwCoord.x;      
    float fV = uvwCoord.y;      
    float fW = uvwCoord.z;
   // 预计算一些需要的值      
    float fUU = fU * fU;      
    float fVV = fV * fV;      
    float fWW = fW * fW;      
    float fUU3 = fUU * 3.0f;      
    float fVV3 = fVV * 3.0f;      
    float fWW3 = fWW * 3.0f;      
    //根据公式和重心坐标计算细分后顶点的位置      
    float3 f3Position = patch.position * fWW * fW +      
                        patch.position * fUU * fU +      
                        patch.position * fVV * fV +      
                        input.f3B210 * fWW3 * fU +      
                        input.f3B120 * fW * fUU3 +      
                        input.f3B201 * fWW3 * fV +      
                        input.f3B021 * fUU3 * fV +      
                        input.f3B102 * fW * fVV3 +      
                        input.f3B012 * fU * fVV3 +      
                        input.f3B111 * 6.0f * fW * fU * fV;
    
    //计算新的顶点在世界坐标系中的位置      
    output.position = mul(float4(f3Position, 1.0f), worldMatrix);      
    output.position = mul(output.position, viewMatrix);      
    output.position = mul(output.position, projectionMatrix);
    // 计算法向      
    float3 f3Normal =   patch.normal * fWW +      
                        patch.normal * fUU +      
                        patch.normal * fVV +      
                        input.f3N110 * fW * fU +      
                        input.f3N011 * fU * fV +      
                        input.f3N101 * fW * fV;
    // 归一化   
    f3Normal = normalize( f3Normal );
    output.normal = f3Normal;
    //新生成顶点颜色也为各个控制点颜色组合      
    output.color = uvwCoord.x * patch.color + uvwCoord.y * patch.color + uvwCoord.z * patch.color;

     程序执行后界面如下,其中tess factor 从1到6,可以看出来,随着细分因子的增大,三角形越接近曲面。
http://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210705221139.pnghttp://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210705374505.pnghttp://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210705527969.pnghttp://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/20120821070607222.pnghttp://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210706226403.pnghttp://images.cnblogs.com/cnblogs_com/mikewolf2002/201208/201208210706377326.png
完整的代码请参考:
工程文件myTutorialD3D11_59
代码下载:
                稍后提供
页: [1]
查看完整版本: Directx11教程(64) tessellation学习(6)-PN Triangles