Directx11教程(64) tessellation學習(6)-PN Triangles


      前面我們用tessellation細分三角形或者四邊形,產生的細分點都是在三角形或四邊形平面內。本教程我們學習一下PN triangles(point normal triangles)的方法,把一個三角形細分為一個曲面。PN triangles的詳細介紹請參考:2001 paper by Vlachos et al ,下面我們簡單介紹一下PN triangles:

     大家都知道,通常我們用貝塞爾函數表示光滑的曲面,貝塞爾函數是多項式函數,它表示的曲面通常也稱作貝塞爾曲面,貝塞爾曲面的詳細介紹,可以到wiki上看看Bezier Surface

     PN triangle是一個特殊的貝塞爾曲面,它的表示形式為:  

image

      u,v, w是重心坐標,bxyz就是控制點,其中u+v+w=1,控制點的位置如下,看以看出來,b003, b030,b300就是三角形的三個頂點控制點,根據這三個控制點位置和法向,我們就可以計算出其它控制點的位置。

image

image

  

image

     PN triangles的法向通過下面的方法計算得到:

image

image

     下面我們在myTutorialD3D_54的基礎上,增加PN triangle支持,用三角形生成曲面。首先修改MeshClass類,為三角形patch頂點結構增加normal屬性,因為計算控制點時候需要它。

struct VertexType
    {
    D3DXVECTOR3 position;
    D3DXVECTOR3 normal;
    D3DXVECTOR4 color;
    };

//創建順時針方向的三角形,左手規則
// 設置頂點數據

vertices[0].position = D3DXVECTOR3(4.0f, 0.0f, -2.0f);  // 左下
vertices[0].normal = D3DXVECTOR3(-1.0f, 1.0f, 0.0f);
vertices[0].color = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f);

vertices[1].position = D3DXVECTOR3(6.0f, 0.0f, 4.0f);  // 中上.
vertices[1].normal = D3DXVECTOR3(0.0f, 1.0f, 1.0f);
vertices[1].color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);

vertices[2].position = D3DXVECTOR3(8.0f, 0.0f, -2.0f);  // 底右
vertices[2].normal = D3DXVECTOR3(1.0f, 1.0f, 0.0f);
vertices[2].color = D3DXVECTOR4(0.0f, 1.0f, 1.0f, 1.0f);

       接下來,修改TessShaderClass類,修改頂點布局,增加normal支持:

polygonLayout[1].SemanticName = "NORMAL";
polygonLayout[1].SemanticIndex = 0;
polygonLayout[1].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[1].InputSlot = 0;
polygonLayout[1].AlignedByteOffset = 12;
polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[1].InstanceDataStepRate = 0;

       接着就是shader 文件的修改,這也是最關鍵的部分,下面看看各個shader文件,vs中基本就是pass through,把頂點屬性傳到hs,和以前比沒有太多的變化,hs中增加了生成新控制點的代碼:

ConstantOutputType ColorPatchConstantFunction(InputPatch<HullInputType, 3> inputPatch, uint patchId : SV_PrimitiveID)
{   
    ConstantOutputType output;


    //設置三條邊的細分因子.
    output.edges[0] = tessellationAmount;
    output.edges[1] = tessellationAmount;
    output.edges[2] = tessellationAmount;

    //設置三角形內的細分因子
    output.inside = tessellationAmount;

   // PN triangle三個控制頂點的位置,和三角形patch的原始控制點是一樣的
    float3 f3B003 = inputPatch[0].position;
    float3 f3B030 = inputPatch[1].position;
    float3 f3B300 = inputPatch[2].position;

   
    // 法向
    float3 f3N002 = inputPatch[0].normal;
    float3 f3N020 = inputPatch[1].normal;
    float3 f3N200 = inputPatch[2].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[0].position * fWW * fW +
                        patch[1].position * fUU * fU +
                        patch[2].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[0].normal * fWW +
                        patch[1].normal * fUU +
                        patch[2].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[0].color + uvwCoord.y * patch[1].color + uvwCoord.z * patch[2].color;

     程序執行后界面如下,其中tess factor 從1到6,可以看出來,隨着細分因子的增大,三角形越接近曲面。

imageimageimageimageimageimage

完整的代碼請參考:

工程文件myTutorialD3D11_59

代碼下載:

稍后提供


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM