240 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			HLSL
		
	
	
	
	
	
		
		
			
		
	
	
			240 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			HLSL
		
	
	
	
	
	
|  | #ifndef UNIVERSAL_SPEEDTREE7_PASSES_INCLUDED | ||
|  | #define UNIVERSAL_SPEEDTREE7_PASSES_INCLUDED | ||
|  | 
 | ||
|  | #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" | ||
|  | #include "SpeedTree7CommonPasses.hlsl" | ||
|  | 
 | ||
|  | void InitializeData(inout SpeedTreeVertexInput input, float lodValue) | ||
|  | { | ||
|  |     float3 finalPosition = input.vertex.xyz; | ||
|  | 
 | ||
|  |     #ifdef ENABLE_WIND | ||
|  |         float windEnabled = dot(_ST_WindVector.xyz, _ST_WindVector.xyz) > 0.0f ? 1.0f : 0.0f; | ||
|  |         half windQuality = _WindQuality * windEnabled; | ||
|  | 
 | ||
|  |         float3 rotatedWindVector, rotatedBranchAnchor; | ||
|  |         if (windQuality <= WIND_QUALITY_NONE) | ||
|  |         { | ||
|  |             rotatedWindVector = float3(0.0f, 0.0f, 0.0f); | ||
|  |             rotatedBranchAnchor = float3(0.0f, 0.0f, 0.0f); | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             // compute rotated wind parameters | ||
|  |             rotatedWindVector = normalize(mul(_ST_WindVector.xyz, (float3x3)UNITY_MATRIX_M)); | ||
|  |             rotatedBranchAnchor = normalize(mul(_ST_WindBranchAnchor.xyz, (float3x3)UNITY_MATRIX_M)) * _ST_WindBranchAnchor.w; | ||
|  |         } | ||
|  |     #endif | ||
|  | 
 | ||
|  |     #if defined(GEOM_TYPE_BRANCH) || defined(GEOM_TYPE_FROND) | ||
|  | 
 | ||
|  |         // smooth LOD | ||
|  |         #ifdef LOD_FADE_PERCENTAGE | ||
|  |             finalPosition = lerp(finalPosition, input.texcoord1.xyz, lodValue); | ||
|  |         #endif | ||
|  | 
 | ||
|  |         // frond wind, if needed | ||
|  |         #if defined(ENABLE_WIND) && defined(GEOM_TYPE_FROND) | ||
|  |             if (windQuality == WIND_QUALITY_PALM) | ||
|  |                 finalPosition = RippleFrond(finalPosition, input.normal, input.texcoord.x, input.texcoord.y, input.texcoord2.x, input.texcoord2.y, input.texcoord2.z); | ||
|  |         #endif | ||
|  | 
 | ||
|  |     #elif defined(GEOM_TYPE_LEAF) | ||
|  | 
 | ||
|  |         // remove anchor position | ||
|  |         finalPosition -= input.texcoord1.xyz; | ||
|  | 
 | ||
|  |         bool isFacingLeaf = input.color.a == 0; | ||
|  |         if (isFacingLeaf) | ||
|  |         { | ||
|  |             #ifdef LOD_FADE_PERCENTAGE | ||
|  |                 finalPosition *= lerp(1.0, input.texcoord1.w, lodValue); | ||
|  |             #endif | ||
|  |             // face camera-facing leaf to camera | ||
|  |             float offsetLen = length(finalPosition); | ||
|  |             finalPosition = mul(finalPosition.xyz, (float3x3)UNITY_MATRIX_IT_MV); // inv(MV) * finalPosition | ||
|  |             finalPosition = normalize(finalPosition) * offsetLen; // make sure the offset vector is still scaled | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             #ifdef LOD_FADE_PERCENTAGE | ||
|  |                 float3 lodPosition = float3(input.texcoord1.w, input.texcoord3.x, input.texcoord3.y); | ||
|  |                 finalPosition = lerp(finalPosition, lodPosition, lodValue); | ||
|  |             #endif | ||
|  |         } | ||
|  | 
 | ||
|  |         #ifdef ENABLE_WIND | ||
|  |             // leaf wind | ||
|  |             if (windQuality > WIND_QUALITY_FASTEST && windQuality < WIND_QUALITY_PALM) | ||
|  |             { | ||
|  |                 float leafWindTrigOffset = input.texcoord1.x + input.texcoord1.y; | ||
|  |                 finalPosition = LeafWind(windQuality == WIND_QUALITY_BEST, input.texcoord2.w > 0.0, finalPosition, input.normal, input.texcoord2.x, float3(0,0,0), input.texcoord2.y, input.texcoord2.z, leafWindTrigOffset, rotatedWindVector); | ||
|  |             } | ||
|  |         #endif | ||
|  | 
 | ||
|  |         // move back out to anchor | ||
|  |         finalPosition += input.texcoord1.xyz; | ||
|  | 
 | ||
|  |     #endif | ||
|  | 
 | ||
|  |     #ifdef ENABLE_WIND | ||
|  |         float3 treePos = float3(UNITY_MATRIX_M[0].w, UNITY_MATRIX_M[1].w, UNITY_MATRIX_M[2].w); | ||
|  | 
 | ||
|  |         #ifndef GEOM_TYPE_MESH | ||
|  |             if (windQuality >= WIND_QUALITY_BETTER) | ||
|  |             { | ||
|  |                 // branch wind (applies to all 3D geometry) | ||
|  |                 finalPosition = BranchWind(windQuality == WIND_QUALITY_PALM, finalPosition, treePos, float4(input.texcoord.zw, 0, 0), rotatedWindVector, rotatedBranchAnchor); | ||
|  |             } | ||
|  |         #endif | ||
|  | 
 | ||
|  |         // global wind | ||
|  |         if (windQuality > WIND_QUALITY_NONE) | ||
|  |         { | ||
|  |             finalPosition = GlobalWind(finalPosition, treePos, true, rotatedWindVector, _ST_WindGlobal.x); | ||
|  |         } | ||
|  |     #endif | ||
|  | 
 | ||
|  |     input.vertex.xyz = finalPosition; | ||
|  | } | ||
|  | 
 | ||
