021-曲面细分阶段

021-曲面细分阶段

曲面细分阶段

曲面细分(Tessellation)是DirectX 11引入的一个新的图形渲染管线阶段,它允许在GPU上动态地增加几何细节。通过曲面细分,可以在距离观察者较近时增加模型的多边形数量,在较远时减少多边形,实现细节层次(Level of Detail, LOD)的平滑过渡。本章将深入探讨曲面细分的原理、实现方法以及实际应用。

14.1 曲面细分的图元类型

曲面细分阶段主要处理两种类型的基本图元:控制点面片和参数化曲面。

14.1.1 控制点面片

控制点面片是由一组控制点定义的面片,这些控制点形成了一个控制网格,用于指导曲面的形状。在DirectX 11中,支持两种基本的控制点面片类型:

四边形面片(Quad Patch):由四个或更多控制点定义的四边形

三角形面片(Triangle Patch):由三个或更多控制点定义的三角形

控制点的数量是可变的,允许灵活定义各种曲面表示,如Bézier曲面、NURBS等。

14.1.2 参数化曲面

参数化曲面通过参数方程定义,常见的类型包括:

Bézier曲面:使用Bernstein多项式作为基函数

B样条曲面:使用B样条基函数

Catmull-Clark曲面:常用于细分曲面

在曲面细分过程中,这些参数化曲面被近似为三角形或四边形网格,细分级别决定了近似的精度。

14.1.3 图元拓扑

DirectX 11定义了以下曲面细分图元拓扑类型:

D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST

D3D11_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST

...

D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST

这些拓扑类型指定了每个面片包含的控制点数量,最多支持32个控制点。

下面是一个设置面片拓扑的示例:

cpp

// 设置6控制点面片列表

context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST);

14.2 外壳着色器

曲面细分管线包含两个新的着色器阶段:外壳着色器(Hull Shader)和域着色器(Domain Shader)。本节重点介绍外壳着色器。

14.2.1 常量外壳着色器

外壳着色器分为两部分:常量函数部分和控制点函数部分。常量函数(Constant Hull Shader)为整个面片执行一次,负责计算细分因子和其他面片常量数据。

常量外壳着色器的主要职责:

计算细分因子(Tessellation Factors)

设置细分模式和分区类型

为域着色器提供额外的面片常量数据

下面是一个常量外壳着色器的示例:

hlsl

// 定义面片常量数据结构

struct PatchConstantData

{

float edgeTessFactors[4] : SV_TessFactor; // 边缘细分因子

float insideTessFactors[2] : SV_InsideTessFactor; // 内部细分因子

// 可以添加其他面片常量数据

};

// 输入和输出结构定义

struct VertexInput

{

float3 Position : POSITION;

float3 Normal : NORMAL;

float2 TexCoord : TEXCOORD0;

};

struct HullOutput

{

float3 Position : POSITION;

float3 Normal : NORMAL;

float2 TexCoord : TEXCOORD0;

};

// 常量外壳函数

PatchConstantData ConstantHS(InputPatch inputPatch)

{

PatchConstantData output;

// 简单示例:设置统一细分因子

float tessAmount = 5.0f; // 在实际应用中可能来自常量缓冲区

// 设置边缘细分因子

output.edgeTessFactors[0] = tessAmount;

output.edgeTessFactors[1] = tessAmount;

output.edgeTessFactors[2] = tessAmount;

output.edgeTessFactors[3] = tessAmount;

// 设置内部细分因子

output.insideTessFactors[0] = tessAmount;

output.insideTessFactors[1] = tessAmount;

return output;

}

细分因子

细分因子决定了图元的细分程度:

对于四边形面片:

4个边缘细分因子(edge tessellation factors)

2个内部细分因子(inside tessellation factors)

对于三角形面片:

3个边缘细分因子

1个内部细分因子

细分因子是浮点数,其整数部分决定了段数,小数部分用于平滑过渡。例如,细分因子4.7会将边分为4段,但在过渡到5段时会考虑0.7的权重。

