February 19, 2023

Unity Shader 学习 Tessellation(曲面细分)

Unity Shader 学习 Tessellation(曲面细分)

关于Tessellation Shader

下图是渲染流程中的Shader顺序�?/p>

aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwNzEyMTgxMDAxMzE0.png

将Tessellation Shader展开后,请看下图�?/p>

aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwNzEyMTgxMDU5NzQy.png

也就是说我们要通过 Hull Shader �?Domain Shader 来控制Tessellation的实现�?/p>

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
#pragma vertex tessvert
#pragma fragment frag
#pragma hull hs
#pragma domain ds
#pragma target 4.6

#include "UnityCG.cginc"
#include "Lighting.cginc"

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;
//定义曲面细分的参�?/span>
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�?/span>
[UNITY_partitioning("fractional_odd")]]//拆分edge的规则,equal_spacing,fractional_odd,fractional_even
[UNITY_outputtopology("triangle_cw")]
[UNITY_patchconstantfunc("hsconst")]//一个patch一共有三个点,但是这三个点都共用这个函�?/span>
[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
}
}
}


根据距离进行不同级别的细�?/p>

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.