|  | SpeedTreeVertexOutput SpeedTree7Vert(SpeedTreeVertexInput input) | ||
|  | { | ||
|  |     SpeedTreeVertexOutput output = (SpeedTreeVertexOutput)0; | ||
|  |     UNITY_SETUP_INSTANCE_ID(input); | ||
|  |     UNITY_TRANSFER_INSTANCE_ID(input, output); | ||
|  |     UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); | ||
|  | 
 | ||
|  |     // handle speedtree wind and lod | ||
|  |     InitializeData(input, unity_LODFade.x); | ||
|  | 
 | ||
|  |     #ifdef VERTEX_COLOR | ||
|  |         output.color = _Color; | ||
|  |         output.color.rgb *= input.color.r; // ambient occlusion factor | ||
|  |     #endif | ||
|  | 
 | ||
|  |     output.uvHueVariation.xy = input.texcoord.xy; | ||
|  | 
 | ||
|  |     #ifdef EFFECT_HUE_VARIATION | ||
|  |         half hueVariationAmount = frac(UNITY_MATRIX_M[0].w + UNITY_MATRIX_M[1].w + UNITY_MATRIX_M[2].w); | ||
|  |         hueVariationAmount += frac(input.vertex.x + input.normal.y + input.normal.x) * 0.5 - 0.3; | ||
|  |         output.uvHueVariation.z = saturate(hueVariationAmount * _HueVariation.a); | ||
|  |     #endif | ||
|  | 
 | ||
|  |     #ifdef GEOM_TYPE_BRANCH_DETAIL | ||
|  |         // The two types are always in different sub-range of the mesh so no interpolation (between detail and blend) problem. | ||
|  |         output.detail.xy = input.texcoord2.xy; | ||
|  |         output.detail.z = input.color.a == 0 ? input.texcoord2.z : 2.5; // stay out of Blend's .z range | ||
|  |     #endif | ||
|  | 
 | ||
|  |     VertexPositionInputs vertexInput = GetVertexPositionInputs(input.vertex.xyz); | ||
|  |     half3 normalWS = TransformObjectToWorldNormal(input.normal); | ||
|  | 
 | ||
|  |     half3 vertexLight = VertexLighting(vertexInput.positionWS, normalWS); | ||
|  | 
 | ||
|  |     half fogFactor = 0; | ||
|  |     #if !defined(_FOG_FRAGMENT) | ||
|  |         fogFactor = ComputeFogFactor(vertexInput.positionCS.z); | ||
|  |     #endif | ||
|  |     output.fogFactorAndVertexLight = half4(fogFactor, vertexLight); | ||
|  | 
 | ||
|  |     half3 viewDirWS = GetWorldSpaceNormalizeViewDir(vertexInput.positionWS); | ||
|  | 
 | ||
|  |     #ifdef EFFECT_BUMP | ||
|  |         real sign = input.tangent.w * GetOddNegativeScale(); | ||
|  |         output.normalWS.xyz = normalWS; | ||
|  |         output.tangentWS.xyz = TransformObjectToWorldDir(input.tangent.xyz); | ||
|  |         output.bitangentWS.xyz = cross(output.normalWS.xyz, output.tangentWS.xyz) * sign; | ||
|  | 
 | ||
|  |         // View dir packed in w. | ||
|  |         output.normalWS.w = viewDirWS.x; | ||
|  |         output.tangentWS.w = viewDirWS.y; | ||
|  |         output.bitangentWS.w = viewDirWS.z; | ||
|  |     #else | ||
|  |         output.normalWS = normalWS; | ||
|  |         output.viewDirWS = viewDirWS; | ||
|  |     #endif | ||
|  | 
 | ||