基于距离的细分因子计算

在实际应用中,通常基于到摄像机的距离计算细分因子:

hlsl

float CalculateDistanceBasedTessFactor(float3 worldPos, float3 cameraPos, float minDist, float maxDist, float minTess, float maxTess)

{

float distance = length(worldPos - cameraPos);

// 距离在[minDist, maxDist]范围内进行差值

float normalizedDist = saturate((distance - minDist) / (maxDist - minDist));

// 反转,使得近处有更高的细分因子

normalizedDist = 1.0 - normalizedDist;

// 在minTess和maxTess之间插值

return minTess + normalizedDist * (maxTess - minTess);

}

视锥裁剪优化

为了优化性能,可以根据面片是否在视锥内调整细分因子:

hlsl

float CalculateFrustumCulledTessFactor(float4 patchCorners[4], float baseTessFactor)

{

// 检查所有控制点是否都在视锥外的同一平面

bool allOutsideLeft = true;

bool allOutsideRight = true;

bool allOutsideTop = true;

bool allOutsideBottom = true;

bool allOutsideFar = true;

bool allOutsideNear = true;

for(int i = 0; i < 4; i++)

{

// 进行透视除法

float4 clipPos = patchCorners[i];

float invW = 1.0f / clipPos.w;

clipPos.xyz *= invW;

// 检查各个平面

allOutsideLeft = allOutsideLeft && (clipPos.x < -1.0f);

allOutsideRight = allOutsideRight && (clipPos.x > 1.0f);

allOutsideTop = allOutsideTop && (clipPos.y > 1.0f);

allOutsideBottom = allOutsideBottom && (clipPos.y < -1.0f);

allOutsideFar = allOutsideFar && (clipPos.z > 1.0f);

allOutsideNear = allOutsideNear && (clipPos.z < 0.0f);

}

// 如果完全在视锥外,返回0以减少细分

if(allOutsideLeft || allOutsideRight || allOutsideTop || allOutsideBottom || allOutsideFar || allOutsideNear)

return 0.0f;

return baseTessFactor;

}

14.2.2 控制点外壳着色器

控制点函数(Control Point Hull Shader)为每个输入控制点执行一次,其主要职责是:

处理和变换输入控制点

输出可用于域着色器的控制点数据

以下是一个控制点外壳着色器的示例:

hlsl

// 控制点外壳函数

[domain("quad")] // 指定域类型:四边形

[partitioning("fractional_even")] // 指定分区模式:分数偶数

[outputtopology("triangle_cw")] // 指定输出图元拓扑:顺时针三角形

[outputcontrolpoints(4)] // 指定输出控制点数量

[patchconstantfunc("ConstantHS")] // 指定面片常量函

相关推荐

杨过个人简介和生肖
365彩票app下载苹果版

杨过个人简介和生肖

09-15 👁️‍🗨️ 5504
自驾神器!自驾宝全功能评测
365彩票app下载苹果版

自驾神器!自驾宝全功能评测

09-05 👁️‍🗨️ 3221
魔族系列降临 讯景HD7770鏖战主流游戏
bt365注册

魔族系列降临 讯景HD7770鏖战主流游戏

07-26 👁️‍🗨️ 3616
输入密码显示此Apple ID已停用 怎么办
线上365bet正网

输入密码显示此Apple ID已停用 怎么办

07-02 👁️‍🗨️ 3419
瞌铳的解释
bt365注册

瞌铳的解释

08-21 👁️‍🗨️ 5907
【投稿发表】投稿被拒的六大原因分析,该如何规避?
正在阅读:荔枝fm中录音具体操作流程 荔枝fm怎么录音荔枝fm中录音具体操作流程 荔枝fm怎么录音
《率土之滨》韩遂(四星)图鉴
线上365bet正网

《率土之滨》韩遂(四星)图鉴

07-24 👁️‍🗨️ 5851
普通舞阳城入门详细攻略
365彩票app下载苹果版

普通舞阳城入门详细攻略

09-16 👁️‍🗨️ 154