Tesselaation Shader & Geometry Shader
曲面细分着色与几何着色
百人计划学习地址:图形 3.3 曲面细分与几何着色器 大规模草渲染
一、曲面细分着色器
1. 原理
顾名思义,可以不断细化一个锐利的几何体,将它变成球体
也可以不断细分一条直线,向曲线逼近
2. 为什么要使用曲面细分
- 直接使用顶点数更多的模型,会带来更高的性能消耗
- 它可以根据自定义的规则来动态调整模型的复杂度,达成对应的效果
3. 应用
使用曲面细分是为了增加模型的细节,但是我们通常没必要在用户关注不到地方增加不必要的细节,因此我们会采取一些策略来得到动态的曲面细分因子:
- 距离相机的远近:距离相机越远,需要越少的模型细节,而离相机越近,曲面细分的程度可以越高。
- 屏幕空间的覆盖范围::我们可以估算出一个模型覆盖到的屏幕区域大小,覆盖区域越小,说明模型在屏幕上占比越小,此时可以使用低多边形模型,相反,覆盖区域越大,曲面细分的程度需要越高。
- 三角面的朝向:三角面的朝向和观察方向的夹角越大,说明越靠近模型边缘(视觉上的轮廓边缘),而此时需要更高的模型精度,因此曲面细分程度要越高。
- 表面粗糙度:粗糙表面相比平滑表面,需要更多的模型细节。例如视觉上粗糙不平的地面相比光滑的镜面,需要更多的模型细节来进行表现。
也可以与置换贴图结合:
二、几何着色器
1. 原理
可以将顶点变换为完全不同的图元,并且还能生成比原来更多的顶点
2. 为什么要使用几何着色器
因为可以修改网格(增删改模型的顶点及三角面等,所以可以实现非常多酷炫的效果
3. 应用
三、着色器的执行顺序
顶点着色器——》曲面细分着色器——》几何着色器——》片元着色器
注:
- Hull Shader 细分控制着色器 和 Domain Shader 细分计算着色器是可编程的
- Tessellation Primitive Generator不可编程
在OpenGL中HullShader 和DomainShader分别被简称:TCS和TES
四、TESS曲面细分工作原理
1. 输入与输出
- 输入:也叫Patch,可以看成多个顶点的集合,包含每个顶点的属性,可以指定一个Patch包含的顶点数以及自己的属性
- 输出:细分之后的顶点
- 功能:将图元细分(可以是三角形,矩形等)
2. 流程
① HuLL Shader
- 决定细分的数量(设定Tessellation factor以及Inside Tessellation factor)
- 对输入的Patch参数进行改变
② Tessellation Primitive Generator
- 进行细分操作
③ Domain Shader
- 对细分的点进行处理,从重心空间转换到屏幕空间
3. 关于HULL Shader各参数解析
- Tessellation Factor:决定将一条边分成几部分
- Inner Tessellation Factor:决定内部三角形怎么划分
五、曲面细分Demo演示
先定义hullshader和domainshader的名称并应用对应的函数库
#pragma hull hullProgram
#pragma domain ds
#include "Tessellation.cginc"
Hull Shader代码:
struct TessVertex {
float4 vertex : INTERNALTESSPOS;
float3 normal: NORMAL;
float4 tangent :TANGENT;
float2 uv : TEXCOORD0;
};
//顶点着色器只传入对应的值
TessVertex tessvert(appdata v)
{
TessVertex o;
o.vertex = v.vertex;
o.uv = v.uv;
o.normal = v.normal;
o.tangent = v.tangent;
return o;
}
//图片结构体
struct OutputPatchConstant
{
float edge[3] : SV_TESSFACTOR;
float inside : SV_INSIDETESSFACTOR;
};
OutputPatchConstant hsconst(InputPatch<TessVertex, 3> patch) {
OutputPatchConstant o;
//定义曲面细分的参数
o.edge[0] = _TessellationFloat;
o.edge[1] = _TessellationFloat;
o.edge[2] = _TessellationFloat;
o.inside = _TessellationFloat;
return o;
}
[UNITY_domain("tri")]//确定图元,quad,triangle等
[UNITY_partitioning("integer")]//拆分edge的规则,equal_spacing,fractional_odd,fractional_even
[UNITY_outputtopology("triangle_cw")]
[UNITY_patchconstantfunc("hsconst")]//一个patch一共有三个点,但是这三个点都共用这个函数
[UNITY_outputcontrolpoints(3)] //不同的图元会对应不同的控制点
TessVertex hullProgram(InputPatch<TessVertex