123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- #ifndef UNIVERSAL_SPEEDTREE8_PASSES_INCLUDED
- #define UNIVERSAL_SPEEDTREE8_PASSES_INCLUDED
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
- struct SpeedTreeVertexInput
- {
- float4 vertex : POSITION;
- float3 normal : NORMAL;
- float4 tangent : TANGENT;
- float4 texcoord : TEXCOORD0;
- float4 texcoord1 : TEXCOORD1;
- float4 texcoord2 : TEXCOORD2;
- float4 texcoord3 : TEXCOORD3;
- float4 color : COLOR;
- UNITY_VERTEX_INPUT_INSTANCE_ID
- };
- struct SpeedTreeVertexOutput
- {
- half2 uv : TEXCOORD0;
- half4 color : TEXCOORD1;
- half4 fogFactorAndVertexLight : TEXCOORD2; // x: fogFactor, yzw: vertex light
- #ifdef EFFECT_BUMP
- half4 normalWS : TEXCOORD3; // xyz: normal, w: viewDir.x
- half4 tangentWS : TEXCOORD4; // xyz: tangent, w: viewDir.y
- half4 bitangentWS : TEXCOORD5; // xyz: bitangent, w: viewDir.z
- #else
- half3 normalWS : TEXCOORD3;
- half3 viewDirWS : TEXCOORD4;
- #endif
- #ifdef _MAIN_LIGHT_SHADOWS
- float4 shadowCoord : TEXCOORD6;
- #endif
- float3 positionWS : TEXCOORD7;
- float4 clipPos : SV_POSITION;
- UNITY_VERTEX_INPUT_INSTANCE_ID
- UNITY_VERTEX_OUTPUT_STEREO
- };
- struct SpeedTreeVertexDepthOutput
- {
- half2 uv : TEXCOORD0;
- half4 color : TEXCOORD1;
- float4 clipPos : SV_POSITION;
- UNITY_VERTEX_INPUT_INSTANCE_ID
- UNITY_VERTEX_OUTPUT_STEREO
- };
- struct SpeedTreeFragmentInput
- {
- SpeedTreeVertexOutput interpolated;
- #ifdef EFFECT_BACKSIDE_NORMALS
- half facing : VFACE;
- #endif
- };
- void InitializeData(inout SpeedTreeVertexInput input, float lodValue)
- {
- // smooth LOD
- #if defined(LOD_FADE_PERCENTAGE) && !defined(EFFECT_BILLBOARD)
- input.vertex.xyz = lerp(input.vertex.xyz, input.texcoord2.xyz, lodValue);
- #endif
- // wind
- #if defined(ENABLE_WIND) && !defined(_WINDQUALITY_NONE)
- if (_WindEnabled > 0)
- {
- float3 rotatedWindVector = mul(_ST_WindVector.xyz, (float3x3)unity_ObjectToWorld);
- float windLength = length(rotatedWindVector);
- if (windLength < 1e-5)
- {
- // sanity check that wind data is available
- return;
- }
- rotatedWindVector /= windLength;
- float3 treePos = float3(unity_ObjectToWorld[0].w, unity_ObjectToWorld[1].w, unity_ObjectToWorld[2].w);
- float3 windyPosition = input.vertex.xyz;
- #ifndef EFFECT_BILLBOARD
- // geometry type
- float geometryType = (int)(input.texcoord3.w + 0.25);
- bool leafTwo = false;
- if (geometryType > GEOM_TYPE_FACINGLEAF)
- {
- geometryType -= 2;
- leafTwo = true;
- }
- // leaves
- if (geometryType > GEOM_TYPE_FROND)
- {
- // remove anchor position
- float3 anchor = float3(input.texcoord1.zw, input.texcoord2.w);
- windyPosition -= anchor;
- if (geometryType == GEOM_TYPE_FACINGLEAF)
- {
- // face camera-facing leaf to camera
- float offsetLen = length(windyPosition);
- windyPosition = mul(windyPosition.xyz, (float3x3)UNITY_MATRIX_IT_MV); // inv(MV) * windyPosition
- windyPosition = normalize(windyPosition) * offsetLen; // make sure the offset vector is still scaled
- }
- // leaf wind
- #if defined(_WINDQUALITY_FAST) || defined(_WINDQUALITY_BETTER) || defined(_WINDQUALITY_BEST)
- #ifdef _WINDQUALITY_BEST
- bool bBestWind = true;
- #else
- bool bBestWind = false;
- #endif
- float leafWindTrigOffset = anchor.x + anchor.y;
- windyPosition = LeafWind(bBestWind, leafTwo, windyPosition, input.normal, input.texcoord3.x, float3(0,0,0), input.texcoord3.y, input.texcoord3.z, leafWindTrigOffset, rotatedWindVector);
- #endif
- // move back out to anchor
- windyPosition += anchor;
- }
- // frond wind
- bool bPalmWind = false;
- #ifdef _WINDQUALITY_PALM
- bPalmWind = true;
- if (geometryType == GEOM_TYPE_FROND)
- {
- windyPosition = RippleFrond(windyPosition, input.normal, input.texcoord.x, input.texcoord.y, input.texcoord3.x, input.texcoord3.y, input.texcoord3.z);
- }
- #endif
- // branch wind (applies to all 3D geometry)
- #if defined(_WINDQUALITY_BETTER) || defined(_WINDQUALITY_BEST) || defined(_WINDQUALITY_PALM)
- float3 rotatedBranchAnchor = normalize(mul(_ST_WindBranchAnchor.xyz, (float3x3)unity_ObjectToWorld)) * _ST_WindBranchAnchor.w;
- windyPosition = BranchWind(bPalmWind, windyPosition, treePos, float4(input.texcoord.zw, 0, 0), rotatedWindVector, rotatedBranchAnchor);
- #endif
- #endif // !EFFECT_BILLBOARD
- // global wind
- float globalWindTime = _ST_WindGlobal.x;
- #if defined(EFFECT_BILLBOARD) && defined(UNITY_INSTANCING_ENABLED)
- globalWindTime += UNITY_ACCESS_INSTANCED_PROP(STWind, _GlobalWindTime);
- #endif
- windyPosition = GlobalWind(windyPosition, treePos, true, rotatedWindVector, globalWindTime);
- input.vertex.xyz = windyPosition;
- }
- #endif
- #if defined(EFFECT_BILLBOARD)
- float3 treePos = float3(UNITY_MATRIX_M[0].w, UNITY_MATRIX_M[1].w, UNITY_MATRIX_M[2].w);
- // crossfade faces
- bool topDown = (input.texcoord.z > 0.5);
- float3 viewDir = UNITY_MATRIX_IT_MV[2].xyz;
- float3 cameraDir = normalize(mul((float3x3)UNITY_MATRIX_M, _WorldSpaceCameraPos - treePos));
- float viewDot = max(dot(viewDir, input.normal), dot(cameraDir, input.normal));
- viewDot *= viewDot;
- viewDot *= viewDot;
- viewDot += topDown ? 0.38 : 0.18; // different scales for horz and vert billboards to fix transition zone
- // if invisible, avoid overdraw
- if (viewDot < 0.3333)
- {
- input.vertex.xyz = float3(0, 0, 0);
- }
- input.color = float4(1, 1, 1, clamp(viewDot, 0, 1));
- // adjust lighting on billboards to prevent seams between the different faces
- if (topDown)
- {
- input.normal += cameraDir;
- }
- else
- {
- half3 binormal = cross(input.normal, input.tangent.xyz) * input.tangent.w;
- float3 right = cross(cameraDir, binormal);
- input.normal = cross(binormal, right);
- }
- input.normal = normalize(input.normal);
- #endif
- }
- SpeedTreeVertexOutput SpeedTree8Vert(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);
- output.uv = input.texcoord.xy;
- output.color = input.color;
- // color already contains (ao, ao, ao, blend)
- // put hue variation amount in there
- #ifdef EFFECT_HUE_VARIATION
- float3 treePos = float3(UNITY_MATRIX_M[0].w, UNITY_MATRIX_M[1].w, UNITY_MATRIX_M[2].w);
- float hueVariationAmount = frac(treePos.x + treePos.y + treePos.z);
- output.color.g = saturate(hueVariationAmount * _HueVariationColor.a);
- #endif
- VertexPositionInputs vertexInput = GetVertexPositionInputs(input.vertex.xyz);
- half3 normalWS = TransformObjectToWorldNormal(input.normal);
- half3 vertexLight = VertexLighting(vertexInput.positionWS, normalWS);
- half fogFactor = ComputeFogFactor(vertexInput.positionCS.z);
- output.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
- half3 viewDirWS = GetCameraPositionWS() - 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
- #ifdef _MAIN_LIGHT_SHADOWS
- output.shadowCoord = GetShadowCoord(vertexInput);
- #endif
- output.positionWS = vertexInput.positionWS;
- output.clipPos = vertexInput.positionCS;
- return output;
- }
- SpeedTreeVertexDepthOutput SpeedTree8VertDepth(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.uv = input.texcoord.xy;
- output.color = input.color;
- VertexPositionInputs vertexInput = GetVertexPositionInputs(input.vertex.xyz);
- #ifdef SHADOW_CASTER
- half3 normalWS = TransformObjectToWorldNormal(input.normal);
- float4 positionCS = TransformWorldToHClip(ApplyShadowBias(vertexInput.positionWS, normalWS, _LightDirection));
- output.clipPos = positionCS;
- #else
- output.clipPos = vertexInput.positionCS;
- #endif
- return output;
- }
- void InitializeInputData(SpeedTreeFragmentInput input, half3 normalTS, out InputData inputData)
- {
- inputData.positionWS = input.interpolated.positionWS.xyz;
- #ifdef EFFECT_BUMP
- inputData.normalWS = TransformTangentToWorld(normalTS, half3x3(input.interpolated.tangentWS.xyz, input.interpolated.bitangentWS.xyz, input.interpolated.normalWS.xyz));
- inputData.normalWS = NormalizeNormalPerPixel(inputData.normalWS);
- inputData.viewDirectionWS = half3(input.interpolated.normalWS.w, input.interpolated.tangentWS.w, input.interpolated.bitangentWS.w);
- #else
- inputData.normalWS = NormalizeNormalPerPixel(input.interpolated.normalWS);
- inputData.viewDirectionWS = input.interpolated.viewDirWS;
- #endif
- #if SHADER_HINT_NICE_QUALITY
- inputData.viewDirectionWS = SafeNormalize(inputData.viewDirectionWS);
- #endif
- #ifdef _MAIN_LIGHT_SHADOWS
- inputData.shadowCoord = input.interpolated.shadowCoord;
- #else
- inputData.shadowCoord = float4(0, 0, 0, 0);
- #endif
- inputData.fogCoord = input.interpolated.fogFactorAndVertexLight.x;
- inputData.vertexLighting = input.interpolated.fogFactorAndVertexLight.yzw;
- inputData.bakedGI = half3(0, 0, 0); // No GI currently.
- }
- half4 SpeedTree8Frag(SpeedTreeFragmentInput input) : SV_Target
- {
- UNITY_SETUP_INSTANCE_ID(input.interpolated);
- #if !defined(SHADER_QUALITY_LOW)
- #ifdef LOD_FADE_CROSSFADE // enable dithering LOD transition if user select CrossFade transition in LOD group
- #ifdef EFFECT_BILLBOARD
- LODDitheringTransition(input.interpolated.clipPos.xy, unity_LODFade.x);
- #endif
- #endif
- #endif
- half2 uv = input.interpolated.uv;
- half4 diffuse = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_MainTex, sampler_MainTex)) * _Color;
- half alpha = diffuse.a * input.interpolated.color.a;
- AlphaDiscard(alpha - 0.3333, 0.0);
- half3 albedo = diffuse.rgb;
- half3 emission = 0;
- half metallic = 0;
- half smoothness = 0;
- half occlusion = 0;
- half3 specular = 0;
- // hue variation
- #ifdef EFFECT_HUE_VARIATION
- half3 shiftedColor = lerp(albedo, _HueVariationColor.rgb, input.interpolated.color.g);
- // preserve vibrance
- half maxBase = max(albedo.r, max(albedo.g, albedo.b));
- half newMaxBase = max(shiftedColor.r, max(shiftedColor.g, shiftedColor.b));
- maxBase /= newMaxBase;
- maxBase = maxBase * 0.5f + 0.5f;
- shiftedColor.rgb *= maxBase;
- albedo = saturate(shiftedColor);
- #endif
- // normal
- #ifdef EFFECT_BUMP
- half3 normalTs = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap));
- #else
- half3 normalTs = half3(0, 0, 1);
- #endif
- // flip normal on backsides
- #ifdef EFFECT_BACKSIDE_NORMALS
- if (input.facing < 0.5)
- {
- normalTs.z = -normalTs.z;
- }
- #endif
- // adjust billboard normals to improve GI and matching
- #ifdef EFFECT_BILLBOARD
- normalTs.z *= 0.5;
- normalTs = normalize(normalTs);
- #endif
- // extra
- #ifdef EFFECT_EXTRA_TEX
- half4 extra = tex2D(_ExtraTex, uv);
- smoothness = extra.r;
- metallic = extra.g;
- occlusion = extra.b * input.interpolated.color.r;
- #else
- smoothness = _Glossiness;
- metallic = _Metallic;
- occlusion = input.interpolated.color.r;
- #endif
- // subsurface (hijack emissive)
- #ifdef EFFECT_SUBSURFACE
- emission = tex2D(_SubsurfaceTex, uv).rgb * _SubsurfaceColor.rgb;
- #endif
- InputData inputData;
- InitializeInputData(input, normalTs, inputData);
- half4 color = UniversalFragmentPBR(inputData, albedo, metallic, specular, smoothness, occlusion, emission, alpha);
- color.rgb = MixFog(color.rgb, inputData.fogCoord);
- return color;
- }
- half4 SpeedTree8FragDepth(SpeedTreeVertexDepthOutput input) : SV_Target
- {
- UNITY_SETUP_INSTANCE_ID(input);
- #if !defined(SHADER_QUALITY_LOW)
- #ifdef LOD_FADE_CROSSFADE // enable dithering LOD transition if user select CrossFade transition in LOD group
- #ifdef EFFECT_BILLBOARD
- LODDitheringTransition(input.clipPos.xy, unity_LODFade.x);
- #endif
- #endif
- #endif
- half2 uv = input.uv;
- half4 diffuse = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_MainTex, sampler_MainTex)) * _Color;
- half alpha = diffuse.a * input.color.a;
- AlphaDiscard(alpha - 0.3333, 0.0);
- #if defined(SCENESELECTIONPASS)
- // We use depth prepass for scene selection in the editor, this code allow to output the outline correctly
- return half4(_ObjectId, _PassValue, 1.0, 1.0);
- #else
- return half4(0, 0, 0, 0);
- #endif
- }
- #endif
|