Directx11教程(59) tessellation學習(1)


      在D3D11管線中,新增加了3個stage, Hull shader, Tessellator, Domain shader,用來實現細分操作,就是在gpu中把低細節的表面細分成高細節的體元。在gpu中把低模通過tessellation轉化為高模,在獲得高細節模型的同時,可以有效降低把頂點數據從system memory傳到 video memory的帶寬消耗。

     下面我們看看這三個階段到底做些什么,輸入是什么,輸出是什么?先畫一張圖。

image

1、Hull shader階段

      Hull shader階段可以分成兩個獨立的階段,它們是並行執行的。

      第一個階段是per control points執行的, 在這個階段對patch中的每個控制點,輸出對應的控制點。所謂patch,簡單理解就是帶控制點的體元,比如一個三角形,它的三個頂點是控制點,那么這個三角形就是有3個控制點的patch。當然,在Hull shader中,我們還可以對輸入的控制點進行轉化操作,生成新的控制點,比如輸入的3個控制點,輸出6個控制點。注意:輸入或者輸出的控制點數量是1~32。

     第二個階段就是patch常量階段,這時HullShader會調用一個const data函數,這個函數主要產生tessellation factor,這些factor決定在TS階段如何細分當前的patch。

    另外,在Hullshader階段還會指定一些TS階段使用的Tessellation模式,比如細分的patch是三角形(拓撲模式),partition mode(選擇什么細分算法)是HS_PARTITION等。

下面看一段Hull shader的代碼:

struct HullInputType

{

float3 position : POSITION;

float4 color : COLOR;

};

struct ConstantOutputType

{

float edges[3] : SV_TessFactor;

float inside : SV_InsideTessFactor;

};

struct HullOutputType

{

float3 position : POSITION;

float4 color : COLOR;

};

// Patch 常量函數,決定tessellation因子,每個patch執行一次,所以是per patch的,不是per控制點的

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;

return output;

}

//注意輸入控制點數量要和 IASetPrimitiveTopology()函數中一致

//本例子中,都為3 INPUT_PATCH_SIZE

// The hull shader is called once per output control point, which is specified with

// outputcontrolpoints. For this sample, we take the control points from the vertex

// shader and pass them directly off to the domain shader. In a more complex scene,

// you might perform a basis conversion from the input control points into a Bezier

// patch, such as the SubD11 Sample of DirectX SDK.

// The input to the hull shader comes from the vertex shader

// The output from the hull shader will go to the domain shader.

// The tessellation factor, topology, and partition mode will go to the fixed function

// tessellator stage to calculate the UVW and domain points

[domain("tri")] //Triangle domain for our shader

[partitioning("integer")] //Partitioning type according to the GUI

[outputtopology("triangle_cw")] //Where the generated triangles should face

[outputcontrolpoints(3)] //Number of times this part of the hull shader will be called for each patch

[patchconstantfunc("ColorPatchConstantFunction")] //The constant hull shader function

HullOutputType ColorHullShader(InputPatch<HullInputType, 3> patch, uint pointId : SV_OutputControlPointID, uint patchId : SV_PrimitiveID)

{

HullOutputType output;

//設置控制點

output.position = patch[pointId].position;

// 輸出顏色為輸入顏色

output.color = patch[pointId].color;

return output;

}

2. Tessellator階段

       Tessellator是一個固定管線階段,它的主要功能就是細分一個domain(三角形, 四邊形或線),把它們細分成很多小的物體,比如三角形,四邊形或者線。

       在細分時,tessellator會在一個歸一化的坐標系統中處理patch,比如輸入是一個quad(四邊形),但這個quad先要映射到一個單位為1的正方形上,然后tessellator會對這個正方形進行細分操作。

      Tessellator是per patch操作的,Hull shader階段傳入的Tess Factor決定細分多少次,而Hull shader階段傳入的partitioning則決定選用何種細分算法。Tessellator輸出為u,v, {w}坐標以及細分后domain的拓撲信息。

3. Domain Shader階段

       Domain Shader 階段會根據TS階段生成的u,v , {w}坐標以及HS階段傳入的控制點在patch中生成細分后頂點的位置。

       Domain shader是per vertex的,對於TS中每個細分產生的頂點,它都要調用一次。它的輸入參數除了u,v,{w}坐標及控制點以外,還有const data,比如Tess factor等。

下面是一段Domain shader的代碼:

struct ConstantOutputType

{

float edges[3] : SV_TessFactor;

float inside : SV_InsideTessFactor;

};

struct HullOutputType

{

float3 position : POSITION;

float4 color : COLOR;

};

struct PixelInputType

{

float4 position : SV_POSITION;

float4 color : COLOR;

};

//每個細分后的頂點調用一次

[domain("tri")]

PixelInputType ColorDomainShader(ConstantOutputType input, float3 uvwCoord : SV_DomainLocation, const OutputPatch<HullOutputType, 3> patch)

{

float3 vertexPosition;

PixelInputType output;

//基於重心坐標的頂點生成

vertexPosition = uvwCoord.x * patch[0].position + uvwCoord.y * patch[1].position + uvwCoord.z * patch[2].position;

// 計算新的頂點在世界坐標系中的位置

output.position = mul(float4(vertexPosition, 1.0f), worldMatrix);

output.position = mul(output.position, viewMatrix);

output.position = mul(output.position, projectionMatrix);

//新生成頂點顏色也為各個控制點顏色組合

output.color = uvwCoord.x * patch[0].color + uvwCoord.y * patch[1].color + uvwCoord.z * patch[2].color;

return output;

}


免責聲明!

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



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