123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844 |
- #ifndef UNIVERSAL_TERRAIN_LIT_PASSES_INCLUDED
- #define UNIVERSAL_TERRAIN_LIT_PASSES_INCLUDED
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
- #if defined(UNITY_INSTANCING_ENABLED) && defined(_TERRAIN_INSTANCED_PERPIXEL_NORMAL)
- #define ENABLE_TERRAIN_PERPIXEL_NORMAL
- #endif
- #ifdef UNITY_INSTANCING_ENABLED
- TEXTURE2D(_TerrainHeightmapTexture);
- TEXTURE2D(_TerrainNormalmapTexture);
- SAMPLER(sampler_TerrainNormalmapTexture);
- float4 _TerrainHeightmapRecipSize; // float4(1.0f/width, 1.0f/height, 1.0f/(width-1), 1.0f/(height-1))
- float4 _TerrainHeightmapScale; // float4(hmScale.x, hmScale.y / (float)(kMaxHeight), hmScale.z, 0.0f)
- #endif
- UNITY_INSTANCING_BUFFER_START(Terrain)
- UNITY_DEFINE_INSTANCED_PROP(float4, _TerrainPatchInstanceData) // float4(xBase, yBase, skipScale, ~)
- UNITY_INSTANCING_BUFFER_END(Terrain)
- #ifdef _ALPHATEST_ON
- // Already defined in TerrainLitinput.hlsl
- // TEXTURE2D(_TerrainHolesTexture);
- // SAMPLER(sampler_TerrainHolesTexture);
- void ClipHoles(float2 uv)
- {
- float hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, sampler_TerrainHolesTexture, uv).r;
- clip(hole == 0.0f ? -1 : 1);
- }
- #endif
- struct Attributes
- {
- float4 positionOS : POSITION;
- float3 normalOS : NORMAL;
- float2 texcoord : TEXCOORD0;
- UNITY_VERTEX_INPUT_INSTANCE_ID
- };
- struct Varyings
- {
- float4 uvMainAndLM : TEXCOORD0; // xy: control, zw: lightmap
- #ifndef TERRAIN_SPLAT_BASEPASS
- float4 uvSplat01 : TEXCOORD1; // xy: splat0, zw: splat1
- float4 uvSplat23 : TEXCOORD2; // xy: splat2, zw: splat3
- #endif
- #if ( defined(_NORMALMAP) || defined(_PARALLAX) ) && !defined(ENABLE_TERRAIN_PERPIXEL_NORMAL)
- float3 normal : TEXCOORD3; // xyz: normal, w: viewDir.x
- float4 tangent : TEXCOORD4; // xyz: tangent, w: viewDir.y
- float3 viewDir : TEXCOORD5;
- #else
- float3 normal : TEXCOORD3;
- float3 viewDir : TEXCOORD4;
- half3 vertexSH : TEXCOORD5; // SH
- #endif
- half4 fogFactorAndVertexLight : TEXCOORD6; // x: fogFactor, yzw: vertex light
- float3 positionWS : TEXCOORD7;
- #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
- float4 shadowCoord : TEXCOORD8;
- #endif
- float4 clipPos : SV_POSITION;
- UNITY_VERTEX_INPUT_INSTANCE_ID
- UNITY_VERTEX_OUTPUT_STEREO
- };
- // -----------------------------------------------------------------------------------------------
- // Procedural Mapping
- real Lux_Luminance(real3 linearRgb) {
- return dot(linearRgb, real3(0.2126729, 0.7151522, 0.0721750));
- }
- void GetProceduralBaseSample(
- Texture2D sampleTex, SamplerState samplerTex, float2 uv,
- #ifdef _TERRAIN_BLEND_HEIGHT
- inout half result,
- #else
- inout half4 result,
- #endif
- inout float2 uv1, inout float2 uv2, inout float2 uv3,
- inout half w1, inout half w2, inout half w3, inout float2 duvdx, inout float2 duvdy)
- {
- float2 uvScaled = uv * 3.464 * _ProceduralScale;
- const float2x2 gridToSkewedGrid = float2x2(1.0, 0.0, -0.57735027, 1.15470054);
- float2 skewedCoord = mul(gridToSkewedGrid, uvScaled);
- int2 baseId = int2(floor(skewedCoord));
- float3 temp = float3(frac(skewedCoord), 0);
- temp.z = 1.0 - temp.x - temp.y;
-
- int2 vertex1, vertex2, vertex3;
- if (temp.z > 0.0) {
- w1 = temp.z;
- w2 = temp.y;
- w3 = temp.x;
- vertex1 = baseId;
- vertex2 = baseId + int2(0, 1);
- vertex3 = baseId + int2(1, 0);
- }
- else {
- w1 = -temp.z;
- w2 = 1.0 - temp.y;
- w3 = 1.0 - temp.x;
- vertex1 = baseId + int2(1, 1);
- vertex2 = baseId + int2(1, 0);
- vertex3 = baseId + int2(0, 1);
- }
- const float2x2 hashMatrix = float2x2(127.1, 311.7, 269.5, 183.3);
- const float hashFactor = 3758.5453;
- uv1 = uv + frac(sin(mul(hashMatrix, (float2)vertex1)) * hashFactor);
- uv2 = uv + frac(sin(mul(hashMatrix, (float2)vertex2)) * hashFactor);
- uv3 = uv + frac(sin(mul(hashMatrix, (float2)vertex3)) * hashFactor);
- // Use a hash function which does not include sin
- // Adds a little bit visible tiling...
- // float2 uv1 = uv + hash22( (float2)vertex1 );
- // float2 uv2 = uv + hash22( (float2)vertex2 );
- // float2 uv3 = uv + hash22( (float2)vertex3 );
- duvdx = ddx(uv);
- duvdy = ddy(uv);
- // Here we have to sample first as we want to calculate the wights based on luminance
- // Albedo – Sample Gaussion values from transformed input
- #ifdef _TERRAIN_BLEND_HEIGHT
- half G1 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv1, duvdx, duvdy).r;
- half G2 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv2, duvdx, duvdy).r;
- half G3 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv3, duvdx, duvdy).r;
- // Weight by Height - somehow
- w1 *= G1;
- w2 *= G2;
- w3 *= G3;
- #else
- half4 G1 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv1, duvdx, duvdy);
- half4 G2 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv2, duvdx, duvdy);
- half4 G3 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv3, duvdx, duvdy);
- // Weight by Luminance
- w1 *= Lux_Luminance(G1.rgb);
- w2 *= Lux_Luminance(G2.rgb);
- w3 *= Lux_Luminance(G3.rgb);
- #endif
-
- // Get weights
- half exponent = 1.0h + _ProceduralBlend * 15.0h;
- w1 = pow(w1, exponent);
- w2 = pow(w2, exponent);
- w3 = pow(w3, exponent);
- // Lets help the compiler here:
- half sum = 1.0h / (w1 + w2 + w3);
- w1 = w1 * sum;
- w2 = w2 * sum;
- w3 = w3 * sum;
-
- // Result
- result = w1 * G1 + w2 * G2 + w3 * G3;
- }
- half4 sampleProcedural(Texture2D sampleTex, SamplerState samplerTex, float2 uv, float2 uv1, float2 uv2, float2 uv3, half w1, half w2, half w3, float2 duvdx, float2 duvdy) {
- half4 G1 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv1, duvdx, duvdy);
- half4 G2 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv2, duvdx, duvdy);
- half4 G3 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv3, duvdx, duvdy);
- return w1 * G1 + w2 * G2 + w3 * G3;
- }
- half1 sampleProceduralHalf(Texture2D sampleTex, SamplerState samplerTex, float2 uv, float2 uv1, float2 uv2, float2 uv3, half w1, half w2, half w3, float2 duvdx, float2 duvdy) {
- half G1 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv1, duvdx, duvdy).r;
- half G2 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv2, duvdx, duvdy).r;
- half G3 = SAMPLE_TEXTURE2D_GRAD(sampleTex, samplerTex, uv3, duvdx, duvdy).r;
- return w1 * G1 + w2 * G2 + w3 * G3;
- }
- // -----------------------------------------------------------------------------------------------
- // ---------------------------
- void InitializeInputData(Varyings IN, half3 normalTS, half3x3 tangentSpaceRotation, half3 viewDirWS, out InputData input)
- {
- input = (InputData)0;
- input.positionWS = IN.positionWS;
- half3 SH = half3(0, 0, 0);
- // Most of this is passed in
- /*
- #if ( defined(_NORMALMAP) || defined (_PARALLAX) ) && !defined(ENABLE_TERRAIN_PERPIXEL_NORMAL)
- //half3 viewDirWS = half3(IN.normal.w, IN.tangent.w, IN.bitangent.w);
- half3 viewDirWS = IN.viewDir;
- float sgn = input.tangentWS.w; // should be either +1 or -1
- float3 bitangent = sgn * cross(IN.normalWS.xyz, IN.tangentWS.xyz);
- input.normalWS = TransformTangentToWorld(normalTS, half3x3(IN.tangent.xyz, bitangent, IN.normal.xyz));
- SH = SampleSH(input.normalWS.xyz);
-
- #elif defined(ENABLE_TERRAIN_PERPIXEL_NORMAL)
- half3 viewDirWS = IN.viewDir;
- float2 sampleCoords = (IN.uvMainAndLM.xy / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
- half3 normalWS = TransformObjectToWorldNormal(normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, sampler_TerrainNormalmapTexture, sampleCoords).rgb * 2 - 1));
-
- // fix orientation
- half3 tangentWS = cross(GetObjectToWorldMatrix()._13_23_33, normalWS) * -1;
- input.normalWS = TransformTangentToWorld(normalTS, half3x3(tangentWS, -cross(normalWS, tangentWS), normalWS));
- SH = SampleSH(input.normalWS.xyz);
- #else
- half3 viewDirWS = IN.viewDir;
- input.normalWS = IN.normal;
- SH = IN.vertexSH;
- #endif
- #if SHADER_HINT_NICE_QUALITY
- viewDirWS = SafeNormalize(viewDirWS);
- #endif
- */
-
- // So this is all that has to be done
- #if defined(_NORMALMAP) || defined (_PARALLAX) || defined(ENABLE_TERRAIN_PERPIXEL_NORMAL)
- input.normalWS = TransformTangentToWorld(normalTS, tangentSpaceRotation);
- SH = SampleSH(input.normalWS.xyz);
- #else
- input.normalWS = IN.normal;
- SH = IN.vertexSH;
- #endif
- input.normalWS = NormalizeNormalPerPixel(input.normalWS);
- input.viewDirectionWS = viewDirWS;
-
- #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
- input.shadowCoord = IN.shadowCoord;
- #elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
- input.shadowCoord = TransformWorldToShadowCoord(input.positionWS);
- #else
- input.shadowCoord = float4(0, 0, 0, 0);
- #endif
- input.fogCoord = IN.fogFactorAndVertexLight.x;
- input.vertexLighting = IN.fogFactorAndVertexLight.yzw;
- input.bakedGI = SAMPLE_GI(IN.uvMainAndLM.zw, SH, input.normalWS);
- //input.normalizedScreenSpaceUV = IN.clipPos.xy;
- input.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(IN.clipPos.xy);
- input.shadowMask = SAMPLE_SHADOWMASK(IN.uvMainAndLM.zw);
- }
- #ifdef _TERRAIN_BLEND_HEIGHT
- void HeightBasedSplatModifyCombined(inout half4 splatControl, in half4 heights, inout half height) {
- #ifndef TERRAIN_SPLAT_ADDPASS // disable for multi-pass
- half4 defaultHeight = heights;
- half4 mweights = splatControl * max(defaultHeight, 1e-5);
- // Go parallel
- half maxWeight = max( max(mweights.x, mweights.y), max(mweights.z, mweights.w) );
- half mtransition = max(_HeightTransition * maxWeight, 1e-5);
- half mthreshold = maxWeight - mtransition;
- half mscale = 1.0h / mtransition;
- mweights = saturate((mweights - mthreshold ) / mtransition); // * mscale );
- half sumHeight = mweights.x + mweights.y + mweights.z + mweights.w;
- half sumSplat = splatControl.x+splatControl.y+splatControl.z+splatControl.w;
- splatControl = mweights / sumHeight;
- // Must not get more than before...
- splatControl *= sumSplat;
- height = maxWeight;
- #endif
- }
- #endif
- // Splatting ----------------------------------------------
- #ifndef TERRAIN_SPLAT_BASEPASS
- void SplatmapMix(float4 uvMainAndLM, float4 uvSplat01, float4 uvSplat23, inout half4 splatControl, out half weight, out half4 mixedDiffuse, out half4 defaultSmoothness, inout half3 mixedNormal)
- {
- // Sample albedo and smoothness
- half4 diffAlbedo[4];
-
- // We may use procedural texturing but do not use height based blending
- #if defined(_PROCEDURALTEXTURING) && !defined(_TERRAIN_BLEND_HEIGHT)
- half4 diffAlbedoNull;
- float2 uv1, uv2, uv3;
- half w1, w2, w3;
- float2 duvdx, duvdy;
- GetProceduralBaseSample(_Splat0, sampler_Splat0, uvSplat01.xy, diffAlbedoNull, uv1, uv2, uv3, w1, w2, w3, duvdx, duvdy);
- diffAlbedo[0] = diffAlbedoNull;
- #else
- diffAlbedo[0] = SAMPLE_TEXTURE2D(_Splat0, sampler_Splat0, uvSplat01.xy);
- #endif
- diffAlbedo[1] = SAMPLE_TEXTURE2D(_Splat1, sampler_Splat0, uvSplat01.zw);
- diffAlbedo[2] = SAMPLE_TEXTURE2D(_Splat2, sampler_Splat0, uvSplat23.xy);
- diffAlbedo[3] = SAMPLE_TEXTURE2D(_Splat3, sampler_Splat0, uvSplat23.zw);
- defaultSmoothness = half4(diffAlbedo[0].a, diffAlbedo[1].a, diffAlbedo[2].a, diffAlbedo[3].a);
- defaultSmoothness *= half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3);
- // Now that splatControl has changed, we can compute the final weight and normalize
- weight = dot(splatControl, 1.0h);
- #ifdef TERRAIN_SPLAT_ADDPASS
- clip(weight <= 0.005h ? -1.0h : 1.0h);
- #endif
- #ifndef _TERRAIN_BASEMAP_GEN
- // Normalize weights before lighting and restore weights in final modifier functions so that the overal
- // lighting result can be correctly weighted.
- splatControl /= (weight + HALF_MIN);
- #endif
- mixedDiffuse = 0.0h;
- mixedDiffuse += diffAlbedo[0] * half4(_DiffuseRemapScale0.rgb * splatControl.rrr, 1.0h);
- mixedDiffuse += diffAlbedo[1] * half4(_DiffuseRemapScale1.rgb * splatControl.ggg, 1.0h);
- mixedDiffuse += diffAlbedo[2] * half4(_DiffuseRemapScale2.rgb * splatControl.bbb, 1.0h);
- mixedDiffuse += diffAlbedo[3] * half4(_DiffuseRemapScale3.rgb * splatControl.aaa, 1.0h);
- #ifdef _NORMALMAP
- half4 normalSamples[4];
- #if defined(_PROCEDURALTEXTURING) && !defined(_TERRAIN_BLEND_HEIGHT)
- normalSamples[0] = sampleProcedural(_Normal0, sampler_Normal0, uvSplat01.xy, uv1, uv2, uv3, w1, w2, w3, duvdx, duvdy);
- #else
- normalSamples[0] = SAMPLE_TEXTURE2D(_Normal0, sampler_Normal0, uvSplat01.xy);
- #endif
- normalSamples[1] = SAMPLE_TEXTURE2D(_Normal1, sampler_Normal0, uvSplat01.zw);
- normalSamples[2] = SAMPLE_TEXTURE2D(_Normal2, sampler_Normal0, uvSplat23.xy);
- normalSamples[3] = SAMPLE_TEXTURE2D(_Normal3, sampler_Normal0, uvSplat23.zw);
-
- half4 normalSample = 0;
- normalSample = splatControl.r * normalSamples[0];
- normalSample += splatControl.g * normalSamples[1];
- normalSample += splatControl.b * normalSamples[2];
- normalSample += splatControl.a * normalSamples[3];
- half3 nrm = 0.0f;
- #if BUMP_SCALE_NOT_SUPPORTED
- nrm = UnpackNormal(normalSample);
- #else
- half normalScale = dot(half4(_NormalScale0, _NormalScale1, _NormalScale2, _NormalScale3), splatControl);
- nrm = UnpackNormalScale(normalSample, normalScale);
- #endif
-
- // avoid risk of NaN when normalizing.
- #if HAS_HALF
- nrm.z += 0.01h;
- #else
- nrm.z += 1e-5f;
- #endif
- mixedNormal = normalize(nrm.xyz);
- #endif
- //mixedDiffuse = height.xxxx;
- }
- void SplatmapMixProcedural(float4 uvMainAndLM, float4 uvSplat01, float4 uvSplat23, inout half4 splatControl, out half weight, out half4 mixedDiffuse, out half4 defaultSmoothness, inout half3 mixedNormal,
- float2 uv1, float2 uv2, float2 uv3, half w1, half w2, half w3, float2 duvdx, float2 duvdy)
- {
- // Sample albedo and smoothness
- half4 diffAlbedo[4];
- diffAlbedo[0] = sampleProcedural(_Splat0, sampler_Splat0, uvSplat01.xy, uv1, uv2, uv3, w1, w2, w3, duvdx, duvdy);
- diffAlbedo[1] = SAMPLE_TEXTURE2D(_Splat1, sampler_Splat0, uvSplat01.zw);
- diffAlbedo[2] = SAMPLE_TEXTURE2D(_Splat2, sampler_Splat0, uvSplat23.xy);
- diffAlbedo[3] = SAMPLE_TEXTURE2D(_Splat3, sampler_Splat0, uvSplat23.zw);
- defaultSmoothness = half4(diffAlbedo[0].a, diffAlbedo[1].a, diffAlbedo[2].a, diffAlbedo[3].a);
- defaultSmoothness *= half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3);
- // Now that splatControl has changed, we can compute the final weight and normalize
- weight = dot(splatControl, 1.0h);
- #ifdef TERRAIN_SPLAT_ADDPASS
- clip(weight <= 0.005h ? -1.0h : 1.0h);
- #endif
- #ifndef _TERRAIN_BASEMAP_GEN
- // Normalize weights before lighting and restore weights in final modifier functions so that the overal
- // lighting result can be correctly weighted.
- splatControl /= (weight + HALF_MIN);
- #endif
- mixedDiffuse = 0.0h;
- mixedDiffuse += diffAlbedo[0] * half4(_DiffuseRemapScale0.rgb * splatControl.rrr, 1.0h);
- mixedDiffuse += diffAlbedo[1] * half4(_DiffuseRemapScale1.rgb * splatControl.ggg, 1.0h);
- mixedDiffuse += diffAlbedo[2] * half4(_DiffuseRemapScale2.rgb * splatControl.bbb, 1.0h);
- mixedDiffuse += diffAlbedo[3] * half4(_DiffuseRemapScale3.rgb * splatControl.aaa, 1.0h);
- #ifdef _NORMALMAP
- half4 normalSamples[4];
- normalSamples[0] = sampleProcedural(_Normal0, sampler_Normal0, uvSplat01.xy, uv1, uv2, uv3, w1, w2, w3, duvdx, duvdy);
- normalSamples[1] = SAMPLE_TEXTURE2D(_Normal1, sampler_Normal0, uvSplat01.zw);
- normalSamples[2] = SAMPLE_TEXTURE2D(_Normal2, sampler_Normal0, uvSplat23.xy);
- normalSamples[3] = SAMPLE_TEXTURE2D(_Normal3, sampler_Normal0, uvSplat23.zw);
-
- half4 normalSample = 0;
- normalSample = splatControl.r * normalSamples[0];
- normalSample += splatControl.g * normalSamples[1];
- normalSample += splatControl.b * normalSamples[2];
- normalSample += splatControl.a * normalSamples[3];
- half3 nrm = 0.0f;
- #if BUMP_SCALE_NOT_SUPPORTED
- nrm = UnpackNormal(normalSample);
- #else
- half normalScale = dot(half4(_NormalScale0, _NormalScale1, _NormalScale2, _NormalScale3), splatControl);
- nrm = UnpackNormalScale(normalSample, normalScale);
- #endif
-
- // avoid risk of NaN when normalizing.
- #if HAS_HALF
- nrm.z += 0.01h;
- #else
- nrm.z += 1e-5f;
- #endif
- mixedNormal = normalize(nrm.xyz);
- #endif
- }
- #endif
- void SplatmapFinalColor(inout half4 color, half fogCoord)
- {
- color.rgb *= color.a;
- #ifdef TERRAIN_SPLAT_ADDPASS
- color.rgb = MixFogColor(color.rgb, half3(0,0,0), fogCoord);
- #else
- color.rgb = MixFog(color.rgb, fogCoord);
- #endif
- }
- void TerrainInstancing(inout float4 positionOS, inout float3 normal, inout float2 uv)
- {
- #ifdef UNITY_INSTANCING_ENABLED
- float2 patchVertex = positionOS.xy;
- float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);
- float2 sampleCoords = (patchVertex.xy + instanceData.xy) * instanceData.z;
- float height = UnpackHeightmap(_TerrainHeightmapTexture.Load(int3(sampleCoords, 0)));
- positionOS.xz = sampleCoords * _TerrainHeightmapScale.xz;
- positionOS.y = height * _TerrainHeightmapScale.y;
- #ifdef ENABLE_TERRAIN_PERPIXEL_NORMAL
- normal = float3(0, 1, 0);
- #else
- normal = _TerrainNormalmapTexture.Load(int3(sampleCoords, 0)).rgb * 2 - 1;
- #endif
- uv = sampleCoords * _TerrainHeightmapRecipSize.zw;
- #endif
- }
- void TerrainInstancing(inout float4 positionOS, inout float3 normal)
- {
- float2 uv = { 0, 0 };
- TerrainInstancing(positionOS, normal, uv);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Vertex and Fragment functions //
- ///////////////////////////////////////////////////////////////////////////////
- // Used in Standard Terrain shader
- Varyings SplatmapVert(Attributes v)
- {
- Varyings o = (Varyings)0;
- UNITY_SETUP_INSTANCE_ID(v);
- //UNITY_TRANSFER_INSTANCE_ID(v, o);
- UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
- TerrainInstancing(v.positionOS, v.normalOS, v.texcoord);
- VertexPositionInputs Attributes = GetVertexPositionInputs(v.positionOS.xyz);
- o.uvMainAndLM.xy = v.texcoord;
- o.uvMainAndLM.zw = v.texcoord * unity_LightmapST.xy + unity_LightmapST.zw;
- #ifndef TERRAIN_SPLAT_BASEPASS
- #if defined(_PROCEDURALTEXTURING)
- o.uvSplat01.xy = Attributes.positionWS.xz / _ProceduralTiling;
- #else
- o.uvSplat01.xy = TRANSFORM_TEX(v.texcoord, _Splat0);
- #endif
- o.uvSplat01.zw = TRANSFORM_TEX(v.texcoord, _Splat1);
- o.uvSplat23.xy = TRANSFORM_TEX(v.texcoord, _Splat2);
- o.uvSplat23.zw = TRANSFORM_TEX(v.texcoord, _Splat3);
- #endif
- float3 viewDirWS = GetCameraPositionWS() - Attributes.positionWS;
- #if !SHADER_HINT_NICE_QUALITY
- viewDirWS = SafeNormalize(viewDirWS);
- #endif
- #if ( defined(_NORMALMAP) || defined(_PARALLAX) ) && !defined(ENABLE_TERRAIN_PERPIXEL_NORMAL)
- float4 vertexTangent = float4(cross(float3(0, 0, 1), v.normalOS), 1.0);
- VertexNormalInputs normalInput = GetVertexNormalInputs(v.normalOS, vertexTangent);
- // fix orientation
- normalInput.tangentWS *= -1;
- o.normal = normalInput.normalWS;
- float sign = vertexTangent.w * GetOddNegativeScale();
- o.tangent = float4(normalInput.tangentWS, sign);
- #else
- o.normal = TransformObjectToWorldNormal(v.normalOS);
- o.vertexSH = SampleSH(o.normal);
- #endif
- o.viewDir = viewDirWS;
- o.fogFactorAndVertexLight.x = ComputeFogFactor(Attributes.positionCS.z);
- o.fogFactorAndVertexLight.yzw = VertexLighting(Attributes.positionWS, o.normal.xyz);
- o.positionWS = Attributes.positionWS;
- o.clipPos = Attributes.positionCS;
- #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
- o.shadowCoord = GetShadowCoord(Attributes);
- #endif
- return o;
- }
- // Used in Standard Terrain shader
- half4 SplatmapFragment(Varyings IN) : SV_TARGET {
- //UNITY_SETUP_INSTANCE_ID(IN);
- UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
- #ifdef _ALPHATEST_ON
- half hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, sampler_TerrainHolesTexture, IN.uvMainAndLM.xy).r;
- clip(hole == 0.0h ? -1 : 1);
- #endif
- half3 normalTS = half3(0.0h, 0.0h, 1.0h);
- half3x3 tangentSpaceRotation = 0;
- half3 viewDirectionWS = SafeNormalize(IN.viewDir);
- #if defined(_NORMALMAP) || defined(_PARALLAX) || defined(TERRAIN_SPLAT_BASEPASS)
- #if !defined(ENABLE_TERRAIN_PERPIXEL_NORMAL) && ( defined(_NORMALMAP) || defined(_PARALLAX) )
- // Same matrix we need to transfer the normalTS
- half3 bitangentWS = cross(IN.normal, IN.tangent.xyz) * -1;
- tangentSpaceRotation = half3x3(IN.tangent.xyz, bitangentWS, IN.normal.xyz);
- half3 tangentWS = IN.tangent.xyz;
- half3 viewDirTS = normalize( mul(tangentSpaceRotation, viewDirectionWS ) );
- #elif defined(ENABLE_TERRAIN_PERPIXEL_NORMAL)
- float2 sampleCoords = (IN.uvMainAndLM.xy / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
- half3 normalWS = TransformObjectToWorldNormal(normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, sampler_TerrainNormalmapTexture, sampleCoords).rgb * 2 - 1));
- // fix orientation
- half3 tangentWS = cross( /*GetObjectToWorldMatrix()._13_23_33*/ half3(0, 0, 1), normalWS) * -1;
- // Ups: * -1?
- half3 bitangentWS = cross(normalWS, tangentWS) * -1;
- tangentSpaceRotation = half3x3(tangentWS, bitangentWS, normalWS);
- half3 viewDirTS = normalize( mul(tangentSpaceRotation, viewDirectionWS) );
- #endif
- #endif
-
- #ifdef TERRAIN_SPLAT_BASEPASS
- half3 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uvMainAndLM.xy).rgb;
- half smoothness = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uvMainAndLM.xy).a;
- // Unity 2019.1
- half metallic = 0; //SAMPLE_TEXTURE2D(_MetallicTex, sampler_MetallicTex, IN.uvMainAndLM.xy).r;
- half alpha = 1;
- half occlusion = 1;
-
- #else
- half4 splatControl;
- half weight;
- half4 mixedDiffuse;
- half4 defaultSmoothness;
- float2 splatUV = (IN.uvMainAndLM.xy * (_Control_TexelSize.zw - 1.0f) + 0.5f) * _Control_TexelSize.xy;
- splatControl = SAMPLE_TEXTURE2D(_Control, sampler_Control, splatUV);
- // Sample heights
- #ifdef _TERRAIN_BLEND_HEIGHT
- half4 heights;
- #if defined(_PROCEDURALTEXTURING)
- half proceduralHeight;
- float2 uv1, uv2, uv3;
- half w1, w2, w3;
- float2 duvdx, duvdy;
- GetProceduralBaseSample(_HeightMaps, sampler_Splat0, IN.uvSplat01.xy, proceduralHeight, uv1, uv2, uv3, w1, w2, w3, duvdx, duvdy);
- heights.x = proceduralHeight;
- #else
- heights.x = SAMPLE_TEXTURE2D(_HeightMaps, sampler_Splat0, IN.uvSplat01.xy).r;
- #endif
- heights.y = SAMPLE_TEXTURE2D(_HeightMaps, sampler_Splat0, IN.uvSplat01.zw).g;
- heights.z = SAMPLE_TEXTURE2D(_HeightMaps, sampler_Splat0, IN.uvSplat23.xy).b;
- heights.w = SAMPLE_TEXTURE2D(_HeightMaps, sampler_Splat0, IN.uvSplat23.zw).a;
- half height;
- // Adjust spaltControl and calculate 1st height
- HeightBasedSplatModifyCombined(splatControl, heights, height);
- // Parallax Extrusion
- #if defined(_PARALLAX)
- float3 v = viewDirTS;
- v.z += 0.42;
- v.xy /= v.z;
- half halfParallax = _Parallax * 0.5h;
-
- half parallax = height * _Parallax - halfParallax;
- float2 offset1 = parallax * v.xy;
- float4 splatUV1 = IN.uvSplat01 + offset1.xyxy;
- float4 splatUV2 = IN.uvSplat23 + offset1.xyxy;
- #if defined(_PROCEDURALTEXTURING)
- uv1 += offset1.xy;
- uv2 += offset1.xy;
- uv2 += offset1.xy;
- heights.x = sampleProceduralHalf(_HeightMaps, sampler_Splat0, splatUV1.xy, uv1, uv2, uv3, w1, w2, w3, duvdx, duvdy);
- #else
- heights.x = SAMPLE_TEXTURE2D(_HeightMaps, sampler_Splat0, splatUV1.xy).r;
- #endif
- heights.y = SAMPLE_TEXTURE2D(_HeightMaps, sampler_Splat0, splatUV1.zw).g;
- heights.z = SAMPLE_TEXTURE2D(_HeightMaps, sampler_Splat0, splatUV2.xy).b;
- heights.w = SAMPLE_TEXTURE2D(_HeightMaps, sampler_Splat0, splatUV2.zw).a;
- // Calculate 2nd height
- half height1 = max( max(heights.x, heights.y), max(heights.z, heights.w) );
- parallax = height1 * _Parallax - halfParallax;
- float2 offset2 = parallax * v.xy;
-
- offset1 = (offset1 + offset2) * 0.5;
- IN.uvSplat01 = IN.uvSplat01 + offset1.xyxy * float4(1,1,1,1);
- IN.uvSplat23 = IN.uvSplat23 + offset1.xyxy * float4(1,1,1,1);
- #endif
- #endif
- #if defined(_PROCEDURALTEXTURING)
- #ifdef _TERRAIN_BLEND_HEIGHT
- SplatmapMixProcedural(IN.uvMainAndLM, IN.uvSplat01, IN.uvSplat23, splatControl, weight, mixedDiffuse, defaultSmoothness, normalTS,
- uv1, uv2, uv3, w1, w2, w3, duvdx, duvdy);
- #else
- SplatmapMix(IN.uvMainAndLM, IN.uvSplat01, IN.uvSplat23, splatControl, weight, mixedDiffuse, defaultSmoothness, normalTS);
- #endif
- #else
- SplatmapMix(IN.uvMainAndLM, IN.uvSplat01, IN.uvSplat23, splatControl, weight, mixedDiffuse, defaultSmoothness, normalTS);
- #endif
-
- half3 albedo = mixedDiffuse.rgb;
- // Looks broken...
- defaultSmoothness *= dot(half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3), splatControl);
- half smoothness = dot(defaultSmoothness, splatControl);
- half metallic = dot(half4(_Metallic0, _Metallic1, _Metallic2, _Metallic3), splatControl);
- half occlusion = 1;
- half alpha = weight;
- #endif
- InputData inputData;
- InitializeInputData(IN, normalTS, tangentSpaceRotation, viewDirectionWS, inputData);
- half4 color = UniversalFragmentPBR(inputData, albedo, metallic, /* specular */ half3(0.0h, 0.0h, 0.0h), smoothness, occlusion, /* emission */ half3(0, 0, 0), alpha);
- SplatmapFinalColor(color, inputData.fogCoord);
- return half4(color.rgb, 1.0h);
- }
- // -----------------------------------------------------------------------------
- // Shadow pass
- // x: global clip space bias, y: normal world space bias
- float3 _LightDirection;
- struct AttributesLean {
- float4 positionOS : POSITION;
- float3 normalOS : NORMAL;
- UNITY_VERTEX_INPUT_INSTANCE_ID
- UNITY_VERTEX_OUTPUT_STEREO
- };
- #ifdef _ALPHATEST_ON
- Varyings ShadowPassVertex (Attributes v)
- {
- Varyings o = (Varyings)0;
- UNITY_SETUP_INSTANCE_ID(v);
- TerrainInstancing(v.positionOS, v.normalOS, v.texcoord);
- o.uvMainAndLM.xy = v.texcoord;
- float3 positionWS = TransformObjectToWorld(v.positionOS.xyz);
- float3 normalWS = TransformObjectToWorldNormal(v.normalOS);
- float4 clipPos = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection));
- #if UNITY_REVERSED_Z
- clipPos.z = min(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE);
- #else
- clipPos.z = max(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE);
- #endif
- o.clipPos = clipPos;
- return o;
- }
- half4 ShadowPassFragment(Varyings input) : SV_TARGET {
- //ClipHoles(input.tc.xy);
- half hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, sampler_TerrainHolesTexture, input.uvMainAndLM.xy).r;
- clip(hole == 0.0h ? -1 : 1);
- return 0;
- }
- #else
- float4 ShadowPassVertex(AttributesLean v) : SV_POSITION {
- Varyings o;
- UNITY_SETUP_INSTANCE_ID(v);
- TerrainInstancing(v.positionOS, v.normalOS);
- float3 positionWS = TransformObjectToWorld(v.positionOS.xyz);
- float3 normalWS = TransformObjectToWorldNormal(v.normalOS);
- float4 clipPos = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection));
- #if UNITY_REVERSED_Z
- clipPos.z = min(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE);
- #else
- clipPos.z = max(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE);
- #endif
- return clipPos;
- }
- half4 ShadowPassFragment(Varyings input) : SV_TARGET {
- return 0;
- }
- #endif
- // -----------------------------------------------------------------------------
- // Depth pass
- //
- #ifdef _ALPHATEST_ON
- Varyings DepthOnlyVertex(Attributes v) {
- Varyings o = (Varyings)0;
- UNITY_SETUP_INSTANCE_ID(v);
- UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
- TerrainInstancing(v.positionOS, v.normalOS, v.texcoord);
- o.uvMainAndLM.xy = v.texcoord;
- o.clipPos = TransformObjectToHClip(v.positionOS.xyz);
- return o;
- }
- half4 DepthOnlyFragment(Varyings input) : SV_TARGET {
- UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
- ClipHoles(input.uvMainAndLM.xy);
- return 0;
- }
- #else
- //float4 DepthOnlyVertex(AttributesLean v) : SV_POSITION {
- Varyings DepthOnlyVertex(AttributesLean v) {
- Varyings o = (Varyings)0;
- UNITY_SETUP_INSTANCE_ID(v);
- UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
- TerrainInstancing(v.positionOS, v.normalOS);
- //return TransformObjectToHClip(v.positionOS.xyz);
- o.clipPos = TransformObjectToHClip(v.positionOS.xyz);
- return o;
- }
- half4 DepthOnlyFragment(Varyings input) : SV_TARGET {
- UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
- return 0;
- }
- #endif
- // -----------------------------------------------------------------------------
- // DepthNormal pass
-
- struct AttributesDepthNormal
- {
- float4 positionOS : POSITION;
- float3 normalOS : NORMAL;
- float2 texcoord : TEXCOORD0;
- UNITY_VERTEX_INPUT_INSTANCE_ID
- };
- struct VaryingsDepthNormal
- {
- float4 uvMainAndLM : TEXCOORD0; // xy: control, zw: lightmap
- #ifndef TERRAIN_SPLAT_BASEPASS
- float4 uvSplat01 : TEXCOORD1; // xy: splat0, zw: splat1
- float4 uvSplat23 : TEXCOORD2; // xy: splat2, zw: splat3
- #endif
- #if defined(_NORMALMAP) && !defined(ENABLE_TERRAIN_PERPIXEL_NORMAL)
- float4 normal : TEXCOORD3; // xyz: normal, w: viewDir.x
- float4 tangent : TEXCOORD4; // xyz: tangent, w: viewDir.y
- float4 bitangent : TEXCOORD5; // xyz: bitangent, w: viewDir.z
- #else
- float3 normal : TEXCOORD3;
- #endif
- float4 clipPos : SV_POSITION;
- UNITY_VERTEX_OUTPUT_STEREO
- };
- VaryingsDepthNormal DepthNormalOnlyVertex(AttributesDepthNormal v)
- {
- VaryingsDepthNormal o = (VaryingsDepthNormal)0;
- UNITY_SETUP_INSTANCE_ID(v);
- UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
- TerrainInstancing(v.positionOS, v.normalOS, v.texcoord);
- VertexPositionInputs Attributes = GetVertexPositionInputs(v.positionOS.xyz);
- o.uvMainAndLM.xy = v.texcoord;
- o.uvMainAndLM.zw = v.texcoord * unity_LightmapST.xy + unity_LightmapST.zw;
- #ifndef TERRAIN_SPLAT_BASEPASS
- o.uvSplat01.xy = TRANSFORM_TEX(v.texcoord, _Splat0);
- o.uvSplat01.zw = TRANSFORM_TEX(v.texcoord, _Splat1);
- o.uvSplat23.xy = TRANSFORM_TEX(v.texcoord, _Splat2);
- o.uvSplat23.zw = TRANSFORM_TEX(v.texcoord, _Splat3);
- #endif
- #if defined(_NORMALMAP) && !defined(ENABLE_TERRAIN_PERPIXEL_NORMAL)
- half3 viewDirWS = GetWorldSpaceViewDir(Attributes.positionWS);
- #if !SHADER_HINT_NICE_QUALITY
- viewDirWS = SafeNormalize(viewDirWS);
- #endif
- float4 vertexTangent = float4(cross(float3(0, 0, 1), v.normalOS), 1.0);
- VertexNormalInputs normalInput = GetVertexNormalInputs(v.normalOS, vertexTangent);
- o.normal = half4(normalInput.normalWS, viewDirWS.x);
- o.tangent = half4(normalInput.tangentWS, viewDirWS.y);
- o.bitangent = half4(normalInput.bitangentWS, viewDirWS.z);
- #else
- o.normal = TransformObjectToWorldNormal(v.normalOS);
- #endif
- o.clipPos = Attributes.positionCS;
- return o;
- }
- half4 DepthNormalOnlyFragment(VaryingsDepthNormal input) : SV_TARGET
- {
- #ifdef _ALPHATEST_ON
- ClipHoles(input.uvMainAndLM.xy);
- #endif
- half3 normalWS = input.normal.xyz;
- return float4(PackNormalOctRectEncode(TransformWorldToViewDir(normalWS, true)), 0.0, 0.0);
- }
- #endif
|