259 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			HLSL
		
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			HLSL
		
	
	
	
// Curved World <http://u3d.as/1W8h>
 | 
						|
// Copyright (c) Amazing Assets <https://amazingassets.world>
 | 
						|
 
 | 
						|
 | 
						|
 | 
						|
#ifndef TERRAIN_SPLATMAP_COMMON_CGINC_INCLUDED
 | 
						|
#define TERRAIN_SPLATMAP_COMMON_CGINC_INCLUDED
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#include "../../../../Core/CurvedWorldTransform.cginc" 
 | 
						|
 | 
						|
 | 
						|
// Since 2018.3 we changed from _TERRAIN_NORMAL_MAP to _NORMALMAP to save 1 keyword.
 | 
						|
// Since 2019.2 terrain keywords are changed to  local keywords so it doesn't really matter. You can use both.
 | 
						|
#if defined(_NORMALMAP) && !defined(_TERRAIN_NORMAL_MAP)
 | 
						|
    #define _TERRAIN_NORMAL_MAP
 | 
						|
#elif !defined(_NORMALMAP) && defined(_TERRAIN_NORMAL_MAP)
 | 
						|
    #define _NORMALMAP
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(SHADER_API_GLCORE) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLES)
 | 
						|
    // GL doesn't support sperating the samplers from the texture object
 | 
						|
    #undef TERRAIN_USE_SEPARATE_VERTEX_SAMPLER
 | 
						|
#else
 | 
						|
    #define TERRAIN_USE_SEPARATE_VERTEX_SAMPLER
 | 
						|
#endif
 | 
						|
 | 
						|
struct Input
 | 
						|
{
 | 
						|
    float4 tc;
 | 
						|
    #ifndef TERRAIN_BASE_PASS
 | 
						|
        UNITY_FOG_COORDS(0) // needed because finalcolor oppresses fog code generation.
 | 
						|
    #endif
 | 
						|
};
 | 
						|
 | 
						|
sampler2D _Control;
 | 
						|
float4 _Control_ST;
 | 
						|
float4 _Control_TexelSize;
 | 
						|
sampler2D _Splat0, _Splat1, _Splat2, _Splat3;
 | 
						|
float4 _Splat0_ST, _Splat1_ST, _Splat2_ST, _Splat3_ST;
 | 
						|
 | 
						|
