• 细分着色器分为:曲面细分着色器(Unity在指定平台硬件支持)、细分计算着色器。使用片面来描述一个物体形状,并增加顶点和片面数量,使模型外观开起来更平滑。
  • 作用‌:动态细分三角面片,提升模型细节(如草地、地形渲染),优化大场景性能 ‌。
  • 这是一个‌可选‌阶段。它在顶点着色器之后运行,负责根据设定的细分因子 (Tessellation Factor) 将输入的图元(通常是三角形面片)动态细分为更小的三角面片,生成更多顶点。‌

【从UnityURP开始探索游戏渲染】专栏-直达

三个子阶段:

Hull Shader:定义每条边和内部分割因子(Tessellation Factor)。‌

  • 接收原始控制点数据并定义细分因子(Tessellation Factor)
  • 通过patch constant function计算每条边和内部的细分等级
  • 支持分数细分模式(fractional_odd/fractional_even)实现平滑过渡

目标‌:

  • 定义原始控制点数据并计算细分因子(Tessellation Factor)
  • 确定每个patch的边和内部细分等级

输入输出‌:

  • 输入:原始控制点数据(位置、法线、UV等)
  • 输出:
    • 细分因子(SV_TessFactor标记边,SV_InsideTessFactor标记内部)
    • 处理后的控制点数据(通过INTERNALTESSPOS语义标记)

实现关键‌:

hlsl
struct TessFactors {
float edge[3] : SV_TessFactor; // 三条边的细分因子
float inside : SV_InsideTessFactor; // 内部细分因子
};

Tessellation Primitive Generator 固定功能‌:硬件根据 Hull Shader 输出的因子实际执行细分操作。‌

  • GPU固定功能阶段,根据Hull Shader输出的细分因子生成新顶点拓扑

目标‌:

  • 根据Hull Shader输出的细分因子生成新顶点拓扑
  • 将原始patch细分为更密集的三角网格

输入输出‌:

  • 输入:Hull Shader输出的细分因子和控制点

    hlsl
    
    // 来自Hull Shader的输出
    struct TessControlPoint {
    float4 positionOS : INTERNALTESSPOS;
    float3 normalOS : NORMAL;
    float2 uv : TEXCOORD0;
    }; // 细分因子定义
    struct TessFactors {
    float edge[3] : SV_TessFactor; // 每条边的细分等级
    float inside : SV_InsideTessFactor; // 内部细分等级
    };
  • 输出:细分后的顶点UV坐标和拓扑关系

    • 生成的重心坐标数据:

      hlsl
      float3 baryCoords : SV_DomainLocation; // 新顶点的重心坐标
    • 输出拓扑类型由Hull Shader的[outputtopology]属性定义(如triangle_cw)

特性‌:

  • GPU自动执行,无需开发者编码
  • 支持分数细分模式实现平滑过渡

实现原理

细分算法

  • 对原始三角面片进行递归细分,采用Delaunay三角剖分原则

    GPU使用的Delaunay三角剖分原则是一种优化网格拓扑的数学方法

    • Delaunay三角剖分原则

      1. 空圆特性‌:任意三角形的外接圆内不包含其他顶点
      2. 最大化最小角‌:避免出现尖锐三角形,提高网格质量
      3. 局部优化‌:通过边翻转(edge flip)逐步优化三角网格
    • URP中的实现特点‌:

      1. 在Tessellation Primitive Generator阶段自动应用
      2. 对细分后的新顶点进行拓扑优化
      3. 保持与原网格的平滑过渡
    • 具体示例‌:

      原始三角面片(控制点A/B/C)经过细分后:

      • 计算细分因子为3时:
      原始三角形: A
      / \
      C---B 细分后拓扑:
      A
      /|\
      / | \
      C--D--B
      \ | /
      \|/
      E
      • 其中D/E是新生成的顶点,所有三角形都满足:

        • ∠ADB + ∠AEB ≈ 180°
        • 外接圆不包含其他顶点
    • URP中的实际应用‌:

      1. 当使用[partitioning("fractional_odd")]时:

        • 会在过渡区域自动应用Delaunay优化
        • 确保不同细分等级间的平滑连接
      2. 位移贴图处理时:
        • 新顶点根据Delaunay规则分布
        • 位移后的法线计算更准确
    • 这种剖分方式使得:

      • 细分后的网格更适应曲面变形
      • 避免渲染时的褶皱现象
      • 提升位移贴图的视觉效果
  • 根据分数细分模式(fractional_odd/even)处理过渡区域

