Unity Shader 学习 Tessellation(曲面细分)
简介
Tessellation,直译的话应该译作”镶嵌化处理技术”,Dx11加入。简单的理解,便是在一个简单的多边形模型中,利用专门的硬件,专门的算法镶嵌入若干多边形,以达到在不耗费CPU资源的情况下,真实的展现曲面的目的。
关于Tessellation Shader
- 应用- 海浪,雪地,沙地
- 置换贴图
 
- Tessellation 的应用技术细节- 渲染流程
 - 下图是渲染流程中的Shader顺序:  - 将Tessellation Shader展开后,请看下图:  - 也就是说我们要通过 Hull Shader 和 Domain Shader 来控制Tessellation的实现。 - Hull Shader- 负责定义细分等级(LOD)和相关控制点在细分中的“形变”趋势
 
- Domain Shader- 对细分后的点进行处理
 
- 实例代码
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113- Shader "Unlit/Tessellation" 
 {
 Properties
 {
 _MainTex ("Texture", 2D) = "white" {}
 }
 SubShader
 {
 Tags { "RenderType"="Opaque" }
 LOD 100
 Pass
 {
 CGPROGRAM
 
 
 
 
 
 
 
 
 struct appdata
 {
 float4 vertex : POSITION;
 float4 tangent : TANGENT;
 float3 normal : NORMAL;
 float2 texcoord : TEXCOORD0;
 };
 struct v2f
 {
 float2 texcoord:TEXCOORD0;
 float4 vertex : SV_POSITION;
 float4 tangent : TANGENT;
 float3 normal : NORMAL;
 };
 struct InternalTessInterp_appdata {
 float4 vertex : INTERNALTESSPOS;
 float4 tangent : TANGENT;
 float3 normal : NORMAL;
 float2 texcoord : TEXCOORD0;
 };
 sampler2D _MainTex;
 float4 _MainTex_ST;
 
 InternalTessInterp_appdata tessvert (appdata v) {
 InternalTessInterp_appdata o;
 o.vertex = v.vertex;
 o.tangent = v.tangent;
 o.normal = v.normal;
 o.texcoord = v.texcoord;
 return o;
 }
 v2f vert (appdata v)
 {
 v2f o;
 o.vertex = UnityObjectToClipPos(v.vertex);
 o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
 return o;
 }
 UnityTessellationFactors hsconst (InputPatch<InternalTessInterp_appdata,3> v) {
 UnityTessellationFactors o;
 float4 tf;
 //定义曲面细分的参数
 tf = float4(4.0f,4.0f,4.0f,4.0f);
 o.edge[0] = tf.x;
 o.edge[1] = tf.y;
 o.edge[2] = tf.z;
 o.inside = tf.w;
 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)]//不同的图元会对应不同的控制点
 InternalTessInterp_appdata hs (InputPatch<InternalTessInterp_appdata,3> v, uint id : SV_OutputControlPointID) {
 return v[id];
 }
 [UNITY_domain("tri")]
 v2f ds (UnityTessellationFactors tessFactors, const OutputPatch<InternalTessInterp_appdata,3> vi, float3 bary : SV_DomainLocation) {
 appdata v;
 v.vertex = vi[0].vertex*bary.x + vi[1].vertex*bary.y + vi[2].vertex*bary.z;
 v.tangent = vi[0].tangent*bary.x + vi[1].tangent*bary.y + vi[2].tangent*bary.z;
 v.normal = vi[0].normal*bary.x + vi[1].normal*bary.y + vi[2].normal*bary.z;
 v.texcoord = vi[0].texcoord*bary.x + vi[1].texcoord*bary.y + vi[2].texcoord*bary.z;
 v2f o = vert (v);
 return o;
 }
 
 fixed4 frag (v2f i) : SV_Target
 {
 return fixed4(1.0f,1.0f,1.0f,1.0f);
 }
 ENDCG
 }
 }
 }- 根据距离进行不同级别的细分 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32- texInput vert(vertexInput0 v) 
 {
 vertexInput vi;
 //计算距离因子
 float dist = distance(_WorldSpaceCameraPos,mul(unity_ObjectToWorld, v.vertex))/(16*5);
 vi.vertex = v.vertex;
 vi.normal = v.normal;
 vi.tangent = v.tangent;
 float tf = (int)(lerp(5.2, 1.2, clamp(dist, 0.0, 1)));
 if(tf==5)tf=4;
 //tf = ((int)(tf*10))/10.0;
 vi.TessFactor = tf;
 return vi;
 }
 TessellationFactors patchConstantFunction (InputPatch<vertexInput, 3> patch)
 {
 TessellationFactors tf;
 //tf.edge[0] = _TessellationUniform;
 //tf.edge[1] = _TessellationUniform;
 //tf.edge[2] = _TessellationUniform;
 //tf.inside = _TessellationUniform;
 //使用基于距离的 Tessellation
 tfTessellation.edge[0] = 0.5fTTTessellation*(patch[1].TessFactor + patch[2].TessFactor);
 tf.edge[1] = 0.5f*(patch[2].TessFactor + patch[0].TessFactor);
 tf.edge[2] = 0.5f*(patch[0].TessFactor + patch[1].TessFactor);
 tf.inside = tf.edge[0];
 return tf;
 }
关于本文
本文作者 Master Gong Sheng, 许可由 CC BY-NC 4.0.