Implementing PN triangles tessellation at DirectX11 ( DirectX11 での PN Triangles Tessellation の実装 )

I have implemented PN Triangles at DirectX11 using Thinkpad W520.

DirectX11 対応の Thikpad W520 を使い, DirectX11 で PN Triangles による Tessellation を実装してみました.

// No tessellation



// PN triangles tessellation ( tessellation factor = 5.2 )



// PN triangles tessellation ( tessellation factor = 30.0 )




This time, I have implemented the shader compared to the PN triangles white paper. So, some part of the shader source code is redundant. I will paste the source code of hull shader and domain shader below.

今回, 元の論文の数式との対応ができるだけわかりやすくなるようにシェーダを書きました. なので, 冗長な箇所もあると思います. ハルシェーダとドメインシェーダ部分のソースコードを貼り付けておきます.

//////////////////////////////////////////////////
//
// PN Triangles Tessellation
//                             hanecci
//
//////////////////////////////////////////////////

struct HS_CONSTANT_DATA_OUTPUT
{
    float Edges[3] : SV_TessFactor;
    float Inside   : SV_InsideTessFactor;

    float3 B210    : POSITION3;
    float3 B120    : POSITION4;
    float3 B021    : POSITION5;
    float3 B012    : POSITION6;
    float3 B102    : POSITION7;
    float3 B201    : POSITION8;
    float3 B111    : CENTER;
    
    float3 N110    : NORMAL3;      
    float3 N011    : NORMAL4;
    float3 N101    : NORMAL5;
};

struct HS_OUTPUT
{
    float3 vPosition : POSITION;
    float3 vNormal   : NORMAL;
};

HS_CONSTANT_DATA_OUTPUT
ConstantHS( InputPatch<VS_CONTROL_POINT_OUTPUT, 3> input,
            uint PatchID : SV_PrimitiveID )
{    
    HS_CONSTANT_DATA_OUTPUT output;

    output.Edges[ 0 ] = g_fTessellationFactor;
    output.Edges[ 1 ] = g_fTessellationFactor;
    output.Edges[ 2 ] = g_fTessellationFactor;        
    output.Inside     = g_fTessellationFactor;

    
    float3 p1   = input[ 0 ].vPosition;
    float3 p2   = input[ 1 ].vPosition;
    float3 p3   = input[ 2 ].vPosition;

    float3 b300 = p1;
    float3 b030 = p2;
    float3 b003 = p3;
    
    float3 n1   = input[ 0 ].vNormal;
    float3 n2   = input[ 1 ].vNormal;
    float3 n3   = input[ 2 ].vNormal;
    
    float3 n200 = n1;
    float3 n020 = n2;
    float3 n002 = n3;
                    

    float w12   = dot( ( p2 - p1 ), n1 );
    output.B210 = ( 2.0f * p1 + p2 - w12 * n1 ) / 3.0f;

    float w21   = dot( ( p1 - p2 ), n2 );    
    output.B120 = ( 2.0f * p2 + p1 - w21 * n2 ) / 3.0f;

    float w23   = dot( ( p3 - p2 ), n2 );
    output.B021 = ( 2.0f * p2 + p3 - w23 * n2 ) / 3.0f;
    
    float w32   = dot( ( p2 - p3 ), n3 );
    output.B012 = ( 2.0f * p3 + p2 - w32 * n3 ) / 3.0f;

    float w31   = dot( ( p1 - p3 ), n3 );
    output.B102 = ( 2.0f * p3 + p1 - w31 * n3 ) / 3.0f;
    
    float w13   = dot( ( p3 - p1 ), n1 );
    output.B201 = ( 2.0f * p1 + p3 - w13 * n1 ) / 3.0f;
    
    float3 e    = ( output.B210 + output.B120 + output.B021 + 
                    output.B012 + output.B102 + output.B201 ) / 6.0f;
    float3 v    = ( p1 + p2 + p3 ) / 3.0f;
    output.B111 = e + ( ( e - v ) / 2.0f );
    
    
    float v12    = 2.0f * dot( ( p2 - p1 ), ( n1 + n2 ) ) / 
                          dot( ( p2 - p1 ), ( p2 - p1 ) );
    output.N110  = normalize( ( n1 + n2 - v12 * ( p2 - p1 ) ) );

    float v23    = 2.0f * dot( ( p3 - p2 ), ( n2 + n3 ) ) /
                          dot( ( p3 - p2 ), ( p3 - p2 ) );
    output.N011  = normalize( ( n2 + n3 - v23 * ( p3 - p2 ) ) );

    float v31    = 2.0f * dot( ( p1 - p3 ), ( n3 + n1 ) ) /
                          dot( ( p1 - p3 ), ( p1 - p3 ) );
    output.N101  = normalize( ( n3 + n1 - v31 * ( p1 - p3 ) ) );

    
    return output;
}


[domain("tri")]
[partitioning(HS_PARTITION)]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("ConstantHS")]
HS_OUTPUT HS( InputPatch<VS_CONTROL_POINT_OUTPUT, 3> input, 
              uint controlPointId : SV_OutputControlPointID,
              uint patchID        : SV_PrimitiveID )
{
    HS_OUTPUT output;

    output.vPosition = input[ controlPointId ].vPosition;
    output.vNormal   = input[ controlPointId ].vNormal;

    return output;
}


struct DS_OUTPUT
{
    float4 vPosition        : SV_POSITION;
    float4 vColor           : COLOR0;
};

[domain("tri")]
DS_OUTPUT DS( HS_CONSTANT_DATA_OUTPUT hsConstantData,
              const OutputPatch<HS_OUTPUT, 3> input,
              float3 uvw : SV_DomainLocation )              
{
    DS_OUTPUT output;

    float u   = uvw.x;
    float v   = uvw.y;
    float w   = uvw.z;    
    float uu  = u * u;
    float vv  = v * v;
    float ww  = w * w;
    float uu3 = 3.0f * uu;
    float vv3 = 3.0f * vv;
    float ww3 = 3.0f * ww;
        
    float3 interpPosition = 
        input[ 0 ].vPosition *  w    * ww + 
        input[ 1 ].vPosition *  u    * uu + 
        input[ 2 ].vPosition *  v    * vv +
        hsConstantData.B210  *  ww3  * u  +
        hsConstantData.B120  *  uu3  * w  +
        hsConstantData.B201  *  ww3  * v  +
        hsConstantData.B021  *  uu3  * v  +
        hsConstantData.B102  *  vv3  * w  +
        hsConstantData.B012  *  vv3  * u  +
        hsConstantData.B111  *  6.0f * w * u * v;
    
    output.vPosition = float4( interpPosition, 1 );


    float3 interpNormal = 
        input[ 0 ].vNormal * ww +
        input[ 1 ].vNormal * uu +
        input[ 2 ].vNormal * vv +
        hsConstantData.N110 * w * u +
        hsConstantData.N011 * u * v +
        hsConstantData.N101 * w * v;
    
    float3 normal      = normalize( interpNormal );
    

    float3 normalColor  = normalize( normal );
    normalColor        *= 0.5f;
    normalColor        += 0.5f;

    float4 color        = float4( normalColor, 1.0f );
    output.vColor       = color;

    return output;    
}