‌坐标转换 $Pnew=P0⋅u+P1⋅v+P2⋅w$

  • 将参数空间坐标(u,v,w)转换为新的顶点位置

性能优化

  • 采用并行计算处理多个patch
  • 自动剔除屏幕空间不可见的细分结果

Domain Shader‌:

将细分后位于重心坐标系(重心坐标内容后续单开一篇讲解)中的新顶点位置转换到目标空间(如世界空间或裁剪空间)。‌

  • 将细分后的UV坐标映射到3D空间
  • 执行顶点位移等后期处理

目标‌:

  • 将细分后的UV坐标映射到3D空间
  • 执行顶点位移等后期处理

输入输出‌:

  • 输入:细分后的UV坐标和原始控制点数据
  • 输出:最终顶点位置(SV_POSITION)和其他顶点属性

实现示例‌:

hlsl
[domain("tri")] // 声明处理三角形patch
Varyings domain(TessFactors factors, OutputPatch<DomainAttributes, 3> patch, float3 baryCoords : SV_DomainLocation) {
Varyings OUT;
// 插值计算新顶点属性
OUT.positionWS = TransformObjectToWorld(patch[0].positionOS * baryCoords.x + ...);
return OUT;
}

动态控制技巧‌:

  • 通过摄像机距离调整细分因子:

    hlsl
    float CalcTessFactor(float3 worldPos) {
    return lerp(_MaxTess, _MinTess, saturate(distance(_WorldSpaceCameraPos, worldPos) / _TessRange));
    }
  • 结合高度图实现位移效果

‌配置:

  • 需显式启用(HLSL 中声明 hull 和 domain 函数)。
  • 必须声明#pragma target 4.6以启用DX11/OpenGL Core特性3
  • 需手动实现Hull/Domain Shader,URP不提供表面着色器的简化写法
  • 建议结合摄像机距离动态控制细分因子以优化性能

URP中的具体实现步骤:

声明编译目标为4.6以上:

hlsl
#pragma target 4.6

定义三个关键程序:

hlsl
#pragma vertex BeforeTessVert
#pragma hull HullProgram
#pragma domain DomainProgram

控制点数据结构需包含顶点位置、法线等基础属性

‌动态细分控制样例:

  • 通过距离或屏幕空间尺寸自动调整细分因子:
hlsl
// 根据摄像机距离动态计算细分因子
float CalcTessFactor(float3 worldPos) {
float dist = distance(_WorldSpaceCameraPos, worldPos);
return lerp(_MaxTess, _MinTess, saturate(dist / _TessRange));
}

常见应用场景:

  • 地形动态LOD:根据视角距离细分地面网格3
  • 曲面平滑:将低模转换为高模曲面2
  • 动态位移:结合高度图实现实时凹凸效果6

‌注意事项:

  • 仅支持DX11/OpenGL Core等现代图形API6
  • 细分过度会导致性能下降,需合理设置上限5
  • URP中需手动实现Hull/Domain Shader,不同于内置管线的表面着色器简化写法

Unity URP中完整的曲面细分着色器示例,包含顶点位移效果和动态细分控制

示例实现功能:

  • 动态细分控制:根据摄像机距离自动调整细分因子
  • 顶点位移效果:通过高度图(_DispTex)驱动顶点偏移
  • 分数细分模式:使用fractional_odd实现平滑过渡
  • 完整渲染管线:包含顶点/细分/片元全阶段处理
  • URP兼容性:使用URP的ShaderLibrary核心函数

使用说明:

  • 创建材质球并应用此着色器
  • 为_DispTex指定高度图纹理
  • 调整_TessFactor控制细分密度
  • 通过_Displacement参数控制位移强度

TessellationExample.shader

