个人学习笔记 ——【技术美术百人计划】图形 3.3 曲面细分与几何着色器 大规模草渲染
图形 3.3 曲面细分与几何着色器
B站:
【技术美术百人计划】图形 3.3 曲面细分与几何着色器 大规模草渲染
PPT:
一 、曲面细分与几何着色器的应用
1.1 曲面细分着色器的应用
1.2 几何着色器的应用
二、着色器执行顺序
- 整体顺序:顶点 → 曲面细分 → 几何 → 片元;
- 曲面细分又分为:Hull shader 、Tessellation Primitive Generator 、 Domain shade;
Hull shader:定义一些细分的参数(如:每条边上如何细分,内部三角形如何细分);
Tessellation Primitive Generator:不可编程的,不需要我们做啥;
Domain shader:经过曲面细分着色器细分后的点是位于重心空间的,这部分的作用就是把它转化到我们要用的空间。
- 在OpenGL中HullShader 和DomainShader分别被简称:TCS和TES
三、曲面细分着色器-Tessellation shader(TESS)
1.TESS的输入和输出
2. TESS流程
3. HULL Shader各参数解析
3.1 Tessellation Factor
决定如何将一条边分成几部分
3.1.1 equal_Spacing
将一条边等分
3.1.2 fractional_even_spacing
even最小值是2,向上取最近的偶数
3.1.3 fractional_odd_spacing
odd最小值是1,向上取最近的奇数
3.2 Inner Tessellation Factor
作延长线,作交点
4. 曲面细分 Demo 演示
4.1 Quad细分
体现具体的使用方法,通过一个quad可以看出不同数值对细分的 影响(之后可以使用在草地中),基于shader再回顾一遍各个参数的作用
//曲面细分Demo1
Shader "Unlit/TessShader"
{
Properties
{
_TessellationUniform("TessellationUniform",Range(1,64)) = 1
}
SubShader
{
Tags {
"RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
//定义2个函数 hull domain
#pragma hull hullProgram
#pragma domain ds
#pragma vertex tessvert
#pragma fragment frag
#include "UnityCG.cginc"
//引入曲面细分的头文件
#include "Tessellation.cginc"
#pragma target 5.0
struct VertexInput
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct VertexOutput
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
VertexOutput vert (VertexInput v)
//这个函数应用在domain函数中,用来空间转换的函数
{
VertexOutput o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.tangent = v.tangent;
o.normal = v.normal;
return o;
}
//有些硬件不支持曲面细分着色器,定义了该宏就能够在不支持的硬件上不会变粉,也不会报错
#ifdef UNITY_CAN_COMPILE_TESSELLATION
//顶点着色器结构的定义
struct TessVertex{
float4 vertex : INTERNALTESSPOS;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float2 uv : TEXCOORD0;
};
struct OutputPatchConstant {
//不同的图元,该结构会有所不同
//该部分用于Hull Shader里面
//定义了patch的属性
//Tessellation Factor和Inner Tessellation Factor
float edge[3] : SV_TESSFACTOR;
float inside : SV_INSIDETESSFACTOR;
};
TessVertex tessvert (VertexInput v){
//顶点着色器函数
TessVertex o;
o.vertex = v.vertex;
o.normal = v.normal;
o.tangent = v.tangent;
o.uv = v.uv;
return o;
}
float _TessellationUniform;
OutputPatchConstant hsconst (InputPatch<TessVertex,3> patch){
//定义曲面细分的参数
OutputPatchConstant o;
o.edge[0] = _TessellationUniform;
o.edge[1] = _TessellationUniform;
o.edge[2] = _TessellationUniform;
o.inside = _TessellationUniform;
return o;
}
[UNITY_domain("tri")]//确定图元,quad,triangle等
[UNITY_partitioning("fractional_odd")]//拆分edge的规则,equal_spacing,fractional_odd,fractional_even
[UNITY_outputtopology("triangle_cw")]
[UNITY_patchconstantfunc("hsconst")]//一个patch一共有三个点,但是这三个点都共用这个函数
[UNITY_outputcontrolpoints(3)] //不同的图元会对应不同的控制点
TessVertex hullProgram (InputPatch<TessVertex,3> patch,uint id : SV_OutputControlPointID){
//定义hullshaderV函数
return patch[id];
}
[UNITY_domain("tri")]//同样需要定义图元
VertexOutput ds (OutputPatchConstant tessFactors, const OutputPatch<TessVertex,3>patch,float3 bary :SV_DOMAINLOCATION)
//bary:重心坐标
{
VertexInput v;
v.vertex = patch[0].vertex*bary.x + patch[1].vertex*bary.y + patch[2].vertex*bary.z;
v.tangent = patch[0].tangent*bary.x + patch[1].tangent*bary.y + patch[2].tangent*bary.z;
v.normal = patch[0].normal*bary.x + patch[1].normal*bary.y + patch[2].normal*bary.z;
v.uv = patch[0].uv*bary.x + patch[1].uv*bary.y + patch[2].uv*bary.z;
VertexOutput o = vert (v);
return o;
}
#endif
float4 frag (VertexOutput i) : SV_Target
{
return float4(1.0,1.0,1.0,1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
4.2 细分和置换贴图结合
简单的展示一下模型的形变,不打算过多讲解细节,包括法线的计算(直接使用了一张能够匹配的法线图),阴影的添加等(感觉可能时间不够)
//曲面细分Demo2:与置换贴图结合使用
Shader "Unlit/Tess_Diss_Shader"
{
Properties
{
_MainTex("MainTex",2D) = "white"{
}
_DisplacementMap("_DisplacementMap",2D)="gray"{
}
_DisplacementStrength("DisplacementStrength"