unity-shader-tutorial-gi

GI.shader

GI.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
Shader "HHF/Tutorial/GI"
{
Properties
{
_Color ("Color",Color) = (1,1,1,1)
}

SubShader
{
Tags { "RenderType"="Opaque" }

Pass
{
Tags {"LightMode" = "ForwardBase"}

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase

#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"
#include "../CGIncludes/GI.cginc"

struct appdata
{
float4 vertex:POSITION;
half3 normal:NORMAL;

#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
float4 texcoord1:TEXCOORD1;
#endif

float4 texcoord2:TEXCOORD2;
};

struct v2f
{
float4 pos:SV_POSITION;
float3 worldPos:TEXCOORD;
half3 worldNormal:NORMAL;

#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
float4 lightmapUV:TEXCOORD1;
#endif

#ifndef LIGHTMAP_ON
#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
half3 sh:TEXCOORD2;
#endif
#endif

// 定义灯光衰减以及实时阴影采样所需的插值器
UNITY_LIGHTING_COORDS(3,4)
};

v2f vert (appdata v)
{
v2f o = (v2f)0;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);

// Baked GI的Tiling与Offset
#if defined(LIGHTMAP_ON)
o.lightmapUV.xy = v.texcoord1 * unity_LightmapST.xy + unity_LightmapST.zw;
#endif

// Realtime GI的Tiling与Offset
#if defined(DYNAMICLIGHTMAP_ON)
o.lightmapUV.zw = v.texcoord1 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif

// 球谐光照和顶点光照的计算
// SH/ambient and vertex lights
#ifndef LIGHTMAP_ON
// 当此对象没有开启静态烘焙时
#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
o.sh = 0;
// Approximated illumination from non-important point lights
// 近似模拟非重要级别的点光在逐顶点上的光照效果
#ifdef VERTEXLIGHT_ON
o.sh += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, o.worldPos, o.worldNormal);
#endif
o.sh = ShadeSHPerVertex (o.worldNormal, o.sh);
#endif
#endif // !LIGHTMAP_ON

UNITY_TRANSFER_LIGHTING(o, v.texcoord2.xy);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
SurfaceOutput o;
UNITY_INITIALIZE_OUTPUT(SurfaceOutput,o)
o.Albedo = 1;
o.Normal = i.worldNormal;

// 计算灯光的衰减效果
// 实时阴影的采样
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos)

UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI,gi);
gi.light.color = _LightColor0;
gi.light.dir = _WorldSpaceLightPos0;
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;

UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput,giInput);
giInput.light = gi.light;
giInput.worldPos = i.worldPos;
giInput.worldViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
giInput.atten = atten;

#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
giInput.ambient = i.sh;
#else
giInput.ambient.rgb = 0.0;
#endif

#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
giInput.lightmapUV = i.lightmapUV;
#endif

// GI间接光照计算,数据存储在gi中
// LightingLambert_GI1(o, giInput, gi);
gi = UnityGI_Base_(giInput, 1, o.Normal);

// GI直接光照计算
fixed4 c = LightingLambert_(o,gi);
return c;
}
ENDCG
}

Pass
{
Tags {"LightMode" = "ForwardAdd"}
Blend One One

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
half3 normal:NORMAL;
};

struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
half3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
};

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
return o;
}

fixed4 frag (v2f i) : SV_Target
{

UNITY_LIGHT_ATTENUATION(atten, 0, i.worldPos)

fixed4 LightColor = _LightColor0 * atten;
fixed3 N = normalize(i.worldNormal);
fixed3 L = _WorldSpaceLightPos0;
fixed4 Diffuse = LightColor * max(0,dot(N,L));

return Diffuse;
}

ENDCG
}

pass
{
Tags {"LightMode" = "ShadowCaster"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"

struct appdata
{
float4 vertex:POSITION;
half3 normal:NORMAL;
};

struct v2f
{
V2F_SHADOW_CASTER;
};

v2f vert(appdata v)
{
v2f o;
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
return o;
}

fixed4 frag(v2f i):SV_TARGET
{
SHADOW_CASTER_FRAGMENT(i)
}

ENDCG
}

// 此Pass用于计算光照的间接光反弹
// 在正常渲染时不会使用此Pass
// 几乎不需要改动,算是通用pass
Pass
{
Name "META"
Tags { "LightMode" = "Meta" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityMetaPass.cginc"

fixed4 _Color;

struct v2f
{
float4 pos : SV_POSITION;
};

v2f vert (appdata_full v)
{
v2f o;
UNITY_INITIALIZE_OUTPUT(v2f,o);
o.pos = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST, unity_DynamicLightmapST);
return o;
}


half4 frag (v2f i) : SV_Target
{
UnityMetaInput metaIN;
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN);
metaIN.Albedo = 1;
metaIN.Emission = _Color;
return UnityMetaFragment(metaIN);
}
ENDCG
}
}
}