// HLSL
Shader "Custom/TessellationExample"
{
Properties
{
_MainTex ("Base Texture", 2D) = "white" {}
_TessFactor ("Tessellation Factor", Range(1, 64)) = 4
_Displacement ("Displacement", Range(0, 1.0)) = 0.3
_DispTex ("Displacement Texture", 2D) = "gray" {}
} SubShader
{
Tags { "RenderPipeline"="UniversalPipeline" } HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
}; struct TessControlPoint
{
float4 positionOS : INTERNALTESSPOS;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
}; struct TessFactors
{
float edge[3] : SV_TessFactor;
float inside : SV_InsideTessFactor;
}; struct DomainOutput
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normalWS : NORMAL;
};
ENDHLSL Pass
{
Name "ForwardLit"
Tags { "LightMode"="UniversalForward" } HLSLPROGRAM
#pragma vertex vert
#pragma hull hull
#pragma domain domain
#pragma fragment frag
#pragma target 4.6 sampler2D _MainTex;
sampler2D _DispTex;
float _TessFactor;
float _Displacement; TessControlPoint vert(Attributes v)
{
TessControlPoint o;
o.positionOS = v.positionOS;
o.normalOS = v.normalOS;
o.uv = v.uv;
return o;
} [domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("patchConstantFunc")]
TessControlPoint hull(InputPatch<TessControlPoint, 3> patch, uint id : SV_OutputControlPointID)
{
return patch[id];
} TessFactors patchConstantFunc(InputPatch<TessControlPoint, 3> patch)
{
TessFactors f;
float avgTess = _TessFactor * (1 - saturate(length(_WorldSpaceCameraPos - TransformObjectToWorld(patch[0].positionOS.xyz)) / 20));
f.edge[0] = f.edge[1] = f.edge[2] = avgTess;
f.inside = avgTess;
return f;
} [domain("tri")]
DomainOutput domain(TessFactors factors, OutputPatch<TessControlPoint, 3> patch, float3 baryCoords : SV_DomainLocation)
{
DomainOutput o; // 插值计算基础属性
float3 positionOS = patch[0].positionOS.xyz * baryCoords.x +
patch[1].positionOS.xyz * baryCoords.y +
patch[2].positionOS.xyz * baryCoords.z; float2 uv = patch[0].uv * baryCoords.x +
patch[1].uv * baryCoords.y +
patch[2].uv * baryCoords.z; // 从高度图获取位移值
float disp = tex2Dlod(_DispTex, float4(uv, 0, 0)).r * _Displacement;
positionOS += normalize(patch[0].normalOS) * disp; // 转换到裁剪空间
o.positionCS = TransformObjectToHClip(positionOS);
o.uv = uv;
o.normalWS = TransformObjectToWorldNormal(patch[0].normalOS);
return o;
} half4 frag(DomainOutput i) : SV_Target
{
half4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDHLSL
}
}
}

【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,)