|  |     #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR) | ||
|  |         output.shadowCoord = GetShadowCoord(vertexInput); | ||
|  |     #endif | ||
|  | 
 | ||
|  |     output.positionWS = vertexInput.positionWS; | ||
|  |     output.clipPos = vertexInput.positionCS; | ||
|  | 
 | ||
|  |     OUTPUT_SH4(vertexInput.positionWS, output.normalWS.xyz, GetWorldSpaceNormalizeViewDir(vertexInput.positionWS), output.vertexSH, output.probeOcclusion); | ||
|  | 
 | ||
|  |     return output; | ||
|  | } | ||
|  | 
 | ||
|  | SpeedTreeVertexDepthOutput SpeedTree7VertDepth(SpeedTreeVertexInput input) | ||
|  | { | ||
|  |     SpeedTreeVertexDepthOutput output = (SpeedTreeVertexDepthOutput)0; | ||
|  |     UNITY_SETUP_INSTANCE_ID(input); | ||
|  |     UNITY_TRANSFER_INSTANCE_ID(input, output); | ||
|  |     UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); | ||
|  | 
 | ||
|  |     // handle speedtree wind and lod | ||
|  |     InitializeData(input, unity_LODFade.x); | ||
|  |     output.uvHueVariation.xy = input.texcoord.xy; | ||
|  |     VertexPositionInputs vertexInput = GetVertexPositionInputs(input.vertex.xyz); | ||
|  | 
 | ||
|  |     output.viewDirWS = GetWorldSpaceNormalizeViewDir(vertexInput.positionWS); | ||
|  | 
 | ||
|  | #ifdef SHADOW_CASTER | ||
|  |     half3 normalWS = TransformObjectToWorldNormal(input.normal); | ||
|  | 
 | ||
|  | #if _CASTING_PUNCTUAL_LIGHT_SHADOW | ||
|  |     float3 lightDirectionWS = normalize(_LightPosition - vertexInput.positionWS); | ||
|  | #else | ||
|  |     float3 lightDirectionWS = _LightDirection; | ||
|  | #endif | ||
|  | 
 | ||
|  |     output.clipPos = TransformWorldToHClip(ApplyShadowBias(vertexInput.positionWS, normalWS, lightDirectionWS)); | ||
|  | #else | ||
|  |     output.clipPos = vertexInput.positionCS; | ||
|  | #endif | ||
|  |     return output; | ||
|  | } | ||
|  | 
 | ||
|  | SpeedTreeVertexDepthNormalOutput SpeedTree7VertDepthNormal(SpeedTreeVertexInput input) | ||
|  | { | ||
|  |     SpeedTreeVertexDepthNormalOutput output = (SpeedTreeVertexDepthNormalOutput)0; | ||
|  |     UNITY_SETUP_INSTANCE_ID(input); | ||
|  |     UNITY_TRANSFER_INSTANCE_ID(input, output); | ||
|  |     UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); | ||
|  | 
 | ||
|  |     // handle speedtree wind and lod | ||
|  |     InitializeData(input, unity_LODFade.x); | ||
|  |     output.uvHueVariation.xy = input.texcoord.xy; | ||
|  |     VertexPositionInputs vertexInput = GetVertexPositionInputs(input.vertex.xyz); | ||
|  |     half3 normalWS = TransformObjectToWorldNormal(input.normal); | ||
|  |     half3 viewDirWS = GetWorldSpaceNormalizeViewDir(vertexInput.positionWS); | ||
|  | 
 | ||
|  |     #ifdef GEOM_TYPE_BRANCH_DETAIL | ||
|  |         // The two types are always in different sub-range of the mesh so no interpolation (between detail and blend) problem. | ||
|  |         output.detail.xy = input.texcoord2.xy; | ||
|  |         output.detail.z = input.color.a == 0 ? input.texcoord2.z : 2.5; // stay out of Blend's .z range | ||
|  |     #endif | ||
|  | 
 | ||
|  |     #ifdef EFFECT_BUMP | ||
|  |         real sign = input.tangent.w * GetOddNegativeScale(); | ||
|  |         output.normalWS.xyz = normalWS; | ||
|  |         output.tangentWS.xyz = TransformObjectToWorldDir(input.tangent.xyz); | ||
|  |         output.bitangentWS.xyz = cross(output.normalWS.xyz, output.tangentWS.xyz) * sign; | ||
|  | 
 | ||
|  |         // View dir packed in w. | ||
|  |         output.normalWS.w = viewDirWS.x; | ||
|  |         output.tangentWS.w = viewDirWS.y; | ||
|  |         output.bitangentWS.w = viewDirWS.z; | ||
|  |     #else | ||
|  |         output.normalWS = normalWS; | ||
|  |         output.viewDirWS = viewDirWS; | ||
|  |     #endif | ||
|  | 
 | ||
|  |     output.clipPos = vertexInput.positionCS; | ||
|  |     return output; | ||
|  | } | ||
|  | 
 | ||
|  | #endif |