-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathTerrainEngine.cginc
More file actions
374 lines (286 loc) · 11.7 KB
/
TerrainEngine.cginc
File metadata and controls
374 lines (286 loc) · 11.7 KB
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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
#ifndef TERRAIN_ENGINE_INCLUDED
#define TERRAIN_ENGINE_INCLUDED
// Terrain engine shader helpers
CBUFFER_START(UnityTerrain)
// grass
fixed4 _WavingTint;
float4 _WaveAndDistance; // wind speed, wave size, wind amount, max sqr distance
float4 _CameraPosition; // .xyz = camera position, .w = 1 / (max sqr distance)
float3 _CameraRight, _CameraUp;
// trees
float4 _Scale;
float4x4 _TerrainEngineBendTree;
float4 _SquashPlaneNormal;
float _SquashAmount;
// billboards
float3 _TreeBillboardCameraRight;
float4 _TreeBillboardCameraUp;
float4 _TreeBillboardCameraFront;
float4 _TreeBillboardCameraPos;
float4 _TreeBillboardDistances; // x = max distance ^ 2
CBUFFER_END
// ---- Vertex input structures
struct appdata_tree {
float4 vertex : POSITION; // position
float4 tangent : TANGENT; // directional AO
float3 normal : NORMAL; // normal
fixed4 color : COLOR; // .w = bend factor
float4 texcoord : TEXCOORD0; // UV
};
struct appdata_tree_billboard {
float4 vertex : POSITION;
fixed4 color : COLOR; // Color
float4 texcoord : TEXCOORD0; // UV Coordinates
float2 texcoord1 : TEXCOORD1; // Billboard extrusion
};
// ---- Grass helpers
// Calculate a 4 fast sine-cosine pairs
// val: the 4 input values - each must be in the range (0 to 1)
// s: The sine of each of the 4 values
// c: The cosine of each of the 4 values
void FastSinCos (float4 val, out float4 s, out float4 c) {
val = val * 6.408849 - 3.1415927;
// powers for taylor series
float4 r5 = val * val; // wavevec ^ 2
float4 r6 = r5 * r5; // wavevec ^ 4;
float4 r7 = r6 * r5; // wavevec ^ 6;
float4 r8 = r6 * r5; // wavevec ^ 8;
float4 r1 = r5 * val; // wavevec ^ 3
float4 r2 = r1 * r5; // wavevec ^ 5;
float4 r3 = r2 * r5; // wavevec ^ 7;
//Vectors for taylor's series expansion of sin and cos
float4 sin7 = {1, -0.16161616, 0.0083333, -0.00019841};
float4 cos8 = {-0.5, 0.041666666, -0.0013888889, 0.000024801587};
// sin
s = val + r1 * sin7.y + r2 * sin7.z + r3 * sin7.w;
// cos
c = 1 + r5 * cos8.x + r6 * cos8.y + r7 * cos8.z + r8 * cos8.w;
}
fixed4 TerrainWaveGrass (inout float4 vertex, float waveAmount, fixed4 color)
{
float4 _waveXSize = float4(0.012, 0.02, 0.06, 0.024) * _WaveAndDistance.y;
float4 _waveZSize = float4 (0.006, .02, 0.02, 0.05) * _WaveAndDistance.y;
float4 waveSpeed = float4 (0.3, .5, .4, 1.2) * 4;
float4 _waveXmove = float4(0.012, 0.02, -0.06, 0.048) * 2;
float4 _waveZmove = float4 (0.006, .02, -0.02, 0.1);
float4 waves;
waves = vertex.x * _waveXSize;
waves += vertex.z * _waveZSize;
// Add in time to model them over time
waves += _WaveAndDistance.x * waveSpeed;
float4 s, c;
waves = frac (waves);
FastSinCos (waves, s,c);
s = s * s;
s = s * s;
float lighting = dot (s, normalize (float4 (1,1,.4,.2))) * .7;
s = s * waveAmount;
float3 waveMove = float3 (0,0,0);
waveMove.x = dot (s, _waveXmove);
waveMove.z = dot (s, _waveZmove);
vertex.xz -= waveMove.xz * _WaveAndDistance.z;
// apply color animation
// fix for dx11/etc warning
fixed3 waveColor = lerp (fixed3(0.5,0.5,0.5), _WavingTint.rgb, fixed3(lighting,lighting,lighting));
// Fade the grass out before detail distance.
// Saturate because Radeon HD drivers on OS X 10.4.10 don't saturate vertex colors properly.
float3 offset = vertex.xyz - _CameraPosition.xyz;
color.a = saturate (2 * (_WaveAndDistance.w - dot (offset, offset)) * _CameraPosition.w);
return fixed4(2 * waveColor * color.rgb, color.a);
}
void TerrainBillboardGrass( inout float4 pos, float2 offset )
{
float3 grasspos = pos.xyz - _CameraPosition.xyz;
if (dot(grasspos, grasspos) > _WaveAndDistance.w)
offset = 0.0;
pos.xyz += offset.x * _CameraRight.xyz;
pos.xyz += offset.y * _CameraUp.xyz;
}
// Grass: appdata_full usage
// color - .xyz = color, .w = wave scale
// normal - normal
// tangent.xy - billboard extrusion
// texcoord - UV coords
// texcoord1 - 2nd UV coords
void WavingGrassVert (inout appdata_full v)
{
// MeshGrass v.color.a: 1 on top vertices, 0 on bottom vertices
// _WaveAndDistance.z == 0 for MeshLit
float waveAmount = v.color.a * _WaveAndDistance.z;
v.color = TerrainWaveGrass (v.vertex, waveAmount, v.color);
}
void WavingGrassBillboardVert (inout appdata_full v)
{
TerrainBillboardGrass (v.vertex, v.tangent.xy);
// wave amount defined by the grass height
float waveAmount = v.tangent.y;
v.color = TerrainWaveGrass (v.vertex, waveAmount, v.color);
}
// ---- Tree helpers
inline float4 Squash(in float4 pos)
{
// To squash the tree the vertex needs to be moved in the direction
// of the squash plane. The plane is defined by the the:
// plane point - point lying on the plane, defined in model space
// plane normal - _SquashPlaneNormal.xyz
// we're pushing squashed tree plane in direction of planeNormal by amount of _SquashPlaneNormal.w
// this squashing has to match logic of tree billboards
float3 planeNormal = _SquashPlaneNormal.xyz;
// unoptimized version:
//float3 planePoint = -planeNormal * _SquashPlaneNormal.w;
//float3 projectedVertex = pos.xyz + dot(planeNormal, (planePoint - pos)) * planeNormal;
// optimized version:
float3 projectedVertex = pos.xyz - (dot(planeNormal.xyz, pos.xyz) + _SquashPlaneNormal.w) * planeNormal;
pos = float4(lerp(projectedVertex, pos.xyz, _SquashAmount), 1);
return pos;
}
void TerrainAnimateTree( inout float4 pos, float alpha )
{
pos.xyz *= _Scale.xyz;
float3 bent = mul(_TerrainEngineBendTree, float4(pos.xyz, 0.0)).xyz;
pos.xyz = lerp( pos.xyz, bent, alpha );
pos = Squash(pos);
}
// ---- Billboarded tree helpers
void TerrainBillboardTree( inout float4 pos, float2 offset, float offsetz )
{
float3 treePos = pos.xyz - _TreeBillboardCameraPos.xyz;
float treeDistanceSqr = dot(treePos, treePos);
if( treeDistanceSqr > _TreeBillboardDistances.x )
offset.xy = offsetz = 0.0;
// positioning of billboard vertices horizontally
pos.xyz += _TreeBillboardCameraRight.xyz * offset.x;
// tree billboards can have non-uniform scale,
// so when looking from above (or bellow) we must use
// billboard width as billboard height
// 1) non-compensating
//pos.xyz += _TreeBillboardCameraUp.xyz * offset.y;
// 2) correct compensating (?)
//float alpha = _TreeBillboardCameraPos.w;
//float a = offset.y;
//float b = offsetz;
// 2a) using elipse-radius formula
////float r = abs(a * b) / sqrt(sqr(a * sin(alpha)) + sqr(b * cos(alpha))) * sign(b);
//float r = abs(a) * b / sqrt(sqr(a * sin(alpha)) + sqr(b * cos(alpha)));
// 2b) sin-cos lerp
//float r = b * sin(alpha) + a * cos(alpha);
//pos.xyz += _TreeBillboardCameraUp.xyz * r;
// 3) incorrect compensating (using lerp)
// _TreeBillboardCameraPos.w contains ImposterRenderTexture::GetBillboardAngleFactor()
//float billboardAngleFactor = _TreeBillboardCameraPos.w;
//float r = lerp(offset.y, offsetz, billboardAngleFactor);
//pos.xyz += _TreeBillboardCameraUp.xyz * r;
// so now we take solution #3 and complicate it even further...
//
// case 49851: Flying trees
// The problem was that tree billboard was fixed on it's center, which means
// the root of the tree is not fixed and can float around. This can be quite visible
// on slopes (checkout the case on fogbugz for screenshots).
//
// We're fixing this by fixing billboards to the root of the tree.
// Note that root of the tree is not necessary the bottom of the tree -
// there might be significant part of the tree bellow terrain.
// This fixation mode doesn't work when looking from above/below, because
// billboard is so close to the ground, so we offset it by certain distance
// when viewing angle is bigger than certain treshold (40 deg at the moment)
// _TreeBillboardCameraPos.w contains ImposterRenderTexture::billboardAngleFactor
float billboardAngleFactor = _TreeBillboardCameraPos.w;
// The following line performs two things:
// 1) peform non-uniform scale, see "3) incorrect compensating (using lerp)" above
// 2) blend between vertical and horizontal billboard mode
float radius = lerp(offset.y, offsetz, billboardAngleFactor);
// positioning of billboard vertices veritally
pos.xyz += _TreeBillboardCameraUp.xyz * radius;
// _TreeBillboardCameraUp.w contains ImposterRenderTexture::billboardOffsetFactor
float billboardOffsetFactor = _TreeBillboardCameraUp.w;
// Offsetting billboad from the ground, so it doesn't get clipped by ztest.
// In theory we should use billboardCenterOffsetY instead of offset.x,
// but we can't because offset.y is not the same for all 4 vertices, so
// we use offset.x which is the same for all 4 vertices (except sign).
// And it doesn't matter a lot how much we offset, we just need to offset
// it by some distance
pos.xyz += _TreeBillboardCameraFront.xyz * abs(offset.x) * billboardOffsetFactor;
}
// ---- Tree Creator
float4 _Wind;
// Expand billboard and modify normal + tangent to fit
inline void ExpandBillboard (in float4x4 mat, inout float4 pos, inout float3 normal, inout float4 tangent)
{
// tangent.w = 0 if this is a billboard
float isBillboard = 1.0f - abs(tangent.w);
// billboard normal
float3 norb = normalize(mul(float4(normal, 0), mat));
// billboard tangent
float3 tanb = normalize(mul(float4(tangent.xyz, 0.0f), mat));
pos += mul(float4(normal.xy, 0, 0), mat) * isBillboard;
normal = lerp(normal, norb, isBillboard);
tangent = lerp(tangent, float4(tanb, -1.0f), isBillboard);
}
float4 SmoothCurve( float4 x ) {
return x * x *( 3.0 - 2.0 * x );
}
float4 TriangleWave( float4 x ) {
return abs( frac( x + 0.5 ) * 2.0 - 1.0 );
}
float4 SmoothTriangleWave( float4 x ) {
return SmoothCurve( TriangleWave( x ) );
}
// Detail bending
inline float4 AnimateVertex(float4 pos, float3 normal, float4 animParams)
{
// animParams stored in color
// animParams.x = branch phase
// animParams.y = edge flutter factor
// animParams.z = primary factor
// animParams.w = secondary factor
float fDetailAmp = 0.1f;
float fBranchAmp = 0.3f;
// Phases (object, vertex, branch)
float fObjPhase = dot(_Object2World[3].xyz, 1);
float fBranchPhase = fObjPhase + animParams.x;
float fVtxPhase = dot(pos.xyz, animParams.y + fBranchPhase);
// x is used for edges; y is used for branches
float2 vWavesIn = _Time.yy + float2(fVtxPhase, fBranchPhase );
// 1.975, 0.793, 0.375, 0.193 are good frequencies
float4 vWaves = (frac( vWavesIn.xxyy * float4(1.975, 0.793, 0.375, 0.193) ) * 2.0 - 1.0);
vWaves = SmoothTriangleWave( vWaves );
float2 vWavesSum = vWaves.xz + vWaves.yw;
// Edge (xz) and branch bending (y)
float3 bend = animParams.y * fDetailAmp * normal.xyz;
bend.y = animParams.w * fBranchAmp;
pos.xyz += ((vWavesSum.xyx * bend) + (_Wind.xyz * vWavesSum.y * animParams.w)) * _Wind.w;
// Primary bending
// Displace position
pos.xyz += animParams.z * _Wind.xyz;
return pos;
}
void TreeVertBark (inout appdata_full v)
{
v.vertex.xyz *= _Scale.xyz;
v.vertex = AnimateVertex(v.vertex, v.normal, float4(v.color.xy, v.texcoord1.xy));
v.vertex = Squash(v.vertex);
v.color = float4 (1, 1, 1, v.color.a);
v.normal = normalize(v.normal);
v.tangent.xyz = normalize(v.tangent.xyz);
}
void TreeVertLeaf (inout appdata_full v)
{
ExpandBillboard (UNITY_MATRIX_IT_MV, v.vertex, v.normal, v.tangent);
v.vertex.xyz *= _Scale.xyz;
v.vertex = AnimateVertex (v.vertex,v.normal, float4(v.color.xy, v.texcoord1.xy));
v.vertex = Squash(v.vertex);
v.color = float4 (1, 1, 1, v.color.a);
v.normal = normalize(v.normal);
v.tangent.xyz = normalize(v.tangent.xyz);
}
// ---- Obsolete
// Use appdata_full instead
struct appdata_grass {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL; // normal
fixed4 color : COLOR; // XSize, ySize, wavyness, unused
float4 texcoord : TEXCOORD0; // UV Coordinates
float4 texcoord1 : TEXCOORD1; // Billboard extrusion
};
#endif