#if defined(UNITY_INSTANCING_ENABLED) && !defined(SHADER_API_D3D11_9X)
 | 
						|
    // Some drivers have undefined behaviors when samplers are used from the vertex shader
 | 
						|
    // with anisotropic filtering enabled. This causes some artifacts on some devices. To be
 | 
						|
    // sure to avoid this we use the vertex_linear_clamp_sampler sampler to sample terrain
 | 
						|
    // maps from the VS when we can.
 | 
						|
    #if defined(TERRAIN_USE_SEPARATE_VERTEX_SAMPLER)
 | 
						|
        UNITY_DECLARE_TEX2D(_TerrainHeightmapTexture);
 | 
						|
        UNITY_DECLARE_TEX2D(_TerrainNormalmapTexture);
 | 
						|
        SamplerState sampler__TerrainNormalmapTexture;
 | 
						|
        SamplerState vertex_linear_clamp_sampler;
 | 
						|
    #else
 | 
						|
    sampler2D _TerrainHeightmapTexture;
 | 
						|
    sampler2D _TerrainNormalmapTexture;
 | 
						|
    #endif
 | 
						|
 | 
						|
    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 _NORMALMAP
 | 
						|
    sampler2D _Normal0, _Normal1, _Normal2, _Normal3;
 | 
						|
    float _NormalScale0, _NormalScale1, _NormalScale2, _NormalScale3;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef _ALPHATEST_ON
 | 
						|
    sampler2D _TerrainHolesTexture;
 | 
						|
 | 
						|
    void ClipHoles(float2 uv)
 | 
						|
    {
 | 
						|
        float hole = tex2D(_TerrainHolesTexture, uv).r;
 | 
						|
        // Fixes bug where compression is enabled and 0 isn't actually 0 but low like 1/2047. (UUM-61913)
 | 
						|
        float epsilon = 0.0005f;
 | 
						|
        clip(hole < epsilon ? -1 : 1);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(TERRAIN_BASE_PASS) && defined(UNITY_PASS_META)
 | 
						|
    // When we render albedo for GI baking, we actually need to take the ST
 | 
						|
    float4 _MainTex_ST;
 | 
						|
#endif
 | 
						|
 | 
						|
void SplatmapVert(inout appdata_full v, out Input data)
 | 
						|
{
 | 
						|
    UNITY_INITIALIZE_OUTPUT(Input, data);
 | 
						|
 | 
						|
#if defined(UNITY_INSTANCING_ENABLED) && !defined(SHADER_API_D3D11_9X)
 | 
						|
 | 
						|
    float2 patchVertex = v.vertex.xy;
 | 
						|
    float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);
 | 
						|
 | 
						|
    float4 uvscale = instanceData.z * _TerrainHeightmapRecipSize;
 | 
						|
    float4 uvoffset = instanceData.xyxy * uvscale;
 | 
						|
    uvoffset.xy += 0.5f * _TerrainHeightmapRecipSize.xy;
 | 
						|
    float2 sampleCoords = (patchVertex.xy * uvscale.xy + uvoffset.xy);
 | 
						|
 | 
						|
    #if defined(TERRAIN_USE_SEPARATE_VERTEX_SAMPLER)
 | 
						|
        float hm = UnpackHeightmap(_TerrainHeightmapTexture.SampleLevel(vertex_linear_clamp_sampler, sampleCoords, 0));
 | 
						|
    #else
 | 
						|
    float hm = UnpackHeightmap(tex2Dlod(_TerrainHeightmapTexture, float4(sampleCoords, 0, 0)));
 | 
						|
    #endif
 | 
						|
 | 
						|
    v.vertex.xz = (patchVertex.xy + instanceData.xy) * _TerrainHeightmapScale.xz * instanceData.z;  //(x + xBase) * hmScale.x * skipScale;
 | 
						|
    v.vertex.y = hm * _TerrainHeightmapScale.y;
 | 
						|
    v.vertex.w = 1.0f;
 | 
						|
 | 
						|
    v.texcoord.xy = (patchVertex.xy * uvscale.zw + uvoffset.zw);
 | 
						|
    v.texcoord3 = v.texcoord2 = v.texcoord1 = v.texcoord;
 | 
						|
 | 
						|
    #ifdef TERRAIN_INSTANCED_PERPIXEL_NORMAL
 | 
						|
        v.normal = float3(0, 1, 0); // TODO: reconstruct the tangent space in the pixel shader. Seems to be hard with surface shader especially when other attributes are packed together with tSpace.
 | 
						|
        data.tc.zw = sampleCoords;
 | 
						|
    #else
 | 
						|
        #if defined(TERRAIN_USE_SEPARATE_VERTEX_SAMPLER)
 | 
						|
            float3 nor = _TerrainNormalmapTexture.SampleLevel(vertex_linear_clamp_sampler, sampleCoords, 0).xyz;
 | 
						|
        #else
 | 
						|
        float3 nor = tex2Dlod(_TerrainNormalmapTexture, float4(sampleCoords, 0, 0)).xyz;
 | 
						|
        #endif
 | 
						|
        v.normal = 2.0f * nor - 1.0f;
 | 
						|
    #endif
 | 
						|
#endif
 | 
						|
 | 
						|
    v.tangent.xyz = cross(v.normal, float3(0,0,1));
 | 
						|
    v.tangent.w = -1;
 | 
						|
 | 
						|
    data.tc.xy = v.texcoord.xy;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
     
 | 
						|
#if defined(CURVEDWORLD_IS_INSTALLED) && !defined(CURVEDWORLD_DISABLED_ON)
 | 
						|
   #ifdef CURVEDWORLD_NORMAL_TRANSFORMATION_ON
 | 
						|
      float4 tangent = float4(cross(v.normal, float3(0, 0, 1)), -1);
 | 
						|
      CURVEDWORLD_TRANSFORM_VERTEX_AND_NORMAL(v.vertex, v.normal, tangent)
 | 
						|
   #else
 | 
						|
      CURVEDWORLD_TRANSFORM_VERTEX(v.vertex)
 | 
						|
   #endif
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#ifdef TERRAIN_BASE_PASS
 | 
						|
    #ifdef UNITY_PASS_META
 | 
						|
        data.tc.xy = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
 | 
						|
    #endif
 | 
						|
#else
 | 
						|
    float4 pos = UnityObjectToClipPos(v.vertex);
 | 
						|
    UNITY_TRANSFER_FOG(data, pos);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
#ifndef TERRAIN_BASE_PASS
 | 
						|
 | 
						|
#ifdef TERRAIN_STANDARD_SHADER
 | 
						|
void SplatmapMix(Input IN, half4 defaultAlpha, out half4 splat_control, out half weight, out fixed4 mixedDiffuse, inout fixed3 mixedNormal)
 | 
						|
#else
 | 
						|
void SplatmapMix(Input IN, out half4 splat_control, out half weight, out fixed4 mixedDiffuse, inout fixed3 mixedNormal)
 | 
						|
#endif
 | 
						|
{
 | 
						|
    #ifdef _ALPHATEST_ON
 | 
						|
        ClipHoles(IN.tc.xy);
 | 
						|
    #endif
 | 
						|
 | 
						|
    // adjust splatUVs so the edges of the terrain tile lie on pixel centers
 | 
						|
    float2 splatUV = (IN.tc.xy * (_Control_TexelSize.zw - 1.0f) + 0.5f) * _Control_TexelSize.xy;
 | 
						|
    splat_control = tex2D(_Control, splatUV);
 | 
						|
    weight = dot(splat_control, half4(1,1,1,1));
 | 
						|
 | 
						|
    #if !defined(SHADER_API_MOBILE) && defined(TERRAIN_SPLAT_ADDPASS)
 | 
						|
        clip(weight == 0.0f ? -1 : 1);
 | 
						|
    #endif
 | 
						|
 | 
						|
    // Normalize weights before lighting and restore weights in final modifier functions so that the overal
 | 
						|
    // lighting result can be correctly weighted.
 | 
						|
    splat_control /= (weight + 1e-3f);
 | 
						|
 | 
						|
    float2 uvSplat0 = TRANSFORM_TEX(IN.tc.xy, _Splat0);
 | 
						|
    float2 uvSplat1 = TRANSFORM_TEX(IN.tc.xy, _Splat1);
 | 
						|
    float2 uvSplat2 = TRANSFORM_TEX(IN.tc.xy, _Splat2);
 | 
						|
    float2 uvSplat3 = TRANSFORM_TEX(IN.tc.xy, _Splat3);
 | 
						|
 | 
						|
    mixedDiffuse = 0.0f;
 | 
						|
    #ifdef TERRAIN_STANDARD_SHADER
 | 
						|
        mixedDiffuse += splat_control.r * tex2D(_Splat0, uvSplat0) * half4(1.0, 1.0, 1.0, defaultAlpha.r);
 | 
						|
        mixedDiffuse += splat_control.g * tex2D(_Splat1, uvSplat1) * half4(1.0, 1.0, 1.0, defaultAlpha.g);
 | 
						|
        mixedDiffuse += splat_control.b * tex2D(_Splat2, uvSplat2) * half4(1.0, 1.0, 1.0, defaultAlpha.b);
 | 
						|
        mixedDiffuse += splat_control.a * tex2D(_Splat3, uvSplat3) * half4(1.0, 1.0, 1.0, defaultAlpha.a);
 | 
						|
    #else
 | 
						|
        mixedDiffuse += splat_control.r * tex2D(_Splat0, uvSplat0);
 | 
						|
        mixedDiffuse += splat_control.g * tex2D(_Splat1, uvSplat1);
 | 
						|
        mixedDiffuse += splat_control.b * tex2D(_Splat2, uvSplat2);
 | 
						|
        mixedDiffuse += splat_control.a * tex2D(_Splat3, uvSplat3);
 | 
						|
    #endif
 | 
						|
 | 
						|
    #ifdef _NORMALMAP
 | 
						|
        mixedNormal  = UnpackNormalWithScale(tex2D(_Normal0, uvSplat0), _NormalScale0) * splat_control.r;
 | 
						|
        mixedNormal += UnpackNormalWithScale(tex2D(_Normal1, uvSplat1), _NormalScale1) * splat_control.g;
 | 
						|
        mixedNormal += UnpackNormalWithScale(tex2D(_Normal2, uvSplat2), _NormalScale2) * splat_control.b;
 | 
						|
        mixedNormal += UnpackNormalWithScale(tex2D(_Normal3, uvSplat3), _NormalScale3) * splat_control.a;
 | 
						|
#if defined(SHADER_API_SWITCH)
 | 
						|
        mixedNormal.z += UNITY_HALF_MIN; // to avoid nan after normalizing
 | 
						|
#else
 | 
						|
        mixedNormal.z += 1e-5f; // to avoid nan after normalizing
 | 
						|
#endif
 | 
						|
    #endif
 | 
						|
 | 
						|
    #if defined(INSTANCING_ON) && defined(SHADER_TARGET_SURFACE_ANALYSIS) && defined(TERRAIN_INSTANCED_PERPIXEL_NORMAL)
 | 
						|
        mixedNormal = float3(0, 0, 1); // make sure that surface shader compiler realizes we write to normal, as UNITY_INSTANCING_ENABLED is not defined for SHADER_TARGET_SURFACE_ANALYSIS.
 | 
						|
    #endif
 | 
						|
 | 
						|
    #if defined(UNITY_INSTANCING_ENABLED) && !defined(SHADER_API_D3D11_9X) && defined(TERRAIN_INSTANCED_PERPIXEL_NORMAL)
 | 
						|
 | 
						|
        #if defined(TERRAIN_USE_SEPARATE_VERTEX_SAMPLER)
 | 
						|
            float3 geomNormal = normalize(_TerrainNormalmapTexture.Sample(sampler__TerrainNormalmapTexture, IN.tc.zw).xyz * 2 - 1);
 | 
						|
        #else
 | 
						|
        float3 geomNormal = normalize(tex2D(_TerrainNormalmapTexture, IN.tc.zw).xyz * 2 - 1);
 | 
						|
        #endif
 | 
						|
 | 
						|
        #ifdef _NORMALMAP
 | 
						|
            float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
 | 
						|
            float3 geomBitangent = normalize(cross(geomTangent, geomNormal));
 | 
						|
            mixedNormal = mixedNormal.x * geomTangent
 | 
						|
                          + mixedNormal.y * geomBitangent
 | 
						|
                          + mixedNormal.z * geomNormal;
 | 
						|
        #else
 | 
						|
            mixedNormal = geomNormal;
 | 
						|
        #endif
 | 
						|
        mixedNormal = mixedNormal.xzy;
 | 
						|
    #endif
 | 
						|
}
 | 
						|
 | 
						|
#ifndef TERRAIN_SURFACE_OUTPUT
 | 
						|
    #define TERRAIN_SURFACE_OUTPUT SurfaceOutput
 | 
						|
#endif
 | 
						|
 | 
						|
void SplatmapFinalColor(Input IN, TERRAIN_SURFACE_OUTPUT o, inout fixed4 color)
 | 
						|
{
 | 
						|
    color *= o.Alpha;
 | 
						|
    #ifdef TERRAIN_SPLAT_ADDPASS
 | 
						|
        UNITY_APPLY_FOG_COLOR(IN.fogCoord, color, fixed4(0,0,0,0));
 | 
						|
    #else
 | 
						|
        UNITY_APPLY_FOG(IN.fogCoord, color);
 | 
						|
    #endif
 | 
						|
}
 | 
						|
 | 
						|
void SplatmapFinalGBuffer(Input IN, TERRAIN_SURFACE_OUTPUT o, inout half4 outGBuffer0, inout half4 outGBuffer1, inout half4 outGBuffer2, inout half4 emission)
 | 
						|
{
 | 
						|
    UnityStandardDataApplyWeightToGbuffer(outGBuffer0, outGBuffer1, outGBuffer2, o.Alpha);
 | 
						|
    emission *= o.Alpha;
 | 
						|
}
 | 
						|
 | 
						|
#endif // TERRAIN_BASE_PASS
 | 
						|
 | 
						|
#endif // TERRAIN_SPLATMAP_COMMON_CGINC_INCLUDED
 |