【渲染流水线】[几何阶段]-[曲面细分]以UnityURP为例的更多相关文章

  1. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十四章:曲面细分阶段

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十四章:曲面细分阶段 代码工程地址: https://github. ...

  2. DirectX11 With Windows SDK--33 曲面细分阶段(Tessellation)

    前言 曲面细分是Direct3D 11带来的其中一项重要的新功能.它引入了两个可编程着色器阶段以及一个固定的镶嵌处理过程.简单来说,曲面细分技术可以将几何体细分为更小的三角形,并以某种方式把这些新生成 ...

  3. GPU渲染流水线的简单概括

    GPU流水线 主要分为两个阶段:几何阶段和光栅化阶段   几何阶段      顶点着色器 --> 曲面细分着色器(可选)----->几何着色器(可选)----->裁剪-->屏幕 ...

  4. Shader 入门笔记(二) CPU和GPU之间的通信,渲染流水线

    渲染流水线 1)应用阶段(CPU处理) 首先,准备好场景数据(摄像机位置,视锥体,模型和光源等) 接着,做粗粒度剔除工作. 最后,设置好每个模型的渲染状态(使用的材质,纹理,shader等) 这一阶段 ...

  5. 《UnityShader入门精要》学习笔记之渲染流水线

    第一种分类方式: 图形管道(如下7步): 顶点数据 : 由3D模型传递的三角形网格 顶点着色 : 编写CG程序对各个顶点进行着色 生成几何图元 : 连接特定的顶点生成几何图元,例如连接三个顶点生成一个 ...

  6. Unity Shader 之 渲染流水线

    Unity Shader 之渲染流水线 什么是渲染流水线 一个渲染流程分成3个步骤: 应用阶段(Application stage) 几何阶段(Geometry stage) 光栅化阶段(Raster ...

  7. Unity Shader入门精要学习笔记 - 第2章 渲染流水线

    来源作者:candycat   http://blog.csdn.net/candycat1992/article/ 2.1 综述 渲染流水线的最终目的在于生成或者说是渲染一张二维纹理,即我们在电脑屏 ...

  8. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线 学习目标 了解几个用以表达真实场景的标志和2D图像 ...

  9. Unity 渲染流水线 :CPU与GPU合作创造的艺术wfd

    前言 对于Unity渲染流程的理解可以帮助我们更好对Unity场景进行性能消耗的分析,进而更好的提升场景渲染的效率,最后提升游戏整体的性能表现 Unity的游戏画面的最终的呈现是由CPU与GPU相互配 ...

  10. Tessellation (曲面细分) Displacement Mapping (贴图置换)

    DirectX 11 Tessellation (曲面细分)-什么是 Tessellation (曲面细分) ? 它为什么可以起到如此关键的数据? 随着近期人们对 DirectX 11 的议论纷纷,你 ...

随机推荐

  1. 使用Streamlit构建批量二维码生成器

    Streamlit是一个优秀的Python库,让数据科学家和开发者能够快速创建交互式Web应用.今天,我将展示如何使用Streamlit和qrcode库构建一个简单而实用的批量二维码生成器. 技术栈 ...

  2. Cursor+Claude-3.7-sonnet 生成一整套APP原型图:AI英语口语学习助手app

    一.引言 在 AI 技术快速发展的今天,特别是随着 Claude 3.7 的发布,AI 辅助设计和开发已经达到了一个新的高度. 本文将详细介绍如何使用 Cursor IDE 配合 Claude-3.7 ...

  3. Spring 注解之 @EnableTransactionManagement:Spring Boot 事务配置

    Spring Boot 开启声明式事务支持 所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务.提交事务以完成数据操纵,或者在发生错误的时候回滚数据.Spring支持声明式事务,这是 ...

  4. Java11 ThreadLocal的remove()方法源码分析

    1. ThreadLocal实现原理 本文参考的java 版本是11. 在讲述ThreadLocal实现原理之前,我先来简单地介绍一下什么是ThreadLocal.ThreadLocal提供线程本地变 ...

  5. springboot在拦截器里注入mapper失败Null问题

    问题 直接在拦截器里这样注入mapper(dao)会导致null 解决方案 修改拦截器配置 原来的配置 修改为如下

  6. Django REST Framework框架介绍以及简单使用

    一. Django REST framework介绍 Django REST framework是基于Django实现的一个RESTful风格API框架,能够帮助我们快速开发RESTful风格的API ...

  7. Etcd异地容灾方案

    一.方案选型 ETCD官网提供了一种实时镜像同步数据的工具mirror-maker,如果出现主机房服务挂掉可以通过切换域名的形式切换到灾备机房,这个过程数据是可以保持一致的. 注意:make-mirr ...

  8. Raft论文(中英翻译)

    In Search of an Understandable Consensus Algorithm(Extended Version) 寻找一种可理解的一致性算法(拓展版) 作者:斯坦福大学的Die ...

  9. 对于linux 程序内存的使用量

    简介 如何查看一个linux程序是否产生内存泄露了呢?? 可以使用valgrind 一般的命令是 valgrind --leak-check=full --show-reachable=yes --t ...

  10. C++ 类中什么时候需要一个operator<

    简介 当涉及类对象的排序的时候可以直接构建一个符号重定义函数 比如以set来组织对象的时候,对象最好带一个operator<函数 code /* used to use Vertex as ke ...