347 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			HLSL
		
	
	
	
		
		
			
		
	
	
			347 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			HLSL
		
	
	
	
| 
								 | 
							
								// Curved World <http://u3d.as/1W8h>
							 | 
						||
| 
								 | 
							
								// Copyright (c) Amazing Assets <https://amazingassets.world>
							 | 
						||
| 
								 | 
							
								 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#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
							 | 
						||
| 
								 | 
							
								    fixed4 _TreeInstanceColor;
							 | 
						||
| 
								 | 
							
								    float4 _TreeInstanceScale;
							 | 
						||
| 
								 | 
							
								    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
							 | 
						||
| 
								 | 
							
								    UNITY_VERTEX_INPUT_INSTANCE_ID
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct appdata_tree_billboard {
							 | 
						||
| 
								 | 
							
								    float4 vertex : POSITION;
							 | 
						||
| 
								 | 
							
								    fixed4 color : COLOR;           // Color
							 | 
						||
| 
								 | 
							
								    float4 texcoord : TEXCOORD0;    // UV Coordinates
							 | 
						||
| 
								 | 
							
								    float2 texcoord1 : TEXCOORD1;   // Billboard extrusion
							 | 
						||
| 
								 | 
							
								    UNITY_VERTEX_INPUT_INSTANCE_ID
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ---- 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)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    CURVEDWORLD_TRANSFORM_VERTEX(v.vertex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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 *= _TreeInstanceScale.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)).xyz;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // billboard tangent
							 | 
						||
| 
								 | 
							
								    float3 tanb = normalize(mul(float4(tangent.xyz, 0.0f), mat)).xyz;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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(unity_ObjectToWorld._14_24_34, 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;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 |