24438 lines
876 KiB
GLSL
24438 lines
876 KiB
GLSL
////////////////////////////////////////
|
|
// MicroSplat
|
|
// Copyright (c) Jason Booth
|
|
//
|
|
// Auto-generated shader code, don't hand edit!
|
|
//
|
|
// Unity Version: 2022.3.20f1
|
|
// MicroSplat Version: 3.9
|
|
// Render Pipeline: URP2022
|
|
// Platform: WindowsEditor
|
|
////////////////////////////////////////
|
|
|
|
|
|
Shader "ABCPolaris_"
|
|
{
|
|
Properties
|
|
{
|
|
[HideInInspector][NoScaleOffset]unity_Lightmaps("unity_Lightmaps", 2DArray) = "" {}
|
|
[HideInInspector][NoScaleOffset]unity_LightmapsInd("unity_LightmapsInd", 2DArray) = "" {}
|
|
[HideInInspector][NoScaleOffset]unity_ShadowMasks("unity_ShadowMasks", 2DArray) = "" {}
|
|
[HideInInspector] _Control0 ("Control0", 2D) = "red" {}
|
|
[HideInInspector] _Control1 ("Control1", 2D) = "black" {}
|
|
[HideInInspector] _Control2 ("Control2", 2D) = "black" {}
|
|
[HideInInspector] _Control3 ("Control3", 2D) = "black" {}
|
|
|
|
|
|
// Splats
|
|
[NoScaleOffset]_Diffuse ("Diffuse Array", 2DArray) = "white" {}
|
|
[NoScaleOffset]_NormalSAO ("Normal Array", 2DArray) = "bump" {}
|
|
[NoScaleOffset]_PerTexProps("Per Texture Properties", 2D) = "black" {}
|
|
[HideInInspector] _TerrainHolesTexture("Holes Map (RGB)", 2D) = "white" {}
|
|
[HideInInspector] _PerPixelNormal("Per Pixel Normal", 2D) = "bump" {}
|
|
_Contrast("Blend Contrast", Range(0.01, 0.99)) = 0.4
|
|
_UVScale("UV Scales", Vector) = (45, 45, 0, 0)
|
|
|
|
// for Unity 2020.3 bug
|
|
_MainTex("Unity Bug", 2D) = "white" {}
|
|
|
|
_TerrainHeightmapTexture("", 2D) = "black" {}
|
|
_TerrainNormalmapTexture("", 2D) = "bump" {}
|
|
|
|
|
|
}
|
|
SubShader
|
|
{
|
|
Tags {"RenderPipeline" = "UniversalPipeline" "RenderType" = "UniversalLitShader" "Queue" = "Geometry+100" "IgnoreProjector" = "False" "SplatCount" = "16"}
|
|
|
|
|
|
|
|
Pass
|
|
{
|
|
Name "Universal Forward"
|
|
Tags
|
|
{
|
|
"LightMode" = "UniversalForward"
|
|
}
|
|
Cull Back
|
|
Blend One Zero
|
|
ZTest LEqual
|
|
ZWrite On
|
|
|
|
|
|
|
|
|
|
|
|
HLSLPROGRAM
|
|
|
|
#pragma vertex Vert
|
|
#pragma fragment Frag
|
|
|
|
#pragma target 3.5
|
|
|
|
#pragma prefer_hlslcc gles
|
|
#pragma exclude_renderers d3d11_9x
|
|
#pragma multi_compile_fog
|
|
#pragma multi_compile_instancing
|
|
#pragma multi_compile _ DOTS_INSTANCING_ON
|
|
#pragma multi_compile_local _ _ALPHATEST_ON
|
|
#pragma instancing_options renderinglayer
|
|
|
|
// Keywords
|
|
#pragma multi_compile _ _SCREEN_SPACE_OCCLUSION
|
|
#pragma multi_compile _ LIGHTMAP_ON
|
|
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
|
|
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
|
|
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
|
|
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
|
|
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
|
|
#pragma multi_compile _ _REFLECTION_PROBE_BLENDING
|
|
#pragma multi_compile _ _REFLECTION_PROBE_BOX_PROJECTION
|
|
#pragma multi_compile _ _SHADOWS_SOFT
|
|
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
|
|
#pragma multi_compile _ SHADOWS_SHADOWMASK
|
|
#pragma multi_compile _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
|
|
#pragma multi_compile _ _LIGHT_LAYERS
|
|
#pragma multi_compile _ DEBUG_DISPLAY
|
|
#pragma multi_compile _ _LIGHT_COOKIES
|
|
#pragma multi_compile_fragment _ _WRITE_RENDERING_LAYERS
|
|
#pragma multi_compile _ _FORWARD_PLUS
|
|
|
|
// GraphKeywords: <None>
|
|
|
|
#define SHADER_PASS SHADERPASS_FORWARD
|
|
#define VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
|
|
#define _FOG_FRAGMENT 1
|
|
#define _PASSFORWARD 1
|
|
|
|
#if _SIMPLELIT
|
|
#define _SPECULAR_COLOR
|
|
#endif
|
|
|
|
|
|
|
|
#define _MICROSPLAT 1
|
|
#define _MICROPOLARISMESH 1
|
|
#define _USEGRADMIP 1
|
|
#define _PERTEXUVSCALEOFFSET 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
#define _MSRENDERLOOP_UNITYLD 1
|
|
#define _MSRENDERLOOP_UNITYURP2020 1
|
|
#define _MSRENDERLOOP_UNITYURP2021 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
|
|
|
|
|
|
#define _URP 1
|
|
|
|
|
|
|
|
// this has to be here or specular color will be ignored. Not in SG code
|
|
#if _SIMPLELIT
|
|
#define _SPECULAR_COLOR
|
|
#endif
|
|
|
|
|
|
// Includes
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
|
|
#if VERSION_GREATER_EQUAL(12, 0)
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
|
|
#endif
|
|
#include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, float3x3(d.worldSpaceTangent, cross(d.worldSpaceTangent, d.worldSpaceNormal), d.worldSpaceNormal))
|
|
|
|
|
|
#define UnityObjectToWorldNormal(normal) mul(GetObjectToWorldMatrix(), normal)
|
|
|
|
#define _WorldSpaceLightPos0 _MainLightPosition
|
|
|
|
#define UNITY_DECLARE_TEX2D(name) TEXTURE2D(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2D_NOSAMPLER(name) TEXTURE2D(name);
|
|
#define UNITY_DECLARE_TEX2DARRAY(name) TEXTURE2D_ARRAY(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2DARRAY_NOSAMPLER(name) TEXTURE2D_ARRAY(name);
|
|
|
|
#define UNITY_SAMPLE_TEX2DARRAY(tex,coord) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, coord.xy, coord.z)
|
|
#define UNITY_SAMPLE_TEX2DARRAY_LOD(tex,coord,lod) SAMPLE_TEXTURE2D_ARRAY_LOD(tex, sampler##tex, coord.xy, coord.z, lod)
|
|
#define UNITY_SAMPLE_TEX2D(tex, coord) SAMPLE_TEXTURE2D(tex, sampler##tex, coord)
|
|
#define UNITY_SAMPLE_TEX2D_SAMPLER(tex, samp, coord) SAMPLE_TEXTURE2D(tex, sampler##samp, coord)
|
|
|
|
#if defined(UNITY_COMPILER_HLSL)
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
|
|
#else
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name)
|
|
#endif
|
|
|
|
#define sampler2D_float sampler2D
|
|
#define sampler2D_half sampler2D
|
|
|
|
|
|
|
|
// data across stages, stripped like the above.
|
|
struct VertexToPixel
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float3 worldPos : TEXCOORD0;
|
|
float3 worldNormal : TEXCOORD1;
|
|
float4 worldTangent : TEXCOORD2;
|
|
float4 texcoord0 : TEXCCOORD3;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 texcoord1 : TEXCCOORD4;
|
|
// float4 texcoord2 : TEXCCOORD5;
|
|
#endif
|
|
// float4 texcoord3 : TEXCCOORD6;
|
|
// float4 screenPos : TEXCOORD7;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
// float4 extraV2F0 : TEXCOORD13;
|
|
// float4 extraV2F1 : TEXCOORD14;
|
|
// float4 extraV2F2 : TEXCOORD15;
|
|
// float4 extraV2F3 : TEXCOORD16;
|
|
// float4 extraV2F4 : TEXCOORD17;
|
|
// float4 extraV2F5 : TEXCOORD18;
|
|
// float4 extraV2F6 : TEXCOORD19;
|
|
// float4 extraV2F7 : TEXCOORD20;
|
|
|
|
|
|
#if defined(LIGHTMAP_ON)
|
|
float2 lightmapUV : TEXCOORD8;
|
|
#endif
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
float2 dynamicLightmapUV : TEXCOORD9;
|
|
#endif
|
|
#if !defined(LIGHTMAP_ON)
|
|
float3 sh : TEXCOORD10;
|
|
#endif
|
|
|
|
float4 fogFactorAndVertexLight : TEXCOORD11;
|
|
float4 shadowCoord : TEXCOORD12;
|
|
|
|
#if UNITY_ANY_INSTANCING_ENABLED
|
|
uint instanceID : CUSTOM_INSTANCE_ID;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_MULTIVIEW_ENABLED)) || (defined(UNITY_STEREO_INSTANCING_ENABLED) && (defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)))
|
|
uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_INSTANCING_ENABLED))
|
|
uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex;
|
|
#endif
|
|
#if defined(SHADER_STAGE_FRAGMENT) && defined(VARYINGS_NEED_CULLFACE)
|
|
FRONT_FACE_TYPE cullFace : FRONT_FACE_SEMANTIC;
|
|
#endif
|
|
};
|
|
|
|
|
|
// TEMPLATE_SHARED
|
|
|
|
// data describing the user output of a pixel
|
|
struct Surface
|
|
{
|
|
half3 Albedo;
|
|
half Height;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half3 Emission;
|
|
half Metallic;
|
|
half3 Specular;
|
|
half Occlusion;
|
|
half Alpha;
|
|
// HDRP Only
|
|
half SpecularOcclusion;
|
|
half SubsurfaceMask;
|
|
half Thickness;
|
|
half CoatMask;
|
|
half Anisotropy;
|
|
half IridescenceMask;
|
|
half IridescenceThickness;
|
|
};
|
|
|
|
// data the user might need, this will grow to be big. But easy to strip
|
|
struct ShaderData
|
|
{
|
|
float3 localSpacePosition;
|
|
float3 localSpaceNormal;
|
|
float3 localSpaceTangent;
|
|
|
|
float3 worldSpacePosition;
|
|
float3 worldSpaceNormal;
|
|
float3 worldSpaceTangent;
|
|
|
|
float3 worldSpaceViewDir;
|
|
float3 tangentSpaceViewDir;
|
|
|
|
float4 texcoord0;
|
|
float4 texcoord1;
|
|
float4 texcoord2;
|
|
float4 texcoord3;
|
|
|
|
float2 screenUV;
|
|
float4 screenPos;
|
|
|
|
float4 vertexColor;
|
|
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
|
|
float3x3 TBNMatrix;
|
|
};
|
|
|
|
struct VertexData
|
|
{
|
|
#if SHADER_TARGET > 30 && _PLANETCOMPUTE
|
|
// // uint vertexID : SV_VertexID;
|
|
#endif
|
|
float4 vertex : POSITION;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD4; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD5; // Add Precomputed Velocity (Alembic computes velocities on runtime side).
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct TessVertex
|
|
{
|
|
float4 vertex : INTERNALTESSPOS;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
// float4 extraV2F0 : TEXCOORD4;
|
|
// float4 extraV2F1 : TEXCOORD5;
|
|
// float4 extraV2F2 : TEXCOORD6;
|
|
// float4 extraV2F3 : TEXCOORD7;
|
|
// float4 extraV2F4 : TEXCOORD8;
|
|
// float4 extraV2F5 : TEXCOORD9;
|
|
// float4 extraV2F6 : TEXCOORD10;
|
|
// float4 extraV2F7 : TEXCOORD11;
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD12; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD13;
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
struct ExtraV2F
|
|
{
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
};
|
|
|
|
|
|
float3 WorldToTangentSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(d.TBNMatrix, normal);
|
|
}
|
|
|
|
float3 TangentToWorldSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(normal, d.TBNMatrix);
|
|
}
|
|
|
|
// in this case, make standard more like SRPs, because we can't fix
|
|
// GetWorldToObjectMatrix() in HDRP, since it already does macro-fu there
|
|
|
|
#if _STANDARD
|
|
float3 TransformWorldToObject(float3 p) { return mul(GetWorldToObjectMatrix(), float4(p, 1)); };
|
|
float3 TransformObjectToWorld(float3 p) { return mul(GetObjectToWorldMatrix(), float4(p, 1)); };
|
|
float4 TransformWorldToObject(float4 p) { return mul(GetWorldToObjectMatrix(), p); };
|
|
float4 TransformObjectToWorld(float4 p) { return mul(GetObjectToWorldMatrix(), p); };
|
|
float4x4 GetWorldToObjectMatrix() { return GetWorldToObjectMatrix(); }
|
|
float4x4 GetObjectToWorldMatrix() { return GetObjectToWorldMatrix(); }
|
|
#endif
|
|
|
|
float3 GetCameraWorldPosition()
|
|
{
|
|
#if _HDRP
|
|
return GetCameraRelativePositionWS(_WorldSpaceCameraPos);
|
|
#else
|
|
return _WorldSpaceCameraPos;
|
|
#endif
|
|
}
|
|
|
|
|
|
#if _HDRP
|
|
|
|
half3 UnpackNormalmapRGorAG(half4 packednormal)
|
|
{
|
|
// This do the trick
|
|
packednormal.x *= packednormal.w;
|
|
|
|
half3 normal;
|
|
normal.xy = packednormal.xy * 2 - 1;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
half3 UnpackNormal(half4 packednormal)
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
return packednormal.xyz * 2 - 1;
|
|
#else
|
|
return UnpackNormalmapRGorAG(packednormal);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if _HDRP || _URP
|
|
|
|
half3 UnpackScaleNormal(half4 packednormal, half scale)
|
|
{
|
|
#ifndef UNITY_NO_DXT5nm
|
|
// Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
|
|
// Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
|
|
packednormal.x *= packednormal.w;
|
|
#endif
|
|
half3 normal;
|
|
normal.xy = (packednormal.xy * 2 - 1) * scale;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void GetSun(out float3 lightDir, out float3 color)
|
|
{
|
|
lightDir = float3(0.5, 0.5, 0);
|
|
color = 1;
|
|
#if _HDRP
|
|
if (_DirectionalLightCount > 0)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[0];
|
|
lightDir = -light.forward.xyz;
|
|
color = light.color;
|
|
}
|
|
#elif _STANDARD
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
color = _LightColor0.rgb;
|
|
#elif _URP
|
|
Light light = GetMainLight();
|
|
lightDir = light.direction;
|
|
color = light.color;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
|
|
|
|
|
|
#if _MESHSUBARRAY
|
|
half4 _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
float4 _Diffuse_TexelSize;
|
|
float4 _NormalSAO_TexelSize;
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
float _HybridHeightBlendDistance;
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
float4 _SmoothAO_TexelSize;
|
|
#endif
|
|
|
|
#ifdef _ALPHATEST_ON
|
|
float4 _TerrainHolesTexture_TexelSize;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
float4 _Specular_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
float4 _EmissiveMetal_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
half _EmissiveMult;
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
half _AutoNormalHeightScale;
|
|
#endif
|
|
|
|
float4 _UVScale; // scale and offset
|
|
|
|
half _Contrast;
|
|
|
|
|
|
|
|
#if _VSSHADOWMAP
|
|
float4 gVSSunDirection;
|
|
#endif
|
|
|
|
#if _FORCELOCALSPACE && _PLANETVECTORS
|
|
float4x4 _PQSToLocal;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
float4x4 _GlobalOriginMTX;
|
|
#endif
|
|
|
|
float4 _Control0_TexelSize;
|
|
#if _CUSTOMSPLATTEXTURES
|
|
float4 _CustomControl0_TexelSize;
|
|
#endif
|
|
float4 _PerPixelNormal_TexelSize;
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
float2 _NoiseUVParams;
|
|
#endif
|
|
|
|
float4 _PerTexProps_TexelSize;
|
|
|
|
#if _SURFACENORMALS
|
|
float3 surfTangent;
|
|
float3 surfBitangent;
|
|
float3 surfNormal;
|
|
#endif
|
|
|
|
|
|
|
|
CBUFFER_END
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, data.TBN)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// In Unity 2020.3LTS, Unity will spew tons of errors about missing this sampler in
|
|
// URP, even though it shouldn't be required.
|
|
TEXTURE2D(_MainTex);
|
|
|
|
// globals, outside of CBuffer, but used by more than one module
|
|
float3 _gGlitterLightDir;
|
|
float3 _gGlitterLightWorldPos;
|
|
half3 _gGlitterLightColor;
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
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)
|
|
float4 _TerrainNormalmapTexture_TexelSize;
|
|
#endif
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
TEXTURE2D(_TerrainHeightmapTexture);
|
|
float4 _TerrainHeightmapTexture_TexelSize;
|
|
TEXTURE2D(_TerrainNormalmapTexture);
|
|
#endif
|
|
|
|
UNITY_INSTANCING_BUFFER_START(Terrain)
|
|
UNITY_DEFINE_INSTANCED_PROP(float4, _TerrainPatchInstanceData) // float4(xBase, yBase, skipScale, ~)
|
|
UNITY_INSTANCING_BUFFER_END(Terrain)
|
|
|
|
|
|
|
|
|
|
// dynamic branching helpers, for regular and aggressive branching
|
|
// debug mode shows how many samples using branching will save us.
|
|
//
|
|
// These macros are always used instead of the UNITY_BRANCH macro
|
|
// to maintain debug displays and allow branching to be disabled
|
|
// on as granular level as we want.
|
|
|
|
#if _BRANCHSAMPLES
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++; if (w > 0)
|
|
#else
|
|
#define MSBRANCH(w) UNITY_BRANCH if (w > 0)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++;
|
|
#else
|
|
#define MSBRANCH(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _BRANCHSAMPLESAGR
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER ||_DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++; if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++; if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++; if (w > 0.001)
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) UNITY_BRANCH if (w > 0.001)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++;
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++;
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++;
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w)
|
|
#define MSBRANCHCLUSTER(w)
|
|
#define MSBRANCHOTHER(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _DEBUG_SAMPLECOUNT
|
|
int _sampleCount;
|
|
#define COUNTSAMPLE { _sampleCount++; }
|
|
#else
|
|
#define COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _DEBUG_PROCLAYERS
|
|
int _procLayerCount;
|
|
#define COUNTPROCLAYER { _procLayerCount++; }
|
|
#else
|
|
#define COUNTPROCLAYER
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
TEXTURE2D(_DebugWorldPos);
|
|
TEXTURE2D(_DebugWorldNormal);
|
|
#endif
|
|
|
|
|
|
// splat
|
|
UNITY_DECLARE_TEX2DARRAY(_Diffuse);
|
|
UNITY_DECLARE_TEX2DARRAY(_NormalSAO);
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
TEXTURE2D(_NoiseUV);
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
UNITY_DECLARE_TEX2DARRAY(_SmoothAO);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
UNITY_DECLARE_TEX2DARRAY(_Specular);
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
UNITY_DECLARE_TEX2DARRAY(_EmissiveMetal);
|
|
#endif
|
|
|
|
TEXTURE2D(_PerPixelNormal);
|
|
|
|
SamplerState shared_linear_clamp_sampler;
|
|
SamplerState shared_point_clamp_sampler;
|
|
|
|
TEXTURE2D(_Control0);
|
|
#if _CUSTOMSPLATTEXTURES
|
|
TEXTURE2D(_CustomControl0);
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_CustomControl1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_CustomControl2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_CustomControl3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl7);
|
|
#endif
|
|
#else
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_Control1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_Control2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_Control3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_Control7);
|
|
#endif
|
|
#endif
|
|
|
|
TEXTURE2D_FLOAT(_PerTexProps);
|
|
|
|
struct DecalLayer
|
|
{
|
|
float3 uv;
|
|
float2 dx;
|
|
float2 dy;
|
|
int decalIndex;
|
|
bool dynamic;
|
|
};
|
|
|
|
struct DecalOutput
|
|
{
|
|
DecalLayer l0;
|
|
DecalLayer l1;
|
|
DecalLayer l2;
|
|
DecalLayer l3;
|
|
|
|
half4 Weights;
|
|
half4 Indexes;
|
|
half4 fxLevels;
|
|
|
|
};
|
|
|
|
|
|
struct TriGradMipFormat
|
|
{
|
|
float4 d0;
|
|
float4 d1;
|
|
float4 d2;
|
|
};
|
|
|
|
float InverseLerp(float x, float y, float v) { return (v-x)/max(y-x, 0.001); }
|
|
float2 InverseLerp(float2 x, float2 y, float2 v) { return (v-x)/max(y-x, float2(0.001, 0.001)); }
|
|
float3 InverseLerp(float3 x, float3 y, float3 v) { return (v-x)/max(y-x, float3(0.001, 0.001, 0.001)); }
|
|
float4 InverseLerp(float4 x, float4 y, float4 v) { return (v-x)/max(y-x, float4(0.001, 0.001, 0.001, 0.001)); }
|
|
|
|
|
|
// 2019.3 holes
|
|
#ifdef _ALPHATEST_ON
|
|
TEXTURE2D(_TerrainHolesTexture);
|
|
|
|
void ClipHoles(float2 uv)
|
|
{
|
|
float hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, shared_linear_clamp_sampler, uv).r;
|
|
COUNTSAMPLE
|
|
clip(hole < 0.5f ? -1 : 1);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT TriGradMipFormat
|
|
#define INITMIPFORMAT (TriGradMipFormat)0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float3
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float3
|
|
#endif
|
|
#else
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT float4
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float
|
|
#endif
|
|
#endif
|
|
|
|
float2 TotalOne(float2 v) { return v * (1.0 / max(v.x + v.y, 0.001)); }
|
|
float3 TotalOne(float3 v) { return v * (1.0 / max(v.x + v.y + v.z, 0.001)); }
|
|
float4 TotalOne(float4 v) { return v * (1.0 / max(v.x + v.y + v.z + v.w, 0.001)); }
|
|
|
|
float2 RotateUV(float2 uv, float amt)
|
|
{
|
|
uv -=0.5;
|
|
float s = sin ( amt);
|
|
float c = cos ( amt );
|
|
float2x2 mtx = float2x2( c, -s, s, c);
|
|
mtx *= 0.5;
|
|
mtx += 0.5;
|
|
mtx = mtx * 2-1;
|
|
uv = mul ( uv, mtx );
|
|
uv += 0.5;
|
|
return uv;
|
|
}
|
|
|
|
float4 DecodeToFloat4(float v)
|
|
{
|
|
uint vi = (uint)(v * (256.0f * 256.0f * 256.0f * 256.0f));
|
|
int ex = (int)(vi / (256 * 256 * 256) % 256);
|
|
int ey = (int)((vi / (256 * 256)) % 256);
|
|
int ez = (int)((vi / (256)) % 256);
|
|
int ew = (int)(vi % 256);
|
|
float4 e = float4(ex / 255.0, ey / 255.0, ez / 255.0, ew / 255.0);
|
|
return e;
|
|
}
|
|
|
|
|
|
|
|
struct Input
|
|
{
|
|
ShaderData shaderData;
|
|
float2 uv_Control0;
|
|
float2 uv2_Diffuse;
|
|
|
|
float worldHeight;
|
|
float3 worldUpVector;
|
|
|
|
float3 viewDir;
|
|
float3 worldPos;
|
|
float3 worldNormal;
|
|
float4 color;
|
|
float3x3 TBN;
|
|
|
|
// vertex/digger workflow data
|
|
half4 w0;
|
|
half4 w1;
|
|
half4 w2;
|
|
half4 w3;
|
|
half4 w4;
|
|
half4 w5;
|
|
half4 w6;
|
|
|
|
// megasplat data
|
|
half4 layer0;
|
|
half4 layer1;
|
|
half3 baryWeights;
|
|
half4 scatter0;
|
|
half4 scatter1;
|
|
|
|
// wetness, puddles, streams, lava from vertex or megasplat
|
|
half4 fx;
|
|
// snow min, snow max
|
|
half4 fx2;
|
|
|
|
|
|
};
|
|
|
|
struct TriplanarConfig
|
|
{
|
|
float3x3 uv0;
|
|
float3x3 uv1;
|
|
float3x3 uv2;
|
|
float3x3 uv3;
|
|
half3 pN;
|
|
half3 pN0;
|
|
half3 pN1;
|
|
half3 pN2;
|
|
half3 pN3;
|
|
half3 axisSign;
|
|
Input IN;
|
|
};
|
|
|
|
|
|
struct Config
|
|
{
|
|
float2 uv;
|
|
float3 uv0;
|
|
float3 uv1;
|
|
float3 uv2;
|
|
float3 uv3;
|
|
|
|
half4 cluster0;
|
|
half4 cluster1;
|
|
half4 cluster2;
|
|
half4 cluster3;
|
|
|
|
};
|
|
|
|
|
|
struct MicroSplatLayer
|
|
{
|
|
half3 Albedo;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half Occlusion;
|
|
half Metallic;
|
|
half Height;
|
|
half3 Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
half3 Specular;
|
|
#endif
|
|
half Alpha;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// raw, unblended samples from arrays
|
|
struct RawSamples
|
|
{
|
|
half4 albedo0;
|
|
half4 albedo1;
|
|
half4 albedo2;
|
|
half4 albedo3;
|
|
#if _SURFACENORMALS
|
|
half3 surf0;
|
|
half3 surf1;
|
|
half3 surf2;
|
|
half3 surf3;
|
|
#endif
|
|
|
|
half4 normSAO0;
|
|
half4 normSAO1;
|
|
half4 normSAO2;
|
|
half4 normSAO3;
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALEMIS || _GLOBALSMOOTHAOMETAL || _PERTEXSSS || _PERTEXRIMLIGHT
|
|
half4 emisMetal0;
|
|
half4 emisMetal1;
|
|
half4 emisMetal2;
|
|
half4 emisMetal3;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
half3 specular0;
|
|
half3 specular1;
|
|
half3 specular2;
|
|
half3 specular3;
|
|
#endif
|
|
};
|
|
|
|
void InitRawSamples(inout RawSamples s)
|
|
{
|
|
s.normSAO0 = half4(0,0,0,1);
|
|
s.normSAO1 = half4(0,0,0,1);
|
|
s.normSAO2 = half4(0,0,0,1);
|
|
s.normSAO3 = half4(0,0,0,1);
|
|
#if _SURFACENORMALS
|
|
s.surf0 = half3(0,0,1);
|
|
s.surf1 = half3(0,0,1);
|
|
s.surf2 = half3(0,0,1);
|
|
s.surf3 = half3(0,0,1);
|
|
#endif
|
|
}
|
|
|
|
float3 GetGlobalLightDir(Input i)
|
|
{
|
|
float3 lightDir = float3(1,0,0);
|
|
|
|
#if _HDRP || PASS_DEFERRED
|
|
lightDir = normalize(_gGlitterLightDir.xyz);
|
|
#elif _URP
|
|
lightDir = GetMainLight().direction;
|
|
#else
|
|
#ifndef USING_DIRECTIONAL_LIGHT
|
|
lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
|
|
#else
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
#endif
|
|
#endif
|
|
return lightDir;
|
|
}
|
|
|
|
float3x3 GetTBN(Input i)
|
|
{
|
|
return i.TBN;
|
|
}
|
|
|
|
float3 GetGlobalLightDirTS(Input i)
|
|
{
|
|
float3 lightDirWS = GetGlobalLightDir(i);
|
|
return mul(GetTBN(i), lightDirWS);
|
|
}
|
|
|
|
half3 GetGlobalLightColor()
|
|
{
|
|
#if _HDRP || PASS_DEFERRED
|
|
return _gGlitterLightColor;
|
|
#elif _URP
|
|
return (GetMainLight().color);
|
|
#else
|
|
return _LightColor0.rgb;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 FuzzyShade(half3 color, half3 normal, half coreMult, half edgeMult, half power, float3 viewDir)
|
|
{
|
|
half dt = saturate(dot(viewDir, normal));
|
|
half dark = 1.0 - (coreMult * dt);
|
|
half edge = pow(1-dt, power) * edgeMult;
|
|
return color * (dark + edge);
|
|
}
|
|
|
|
half3 ComputeSSS(Input i, float3 V, float3 N, half3 tint, half thickness, half distortion, half scale, half power)
|
|
{
|
|
float3 L = GetGlobalLightDir(i);
|
|
half3 lightColor = GetGlobalLightColor();
|
|
float3 H = normalize(L + N * distortion);
|
|
float VdotH = pow(saturate(dot(V, -H)), power) * scale;
|
|
float3 I = (VdotH) * thickness;
|
|
return lightColor * I * tint;
|
|
}
|
|
|
|
|
|
#if _MAX2LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
#elif _MAX3LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
#else
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
#endif
|
|
|
|
|
|
#if _MAX3LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#elif _MAX2LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#else
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##3 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv3.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#endif
|
|
|
|
half2 BlendNormal2(half2 base, half2 blend) { return normalize(half3(base.xy + blend.xy, 1)).xy; }
|
|
half3 BlendOverlay(half3 base, half3 blend) { return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))); }
|
|
half3 BlendMult2X(half3 base, half3 blend) { return (base * (blend * 2)); }
|
|
half3 BlendLighterColor(half3 s, half3 d) { return (s.x + s.y + s.z > d.x + d.y + d.z) ? s : d; }
|
|
|
|
|
|
#if _SURFACENORMALS
|
|
|
|
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
|
|
|
|
|
|
|
|
void ConstructSurfaceGradientTBN(Input i)
|
|
{
|
|
float3x3 tbn = GetTBN(i);
|
|
float3 t = tbn[0];
|
|
float3 b = tbn[1];
|
|
float3 n = tbn[2];
|
|
|
|
surfNormal = n;//mul(GetWorldToObjectMatrix(), float4(n, 1)).xyz;
|
|
surfTangent = t;//mul(GetWorldToObjectMatrix(), float4(t, 1)).xyz;
|
|
surfBitangent = b;//cross(surfNormal, surfTangent);
|
|
|
|
float renormFactor = 1.0 / length(surfNormal);
|
|
surfNormal *= renormFactor;
|
|
surfTangent *= renormFactor;
|
|
surfBitangent *= renormFactor;
|
|
}
|
|
|
|
half3 SurfaceGradientFromTBN(half2 deriv)
|
|
{
|
|
return deriv.x * surfTangent + deriv.y * surfBitangent;
|
|
}
|
|
|
|
// Input: vM is tangent space normal in [-1;1].
|
|
// Output: convert vM to a derivative.
|
|
half2 TspaceNormalToDerivative(half3 vM)
|
|
{
|
|
const half scale = 1.0/128.0;
|
|
|
|
// Ensure vM delivers a positive third component using abs() and
|
|
// constrain vM.z so the range of the derivative is [-128; 128].
|
|
const half3 vMa = abs(vM);
|
|
const half z_ma = max(vMa.z, scale*max(vMa.x, vMa.y));
|
|
|
|
return -half2(vM.x, vM.y)/z_ma;
|
|
}
|
|
|
|
// Used to produce a surface gradient from the gradient of a volume
|
|
// bump function such as 3D Perlin noise. Equation 2 in [Mik10].
|
|
half3 SurfgradFromVolumeGradient(half3 grad)
|
|
{
|
|
return grad - dot(surfNormal, grad) * surfNormal;
|
|
}
|
|
|
|
half3 SurfgradFromTriplanarProjection(half3 pN, half2 xPlaneTN, half2 yPlaneTN, half2 zPlaneTN)
|
|
{
|
|
const half w0 = pN.x;
|
|
const half w1 = pN.y;
|
|
const half w2 = pN.z;
|
|
|
|
// X-plane tangent normal to gradient derivative
|
|
xPlaneTN = xPlaneTN * 2.0 - 1.0;
|
|
half xPlaneRcpZ = rsqrt(max(1 - dot(xPlaneTN.x, xPlaneTN.x) - dot(xPlaneTN.y, xPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_xplane = xPlaneTN * -xPlaneRcpZ;
|
|
|
|
// Y-plane tangent normal to gradient derivative
|
|
yPlaneTN = yPlaneTN * 2.0 - 1.0;
|
|
half yPlaneRcpZ = rsqrt(max(1 - dot(yPlaneTN.x, yPlaneTN.x) - dot(yPlaneTN.y, yPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_yplane = yPlaneTN * -yPlaneRcpZ;
|
|
|
|
// Z-plane tangent normal to gradient derivative
|
|
zPlaneTN = zPlaneTN * 2.0 - 1.0;
|
|
half zPlaneRcpZ = rsqrt(max(1 - dot(zPlaneTN.x, zPlaneTN.x) - dot(zPlaneTN.y, zPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_zplane = zPlaneTN * -zPlaneRcpZ;
|
|
|
|
// Assume deriv xplane, deriv yplane, and deriv zplane are
|
|
// sampled using (z,y), (x,z), and (x,y), respectively.
|
|
// Positive scales of the lookup coordinate will work
|
|
// as well, but for negative scales the derivative components
|
|
// will need to be negated accordingly.
|
|
float3 grad = float3(w2*d_zplane.x + w1*d_yplane.x,
|
|
w2*d_zplane.y + w0*d_xplane.y,
|
|
w0*d_xplane.x + w1*d_yplane.y);
|
|
|
|
return SurfgradFromVolumeGradient(grad);
|
|
}
|
|
|
|
half3 ConvertNormalToGradient(half3 normal)
|
|
{
|
|
half2 deriv = TspaceNormalToDerivative(normal);
|
|
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
half3 ConvertNormal2ToGradient(half2 packedNormal)
|
|
{
|
|
half2 tNormal = packedNormal;
|
|
half rcpZ = rsqrt(max(1 - dot(tNormal.x, tNormal.x) - dot(tNormal.y, tNormal.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
half2 deriv = tNormal * -rcpZ;
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
|
|
half3 ResolveNormalFromSurfaceGradient(half3 gradient)
|
|
{
|
|
return normalize(surfNormal - gradient);
|
|
}
|
|
|
|
|
|
#endif // _SURFACENORMALS
|
|
|
|
void BlendNormalPerTex(inout RawSamples o, half2 noise, float4 fades)
|
|
{
|
|
#if _SURFACENORMALS
|
|
float3 grad = ConvertNormal2ToGradient(noise.xy);
|
|
o.surf0 += grad * fades.x;
|
|
o.surf1 += grad * fades.y;
|
|
#if !_MAX2LAYER
|
|
o.surf2 += grad * fades.z;
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.surf3 += grad * fades.w;
|
|
#endif
|
|
#else
|
|
o.normSAO0.xy = lerp(o.normSAO0.xy, BlendNormal2(o.normSAO0.xy, noise.xy), fades.x);
|
|
o.normSAO1.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#if !_MAX2LAYER
|
|
o.normSAO2.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO2.xy, noise.xy), fades.y);
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.normSAO3.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 BlendNormal3(half3 n1, half3 n2)
|
|
{
|
|
n1 += float3( 0, 0, 1);
|
|
n2 *= float3(-1, -1, 1);
|
|
return n1*dot(n1, n2) / n1.z - n2;
|
|
}
|
|
|
|
half2 TransformTriplanarNormal(Input IN, float3x3 t2w, half3 axisSign, half3 absVertNormal,
|
|
half3 pN, half2 a0, half2 a1, half2 a2)
|
|
{
|
|
|
|
a0 = a0 * 2 - 1;
|
|
a1 = a1 * 2 - 1;
|
|
a2 = a2 * 2 - 1;
|
|
|
|
a0.x *= axisSign.x;
|
|
a1.x *= axisSign.y;
|
|
a2.x *= axisSign.z;
|
|
|
|
half3 n0 = half3(a0.xy, 1);
|
|
half3 n1 = half3(a1.xy, 1);
|
|
half3 n2 = half3(a2.xy, 1);
|
|
|
|
float3 wn = IN.worldNormal;
|
|
|
|
n0 = BlendNormal3(half3(wn.zy, absVertNormal.x), n0);
|
|
n1 = BlendNormal3(half3(wn.xz, absVertNormal.y), n1 * float3(-1, 1, 1));
|
|
n2 = BlendNormal3(half3(wn.xy, absVertNormal.z), n2);
|
|
|
|
n0.z *= axisSign.x;
|
|
n1.z *= axisSign.y;
|
|
n2.z *= -axisSign.z;
|
|
|
|
half3 worldNormal = (n0.zyx * pN.x + n1.xzy * pN.y + n2.xyz * pN.z);
|
|
return mul(t2w, worldNormal).xy;
|
|
|
|
}
|
|
|
|
// funcs
|
|
|
|
inline half MSLuminance(half3 rgb)
|
|
{
|
|
#ifdef UNITY_COLORSPACE_GAMMA
|
|
return dot(rgb, half3(0.22, 0.707, 0.071));
|
|
#else
|
|
return dot(rgb, half3(0.0396819152, 0.458021790, 0.00609653955));
|
|
#endif
|
|
}
|
|
|
|
|
|
float2 Hash2D( float2 x )
|
|
{
|
|
float2 k = float2( 0.3183099, 0.3678794 );
|
|
x = x*k + k.yx;
|
|
return -1.0 + 2.0*frac( 16.0 * k*frac( x.x*x.y*(x.x+x.y)) );
|
|
}
|
|
|
|
float Noise2D(float2 p )
|
|
{
|
|
float2 i = floor( p );
|
|
float2 f = frac( p );
|
|
|
|
float2 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( dot( Hash2D( i + float2(0.0,0.0) ), f - float2(0.0,0.0) ),
|
|
dot( Hash2D( i + float2(1.0,0.0) ), f - float2(1.0,0.0) ), u.x),
|
|
lerp( dot( Hash2D( i + float2(0.0,1.0) ), f - float2(0.0,1.0) ),
|
|
dot( Hash2D( i + float2(1.0,1.0) ), f - float2(1.0,1.0) ), u.x), u.y);
|
|
}
|
|
|
|
float FBM2D(float2 uv)
|
|
{
|
|
float f = 0.5000*Noise2D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise2D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise2D( uv );
|
|
return f;
|
|
}
|
|
|
|
float3 Hash3D( float3 p )
|
|
{
|
|
p = float3( dot(p,float3(127.1,311.7, 74.7)),
|
|
dot(p,float3(269.5,183.3,246.1)),
|
|
dot(p,float3(113.5,271.9,124.6)));
|
|
|
|
return -1.0 + 2.0*frac(sin(p)*437.5453123);
|
|
}
|
|
|
|
float Noise3D( float3 p )
|
|
{
|
|
float3 i = floor( p );
|
|
float3 f = frac( p );
|
|
|
|
float3 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,0.0) ), f - float3(0.0,0.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,0.0) ), f - float3(1.0,0.0,0.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,0.0) ), f - float3(0.0,1.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,0.0) ), f - float3(1.0,1.0,0.0) ), u.x), u.y),
|
|
lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,1.0) ), f - float3(0.0,0.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,1.0) ), f - float3(1.0,0.0,1.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,1.0) ), f - float3(0.0,1.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,1.0) ), f - float3(1.0,1.0,1.0) ), u.x), u.y), u.z );
|
|
}
|
|
|
|
float FBM3D(float3 uv)
|
|
{
|
|
float f = 0.5000*Noise3D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise3D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise3D( uv );
|
|
return f;
|
|
}
|
|
|
|
|
|
|
|
float GetSaturation(float3 c)
|
|
{
|
|
float mi = min(min(c.x, c.y), c.z);
|
|
float ma = max(max(c.x, c.y), c.z);
|
|
return (ma - mi)/(ma + 1e-7);
|
|
}
|
|
|
|
// Better Color Lerp, does not have darkening issue
|
|
float3 BetterColorLerp(float3 a, float3 b, float x)
|
|
{
|
|
float3 ic = lerp(a, b, x) + float3(1e-6,0.0,0.0);
|
|
float sd = abs(GetSaturation(ic) - lerp(GetSaturation(a), GetSaturation(b), x));
|
|
|
|
float3 dir = normalize(float3(2.0 * ic.x - ic.y - ic.z, 2.0 * ic.y - ic.x - ic.z, 2.0 * ic.z - ic.y - ic.x));
|
|
float lgt = dot(float3(1.0, 1.0, 1.0), ic);
|
|
|
|
float ff = dot(dir, normalize(ic));
|
|
|
|
const float dsp_str = 1.5;
|
|
ic += dsp_str * dir * sd * ff * lgt;
|
|
return saturate(ic);
|
|
}
|
|
|
|
|
|
half4 ComputeWeights(half4 iWeights, half h0, half h1, half h2, half h3, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return iWeights;
|
|
#else
|
|
// compute weight with height map
|
|
//half4 weights = half4(iWeights.x * h0, iWeights.y * h1, iWeights.z * h2, iWeights.w * h3);
|
|
half4 weights = half4(iWeights.x * max(h0,0.001), iWeights.y * max(h1,0.001), iWeights.z * max(h2,0.001), iWeights.w * max(h3,0.001));
|
|
|
|
// Contrast weights
|
|
half maxWeight = max(max(weights.x, max(weights.y, weights.z)), weights.w);
|
|
half transition = max(contrast * maxWeight, 0.0001);
|
|
half threshold = maxWeight - transition;
|
|
half scale = 1.0 / transition;
|
|
weights = saturate((weights - threshold) * scale);
|
|
|
|
weights = TotalOne(weights);
|
|
return weights;
|
|
#endif
|
|
}
|
|
|
|
half HeightBlend(half h1, half h2, half slope, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return slope;
|
|
#else
|
|
h2 = 1 - h2;
|
|
half tween = saturate((slope - min(h1, h2)) / max(abs(h1 - h2), 0.001));
|
|
half blend = saturate( ( tween - (1-contrast) ) / max(contrast, 0.001));
|
|
return blend;
|
|
#endif
|
|
}
|
|
|
|
#if _MAX4TEXTURES
|
|
#define TEXCOUNT 4
|
|
#elif _MAX8TEXTURES
|
|
#define TEXCOUNT 8
|
|
#elif _MAX12TEXTURES
|
|
#define TEXCOUNT 12
|
|
#elif _MAX20TEXTURES
|
|
#define TEXCOUNT 20
|
|
#elif _MAX24TEXTURES
|
|
#define TEXCOUNT 24
|
|
#elif _MAX28TEXTURES
|
|
#define TEXCOUNT 28
|
|
#elif _MAX32TEXTURES
|
|
#define TEXCOUNT 32
|
|
#else
|
|
#define TEXCOUNT 16
|
|
#endif
|
|
|
|
#if _DECAL_SPLAT
|
|
|
|
void DoMergeDecalSplats(half4 iWeights, half4 iIndexes, inout half4 indexes, inout half4 weights)
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
half w = iWeights[i];
|
|
half index = iIndexes[i];
|
|
if (w > weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = index;
|
|
}
|
|
else if (w > weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = index;
|
|
}
|
|
else if (w > weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = index;
|
|
}
|
|
else if (w > weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = index;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
void Setup(out half4 weights, float2 uv, out Config config, half4 w0, half4 w1, half4 w2, half4 w3, half4 w4, half4 w5, half4 w6, half4 w7, float3 worldPos, DecalOutput decalOutput)
|
|
{
|
|
config = (Config)0;
|
|
half4 indexes = 0;
|
|
|
|
config.uv = uv;
|
|
|
|
#if _WORLDUV
|
|
uv = worldPos.xz;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
float2 scaledUV = uv;
|
|
#else
|
|
float2 scaledUV = uv * _UVScale.xy + _UVScale.zw;
|
|
#endif
|
|
|
|
// if only 4 textures, and blending 4 textures, skip this whole thing..
|
|
// this saves about 25% of the ALU of the base shader on low end. However if
|
|
// we rely on sorted texture weights (distance resampling) we have to sort..
|
|
float4 defaultIndexes = float4(0,1,2,3);
|
|
#if _MESHSUBARRAY
|
|
defaultIndexes = _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
#if _MESHSUBARRAY && !_DECAL_SPLAT || (_MAX4TEXTURES && !_MAX3LAYER && !_MAX2LAYER && !_DISTANCERESAMPLE && !_POM && !_DECAL_SPLAT)
|
|
weights = w0;
|
|
config.uv0 = float3(scaledUV, defaultIndexes.x);
|
|
config.uv1 = float3(scaledUV, defaultIndexes.y);
|
|
config.uv2 = float3(scaledUV, defaultIndexes.z);
|
|
config.uv3 = float3(scaledUV, defaultIndexes.w);
|
|
return;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
weights = float4(1,0,0,0);
|
|
return;
|
|
#else
|
|
half splats[TEXCOUNT];
|
|
|
|
splats[0] = w0.x;
|
|
splats[1] = w0.y;
|
|
splats[2] = w0.z;
|
|
splats[3] = w0.w;
|
|
#if !_MAX4TEXTURES
|
|
splats[4] = w1.x;
|
|
splats[5] = w1.y;
|
|
splats[6] = w1.z;
|
|
splats[7] = w1.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
splats[8] = w2.x;
|
|
splats[9] = w2.y;
|
|
splats[10] = w2.z;
|
|
splats[11] = w2.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
splats[12] = w3.x;
|
|
splats[13] = w3.y;
|
|
splats[14] = w3.z;
|
|
splats[15] = w3.w;
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[16] = w4.x;
|
|
splats[17] = w4.y;
|
|
splats[18] = w4.z;
|
|
splats[19] = w4.w;
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[20] = w5.x;
|
|
splats[21] = w5.y;
|
|
splats[22] = w5.z;
|
|
splats[23] = w5.w;
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[24] = w6.x;
|
|
splats[25] = w6.y;
|
|
splats[26] = w6.z;
|
|
splats[27] = w6.w;
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
splats[28] = w7.x;
|
|
splats[29] = w7.y;
|
|
splats[30] = w7.z;
|
|
splats[31] = w7.w;
|
|
#endif
|
|
|
|
|
|
|
|
weights[0] = 0;
|
|
weights[1] = 0;
|
|
weights[2] = 0;
|
|
weights[3] = 0;
|
|
indexes[0] = 0;
|
|
indexes[1] = 0;
|
|
indexes[2] = 0;
|
|
indexes[3] = 0;
|
|
|
|
int i = 0;
|
|
for (i = 0; i < TEXCOUNT; ++i)
|
|
{
|
|
half w = splats[i];
|
|
if (w >= weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = i;
|
|
}
|
|
else if (w >= weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = i;
|
|
}
|
|
else if (w >= weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = i;
|
|
}
|
|
else if (w >= weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = i;
|
|
}
|
|
}
|
|
|
|
// NaN Prevention
|
|
if (weights.x <= 0)
|
|
weights = float4(1, 0, 0, 0);
|
|
|
|
#if _DECAL_SPLAT
|
|
DoMergeDecalSplats(decalOutput.Weights, decalOutput.Indexes, weights, indexes);
|
|
#endif
|
|
|
|
|
|
|
|
// clamp and renormalize
|
|
#if _MAX2LAYER
|
|
weights.zw = 0;
|
|
weights.xy = TotalOne(weights.xy);
|
|
#elif _MAX3LAYER
|
|
weights.w = 0;
|
|
weights.xyz = TotalOne(weights.xyz);
|
|
#elif !_DISABLEHEIGHTBLENDING || _NORMALIZEWEIGHTS // prevents black when painting, which the unity shader does not prevent.
|
|
weights = normalize(weights);
|
|
#endif
|
|
|
|
|
|
config.uv0 = float3(scaledUV, indexes.x);
|
|
config.uv1 = float3(scaledUV, indexes.y);
|
|
config.uv2 = float3(scaledUV, indexes.z);
|
|
config.uv3 = float3(scaledUV, indexes.w);
|
|
|
|
|
|
#endif //_DISABLESPLATMAPS
|
|
|
|
|
|
}
|
|
|
|
float3 HeightToNormal(float height, float3 worldPos)
|
|
{
|
|
float3 dx = ddx(worldPos);
|
|
float3 dy = ddy(worldPos);
|
|
float3 crossX = cross(float3(0,1,0), dx);
|
|
float3 crossY = cross(float3(0,1,0), dy);
|
|
float3 d = abs(dot(crossY, dx));
|
|
float3 n = ((((height + ddx(height)) - height) * crossY) + (((height + ddy(height)) - height) * crossX)) * sign(d);
|
|
n.z *= -1;
|
|
return normalize((d * float3(0,1,0)) - n).xzy;
|
|
}
|
|
|
|
float ComputeMipLevel(float2 uv, float2 textureSize)
|
|
{
|
|
uv *= textureSize;
|
|
float2 dx_vtc = ddx(uv);
|
|
float2 dy_vtc = ddy(uv);
|
|
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
|
|
return 0.5 * log2(delta_max_sqr);
|
|
}
|
|
|
|
inline half2 UnpackNormal2(half4 packednormal)
|
|
{
|
|
return packednormal.wy * 2 - 1;
|
|
|
|
}
|
|
|
|
half3 TriplanarHBlend(half h0, half h1, half h2, half3 pN, half contrast)
|
|
{
|
|
half3 blend = pN / dot(pN, half3(1,1,1));
|
|
float3 heights = float3(h0, h1, h2) + (blend * 3.0);
|
|
half height_start = max(max(heights.x, heights.y), heights.z) - contrast;
|
|
half3 h = max(heights - height_start.xxx, half3(0,0,0));
|
|
blend = h / dot(h, half3(1,1,1));
|
|
return blend;
|
|
}
|
|
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half3 display)
|
|
{
|
|
o.Albedo = display.rgb;
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half display)
|
|
{
|
|
o.Albedo = half3(display, display, display);
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
half MicroShadow(float3 lightDir, half3 normal, half ao, half strength)
|
|
{
|
|
half shadow = saturate(abs(dot(normal, lightDir)) + (ao * ao * 2.0) - 1.0);
|
|
return 1 - ((1-shadow) * strength);
|
|
}
|
|
|
|
|
|
void DoDebugOutput(inout MicroSplatLayer l)
|
|
{
|
|
#if _DEBUG_OUTPUT_ALBEDO
|
|
ClearAllButAlbedo(l, l.Albedo);
|
|
#elif _DEBUG_OUTPUT_NORMAL
|
|
// oh unit shader compiler normal stripping, how I hate you so..
|
|
// must multiply by albedo to stop the normal from being white. Why, fuck knows?
|
|
ClearAllButAlbedo(l, float3(l.Normal.xy * 0.5 + 0.5, l.Normal.z * saturate(l.Albedo.z+1)));
|
|
#elif _DEBUG_OUTPUT_SMOOTHNESS
|
|
ClearAllButAlbedo(l, l.Smoothness.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_METAL
|
|
ClearAllButAlbedo(l, l.Metallic.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_AO
|
|
ClearAllButAlbedo(l, l.Occlusion.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_EMISSION
|
|
ClearAllButAlbedo(l, l.Emission * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_HEIGHT
|
|
ClearAllButAlbedo(l, l.Height.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_SPECULAR && _USESPECULARWORKFLOW
|
|
ClearAllButAlbedo(l, l.Specular * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_BRANCHCOUNT_WEIGHT
|
|
ClearAllButAlbedo(l, _branchWeightCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TRIPLANAR
|
|
ClearAllButAlbedo(l, _branchTriplanarCount / 24 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_CLUSTER
|
|
ClearAllButAlbedo(l, _branchClusterCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_OTHER
|
|
ClearAllButAlbedo(l, _branchOtherCount / 8 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TOTAL
|
|
l.Albedo.r = _branchWeightCount / 12;
|
|
l.Albedo.g = _branchTriplanarCount / 24;
|
|
l.Albedo.b = _branchClusterCount / 12;
|
|
ClearAllButAlbedo(l, (l.Albedo.r + l.Albedo.g + l.Albedo.b + (_branchOtherCount / 8)) / 4);
|
|
#elif _DEBUG_OUTPUT_MICROSHADOWS
|
|
ClearAllButAlbedo(l,l.Albedo);
|
|
#elif _DEBUG_SAMPLECOUNT
|
|
float sdisp = (float)_sampleCount / max(_SampleCountDiv, 1);
|
|
half3 sdcolor = float3(sdisp, sdisp > 1 ? 1 : 0, 0);
|
|
ClearAllButAlbedo(l, sdcolor * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_PROCLAYERS
|
|
ClearAllButAlbedo(l, (float)_procLayerCount / (float)_PCLayerCount * saturate(l.Albedo.z + 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
// abstraction around sampler mode
|
|
#if _USELODMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_LOD(tex, sampler##tex, u, l.x)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u, l.x)
|
|
#elif _USEGRADMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_GRAD(tex, sampler##tex, u, l.xy, l.zw)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY_GRAD(tex, ss, u.xy, u.z, l.xy, l.zw)
|
|
#else
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, u.xy, u.z)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u.xy, y.z)
|
|
#endif
|
|
|
|
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE(u, cl, l) MICROSPLAT_SAMPLE(_Diffuse, u, l)
|
|
#define MICROSPLAT_SAMPLE_EMIS(u, cl, l) MICROSPLAT_SAMPLE(_EmissiveMetal, u, l)
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE_LOD(u, cl, l) UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, u, l)
|
|
|
|
|
|
#if _PACKINGHQ
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) half4(MICROSPLAT_SAMPLE(_NormalSAO, u, l).ga, MICROSPLAT_SAMPLE(_SmoothAO, u, l).ga).brag
|
|
#else
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) MICROSPLAT_SAMPLE(_NormalSAO, u, l)
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
#define MICROSPLAT_SAMPLE_SPECULAR(u, cl, l) MICROSPLAT_SAMPLE(_Specular, u, l)
|
|
#endif
|
|
|
|
struct SimpleTriplanarConfig
|
|
{
|
|
float3 pn;
|
|
float2 uv0;
|
|
float2 uv1;
|
|
float2 uv2;
|
|
};
|
|
|
|
void PrepSimpleTriplanarConfig(inout SimpleTriplanarConfig tc, float3 worldPos, float3 normal, float contrast)
|
|
{
|
|
tc.pn = pow(abs(normal), contrast);
|
|
tc.pn = tc.pn / (tc.pn.x + tc.pn.y + tc.pn.z);
|
|
|
|
half3 axisSign = sign(normal);
|
|
|
|
tc.uv0 = worldPos.zy * axisSign.x;
|
|
tc.uv1 = worldPos.xz * axisSign.y;
|
|
tc.uv2 = worldPos.xy * axisSign.z;
|
|
}
|
|
|
|
#define SimpleTriplanarSample(tex, tc, scale) (SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv0 * scale) * tc.pn.x + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv1 * scale) * tc.pn.y + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv2 * scale) * tc.pn.z)
|
|
#define SimpleTriplanarSampleLOD(tex, tc, scale, lod) (SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv0 * scale, lod) * tc.pn.x + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv1 * scale, lod) * tc.pn.y + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv2 * scale, lod) * tc.pn.z)
|
|
#define SimpleTriplanarSampleGrad(tex, tc, scale) (SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv0 * scale, ddx(tc.uv0) * scale, ddy(tc.uv0) * scale) * tc.pn.x + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv1 * scale, ddx(tc.uv1) * scale, ddy(tc.uv1) * scale) * tc.pn.y + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv2 * scale, ddx(tc.uv2) * scale, ddy(tc.uv2) * scale) * tc.pn.z)
|
|
|
|
|
|
inline half3 MicroSplatDiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
|
|
{
|
|
specColor = lerp (half3(0,0,0), albedo, metallic);
|
|
oneMinusReflectivity = (1-metallic);
|
|
return albedo * oneMinusReflectivity;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Input DescToInput(ShaderData IN)
|
|
{
|
|
Input s = (Input)0;
|
|
s.shaderData = IN;
|
|
s.TBN = IN.TBNMatrix;
|
|
s.worldNormal = IN.worldSpaceNormal;
|
|
s.worldPos = IN.worldSpacePosition;
|
|
s.viewDir = IN.tangentSpaceViewDir;
|
|
s.uv_Control0 = IN.texcoord0.xy;
|
|
|
|
s.worldUpVector = float3(0,1,0);
|
|
s.worldHeight = IN.worldSpacePosition.y;
|
|
|
|
#if _PLANETVECTORS
|
|
float3 rwp = mul(_PQSToLocal, float4(IN.worldSpacePosition, 1));
|
|
s.worldHeight = distance(rwp, float3(0,0,0));
|
|
s.worldUpVector = normalize(rwp);
|
|
#endif
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
s.uv2_Diffuse = IN.texcoord1.xy;
|
|
#endif
|
|
|
|
#if _MEGASPLAT
|
|
UnpackMegaSplat(s, IN);
|
|
#endif
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
UnpackVertexWorkflow(s, IN);
|
|
#endif
|
|
|
|
#if _PLANETVECTORS
|
|
DoPlanetDataInputCopy(s, IN);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
void SampleAlbedo(inout Config config, inout TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half4 contrasts = _Contrast.xxxx;
|
|
#if _PERTEXTRIPLANARCONTRAST
|
|
SAMPLE_PER_TEX(ptc, 9.5, config, half4(1,0.5,0,0));
|
|
contrasts = half4(ptc0.y, ptc1.y, ptc2.y, ptc3.y);
|
|
#endif
|
|
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
SAMPLE_PER_TEX(pttri, 9.5, config, half4(0,0,0,0));
|
|
#endif
|
|
|
|
{
|
|
// For per-texture triplanar, we modify the view based blending factor of the triplanar
|
|
// such that you get a pure blend of either top down projection, or with the top down projection
|
|
// removed and renormalized. This causes dynamic flow control optimizations to kick in and avoid
|
|
// the extra texture samples while keeping the code simple. Yay..
|
|
|
|
// We also only have to do this in the Albedo, because the pN values will be adjusted after the
|
|
// albedo is sampled, causing future samples to use this data.
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri0.x > 0.66)
|
|
{
|
|
tc.pN0 = half3(0,1,0);
|
|
}
|
|
else if (pttri0.x > 0.33)
|
|
{
|
|
tc.pN0.y = 0;
|
|
tc.pN0.xz = TotalOne(tc.pN0.xz);
|
|
}
|
|
#endif
|
|
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN0;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN0, contrasts.x);
|
|
tc.pN0 = bf;
|
|
#endif
|
|
|
|
s.albedo0 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri1.x > 0.66)
|
|
{
|
|
tc.pN1 = half3(0,1,0);
|
|
}
|
|
else if (pttri1.x > 0.33)
|
|
{
|
|
tc.pN1.y = 0;
|
|
tc.pN1.xz = TotalOne(tc.pN1.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
COUNTSAMPLE
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[2], config.cluster1, d2);
|
|
}
|
|
half3 bf = tc.pN1;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN1, contrasts.x);
|
|
tc.pN1 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo1 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri2.x > 0.66)
|
|
{
|
|
tc.pN2 = half3(0,1,0);
|
|
}
|
|
else if (pttri2.x > 0.33)
|
|
{
|
|
tc.pN2.y = 0;
|
|
tc.pN2.xz = TotalOne(tc.pN2.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN2;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN2, contrasts.x);
|
|
tc.pN2 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo2 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri3.x > 0.66)
|
|
{
|
|
tc.pN3 = half3(0,1,0);
|
|
}
|
|
else if (pttri3.x > 0.33)
|
|
{
|
|
tc.pN3.y = 0;
|
|
tc.pN3.xz = TotalOne(tc.pN3.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN3;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN3, contrasts.x);
|
|
tc.pN3 = bf;
|
|
#endif
|
|
|
|
s.albedo3 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.albedo0 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.albedo1 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.albedo2 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.albedo3 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXHEIGHTOFFSET || _PERTEXHEIGHTCONTRAST
|
|
SAMPLE_PER_TEX(ptHeight, 10.5, config, 1);
|
|
|
|
#if _PERTEXHEIGHTOFFSET
|
|
s.albedo0.a = saturate(s.albedo0.a + ptHeight0.b - 1);
|
|
s.albedo1.a = saturate(s.albedo1.a + ptHeight1.b - 1);
|
|
s.albedo2.a = saturate(s.albedo2.a + ptHeight2.b - 1);
|
|
s.albedo3.a = saturate(s.albedo3.a + ptHeight3.b - 1);
|
|
#endif
|
|
#if _PERTEXHEIGHTCONTRAST
|
|
s.albedo0.a = saturate(pow(s.albedo0.a + 0.5, abs(ptHeight0.a)) - 0.5);
|
|
s.albedo1.a = saturate(pow(s.albedo1.a + 0.5, abs(ptHeight1.a)) - 0.5);
|
|
s.albedo2.a = saturate(pow(s.albedo2.a + 0.5, abs(ptHeight2.a)) - 0.5);
|
|
s.albedo3.a = saturate(pow(s.albedo3.a + 0.5, abs(ptHeight3.a)) - 0.5);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void SampleNormal(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
|
|
#if _NONORMALMAP || _AUTONORMAL
|
|
s.normSAO0 = half4(0,0, 0, 1);
|
|
s.normSAO1 = half4(0,0, 0, 1);
|
|
s.normSAO2 = half4(0,0, 0, 1);
|
|
s.normSAO3 = half4(0,0, 0, 1);
|
|
return;
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half3 absVertNormal = abs(tc.IN.worldNormal);
|
|
float3x3 t2w = tc.IN.TBN;
|
|
|
|
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[0], config.cluster0, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[1], config.cluster0, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[2], config.cluster0, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = SurfgradFromTriplanarProjection(tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO0.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO0.zw = a0.zw * tc.pN0.x + a1.zw * tc.pN0.y + a2.zw * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[0], config.cluster1, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[1], config.cluster1, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[2], config.cluster1, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = SurfgradFromTriplanarProjection(tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO1.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO1.zw = a0.zw * tc.pN1.x + a1.zw * tc.pN1.y + a2.zw * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[0], config.cluster2, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[1], config.cluster2, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[2], config.cluster2, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf2 = SurfgradFromTriplanarProjection(tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO2.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO2.zw = a0.zw * tc.pN2.x + a1.zw * tc.pN2.y + a2.zw * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[0], config.cluster3, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[1], config.cluster3, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[2], config.cluster3, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf3 = SurfgradFromTriplanarProjection(tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO3.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO3.zw = a0.zw * tc.pN3.x + a1.zw * tc.pN3.y + a2.zw * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.normSAO0 = MICROSPLAT_SAMPLE_NORMAL(config.uv0, config.cluster0, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO0.xy = s.normSAO0.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = ConvertNormal2ToGradient(s.normSAO0.xy);
|
|
#endif
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.normSAO1 = MICROSPLAT_SAMPLE_NORMAL(config.uv1, config.cluster1, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO1.xy = s.normSAO1.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = ConvertNormal2ToGradient(s.normSAO1.xy);
|
|
#endif
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.normSAO2 = MICROSPLAT_SAMPLE_NORMAL(config.uv2, config.cluster2, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO2.xy = s.normSAO2.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf2 = ConvertNormal2ToGradient(s.normSAO2.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.normSAO3 = MICROSPLAT_SAMPLE_NORMAL(config.uv3, config.cluster3, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO3.xy = s.normSAO3.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf3 = ConvertNormal2ToGradient(s.normSAO3.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleEmis(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
s.emisMetal0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.emisMetal0 = MICROSPLAT_SAMPLE_EMIS(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.emisMetal1 = MICROSPLAT_SAMPLE_EMIS(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.emisMetal2 = MICROSPLAT_SAMPLE_EMIS(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.emisMetal3 = MICROSPLAT_SAMPLE_EMIS(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleSpecular(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.specular0 = MICROSPLAT_SAMPLE_SPECULAR(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.specular1 = MICROSPLAT_SAMPLE_SPECULAR(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.specular2 = MICROSPLAT_SAMPLE_SPECULAR(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.specular3 = MICROSPLAT_SAMPLE_SPECULAR(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
MicroSplatLayer Sample(Input i, half4 weights, inout Config config, float camDist, float3 worldNormalVertex, DecalOutput decalOutput)
|
|
{
|
|
MicroSplatLayer o = (MicroSplatLayer)0;
|
|
UNITY_INITIALIZE_OUTPUT(MicroSplatLayer,o);
|
|
|
|
RawSamples samples = (RawSamples)0;
|
|
InitRawSamples(samples);
|
|
|
|
half4 albedo = 0;
|
|
half4 normSAO = half4(0,0,0,1);
|
|
half3 surfGrad = half3(0,0,0);
|
|
half4 emisMetal = 0;
|
|
half3 specular = 0;
|
|
|
|
float worldHeight = i.worldPos.y;
|
|
float3 upVector = float3(0,1,0);
|
|
|
|
#if _GLOBALTINT || _GLOBALNORMALS || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _GLOBALSPECULAR
|
|
float globalSlopeFilter = 1;
|
|
#if _GLOBALSLOPEFILTER
|
|
float2 gfilterUV = float2(1 - saturate(dot(worldNormalVertex, upVector) * 0.5 + 0.49), 0.5);
|
|
globalSlopeFilter = SAMPLE_TEXTURE2D(_GlobalSlopeTex, sampler_Diffuse, gfilterUV).a;
|
|
#endif
|
|
#endif
|
|
|
|
// declare outside of branchy areas..
|
|
half4 fxLevels = half4(0,0,0,0);
|
|
half burnLevel = 0;
|
|
half wetLevel = 0;
|
|
half3 waterNormalFoam = half3(0, 0, 0);
|
|
half porosity = 0.4;
|
|
float streamFoam = 1.0f;
|
|
half pud = 0;
|
|
half snowCover = 0;
|
|
half SSSThickness = 0;
|
|
half3 SSSTint = half3(1,1,1);
|
|
float traxBuffer = 0;
|
|
float3 traxNormal = 0;
|
|
float2 noiseUV = 0;
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(1 - saturate(camDist - _SplatFade.y))
|
|
{
|
|
#endif
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE || _SNOWFOOTSTEPS
|
|
traxBuffer = SampleTraxBuffer(i.worldPos, worldNormalVertex, traxNormal);
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
#if _MICROMESH
|
|
fxLevels = SampleFXLevels(InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, config.uv), wetLevel, burnLevel, traxBuffer);
|
|
#elif _MICROVERTEXMESH || _MICRODIGGERMESH || _MEGASPLAT
|
|
fxLevels = ProcessFXLevels(i.fx, traxBuffer);
|
|
#else
|
|
fxLevels = SampleFXLevels(config.uv, wetLevel, burnLevel, traxBuffer);
|
|
#endif
|
|
#endif
|
|
|
|
#if _DECAL
|
|
fxLevels = max(fxLevels, decalOutput.fxLevels);
|
|
#endif
|
|
|
|
TriplanarConfig tc = (TriplanarConfig)0;
|
|
UNITY_INITIALIZE_OUTPUT(TriplanarConfig,tc);
|
|
|
|
|
|
MIPFORMAT albedoLOD = INITMIPFORMAT
|
|
MIPFORMAT normalLOD = INITMIPFORMAT
|
|
MIPFORMAT emisLOD = INITMIPFORMAT
|
|
MIPFORMAT specLOD = INITMIPFORMAT
|
|
MIPFORMAT origAlbedoLOD = INITMIPFORMAT;
|
|
|
|
#if _TRIPLANAR && !_DISABLESPLATMAPS
|
|
PrepTriplanar(i.shaderData.texcoord0, worldNormalVertex, i.worldPos, config, tc, weights, albedoLOD, normalLOD, emisLOD, origAlbedoLOD);
|
|
tc.IN = i;
|
|
#endif
|
|
|
|
|
|
#if !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
#if _USELODMIP
|
|
albedoLOD = ComputeMipLevel(config.uv0.xy, _Diffuse_TexelSize.zw);
|
|
normalLOD = ComputeMipLevel(config.uv0.xy, _NormalSAO_TexelSize.zw);
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = ComputeMipLevel(config.uv0.xy, _EmissiveMetal_TexelSize.zw);
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = ComputeMipLevel(config.uv0.xy, _Specular_TexelSize.zw);;
|
|
#endif
|
|
#elif _USEGRADMIP
|
|
albedoLOD = float4(ddx(config.uv0.xy), ddy(config.uv0.xy));
|
|
normalLOD = albedoLOD;
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
|
|
origAlbedoLOD = albedoLOD;
|
|
#endif
|
|
|
|
#if _PERTEXCURVEWEIGHT
|
|
SAMPLE_PER_TEX(ptCurveWeight, 19.5, config, half4(0.5,1,1,1));
|
|
weights.x = lerp(smoothstep(0.5 - ptCurveWeight0.r, 0.5 + ptCurveWeight0.r, weights.x), weights.x, ptCurveWeight0.r*2);
|
|
weights.y = lerp(smoothstep(0.5 - ptCurveWeight1.r, 0.5 + ptCurveWeight1.r, weights.y), weights.y, ptCurveWeight1.r*2);
|
|
weights.z = lerp(smoothstep(0.5 - ptCurveWeight2.r, 0.5 + ptCurveWeight2.r, weights.z), weights.z, ptCurveWeight2.r*2);
|
|
weights.w = lerp(smoothstep(0.5 - ptCurveWeight3.r, 0.5 + ptCurveWeight3.r, weights.w), weights.w, ptCurveWeight3.r*2);
|
|
weights = TotalOne(weights);
|
|
#endif
|
|
|
|
|
|
|
|
// uvScale before anything
|
|
#if _PERTEXUVSCALEOFFSET && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
config.uv0.xy = config.uv0.xy * ptUVScale0.rg + ptUVScale0.ba;
|
|
config.uv1.xy = config.uv1.xy * ptUVScale1.rg + ptUVScale1.ba;
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = config.uv2.xy * ptUVScale2.rg + ptUVScale2.ba;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = config.uv3.xy * ptUVScale3.rg + ptUVScale3.ba;
|
|
#endif
|
|
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = albedoLOD * ptUVScale0.rgrg * weights.x +
|
|
albedoLOD * ptUVScale1.rgrg * weights.y +
|
|
albedoLOD * ptUVScale2.rgrg * weights.z +
|
|
albedoLOD * ptUVScale3.rgrg * weights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXUVROTATION && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptUVRot, 16.5, config, half4(0,0,0,0));
|
|
config.uv0.xy = RotateUV(config.uv0.xy, ptUVRot0.x);
|
|
config.uv1.xy = RotateUV(config.uv1.xy, ptUVRot1.x);
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = RotateUV(config.uv2.xy, ptUVRot2.x);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = RotateUV(config.uv3.xy, ptUVRot0.x);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
o.Alpha = 1;
|
|
|
|
|
|
#if _POM && !_DISABLESPLATMAPS
|
|
DoPOM(i, config, tc, albedoLOD, weights, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
SampleAlbedo(config, tc, samples, albedoLOD, weights);
|
|
|
|
#if _NOISEHEIGHT
|
|
ApplyNoiseHeight(samples, config.uv, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STREAMS || (_PARALLAX && !_DISABLESPLATMAPS)
|
|
half earlyHeight = BlendWeights(samples.albedo0.w, samples.albedo1.w, samples.albedo2.w, samples.albedo3.w, weights);
|
|
#endif
|
|
|
|
|
|
#if _STREAMS
|
|
waterNormalFoam = GetWaterNormal(i, config.uv, worldNormalVertex);
|
|
DoStreamRefract(config, tc, waterNormalFoam, fxLevels.b, earlyHeight);
|
|
#endif
|
|
|
|
#if _PARALLAX && !_DISABLESPLATMAPS
|
|
DoParallax(i, earlyHeight, config, tc, samples, weights, camDist);
|
|
#endif
|
|
|
|
|
|
// Blend results
|
|
#if _PERTEXINTERPCONTRAST && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptContrasts, 1.5, config, 0.5);
|
|
half4 contrast = 0.5;
|
|
contrast.x = ptContrasts0.a;
|
|
contrast.y = ptContrasts1.a;
|
|
#if !_MAX2LAYER
|
|
contrast.z = ptContrasts2.a;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
contrast.w = ptContrasts3.a;
|
|
#endif
|
|
contrast = clamp(contrast + _Contrast, 0.0001, 1.0);
|
|
half cnt = contrast.x * weights.x + contrast.y * weights.y + contrast.z * weights.z + contrast.w * weights.w;
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, cnt);
|
|
#else
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, _Contrast);
|
|
#endif
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
heightWeights = lerp(heightWeights, TotalOne(weights), saturate(camDist/max(1.0, _HybridHeightBlendDistance)));
|
|
#endif
|
|
|
|
|
|
// rescale derivatives after height weighting. Basically, in gradmip mode we blend the mip levels,
|
|
// but this is before height mapping is sampled, so reblending them after alpha will make sure the other
|
|
// channels (normal, etc) are sharper, which likely matters most..
|
|
#if _PERTEXUVSCALEOFFSET && !_DISABLESPLATMAPS
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
|
|
albedoLOD.d0 = origAlbedoLOD.d0 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d0 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d0 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d0 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d1 = origAlbedoLOD.d1 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d1 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d1 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d1 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d2 = origAlbedoLOD.d2 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d2 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d2 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d2 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
normalLOD.d0 = albedoLOD.d0;
|
|
normalLOD.d1 = albedoLOD.d1;
|
|
normalLOD.d2 = albedoLOD.d2;
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD.d0 = albedoLOD.d0;
|
|
emisLOD.d1 = albedoLOD.d1;
|
|
emisLOD.d2 = albedoLOD.d2;
|
|
#endif
|
|
#endif // gradmip
|
|
#else // not triplanar
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = origAlbedoLOD * ptUVScale0.rgrg * heightWeights.x +
|
|
origAlbedoLOD * ptUVScale1.rgrg * heightWeights.y +
|
|
origAlbedoLOD * ptUVScale2.rgrg * heightWeights.z +
|
|
origAlbedoLOD * ptUVScale3.rgrg * heightWeights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _PARALLAX || _STREAMS
|
|
SampleAlbedo(config, tc, samples, albedoLOD, heightWeights);
|
|
#endif
|
|
|
|
|
|
SampleNormal(config, tc, samples, normalLOD, heightWeights);
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
SampleEmis(config, tc, samples, emisLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
SampleSpecular(config, tc, samples, specLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _DISTANCERESAMPLE && !_DISABLESPLATMAPS
|
|
DistanceResample(samples, config, tc, camDist, i.viewDir, fxLevels, albedoLOD, i.worldPos, heightWeights, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STARREACHFORMAT
|
|
samples.normSAO0.w = length(samples.normSAO0.xy);
|
|
samples.normSAO1.w = length(samples.normSAO1.xy);
|
|
samples.normSAO2.w = length(samples.normSAO2.xy);
|
|
samples.normSAO3.w = length(samples.normSAO3.xy);
|
|
#endif
|
|
|
|
// PerTexture sampling goes here, passing the samples structure
|
|
|
|
#if _PERTEXMICROSHADOWS || _PERTEXFUZZYSHADE
|
|
SAMPLE_PER_TEX(ptFuzz, 17.5, config, half4(0, 0, 1, 1));
|
|
#endif
|
|
|
|
#if _PERTEXMICROSHADOWS
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
{
|
|
half3 lightDir = GetGlobalLightDirTS(i);
|
|
half4 microShadows = half4(1,1,1,1);
|
|
microShadows.x = MicroShadow(lightDir, half3(samples.normSAO0.xy, 1), samples.normSAO0.a, ptFuzz0.a);
|
|
microShadows.y = MicroShadow(lightDir, half3(samples.normSAO1.xy, 1), samples.normSAO1.a, ptFuzz1.a);
|
|
microShadows.z = MicroShadow(lightDir, half3(samples.normSAO2.xy, 1), samples.normSAO2.a, ptFuzz2.a);
|
|
microShadows.w = MicroShadow(lightDir, half3(samples.normSAO3.xy, 1), samples.normSAO3.a, ptFuzz3.a);
|
|
samples.normSAO0.a *= microShadows.x;
|
|
samples.normSAO1.a *= microShadows.y;
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a *= microShadows.z;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a *= microShadows.w;
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_OUTPUT_MICROSHADOWS
|
|
o.Albedo = BlendWeights(microShadows.x, microShadows.y, microShadows.z, microShadows.a, heightWeights);
|
|
return o;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
#endif // _PERTEXMICROSHADOWS
|
|
|
|
|
|
#if _PERTEXFUZZYSHADE
|
|
samples.albedo0.rgb = FuzzyShade(samples.albedo0.rgb, half3(samples.normSAO0.rg, 1), ptFuzz0.r, ptFuzz0.g, ptFuzz0.b, i.viewDir);
|
|
samples.albedo1.rgb = FuzzyShade(samples.albedo1.rgb, half3(samples.normSAO1.rg, 1), ptFuzz1.r, ptFuzz1.g, ptFuzz1.b, i.viewDir);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = FuzzyShade(samples.albedo2.rgb, half3(samples.normSAO2.rg, 1), ptFuzz2.r, ptFuzz2.g, ptFuzz2.b, i.viewDir);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = FuzzyShade(samples.albedo3.rgb, half3(samples.normSAO3.rg, 1), ptFuzz3.r, ptFuzz3.g, ptFuzz3.b, i.viewDir);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSATURATION && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptSaturattion, 9.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = lerp(MSLuminance(samples.albedo0.rgb), samples.albedo0.rgb, ptSaturattion0.a);
|
|
samples.albedo1.rgb = lerp(MSLuminance(samples.albedo1.rgb), samples.albedo1.rgb, ptSaturattion1.a);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = lerp(MSLuminance(samples.albedo2.rgb), samples.albedo2.rgb, ptSaturattion2.a);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = lerp(MSLuminance(samples.albedo3.rgb), samples.albedo3.rgb, ptSaturattion3.a);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if _PERTEXTINT && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptTints, 1.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb *= ptTints0.rgb;
|
|
samples.albedo1.rgb *= ptTints1.rgb;
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb *= ptTints2.rgb;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb *= ptTints3.rgb;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PCHEIGHTGRADIENT || _PCHEIGHTHSV || _PCSLOPEGRADIENT || _PCSLOPEHSV
|
|
ProceduralGradients(i, samples, config, worldHeight, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS
|
|
porosity = _GlobalPorosity;
|
|
#endif
|
|
|
|
|
|
#if _PERTEXCOLORINTENSITY
|
|
SAMPLE_PER_TEX(ptCI, 23.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb * (1 + ptCI0.rrr));
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb * (1 + ptCI1.rrr));
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb * (1 + ptCI2.rrr));
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb * (1 + ptCI3.rrr));
|
|
#endif
|
|
#endif
|
|
|
|
#if (_PERTEXBRIGHTNESS || _PERTEXCONTRAST || _PERTEXPOROSITY || _PERTEXFOAM) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptBC, 3.5, config, half4(1, 1, 1, 1));
|
|
#if _PERTEXCONTRAST
|
|
samples.albedo0.rgb = saturate(((samples.albedo0.rgb - 0.5) * ptBC0.g) + 0.5);
|
|
samples.albedo1.rgb = saturate(((samples.albedo1.rgb - 0.5) * ptBC1.g) + 0.5);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(((samples.albedo2.rgb - 0.5) * ptBC2.g) + 0.5);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(((samples.albedo3.rgb - 0.5) * ptBC3.g) + 0.5);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXBRIGHTNESS
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb + ptBC0.rrr);
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb + ptBC1.rrr);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb + ptBC2.rrr);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb + ptBC3.rrr);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXPOROSITY
|
|
porosity = BlendWeights(ptBC0.b, ptBC1.b, ptBC2.b, ptBC3.b, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXFOAM
|
|
streamFoam = BlendWeights(ptBC0.a, ptBC1.a, ptBC2.a, ptBC3.a, heightWeights);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if (_PERTEXNORMSTR || _PERTEXAOSTR || _PERTEXSMOOTHSTR || _PERTEXMETALLIC) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(perTexMatSettings, 2.5, config, half4(1.0, 1.0, 1.0, 0.0));
|
|
#endif
|
|
|
|
#if _PERTEXNORMSTR && !_DISABLESPLATMAPS
|
|
#if _SURFACENORMALS
|
|
samples.surf0 *= perTexMatSettings0.r;
|
|
samples.surf1 *= perTexMatSettings1.r;
|
|
samples.surf2 *= perTexMatSettings2.r;
|
|
samples.surf3 *= perTexMatSettings3.r;
|
|
#else
|
|
samples.normSAO0.xy *= perTexMatSettings0.r;
|
|
samples.normSAO1.xy *= perTexMatSettings1.r;
|
|
samples.normSAO2.xy *= perTexMatSettings2.r;
|
|
samples.normSAO3.xy *= perTexMatSettings3.r;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXAOSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.a = pow(abs(samples.normSAO0.a), perTexMatSettings0.b);
|
|
samples.normSAO1.a = pow(abs(samples.normSAO1.a), perTexMatSettings1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a = pow(abs(samples.normSAO2.a), perTexMatSettings2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a = pow(abs(samples.normSAO3.a), perTexMatSettings3.b);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSMOOTHSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.b += perTexMatSettings0.g;
|
|
samples.normSAO1.b += perTexMatSettings1.g;
|
|
samples.normSAO0.b = saturate(samples.normSAO0.b);
|
|
samples.normSAO1.b = saturate(samples.normSAO1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.b += perTexMatSettings2.g;
|
|
samples.normSAO2.b = saturate(samples.normSAO2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.b += perTexMatSettings3.g;
|
|
samples.normSAO3.b = saturate(samples.normSAO3.b);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
#if _PERTEXSSS
|
|
{
|
|
SAMPLE_PER_TEX(ptSSS, 18.5, config, half4(1, 1, 1, 1)); // tint, thickness
|
|
half4 vals = ptSSS0 * heightWeights.x + ptSSS1 * heightWeights.y + ptSSS2 * heightWeights.z + ptSSS3 * heightWeights.w;
|
|
SSSThickness = vals.a;
|
|
SSSTint = vals.rgb;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXRIMLIGHT
|
|
{
|
|
SAMPLE_PER_TEX(ptRimA, 26.5, config, half4(1, 1, 1, 1));
|
|
SAMPLE_PER_TEX(ptRimB, 27.5, config, half4(1, 1, 1, 0));
|
|
samples.emisMetal0.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO0.xy, 1))), max(0.0001, ptRimA0.g)) * ptRimB0.rgb * ptRimB0.a;
|
|
samples.emisMetal1.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO1.xy, 1))), max(0.0001, ptRimA1.g)) * ptRimB1.rgb * ptRimB1.a;
|
|
samples.emisMetal2.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO2.xy, 1))), max(0.0001, ptRimA2.g)) * ptRimB2.rgb * ptRimB2.a;
|
|
samples.emisMetal3.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO3.xy, 1))), max(0.0001, ptRimA3.g)) * ptRimB3.rgb * ptRimB3.a;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#if (((_DETAILNOISE && _PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && _PERTEXDISTANCENOISESTRENGTH)) || (_NORMALNOISE && _PERTEXNORMALNOISESTRENGTH)) && !_DISABLESPLATMAPS
|
|
ApplyDetailDistanceNoisePerTex(samples, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALNOISEUV
|
|
// noise defaults so that a value of 1, 1 is 4 pixels in size and moves the uvs by 1 pixel max.
|
|
#if _CUSTOMSPLATTEXTURES
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#else
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE
|
|
ApplyTrax(samples, config, i.worldPos, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if (_ANTITILEARRAYDETAIL || _ANTITILEARRAYDISTANCE || _ANTITILEARRAYNORMAL) && !_DISABLESPLATMAPS
|
|
ApplyAntiTilePerTex(samples, config, camDist, i.worldPos, worldNormalVertex, heightWeights);
|
|
#endif
|
|
|
|
#if _GEOMAP && !_DISABLESPLATMAPS
|
|
GeoTexturePerTex(samples, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
#if _GLOBALTINT && _PERTEXGLOBALTINTSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalTintTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && _PERTEXGLOBALNORMALSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalNormalTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && _PERTEXGLOBALSAOMSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalSAOMTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && _PERTEXGLOBALEMISSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalEmisTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && _PERTEXGLOBALSPECULARSTRENGTH && !_DISABLESPLATMAPS && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _PERTEXMETALLIC && !_DISABLESPLATMAPS
|
|
half metallic = BlendWeights(perTexMatSettings0.a, perTexMatSettings1.a, perTexMatSettings2.a, perTexMatSettings3.a, heightWeights);
|
|
o.Metallic = metallic;
|
|
#endif
|
|
|
|
#if _GLITTER && !_DISABLESPLATMAPS
|
|
DoGlitter(i, samples, config, camDist, worldNormalVertex, i.worldPos);
|
|
#endif
|
|
|
|
// Blend em..
|
|
#if _DISABLESPLATMAPS
|
|
// If we don't sample from the _Diffuse, then the shader compiler will strip the sampler on
|
|
// some platforms, which will cause everything to break. So we sample from the lowest mip
|
|
// and saturate to 1 to keep the cost minimal. Annoying, but the compiler removes the texture
|
|
// and sampler, even though the sampler is still used.
|
|
albedo = saturate(UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, float3(0,0,0), 12) + 1);
|
|
albedo.a = 0.5; // make height something we can blend with for the combined mesh mode, since it still height blends.
|
|
normSAO = half4(0,0,0,1);
|
|
#else
|
|
albedo = BlendWeights(samples.albedo0, samples.albedo1, samples.albedo2, samples.albedo3, heightWeights);
|
|
normSAO = BlendWeights(samples.normSAO0, samples.normSAO1, samples.normSAO2, samples.normSAO3, heightWeights);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = BlendWeights(samples.surf0, samples.surf1, samples.surf2, samples.surf3, heightWeights);
|
|
#endif
|
|
|
|
#if (_USEEMISSIVEMETAL || _PERTEXRIMLIGHT) && !_DISABLESPLATMAPS
|
|
emisMetal = BlendWeights(samples.emisMetal0, samples.emisMetal1, samples.emisMetal2, samples.emisMetal3, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW && !_DISABLESPLATMAPS
|
|
specular = BlendWeights(samples.specular0, samples.specular1, samples.specular2, samples.specular3, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXOUTLINECOLOR
|
|
SAMPLE_PER_TEX(ptOutlineColor, 28.5, config, half4(0.5, 0.5, 0.5, 1));
|
|
half4 outlineColor = BlendWeights(ptOutlineColor0, ptOutlineColor1, ptOutlineColor2, ptOutlineColor3, heightWeights);
|
|
half4 tstr = saturate(abs(heightWeights - 0.5) * 2);
|
|
half transitionBlend = min(min(min(tstr.x, tstr.y), tstr.z), tstr.w);
|
|
albedo.rgb = lerp(albedo.rgb * outlineColor.rgb * 2, albedo.rgb, outlineColor.a * transitionBlend);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHOVERLAYSPLATS || _MESHCOMBINED
|
|
o.Alpha = 1.0;
|
|
if (config.uv0.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.x;
|
|
else if (config.uv1.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.y;
|
|
else if (config.uv2.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.z;
|
|
else if (config.uv3.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.w;
|
|
#endif
|
|
|
|
|
|
|
|
// effects which don't require per texture adjustments and are part of the splats sample go here.
|
|
// Often, as an optimization, you can compute the non-per tex version of above effects here..
|
|
|
|
|
|
#if ((_DETAILNOISE && !_PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && !_PERTEXDISTANCENOISESTRENGTH) || (_NORMALNOISE && !_PERTEXNORMALNOISESTRENGTH))
|
|
ApplyDetailDistanceNoise(albedo.rgb, normSAO, surfGrad, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
}
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
|
|
float2 sfDX = ddx(config.uv * _UVScale);
|
|
float2 sfDY = ddy(config.uv * _UVScale);
|
|
|
|
MSBRANCHOTHER(camDist - _SplatFade.x)
|
|
{
|
|
float falloff = saturate(InverseLerp(_SplatFade.x, _SplatFade.y, camDist));
|
|
half4 sfalb = SAMPLE_TEXTURE2D_ARRAY_GRAD(_Diffuse, sampler_Diffuse, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY);
|
|
COUNTSAMPLE
|
|
albedo.rgb = lerp(albedo.rgb, sfalb.rgb, falloff);
|
|
|
|
#if !_NONORMALMAP && !_AUTONORMAL
|
|
half4 sfnormSAO = SAMPLE_TEXTURE2D_ARRAY_GRAD(_NormalSAO, sampler_NormalSAO, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY).agrb;
|
|
COUNTSAMPLE
|
|
sfnormSAO.xy = sfnormSAO.xy * 2 - 1;
|
|
|
|
normSAO = lerp(normSAO, sfnormSAO, falloff);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = lerp(surfGrad, ConvertNormal2ToGradient(sfnormSAO.xy), falloff);
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
float3 autoNormal = HeightToNormal(albedo.a * _AutoNormalHeightScale, i.worldPos);
|
|
normSAO.xy = autoNormal;
|
|
normSAO.z = 0;
|
|
normSAO.w = (autoNormal.z * autoNormal.z);
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHCOMBINED
|
|
SampleMeshCombined(albedo, normSAO, surfGrad, emisMetal, specular, o.Alpha, SSSThickness, SSSTint, config, heightWeights);
|
|
#endif
|
|
|
|
#if _ISOBJECTSHADER
|
|
SampleObjectShader(i, albedo, normSAO, surfGrad, emisMetal, specular, config);
|
|
#endif
|
|
|
|
#if _GEOMAP
|
|
GeoTexture(albedo.rgb, normSAO, surfGrad, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
|
|
#if _SCATTER
|
|
ApplyScatter(
|
|
#if _MEGASPLAT
|
|
config,
|
|
#endif
|
|
i, albedo, normSAO, surfGrad, config.uv, camDist);
|
|
#endif
|
|
|
|
#if _DECAL
|
|
DoDecalBlend(decalOutput, albedo, normSAO, surfGrad, emisMetal, i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALTINT && !_PERTEXGLOBALTINTSTRENGTH
|
|
GlobalTintTexture(albedo.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _VSGRASSMAP
|
|
VSGrassTexture(albedo.rgb, config, camDist);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && !_PERTEXGLOBALNORMALSTRENGTH
|
|
GlobalNormalTexture(normSAO, surfGrad, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && !_PERTEXGLOBALSAOMSTRENGTH
|
|
GlobalSAOMTexture(normSAO, emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && !_PERTEXGLOBALEMISSTRENGTH
|
|
GlobalEmisTexture(emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && !_PERTEXGLOBALSPECULARSTRENGTH && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexture(specular.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
|
|
|
|
o.Albedo = albedo.rgb;
|
|
o.Height = albedo.a;
|
|
|
|
#if _NONORMALMAP
|
|
o.Normal = half3(0,0,1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#elif _SURFACENORMALS
|
|
o.Normal = ResolveNormalFromSurfaceGradient(surfGrad);
|
|
o.Normal = mul(GetTBN(i), o.Normal);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#else
|
|
o.Normal = half3(normSAO.xy, 1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _PERTEXRIMLIGHT
|
|
#if _USEEMISSIVEMETAL
|
|
emisMetal.rgb *= _EmissiveMult;
|
|
#endif
|
|
|
|
o.Emission += emisMetal.rgb;
|
|
o.Metallic = emisMetal.a;
|
|
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = specular;
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
pud = DoStreams(i, o, fxLevels, config.uv, porosity, waterNormalFoam, worldNormalVertex, streamFoam, wetLevel, burnLevel, i.worldPos);
|
|
#endif
|
|
|
|
|
|
#if _SNOW
|
|
snowCover = DoSnow(i, o, config.uv, WorldNormalVector(i, o.Normal), worldNormalVertex, i.worldPos, pud, porosity, camDist,
|
|
config, weights, SSSTint, SSSThickness, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if _PERTEXSSS || _MESHCOMBINEDUSESSS || (_SNOW && _SNOWSSS)
|
|
{
|
|
half3 worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
|
|
|
|
o.Emission += ComputeSSS(i, worldView, WorldNormalVector(i, o.Normal),
|
|
SSSTint, SSSThickness, _SSSDistance, _SSSScale, _SSSPower);
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWGLITTER
|
|
DoSnowGlitter(i, config, o, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
#if _WINDPARTICULATE || _SNOWPARTICULATE
|
|
DoWindParticulate(i, o, config, weights, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
o.Normal.z = sqrt(1 - saturate(dot(o.Normal.xy, o.Normal.xy)));
|
|
|
|
#if _SPECULARFADE
|
|
{
|
|
float specFade = saturate((i.worldPos.y - _SpecularFades.x) / max(_SpecularFades.y - _SpecularFades.x, 0.0001));
|
|
o.Metallic *= specFade;
|
|
o.Smoothness *= specFade;
|
|
}
|
|
#endif
|
|
|
|
#if _VSSHADOWMAP
|
|
VSShadowTexture(o, i, config, camDist);
|
|
#endif
|
|
|
|
#if _TOONWIREFRAME
|
|
ToonWireframe(config.uv, o.Albedo, camDist);
|
|
#endif
|
|
|
|
#if _SEETHROUGHSHADER
|
|
SeethroughShader(o.Albedo, o.Emission, o.Alpha, i.worldPos, o.Normal, i.worldNormal);
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_TRAXBUFFER
|
|
ClearAllButAlbedo(o, half3(traxBuffer, 0, 0) * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMALVERTEX
|
|
ClearAllButAlbedo(o, worldNormalVertex * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(o, WorldNormalVector(i, o.Normal) * saturate(o.Albedo.z+1));
|
|
#endif
|
|
|
|
#if _DEBUG_MEGABARY && _MEGASPLAT
|
|
o.Albedo = i.baryWeights.xyz;
|
|
#endif
|
|
|
|
|
|
return o;
|
|
}
|
|
|
|
void SampleSplats(float2 controlUV, inout half4 w0, inout half4 w1, inout half4 w2, inout half4 w3, inout half4 w4, inout half4 w5, inout half4 w6, inout half4 w7)
|
|
{
|
|
#if _CUSTOMSPLATTEXTURES
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_CustomControl0_TexelSize.zw - 1.0f) + 0.5f) * _CustomControl0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_CustomControl0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_CustomControl1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_CustomControl2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_CustomControl3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_CustomControl4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_CustomControl5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_CustomControl6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_CustomControl7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#else
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_Control0_TexelSize.zw - 1.0f) + 0.5f) * _Control0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_Control0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_Control1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_Control2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_Control3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_Control4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_Control5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_Control6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_Control7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
MicroSplatLayer SurfImpl(Input i, float3 worldNormalVertex)
|
|
{
|
|
#if _MEGANOUV
|
|
i.uv_Control0 = i.worldPos.xz;
|
|
#endif
|
|
|
|
float camDist = distance(_WorldSpaceCameraPos, i.worldPos);
|
|
|
|
#if _FORCELOCALSPACE
|
|
worldNormalVertex = mul((float3x3)GetWorldToObjectMatrix(), worldNormalVertex).xyz;
|
|
i.worldPos = i.worldPos - mul(GetObjectToWorldMatrix(), float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
i.worldPos = i.worldPos + mul(_GlobalOriginMTX, float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
i.worldPos = SAMPLE_TEXTURE2D(_DebugWorldPos, sampler_Diffuse, i.uv_Control0);
|
|
worldNormalVertex = SAMPLE_TEXTURE2D(_DebugWorldNormal, sampler_Diffuse, i.uv_Control0);
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ALPHABELOWHEIGHT && !_TBDISABLEALPHAHOLES
|
|
ClipWaterLevel(i.worldPos);
|
|
#endif
|
|
|
|
#if !_TBDISABLEALPHAHOLES && defined(_ALPHATEST_ON)
|
|
// UNITY 2019.3 holes
|
|
ClipHoles(i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
float2 origUV = i.uv_Control0;
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
float2 controlUV = i.uv2_Diffuse;
|
|
#else
|
|
float2 controlUV = i.uv_Control0;
|
|
#endif
|
|
|
|
|
|
#if _MICROMESH
|
|
controlUV = InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, controlUV);
|
|
#endif
|
|
|
|
half4 weights = half4(1,0,0,0);
|
|
|
|
Config config = (Config)0;
|
|
UNITY_INITIALIZE_OUTPUT(Config,config);
|
|
config.uv = origUV;
|
|
|
|
DecalOutput decalOutput = (DecalOutput)0;
|
|
#if _DECAL
|
|
decalOutput = DoDecals(i.uv_Control0, i.worldPos, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SURFACENORMALS
|
|
// Initialize the surface gradient basis vectors
|
|
ConstructSurfaceGradientTBN(i);
|
|
#endif
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(_SplatFade.y - camDist)
|
|
#endif // _SPLATFADE
|
|
{
|
|
#if !_DISABLESPLATMAPS
|
|
|
|
// Sample the splat data, from textures or vertices, and setup the config..
|
|
#if _MICRODIGGERMESH
|
|
DiggerSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLAT
|
|
MegaSplatVertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLATTEXTURE
|
|
MegaSplatTextureSetup(controlUV, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MICROVERTEXMESH
|
|
VertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif !_PROCEDURALTEXTURE || _PROCEDURALBLENDSPLATS
|
|
half4 w0 = 0; half4 w1 = 0; half4 w2 = 0; half4 w3 = 0; half4 w4 = 0; half4 w5 = 0; half4 w6 = 0; half4 w7 = 0;
|
|
SampleSplats(controlUV, w0, w1, w2, w3, w4, w5, w6, w7);
|
|
Setup(weights, origUV, config, w0, w1, w2, w3, w4, w5, w6, w7, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
float3 procNormal = worldNormalVertex;
|
|
float3 worldPos = i.worldPos;
|
|
ProceduralSetup(i, worldPos, i.worldHeight, procNormal, i.worldUpVector, weights, origUV, config, ddx(origUV), ddy(origUV), ddx(worldPos), ddy(worldPos), decalOutput);
|
|
#endif
|
|
#else // _DISABLESPLATMAPS
|
|
Setup(weights, origUV, config, half4(1,0,0,0), 0, 0, 0, 0, 0, 0, 0, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _SLOPETEXTURE
|
|
SlopeTexture(config, weights, worldNormalVertex);
|
|
#endif
|
|
} // _SPLATFADE else case
|
|
|
|
|
|
#if _TOONFLATTEXTURE
|
|
float2 quv = floor(origUV * _ToonTerrainSize);
|
|
float2 fuv = frac(origUV * _ToonTerrainSize);
|
|
#if !_TOONFLATTEXTUREQUAD
|
|
quv = Hash2D((fuv.x > fuv.y) ? quv : quv * 0.333);
|
|
#endif
|
|
float2 uvq = quv / _ToonTerrainSize;
|
|
config.uv0.xy = uvq;
|
|
config.uv1.xy = uvq;
|
|
config.uv2.xy = uvq;
|
|
config.uv3.xy = uvq;
|
|
#endif
|
|
|
|
#if (_TEXTURECLUSTER2 || _TEXTURECLUSTER3) && !_DISABLESPLATMAPS
|
|
PrepClusters(origUV, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if (_ALPHAHOLE || _ALPHAHOLETEXTURE) && !_DISABLESPLATMAPS && !_TBDISABLEALPHAHOLES
|
|
ClipAlphaHole(config, weights);
|
|
#endif
|
|
|
|
|
|
|
|
MicroSplatLayer l = Sample(i, weights, config, camDist, worldNormalVertex, decalOutput);
|
|
|
|
// On windows, sometimes the shared samplers gets stripped, so we have to do this crap.
|
|
// We sample from the lowest mip, so it shouldn't cost much, but still, I hate this, wtf..
|
|
float stripVal = saturate(SAMPLE_TEXTURE2D_LOD(_Diffuse, sampler_Diffuse, config.uv0, 11).r + 2);
|
|
stripVal *= saturate(SAMPLE_TEXTURE2D_LOD(_NormalSAO, sampler_NormalSAO, config.uv0, 11).r + 2);
|
|
l.Albedo *= stripVal;
|
|
l.Normal *= stripVal;
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
ProceduralTextureDebugOutput(l, weights, config);
|
|
#endif
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float4 ConstructTerrainTangent(float3 normal, float3 positiveZ)
|
|
{
|
|
// Consider a flat terrain. It should have tangent be (1, 0, 0) and bitangent be (0, 0, 1) as the UV of the terrain grid mesh is a scale of the world XZ position.
|
|
// In CreateTangentToWorld function (in SpaceTransform.hlsl), it is cross(normal, tangent) * sgn for the bitangent vector.
|
|
// It is not true in a left-handed coordinate system for the terrain bitangent, if we provide 1 as the tangent.w. It would produce (0, 0, -1) instead of (0, 0, 1).
|
|
// Also terrain's tangent calculation was wrong in a left handed system because cross((0,0,1), terrainNormalOS) points to the wrong direction as negative X.
|
|
// Therefore all the 4 xyzw components of the tangent needs to be flipped to correct the tangent frame.
|
|
// (See TerrainLitData.hlsl - GetSurfaceAndBuiltinData)
|
|
float3 tangent = normalize(cross(normal, positiveZ));
|
|
return float4(tangent, -1);
|
|
}
|
|
|
|
|
|
|
|
void TerrainInstancing(inout float4 vertex, inout float3 normal, inout float2 uv)
|
|
{
|
|
#if _MICROTERRAIN && defined(UNITY_INSTANCING_ENABLED) && !_TERRAINBLENDABLESHADER
|
|
|
|
float2 patchVertex = vertex.xy;
|
|
float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);
|
|
|
|
float2 sampleCoords = (patchVertex.xy + instanceData.xy) * instanceData.z; // (xy + float2(xBase,yBase)) * skipScale
|
|
uv = sampleCoords * _TerrainHeightmapRecipSize.zw;
|
|
|
|
float2 sampleUV = (uv / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleUV, 0));
|
|
|
|
vertex.xz = sampleCoords * _TerrainHeightmapScale.xz;
|
|
vertex.y = height * _TerrainHeightmapScale.y;
|
|
|
|
|
|
normal = float3(0, 1, 0);
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
void ApplyMeshModification(inout VertexData input)
|
|
{
|
|
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
|
|
float2 uv = input.texcoord0.xy;
|
|
TerrainInstancing(input.vertex, input.normal, uv);
|
|
input.texcoord0.xy = uv;
|
|
#endif
|
|
#if _PERPIXNORMAL && !_TERRAINBLENDABLESHADER
|
|
input.normal = float3(0,1,0);
|
|
#endif
|
|
|
|
#if _MICROVERSEPREVIEW
|
|
float4 recipSize = _TerrainHeightmapTexture_TexelSize;
|
|
recipSize.zw = (1.0f / (_TerrainHeightmapTexture_TexelSize.zw-1));
|
|
float2 sampleCoords = (input.texcoord0.xy / recipSize.zw + 0.5f) * recipSize.xy;
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleCoords, 0));
|
|
input.vertex.xyz += float3(0,1,0) * height * _TerrainHeight * 2;
|
|
#endif
|
|
|
|
}
|
|
|
|
// called by the template, so we can remove tangent from VertexData
|
|
void ApplyTerrainTangent(inout VertexToPixel input)
|
|
{
|
|
#if (_MICROTERRAIN || _PERPIXNORMAL) && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
|
|
// digger meshes ain't got no tangent either..
|
|
#if _MICRODIGGERMESH && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
void ModifyVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
ApplyMeshModification(v);
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
EncodeVertexWorkflow(v, d);
|
|
#elif _MEGASPLAT
|
|
EncodeMegaSplatVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void ModifyTessellatedVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
#if _MICROVERSEPREVIEW
|
|
v.vertex.y = OffsetVertex(v, d).y;
|
|
#elif _TESSDISTANCE || _TESSEDGE
|
|
v.vertex.xyz += OffsetVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
float3 GetTessFactors ()
|
|
{
|
|
#if _TESSEDGE
|
|
return float3(_TessData1.x, _TessData1.w, 0);
|
|
#endif
|
|
#if _TESSDISTANCE
|
|
return float3(_TessData2.x, _TessData2.y, _TessData1.x);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SurfaceFunction(inout Surface o, inout ShaderData d)
|
|
{
|
|
|
|
float3 worldNormalVertex = d.worldSpaceNormal;
|
|
#if _MICROVERSEPREVIEW
|
|
float2 sampleCoords = d.texcoord0.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif (defined(UNITY_INSTANCING_ENABLED) && _MICROTERRAIN && !_TERRAINBLENDABLESHADER)
|
|
float2 sampleCoords = (d.texcoord0.xy / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif _PERPIXNORMAL && (_MICROTERRAIN || _MICROMESHTERRAIN) && !_TERRAINBLENDABLESHADER
|
|
float2 sampleCoords = (d.texcoord0.xy * _PerPixelNormal_TexelSize.zw + 0.5f) * _PerPixelNormal_TexelSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_PerPixelNormal, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
|
|
float3 geomBitangent = normalize(cross(geomTangent, geomNormal)) * -1;
|
|
#if _MICROMESHTERRAIN
|
|
geomBitangent *= -1;
|
|
#endif
|
|
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#endif
|
|
|
|
#if _TOONPOLYEDGE
|
|
FlatShade(d);
|
|
#endif
|
|
|
|
Input i = DescToInput(d);
|
|
|
|
|
|
|
|
#if _SRPTERRAINBLEND
|
|
MicroSplatLayer l = BlendWithTerrain(d);
|
|
|
|
#if _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(l, normalize(TangentToWorldSpace(d, l.Normal)) * saturate(l.Albedo.z+1));
|
|
#endif
|
|
#else
|
|
MicroSplatLayer l = SurfImpl(i, worldNormalVertex);
|
|
#endif
|
|
|
|
DoDebugOutput(l);
|
|
|
|
|
|
|
|
|
|
o.Albedo = l.Albedo;
|
|
o.Normal = l.Normal;
|
|
o.Smoothness = l.Smoothness;
|
|
o.Occlusion = l.Occlusion;
|
|
o.Metallic = l.Metallic;
|
|
o.Emission = l.Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = l.Specular;
|
|
#endif
|
|
o.Height = l.Height;
|
|
o.Alpha = l.Alpha;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SHADERDESC
|
|
|
|
ShaderData CreateShaderData(VertexToPixel i)
|
|
{
|
|
ShaderData d = (ShaderData)0;
|
|
d.worldSpacePosition = i.worldPos;
|
|
|
|
d.worldSpaceNormal = i.worldNormal;
|
|
d.worldSpaceTangent = i.worldTangent.xyz;
|
|
float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * -1;
|
|
|
|
|
|
d.TBNMatrix = float3x3(d.worldSpaceTangent, bitangent, d.worldSpaceNormal);
|
|
d.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
d.texcoord0 = i.texcoord0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
d.texcoord1 = i.texcoord1;
|
|
// d.texcoord2 = i.texcoord2;
|
|
#endif
|
|
// d.texcoord3 = i.texcoord3;
|
|
// d.vertexColor = i.vertexColor;
|
|
|
|
// these rarely get used, so we back transform them. Usually will be stripped.
|
|
#if _HDRP
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(GetCameraRelativePositionWS(i.worldPos), 1));
|
|
#else
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(i.worldPos, 1));
|
|
#endif
|
|
// d.localSpaceNormal = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldNormal));
|
|
// d.localSpaceTangent = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldTangent.xyz));
|
|
|
|
// d.screenPos = i.screenPos;
|
|
// d.screenUV = i.screenPos.xy / i.screenPos.w;
|
|
|
|
// d.extraV2F0 = i.extraV2F0;
|
|
// d.extraV2F1 = i.extraV2F1;
|
|
// d.extraV2F2 = i.extraV2F2;
|
|
// d.extraV2F3 = i.extraV2F3;
|
|
// d.extraV2F4 = i.extraV2F4;
|
|
// d.extraV2F5 = i.extraV2F5;
|
|
// d.extraV2F6 = i.extraV2F6;
|
|
// d.extraV2F7 = i.extraV2F7;
|
|
|
|
return d;
|
|
}
|
|
// CHAINS
|
|
|
|
void ChainModifyVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
ModifyVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
void ChainModifyTessellatedVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
// d.extraV2F0 = v2p.extraV2F0;
|
|
// d.extraV2F1 = v2p.extraV2F1;
|
|
// d.extraV2F2 = v2p.extraV2F2;
|
|
// d.extraV2F3 = v2p.extraV2F3;
|
|
// d.extraV2F4 = v2p.extraV2F4;
|
|
// d.extraV2F5 = v2p.extraV2F5;
|
|
// d.extraV2F6 = v2p.extraV2F6;
|
|
// d.extraV2F7 = v2p.extraV2F7;
|
|
|
|
ModifyTessellatedVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
|
|
void ChainFinalColorForward(inout Surface l, inout ShaderData d, inout half4 color)
|
|
{
|
|
|
|
}
|
|
|
|
void ChainFinalGBufferStandard(inout Surface s, inout ShaderData d, inout half4 GBuffer0, inout half4 GBuffer1, inout half4 GBuffer2, inout half4 outEmission, inout half4 outShadowMask)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _PASSSHADOW
|
|
float3 _LightDirection;
|
|
float3 _LightPosition;
|
|
#endif
|
|
|
|
// vertex shader
|
|
VertexToPixel Vert (VertexData v)
|
|
{
|
|
|
|
VertexToPixel o = (VertexToPixel)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
|
|
|
|
|
#if !_TESSELLATION_ON
|
|
ChainModifyVertex(v, o);
|
|
#endif
|
|
|
|
o.texcoord0 = v.texcoord0;
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
o.texcoord1 = v.texcoord1;
|
|
// o.texcoord2 = v.texcoord2;
|
|
#endif
|
|
|
|
// o.texcoord3 = v.texcoord3;
|
|
// o.vertexColor = v.vertexColor;
|
|
|
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
|
|
o.worldPos = TransformObjectToWorld(v.vertex.xyz);
|
|
o.worldNormal = TransformObjectToWorldNormal(v.normal);
|
|
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float2 uv1 = v.texcoord1.xy;
|
|
float2 uv2 = v.texcoord2.xy;
|
|
o.worldTangent = float4(TransformObjectToWorldDir(v.tangent.xyz), v.tangent.w);
|
|
#else
|
|
float2 uv1 = v.texcoord0.xy;
|
|
float2 uv2 = uv1;
|
|
#endif
|
|
|
|
// MS Only
|
|
ApplyTerrainTangent(o);
|
|
|
|
|
|
#if _PASSSHADOW
|
|
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
float3 lightDirectionWS = normalize(_LightPosition - o.worldPos);
|
|
#else
|
|
float3 lightDirectionWS = _LightDirection;
|
|
#endif
|
|
// Define shadow pass specific clip position for Universal
|
|
o.pos = TransformWorldToHClip(ApplyShadowBias(o.worldPos, o.worldNormal, lightDirectionWS));
|
|
#if UNITY_REVERSED_Z
|
|
o.pos.z = min(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#else
|
|
o.pos.z = max(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#endif
|
|
#elif _PASSMETA
|
|
#if _MICROTERRAIN
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), v.texcoord0.xy, v.texcoord0.xy, unity_LightmapST, unity_DynamicLightmapST);
|
|
#else
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), uv1, uv2, unity_LightmapST, unity_DynamicLightmapST);
|
|
#endif
|
|
#else
|
|
o.pos = TransformWorldToHClip(o.worldPos);
|
|
#endif
|
|
|
|
|
|
|
|
// o.screenPos = ComputeScreenPos(o.pos, _ProjectionParams.x);
|
|
|
|
|
|
#if _PASSFORWARD || _PASSGBUFFER
|
|
#if _MICROTERRAIN
|
|
OUTPUT_LIGHTMAP_UV(v.texcoord0.xy, unity_LightmapST, o.lightmapUV);
|
|
#else
|
|
OUTPUT_LIGHTMAP_UV(uv1, unity_LightmapST, o.lightmapUV);
|
|
#endif
|
|
OUTPUT_SH(o.worldNormal, o.sh);
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
o.dynamicLightmapUV.xy = uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
|
|
half fogFactor = 0;
|
|
#if defined(_FOG_FRAGMENT)
|
|
fogFactor = ComputeFogFactor(o.pos.z);
|
|
#endif
|
|
#if _BAKEDLIT
|
|
half3 vertexLight = VertexLighting(o.worldPos, o.worldNormal);
|
|
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
|
|
#else
|
|
o.fogFactorAndVertexLight = half4(fogFactor, 0,0,0);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
|
|
o.shadowCoord = GetShadowCoord(vertexInput);
|
|
#endif
|
|
|
|
return o;
|
|
}
|
|
|
|
|
|
|
|
|
|
#if _UNLIT
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Unlit.hlsl"
|
|
#endif
|
|
|
|
// fragment shader
|
|
void Frag (VertexToPixel IN
|
|
, out half4 outColor : SV_Target0
|
|
#ifdef _WRITE_RENDERING_LAYERS
|
|
, out float4 outRenderingLayers : SV_Target1
|
|
#endif
|
|
#ifdef _DEPTHOFFSET_ON
|
|
, out float outputDepth : SV_Depth
|
|
#endif
|
|
#if NEED_FACING
|
|
, bool facing : SV_IsFrontFace
|
|
#endif
|
|
)
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
|
|
|
|
#if defined(LOD_FADE_CROSSFADE)
|
|
LODFadeCrossFade(IN.pos);
|
|
#endif
|
|
|
|
ShaderData d = CreateShaderData(IN);
|
|
Surface l = (Surface)0;
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
l.outputDepth = outputDepth;
|
|
#endif
|
|
|
|
l.Albedo = half3(0.5, 0.5, 0.5);
|
|
l.Normal = float3(0,0,1);
|
|
l.Occlusion = 1;
|
|
l.Alpha = 1;
|
|
|
|
SurfaceFunction(l, d);
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
outputDepth = l.outputDepth;
|
|
#endif
|
|
|
|
#if defined(_USESPECULAR) || _SIMPLELIT
|
|
float3 specular = l.Specular;
|
|
float metallic = 0;
|
|
#else
|
|
float3 specular = 0;
|
|
float metallic = l.Metallic;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
InputData inputData = (InputData)0;
|
|
|
|
inputData.positionWS = IN.worldPos;
|
|
inputData.normalWS = mul(l.Normal, d.TBNMatrix);
|
|
inputData.viewDirectionWS = SafeNormalize(d.worldSpaceViewDir);
|
|
|
|
|
|
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
|
|
inputData.shadowCoord = IN.shadowCoord;
|
|
#elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
|
|
inputData.shadowCoord = TransformWorldToShadowCoord(IN.worldPos);
|
|
#else
|
|
inputData.shadowCoord = float4(0, 0, 0, 0);
|
|
#endif
|
|
|
|
#if _BAKEDLIT
|
|
inputData.fogCoord = IN.fogFactorAndVertexLight.x;
|
|
#elif VERSION_GREATER_EQUAL(12, 0)
|
|
inputData.fogCoord = InitializeInputDataFog(float4(IN.worldPos, 1.0), IN.fogFactorAndVertexLight.x);
|
|
#else
|
|
inputData.fogCoord = IN.fogFactorAndVertexLight.x;
|
|
#endif
|
|
|
|
inputData.vertexLighting = IN.fogFactorAndVertexLight.yzw;
|
|
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
inputData.bakedGI = SAMPLE_GI(IN.lightmapUV, IN.dynamicLightmapUV.xy, IN.sh, inputData.normalWS);
|
|
#else
|
|
inputData.bakedGI = SAMPLE_GI(IN.lightmapUV, IN.sh, inputData.normalWS);
|
|
#endif
|
|
|
|
inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(IN.pos);
|
|
#if !_BAKEDLIT && defined(LIGHTMAP_ON)
|
|
inputData.shadowMask = SAMPLE_SHADOWMASK(IN.lightmapUV);
|
|
#endif
|
|
|
|
#if defined(DEBUG_DISPLAY)
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
inputData.dynamicLightmapUV = IN.dynamicLightmapUV.xy;
|
|
#endif
|
|
#if defined(LIGHTMAP_ON)
|
|
inputData.staticLightmapUV = IN.lightmapUV;
|
|
#else
|
|
inputData.vertexSH = IN.sh;
|
|
#endif
|
|
#endif
|
|
|
|
SurfaceData surface = (SurfaceData)0;
|
|
surface.albedo = l.Albedo;
|
|
surface.metallic = saturate(metallic);
|
|
surface.specular = specular;
|
|
surface.smoothness = saturate(l.Smoothness),
|
|
surface.occlusion = l.Occlusion,
|
|
surface.emission = l.Emission,
|
|
surface.alpha = saturate(l.Alpha);
|
|
surface.clearCoatMask = 0;
|
|
surface.clearCoatSmoothness = 1;
|
|
|
|
half4 color = half4(l.Albedo, l.Alpha);
|
|
#ifdef _DBUFFER
|
|
#if _BAKEDLIT
|
|
ApplyDecalToBaseColorAndNormal(IN.pos, color, inputData.normalWS);
|
|
#else
|
|
ApplyDecalToSurfaceData(IN.pos, surface, inputData);
|
|
#endif
|
|
#endif
|
|
|
|
#if !_UNLIT
|
|
#if _SIMPLELIT
|
|
color = UniversalFragmentBlinnPhong(
|
|
inputData,
|
|
surface);
|
|
#elif _BAKEDLIT
|
|
color = UniversalFragmentBakedLit(inputData, color.rgb, color.a, l.Normal);
|
|
#else
|
|
color = UniversalFragmentPBR(inputData, surface);
|
|
#endif
|
|
color.rgb = MixFog(color.rgb, inputData.fogCoord);
|
|
|
|
#else
|
|
#ifdef _DBUFFER
|
|
ApplyDecalToSurfaceData(IN.pos, surface, inputData);
|
|
#endif
|
|
color = UniversalFragmentUnlit(inputData, l.Albedo, l.Alpha);
|
|
#endif
|
|
ChainFinalColorForward(l, d, color);
|
|
|
|
outColor = color;
|
|
|
|
#ifdef _WRITE_RENDERING_LAYERS
|
|
uint renderingLayers = GetMeshRenderingLayer();
|
|
outRenderingLayers = float4(EncodeMeshRenderingLayer(renderingLayers), 0, 0, 0);
|
|
#endif
|
|
|
|
}
|
|
|
|
ENDHLSL
|
|
|
|
}
|
|
|
|
|
|
|
|
Pass
|
|
{
|
|
Name "GBuffer"
|
|
Tags
|
|
{
|
|
"LightMode" = "UniversalGBuffer"
|
|
}
|
|
|
|
Blend One Zero
|
|
ZTest LEqual
|
|
ZWrite On
|
|
|
|
|
|
|
|
HLSLPROGRAM
|
|
|
|
#pragma vertex Vert
|
|
#pragma fragment Frag
|
|
|
|
#pragma target 3.5
|
|
|
|
#pragma prefer_hlslcc gles
|
|
#pragma exclude_renderers d3d11_9x
|
|
#pragma multi_compile_instancing
|
|
#pragma multi_compile_fog
|
|
#pragma multi_compile _ DOTS_INSTANCING_ON
|
|
#pragma multi_compile_local _ _ALPHATEST_ON
|
|
#pragma instancing_options renderinglayer
|
|
|
|
|
|
#pragma multi_compile _ LIGHTMAP_ON
|
|
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
|
|
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
|
|
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
|
|
#pragma multi_compile _ _REFLECTION_PROBE_BLENDING
|
|
#pragma multi_compile _ _REFLECTION_PROBE_BOX_PROJECTION
|
|
#pragma multi_compile _ _SHADOWS_SOFT
|
|
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
|
|
#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE
|
|
#pragma multi_compile _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
|
|
#pragma multi_compile _ _GBUFFER_NORMALS_OCT
|
|
#pragma multi_compile _ _LIGHT_LAYERS
|
|
#pragma multi_compile _ _RENDER_PASS_ENABLED
|
|
#pragma multi_compile _ DEBUG_DISPLAY
|
|
#pragma multi_compile _ SHADOWS_SHADOWMASK
|
|
#pragma multi_compile_fragment _ _WRITE_RENDERING_LAYERS
|
|
#define _FOG_FRAGMENT 1
|
|
|
|
|
|
#define _MICROSPLAT 1
|
|
#define _MICROPOLARISMESH 1
|
|
#define _USEGRADMIP 1
|
|
#define _PERTEXUVSCALEOFFSET 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
#define _MSRENDERLOOP_UNITYLD 1
|
|
#define _MSRENDERLOOP_UNITYURP2020 1
|
|
#define _MSRENDERLOOP_UNITYURP2021 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
|
|
|
|
|
|
#define _URP 1
|
|
|
|
|
|
|
|
#define VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
|
|
#define SHADERPASS SHADERPASS_GBUFFER
|
|
#define _PASSGBUFFER 1
|
|
|
|
// Includes
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
|
|
#if VERSION_GREATER_EQUAL(12, 0)
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
|
|
#endif
|
|
#include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, float3x3(d.worldSpaceTangent, cross(d.worldSpaceTangent, d.worldSpaceNormal), d.worldSpaceNormal))
|
|
|
|
|
|
#define UnityObjectToWorldNormal(normal) mul(GetObjectToWorldMatrix(), normal)
|
|
|
|
#define _WorldSpaceLightPos0 _MainLightPosition
|
|
|
|
#define UNITY_DECLARE_TEX2D(name) TEXTURE2D(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2D_NOSAMPLER(name) TEXTURE2D(name);
|
|
#define UNITY_DECLARE_TEX2DARRAY(name) TEXTURE2D_ARRAY(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2DARRAY_NOSAMPLER(name) TEXTURE2D_ARRAY(name);
|
|
|
|
#define UNITY_SAMPLE_TEX2DARRAY(tex,coord) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, coord.xy, coord.z)
|
|
#define UNITY_SAMPLE_TEX2DARRAY_LOD(tex,coord,lod) SAMPLE_TEXTURE2D_ARRAY_LOD(tex, sampler##tex, coord.xy, coord.z, lod)
|
|
#define UNITY_SAMPLE_TEX2D(tex, coord) SAMPLE_TEXTURE2D(tex, sampler##tex, coord)
|
|
#define UNITY_SAMPLE_TEX2D_SAMPLER(tex, samp, coord) SAMPLE_TEXTURE2D(tex, sampler##samp, coord)
|
|
|
|
#if defined(UNITY_COMPILER_HLSL)
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
|
|
#else
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name)
|
|
#endif
|
|
|
|
#define sampler2D_float sampler2D
|
|
#define sampler2D_half sampler2D
|
|
|
|
|
|
|
|
// data across stages, stripped like the above.
|
|
struct VertexToPixel
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float3 worldPos : TEXCOORD0;
|
|
float3 worldNormal : TEXCOORD1;
|
|
float4 worldTangent : TEXCOORD2;
|
|
float4 texcoord0 : TEXCCOORD3;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 texcoord1 : TEXCCOORD4;
|
|
// float4 texcoord2 : TEXCCOORD5;
|
|
#endif
|
|
// float4 texcoord3 : TEXCCOORD6;
|
|
// float4 screenPos : TEXCOORD7;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
// float4 extraV2F0 : TEXCOORD13;
|
|
// float4 extraV2F1 : TEXCOORD14;
|
|
// float4 extraV2F2 : TEXCOORD15;
|
|
// float4 extraV2F3 : TEXCOORD16;
|
|
// float4 extraV2F4 : TEXCOORD17;
|
|
// float4 extraV2F5 : TEXCOORD18;
|
|
// float4 extraV2F6 : TEXCOORD19;
|
|
// float4 extraV2F7 : TEXCOORD20;
|
|
|
|
|
|
#if defined(LIGHTMAP_ON)
|
|
float2 lightmapUV : TEXCOORD8;
|
|
#endif
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
float2 dynamicLightmapUV : TEXCOORD9;
|
|
#endif
|
|
#if !defined(LIGHTMAP_ON)
|
|
float3 sh : TEXCOORD10;
|
|
#endif
|
|
|
|
float4 fogFactorAndVertexLight : TEXCOORD11;
|
|
float4 shadowCoord : TEXCOORD12;
|
|
|
|
#if UNITY_ANY_INSTANCING_ENABLED
|
|
uint instanceID : CUSTOM_INSTANCE_ID;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_MULTIVIEW_ENABLED)) || (defined(UNITY_STEREO_INSTANCING_ENABLED) && (defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)))
|
|
uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_INSTANCING_ENABLED))
|
|
uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex;
|
|
#endif
|
|
#if defined(SHADER_STAGE_FRAGMENT) && defined(VARYINGS_NEED_CULLFACE)
|
|
FRONT_FACE_TYPE cullFace : FRONT_FACE_SEMANTIC;
|
|
#endif
|
|
};
|
|
|
|
|
|
|
|
// TEMPLATE_SHARED
|
|
|
|
// data describing the user output of a pixel
|
|
struct Surface
|
|
{
|
|
half3 Albedo;
|
|
half Height;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half3 Emission;
|
|
half Metallic;
|
|
half3 Specular;
|
|
half Occlusion;
|
|
half Alpha;
|
|
// HDRP Only
|
|
half SpecularOcclusion;
|
|
half SubsurfaceMask;
|
|
half Thickness;
|
|
half CoatMask;
|
|
half Anisotropy;
|
|
half IridescenceMask;
|
|
half IridescenceThickness;
|
|
};
|
|
|
|
// data the user might need, this will grow to be big. But easy to strip
|
|
struct ShaderData
|
|
{
|
|
float3 localSpacePosition;
|
|
float3 localSpaceNormal;
|
|
float3 localSpaceTangent;
|
|
|
|
float3 worldSpacePosition;
|
|
float3 worldSpaceNormal;
|
|
float3 worldSpaceTangent;
|
|
|
|
float3 worldSpaceViewDir;
|
|
float3 tangentSpaceViewDir;
|
|
|
|
float4 texcoord0;
|
|
float4 texcoord1;
|
|
float4 texcoord2;
|
|
float4 texcoord3;
|
|
|
|
float2 screenUV;
|
|
float4 screenPos;
|
|
|
|
float4 vertexColor;
|
|
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
|
|
float3x3 TBNMatrix;
|
|
};
|
|
|
|
struct VertexData
|
|
{
|
|
#if SHADER_TARGET > 30 && _PLANETCOMPUTE
|
|
// // uint vertexID : SV_VertexID;
|
|
#endif
|
|
float4 vertex : POSITION;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD4; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD5; // Add Precomputed Velocity (Alembic computes velocities on runtime side).
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct TessVertex
|
|
{
|
|
float4 vertex : INTERNALTESSPOS;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
// float4 extraV2F0 : TEXCOORD4;
|
|
// float4 extraV2F1 : TEXCOORD5;
|
|
// float4 extraV2F2 : TEXCOORD6;
|
|
// float4 extraV2F3 : TEXCOORD7;
|
|
// float4 extraV2F4 : TEXCOORD8;
|
|
// float4 extraV2F5 : TEXCOORD9;
|
|
// float4 extraV2F6 : TEXCOORD10;
|
|
// float4 extraV2F7 : TEXCOORD11;
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD12; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD13;
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
struct ExtraV2F
|
|
{
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
};
|
|
|
|
|
|
float3 WorldToTangentSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(d.TBNMatrix, normal);
|
|
}
|
|
|
|
float3 TangentToWorldSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(normal, d.TBNMatrix);
|
|
}
|
|
|
|
// in this case, make standard more like SRPs, because we can't fix
|
|
// GetWorldToObjectMatrix() in HDRP, since it already does macro-fu there
|
|
|
|
#if _STANDARD
|
|
float3 TransformWorldToObject(float3 p) { return mul(GetWorldToObjectMatrix(), float4(p, 1)); };
|
|
float3 TransformObjectToWorld(float3 p) { return mul(GetObjectToWorldMatrix(), float4(p, 1)); };
|
|
float4 TransformWorldToObject(float4 p) { return mul(GetWorldToObjectMatrix(), p); };
|
|
float4 TransformObjectToWorld(float4 p) { return mul(GetObjectToWorldMatrix(), p); };
|
|
float4x4 GetWorldToObjectMatrix() { return GetWorldToObjectMatrix(); }
|
|
float4x4 GetObjectToWorldMatrix() { return GetObjectToWorldMatrix(); }
|
|
#endif
|
|
|
|
float3 GetCameraWorldPosition()
|
|
{
|
|
#if _HDRP
|
|
return GetCameraRelativePositionWS(_WorldSpaceCameraPos);
|
|
#else
|
|
return _WorldSpaceCameraPos;
|
|
#endif
|
|
}
|
|
|
|
|
|
#if _HDRP
|
|
|
|
half3 UnpackNormalmapRGorAG(half4 packednormal)
|
|
{
|
|
// This do the trick
|
|
packednormal.x *= packednormal.w;
|
|
|
|
half3 normal;
|
|
normal.xy = packednormal.xy * 2 - 1;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
half3 UnpackNormal(half4 packednormal)
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
return packednormal.xyz * 2 - 1;
|
|
#else
|
|
return UnpackNormalmapRGorAG(packednormal);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if _HDRP || _URP
|
|
|
|
half3 UnpackScaleNormal(half4 packednormal, half scale)
|
|
{
|
|
#ifndef UNITY_NO_DXT5nm
|
|
// Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
|
|
// Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
|
|
packednormal.x *= packednormal.w;
|
|
#endif
|
|
half3 normal;
|
|
normal.xy = (packednormal.xy * 2 - 1) * scale;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void GetSun(out float3 lightDir, out float3 color)
|
|
{
|
|
lightDir = float3(0.5, 0.5, 0);
|
|
color = 1;
|
|
#if _HDRP
|
|
if (_DirectionalLightCount > 0)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[0];
|
|
lightDir = -light.forward.xyz;
|
|
color = light.color;
|
|
}
|
|
#elif _STANDARD
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
color = _LightColor0.rgb;
|
|
#elif _URP
|
|
Light light = GetMainLight();
|
|
lightDir = light.direction;
|
|
color = light.color;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
|
|
|
|
|
|
#if _MESHSUBARRAY
|
|
half4 _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
float4 _Diffuse_TexelSize;
|
|
float4 _NormalSAO_TexelSize;
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
float _HybridHeightBlendDistance;
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
float4 _SmoothAO_TexelSize;
|
|
#endif
|
|
|
|
#ifdef _ALPHATEST_ON
|
|
float4 _TerrainHolesTexture_TexelSize;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
float4 _Specular_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
float4 _EmissiveMetal_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
half _EmissiveMult;
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
half _AutoNormalHeightScale;
|
|
#endif
|
|
|
|
float4 _UVScale; // scale and offset
|
|
|
|
half _Contrast;
|
|
|
|
|
|
|
|
#if _VSSHADOWMAP
|
|
float4 gVSSunDirection;
|
|
#endif
|
|
|
|
#if _FORCELOCALSPACE && _PLANETVECTORS
|
|
float4x4 _PQSToLocal;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
float4x4 _GlobalOriginMTX;
|
|
#endif
|
|
|
|
float4 _Control0_TexelSize;
|
|
#if _CUSTOMSPLATTEXTURES
|
|
float4 _CustomControl0_TexelSize;
|
|
#endif
|
|
float4 _PerPixelNormal_TexelSize;
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
float2 _NoiseUVParams;
|
|
#endif
|
|
|
|
float4 _PerTexProps_TexelSize;
|
|
|
|
#if _SURFACENORMALS
|
|
float3 surfTangent;
|
|
float3 surfBitangent;
|
|
float3 surfNormal;
|
|
#endif
|
|
|
|
|
|
|
|
CBUFFER_END
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, data.TBN)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// In Unity 2020.3LTS, Unity will spew tons of errors about missing this sampler in
|
|
// URP, even though it shouldn't be required.
|
|
TEXTURE2D(_MainTex);
|
|
|
|
// globals, outside of CBuffer, but used by more than one module
|
|
float3 _gGlitterLightDir;
|
|
float3 _gGlitterLightWorldPos;
|
|
half3 _gGlitterLightColor;
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
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)
|
|
float4 _TerrainNormalmapTexture_TexelSize;
|
|
#endif
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
TEXTURE2D(_TerrainHeightmapTexture);
|
|
float4 _TerrainHeightmapTexture_TexelSize;
|
|
TEXTURE2D(_TerrainNormalmapTexture);
|
|
#endif
|
|
|
|
UNITY_INSTANCING_BUFFER_START(Terrain)
|
|
UNITY_DEFINE_INSTANCED_PROP(float4, _TerrainPatchInstanceData) // float4(xBase, yBase, skipScale, ~)
|
|
UNITY_INSTANCING_BUFFER_END(Terrain)
|
|
|
|
|
|
|
|
|
|
// dynamic branching helpers, for regular and aggressive branching
|
|
// debug mode shows how many samples using branching will save us.
|
|
//
|
|
// These macros are always used instead of the UNITY_BRANCH macro
|
|
// to maintain debug displays and allow branching to be disabled
|
|
// on as granular level as we want.
|
|
|
|
#if _BRANCHSAMPLES
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++; if (w > 0)
|
|
#else
|
|
#define MSBRANCH(w) UNITY_BRANCH if (w > 0)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++;
|
|
#else
|
|
#define MSBRANCH(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _BRANCHSAMPLESAGR
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER ||_DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++; if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++; if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++; if (w > 0.001)
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) UNITY_BRANCH if (w > 0.001)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++;
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++;
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++;
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w)
|
|
#define MSBRANCHCLUSTER(w)
|
|
#define MSBRANCHOTHER(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _DEBUG_SAMPLECOUNT
|
|
int _sampleCount;
|
|
#define COUNTSAMPLE { _sampleCount++; }
|
|
#else
|
|
#define COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _DEBUG_PROCLAYERS
|
|
int _procLayerCount;
|
|
#define COUNTPROCLAYER { _procLayerCount++; }
|
|
#else
|
|
#define COUNTPROCLAYER
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
TEXTURE2D(_DebugWorldPos);
|
|
TEXTURE2D(_DebugWorldNormal);
|
|
#endif
|
|
|
|
|
|
// splat
|
|
UNITY_DECLARE_TEX2DARRAY(_Diffuse);
|
|
UNITY_DECLARE_TEX2DARRAY(_NormalSAO);
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
TEXTURE2D(_NoiseUV);
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
UNITY_DECLARE_TEX2DARRAY(_SmoothAO);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
UNITY_DECLARE_TEX2DARRAY(_Specular);
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
UNITY_DECLARE_TEX2DARRAY(_EmissiveMetal);
|
|
#endif
|
|
|
|
TEXTURE2D(_PerPixelNormal);
|
|
|
|
SamplerState shared_linear_clamp_sampler;
|
|
SamplerState shared_point_clamp_sampler;
|
|
|
|
TEXTURE2D(_Control0);
|
|
#if _CUSTOMSPLATTEXTURES
|
|
TEXTURE2D(_CustomControl0);
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_CustomControl1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_CustomControl2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_CustomControl3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl7);
|
|
#endif
|
|
#else
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_Control1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_Control2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_Control3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_Control7);
|
|
#endif
|
|
#endif
|
|
|
|
TEXTURE2D_FLOAT(_PerTexProps);
|
|
|
|
struct DecalLayer
|
|
{
|
|
float3 uv;
|
|
float2 dx;
|
|
float2 dy;
|
|
int decalIndex;
|
|
bool dynamic;
|
|
};
|
|
|
|
struct DecalOutput
|
|
{
|
|
DecalLayer l0;
|
|
DecalLayer l1;
|
|
DecalLayer l2;
|
|
DecalLayer l3;
|
|
|
|
half4 Weights;
|
|
half4 Indexes;
|
|
half4 fxLevels;
|
|
|
|
};
|
|
|
|
|
|
struct TriGradMipFormat
|
|
{
|
|
float4 d0;
|
|
float4 d1;
|
|
float4 d2;
|
|
};
|
|
|
|
float InverseLerp(float x, float y, float v) { return (v-x)/max(y-x, 0.001); }
|
|
float2 InverseLerp(float2 x, float2 y, float2 v) { return (v-x)/max(y-x, float2(0.001, 0.001)); }
|
|
float3 InverseLerp(float3 x, float3 y, float3 v) { return (v-x)/max(y-x, float3(0.001, 0.001, 0.001)); }
|
|
float4 InverseLerp(float4 x, float4 y, float4 v) { return (v-x)/max(y-x, float4(0.001, 0.001, 0.001, 0.001)); }
|
|
|
|
|
|
// 2019.3 holes
|
|
#ifdef _ALPHATEST_ON
|
|
TEXTURE2D(_TerrainHolesTexture);
|
|
|
|
void ClipHoles(float2 uv)
|
|
{
|
|
float hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, shared_linear_clamp_sampler, uv).r;
|
|
COUNTSAMPLE
|
|
clip(hole < 0.5f ? -1 : 1);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT TriGradMipFormat
|
|
#define INITMIPFORMAT (TriGradMipFormat)0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float3
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float3
|
|
#endif
|
|
#else
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT float4
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float
|
|
#endif
|
|
#endif
|
|
|
|
float2 TotalOne(float2 v) { return v * (1.0 / max(v.x + v.y, 0.001)); }
|
|
float3 TotalOne(float3 v) { return v * (1.0 / max(v.x + v.y + v.z, 0.001)); }
|
|
float4 TotalOne(float4 v) { return v * (1.0 / max(v.x + v.y + v.z + v.w, 0.001)); }
|
|
|
|
float2 RotateUV(float2 uv, float amt)
|
|
{
|
|
uv -=0.5;
|
|
float s = sin ( amt);
|
|
float c = cos ( amt );
|
|
float2x2 mtx = float2x2( c, -s, s, c);
|
|
mtx *= 0.5;
|
|
mtx += 0.5;
|
|
mtx = mtx * 2-1;
|
|
uv = mul ( uv, mtx );
|
|
uv += 0.5;
|
|
return uv;
|
|
}
|
|
|
|
float4 DecodeToFloat4(float v)
|
|
{
|
|
uint vi = (uint)(v * (256.0f * 256.0f * 256.0f * 256.0f));
|
|
int ex = (int)(vi / (256 * 256 * 256) % 256);
|
|
int ey = (int)((vi / (256 * 256)) % 256);
|
|
int ez = (int)((vi / (256)) % 256);
|
|
int ew = (int)(vi % 256);
|
|
float4 e = float4(ex / 255.0, ey / 255.0, ez / 255.0, ew / 255.0);
|
|
return e;
|
|
}
|
|
|
|
|
|
|
|
struct Input
|
|
{
|
|
ShaderData shaderData;
|
|
float2 uv_Control0;
|
|
float2 uv2_Diffuse;
|
|
|
|
float worldHeight;
|
|
float3 worldUpVector;
|
|
|
|
float3 viewDir;
|
|
float3 worldPos;
|
|
float3 worldNormal;
|
|
float4 color;
|
|
float3x3 TBN;
|
|
|
|
// vertex/digger workflow data
|
|
half4 w0;
|
|
half4 w1;
|
|
half4 w2;
|
|
half4 w3;
|
|
half4 w4;
|
|
half4 w5;
|
|
half4 w6;
|
|
|
|
// megasplat data
|
|
half4 layer0;
|
|
half4 layer1;
|
|
half3 baryWeights;
|
|
half4 scatter0;
|
|
half4 scatter1;
|
|
|
|
// wetness, puddles, streams, lava from vertex or megasplat
|
|
half4 fx;
|
|
// snow min, snow max
|
|
half4 fx2;
|
|
|
|
|
|
};
|
|
|
|
struct TriplanarConfig
|
|
{
|
|
float3x3 uv0;
|
|
float3x3 uv1;
|
|
float3x3 uv2;
|
|
float3x3 uv3;
|
|
half3 pN;
|
|
half3 pN0;
|
|
half3 pN1;
|
|
half3 pN2;
|
|
half3 pN3;
|
|
half3 axisSign;
|
|
Input IN;
|
|
};
|
|
|
|
|
|
struct Config
|
|
{
|
|
float2 uv;
|
|
float3 uv0;
|
|
float3 uv1;
|
|
float3 uv2;
|
|
float3 uv3;
|
|
|
|
half4 cluster0;
|
|
half4 cluster1;
|
|
half4 cluster2;
|
|
half4 cluster3;
|
|
|
|
};
|
|
|
|
|
|
struct MicroSplatLayer
|
|
{
|
|
half3 Albedo;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half Occlusion;
|
|
half Metallic;
|
|
half Height;
|
|
half3 Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
half3 Specular;
|
|
#endif
|
|
half Alpha;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// raw, unblended samples from arrays
|
|
struct RawSamples
|
|
{
|
|
half4 albedo0;
|
|
half4 albedo1;
|
|
half4 albedo2;
|
|
half4 albedo3;
|
|
#if _SURFACENORMALS
|
|
half3 surf0;
|
|
half3 surf1;
|
|
half3 surf2;
|
|
half3 surf3;
|
|
#endif
|
|
|
|
half4 normSAO0;
|
|
half4 normSAO1;
|
|
half4 normSAO2;
|
|
half4 normSAO3;
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALEMIS || _GLOBALSMOOTHAOMETAL || _PERTEXSSS || _PERTEXRIMLIGHT
|
|
half4 emisMetal0;
|
|
half4 emisMetal1;
|
|
half4 emisMetal2;
|
|
half4 emisMetal3;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
half3 specular0;
|
|
half3 specular1;
|
|
half3 specular2;
|
|
half3 specular3;
|
|
#endif
|
|
};
|
|
|
|
void InitRawSamples(inout RawSamples s)
|
|
{
|
|
s.normSAO0 = half4(0,0,0,1);
|
|
s.normSAO1 = half4(0,0,0,1);
|
|
s.normSAO2 = half4(0,0,0,1);
|
|
s.normSAO3 = half4(0,0,0,1);
|
|
#if _SURFACENORMALS
|
|
s.surf0 = half3(0,0,1);
|
|
s.surf1 = half3(0,0,1);
|
|
s.surf2 = half3(0,0,1);
|
|
s.surf3 = half3(0,0,1);
|
|
#endif
|
|
}
|
|
|
|
float3 GetGlobalLightDir(Input i)
|
|
{
|
|
float3 lightDir = float3(1,0,0);
|
|
|
|
#if _HDRP || PASS_DEFERRED
|
|
lightDir = normalize(_gGlitterLightDir.xyz);
|
|
#elif _URP
|
|
lightDir = GetMainLight().direction;
|
|
#else
|
|
#ifndef USING_DIRECTIONAL_LIGHT
|
|
lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
|
|
#else
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
#endif
|
|
#endif
|
|
return lightDir;
|
|
}
|
|
|
|
float3x3 GetTBN(Input i)
|
|
{
|
|
return i.TBN;
|
|
}
|
|
|
|
float3 GetGlobalLightDirTS(Input i)
|
|
{
|
|
float3 lightDirWS = GetGlobalLightDir(i);
|
|
return mul(GetTBN(i), lightDirWS);
|
|
}
|
|
|
|
half3 GetGlobalLightColor()
|
|
{
|
|
#if _HDRP || PASS_DEFERRED
|
|
return _gGlitterLightColor;
|
|
#elif _URP
|
|
return (GetMainLight().color);
|
|
#else
|
|
return _LightColor0.rgb;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 FuzzyShade(half3 color, half3 normal, half coreMult, half edgeMult, half power, float3 viewDir)
|
|
{
|
|
half dt = saturate(dot(viewDir, normal));
|
|
half dark = 1.0 - (coreMult * dt);
|
|
half edge = pow(1-dt, power) * edgeMult;
|
|
return color * (dark + edge);
|
|
}
|
|
|
|
half3 ComputeSSS(Input i, float3 V, float3 N, half3 tint, half thickness, half distortion, half scale, half power)
|
|
{
|
|
float3 L = GetGlobalLightDir(i);
|
|
half3 lightColor = GetGlobalLightColor();
|
|
float3 H = normalize(L + N * distortion);
|
|
float VdotH = pow(saturate(dot(V, -H)), power) * scale;
|
|
float3 I = (VdotH) * thickness;
|
|
return lightColor * I * tint;
|
|
}
|
|
|
|
|
|
#if _MAX2LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
#elif _MAX3LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
#else
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
#endif
|
|
|
|
|
|
#if _MAX3LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#elif _MAX2LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#else
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##3 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv3.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#endif
|
|
|
|
half2 BlendNormal2(half2 base, half2 blend) { return normalize(half3(base.xy + blend.xy, 1)).xy; }
|
|
half3 BlendOverlay(half3 base, half3 blend) { return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))); }
|
|
half3 BlendMult2X(half3 base, half3 blend) { return (base * (blend * 2)); }
|
|
half3 BlendLighterColor(half3 s, half3 d) { return (s.x + s.y + s.z > d.x + d.y + d.z) ? s : d; }
|
|
|
|
|
|
#if _SURFACENORMALS
|
|
|
|
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
|
|
|
|
|
|
|
|
void ConstructSurfaceGradientTBN(Input i)
|
|
{
|
|
float3x3 tbn = GetTBN(i);
|
|
float3 t = tbn[0];
|
|
float3 b = tbn[1];
|
|
float3 n = tbn[2];
|
|
|
|
surfNormal = n;//mul(GetWorldToObjectMatrix(), float4(n, 1)).xyz;
|
|
surfTangent = t;//mul(GetWorldToObjectMatrix(), float4(t, 1)).xyz;
|
|
surfBitangent = b;//cross(surfNormal, surfTangent);
|
|
|
|
float renormFactor = 1.0 / length(surfNormal);
|
|
surfNormal *= renormFactor;
|
|
surfTangent *= renormFactor;
|
|
surfBitangent *= renormFactor;
|
|
}
|
|
|
|
half3 SurfaceGradientFromTBN(half2 deriv)
|
|
{
|
|
return deriv.x * surfTangent + deriv.y * surfBitangent;
|
|
}
|
|
|
|
// Input: vM is tangent space normal in [-1;1].
|
|
// Output: convert vM to a derivative.
|
|
half2 TspaceNormalToDerivative(half3 vM)
|
|
{
|
|
const half scale = 1.0/128.0;
|
|
|
|
// Ensure vM delivers a positive third component using abs() and
|
|
// constrain vM.z so the range of the derivative is [-128; 128].
|
|
const half3 vMa = abs(vM);
|
|
const half z_ma = max(vMa.z, scale*max(vMa.x, vMa.y));
|
|
|
|
return -half2(vM.x, vM.y)/z_ma;
|
|
}
|
|
|
|
// Used to produce a surface gradient from the gradient of a volume
|
|
// bump function such as 3D Perlin noise. Equation 2 in [Mik10].
|
|
half3 SurfgradFromVolumeGradient(half3 grad)
|
|
{
|
|
return grad - dot(surfNormal, grad) * surfNormal;
|
|
}
|
|
|
|
half3 SurfgradFromTriplanarProjection(half3 pN, half2 xPlaneTN, half2 yPlaneTN, half2 zPlaneTN)
|
|
{
|
|
const half w0 = pN.x;
|
|
const half w1 = pN.y;
|
|
const half w2 = pN.z;
|
|
|
|
// X-plane tangent normal to gradient derivative
|
|
xPlaneTN = xPlaneTN * 2.0 - 1.0;
|
|
half xPlaneRcpZ = rsqrt(max(1 - dot(xPlaneTN.x, xPlaneTN.x) - dot(xPlaneTN.y, xPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_xplane = xPlaneTN * -xPlaneRcpZ;
|
|
|
|
// Y-plane tangent normal to gradient derivative
|
|
yPlaneTN = yPlaneTN * 2.0 - 1.0;
|
|
half yPlaneRcpZ = rsqrt(max(1 - dot(yPlaneTN.x, yPlaneTN.x) - dot(yPlaneTN.y, yPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_yplane = yPlaneTN * -yPlaneRcpZ;
|
|
|
|
// Z-plane tangent normal to gradient derivative
|
|
zPlaneTN = zPlaneTN * 2.0 - 1.0;
|
|
half zPlaneRcpZ = rsqrt(max(1 - dot(zPlaneTN.x, zPlaneTN.x) - dot(zPlaneTN.y, zPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_zplane = zPlaneTN * -zPlaneRcpZ;
|
|
|
|
// Assume deriv xplane, deriv yplane, and deriv zplane are
|
|
// sampled using (z,y), (x,z), and (x,y), respectively.
|
|
// Positive scales of the lookup coordinate will work
|
|
// as well, but for negative scales the derivative components
|
|
// will need to be negated accordingly.
|
|
float3 grad = float3(w2*d_zplane.x + w1*d_yplane.x,
|
|
w2*d_zplane.y + w0*d_xplane.y,
|
|
w0*d_xplane.x + w1*d_yplane.y);
|
|
|
|
return SurfgradFromVolumeGradient(grad);
|
|
}
|
|
|
|
half3 ConvertNormalToGradient(half3 normal)
|
|
{
|
|
half2 deriv = TspaceNormalToDerivative(normal);
|
|
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
half3 ConvertNormal2ToGradient(half2 packedNormal)
|
|
{
|
|
half2 tNormal = packedNormal;
|
|
half rcpZ = rsqrt(max(1 - dot(tNormal.x, tNormal.x) - dot(tNormal.y, tNormal.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
half2 deriv = tNormal * -rcpZ;
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
|
|
half3 ResolveNormalFromSurfaceGradient(half3 gradient)
|
|
{
|
|
return normalize(surfNormal - gradient);
|
|
}
|
|
|
|
|
|
#endif // _SURFACENORMALS
|
|
|
|
void BlendNormalPerTex(inout RawSamples o, half2 noise, float4 fades)
|
|
{
|
|
#if _SURFACENORMALS
|
|
float3 grad = ConvertNormal2ToGradient(noise.xy);
|
|
o.surf0 += grad * fades.x;
|
|
o.surf1 += grad * fades.y;
|
|
#if !_MAX2LAYER
|
|
o.surf2 += grad * fades.z;
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.surf3 += grad * fades.w;
|
|
#endif
|
|
#else
|
|
o.normSAO0.xy = lerp(o.normSAO0.xy, BlendNormal2(o.normSAO0.xy, noise.xy), fades.x);
|
|
o.normSAO1.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#if !_MAX2LAYER
|
|
o.normSAO2.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO2.xy, noise.xy), fades.y);
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.normSAO3.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 BlendNormal3(half3 n1, half3 n2)
|
|
{
|
|
n1 += float3( 0, 0, 1);
|
|
n2 *= float3(-1, -1, 1);
|
|
return n1*dot(n1, n2) / n1.z - n2;
|
|
}
|
|
|
|
half2 TransformTriplanarNormal(Input IN, float3x3 t2w, half3 axisSign, half3 absVertNormal,
|
|
half3 pN, half2 a0, half2 a1, half2 a2)
|
|
{
|
|
|
|
a0 = a0 * 2 - 1;
|
|
a1 = a1 * 2 - 1;
|
|
a2 = a2 * 2 - 1;
|
|
|
|
a0.x *= axisSign.x;
|
|
a1.x *= axisSign.y;
|
|
a2.x *= axisSign.z;
|
|
|
|
half3 n0 = half3(a0.xy, 1);
|
|
half3 n1 = half3(a1.xy, 1);
|
|
half3 n2 = half3(a2.xy, 1);
|
|
|
|
float3 wn = IN.worldNormal;
|
|
|
|
n0 = BlendNormal3(half3(wn.zy, absVertNormal.x), n0);
|
|
n1 = BlendNormal3(half3(wn.xz, absVertNormal.y), n1 * float3(-1, 1, 1));
|
|
n2 = BlendNormal3(half3(wn.xy, absVertNormal.z), n2);
|
|
|
|
n0.z *= axisSign.x;
|
|
n1.z *= axisSign.y;
|
|
n2.z *= -axisSign.z;
|
|
|
|
half3 worldNormal = (n0.zyx * pN.x + n1.xzy * pN.y + n2.xyz * pN.z);
|
|
return mul(t2w, worldNormal).xy;
|
|
|
|
}
|
|
|
|
// funcs
|
|
|
|
inline half MSLuminance(half3 rgb)
|
|
{
|
|
#ifdef UNITY_COLORSPACE_GAMMA
|
|
return dot(rgb, half3(0.22, 0.707, 0.071));
|
|
#else
|
|
return dot(rgb, half3(0.0396819152, 0.458021790, 0.00609653955));
|
|
#endif
|
|
}
|
|
|
|
|
|
float2 Hash2D( float2 x )
|
|
{
|
|
float2 k = float2( 0.3183099, 0.3678794 );
|
|
x = x*k + k.yx;
|
|
return -1.0 + 2.0*frac( 16.0 * k*frac( x.x*x.y*(x.x+x.y)) );
|
|
}
|
|
|
|
float Noise2D(float2 p )
|
|
{
|
|
float2 i = floor( p );
|
|
float2 f = frac( p );
|
|
|
|
float2 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( dot( Hash2D( i + float2(0.0,0.0) ), f - float2(0.0,0.0) ),
|
|
dot( Hash2D( i + float2(1.0,0.0) ), f - float2(1.0,0.0) ), u.x),
|
|
lerp( dot( Hash2D( i + float2(0.0,1.0) ), f - float2(0.0,1.0) ),
|
|
dot( Hash2D( i + float2(1.0,1.0) ), f - float2(1.0,1.0) ), u.x), u.y);
|
|
}
|
|
|
|
float FBM2D(float2 uv)
|
|
{
|
|
float f = 0.5000*Noise2D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise2D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise2D( uv );
|
|
return f;
|
|
}
|
|
|
|
float3 Hash3D( float3 p )
|
|
{
|
|
p = float3( dot(p,float3(127.1,311.7, 74.7)),
|
|
dot(p,float3(269.5,183.3,246.1)),
|
|
dot(p,float3(113.5,271.9,124.6)));
|
|
|
|
return -1.0 + 2.0*frac(sin(p)*437.5453123);
|
|
}
|
|
|
|
float Noise3D( float3 p )
|
|
{
|
|
float3 i = floor( p );
|
|
float3 f = frac( p );
|
|
|
|
float3 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,0.0) ), f - float3(0.0,0.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,0.0) ), f - float3(1.0,0.0,0.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,0.0) ), f - float3(0.0,1.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,0.0) ), f - float3(1.0,1.0,0.0) ), u.x), u.y),
|
|
lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,1.0) ), f - float3(0.0,0.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,1.0) ), f - float3(1.0,0.0,1.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,1.0) ), f - float3(0.0,1.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,1.0) ), f - float3(1.0,1.0,1.0) ), u.x), u.y), u.z );
|
|
}
|
|
|
|
float FBM3D(float3 uv)
|
|
{
|
|
float f = 0.5000*Noise3D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise3D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise3D( uv );
|
|
return f;
|
|
}
|
|
|
|
|
|
|
|
float GetSaturation(float3 c)
|
|
{
|
|
float mi = min(min(c.x, c.y), c.z);
|
|
float ma = max(max(c.x, c.y), c.z);
|
|
return (ma - mi)/(ma + 1e-7);
|
|
}
|
|
|
|
// Better Color Lerp, does not have darkening issue
|
|
float3 BetterColorLerp(float3 a, float3 b, float x)
|
|
{
|
|
float3 ic = lerp(a, b, x) + float3(1e-6,0.0,0.0);
|
|
float sd = abs(GetSaturation(ic) - lerp(GetSaturation(a), GetSaturation(b), x));
|
|
|
|
float3 dir = normalize(float3(2.0 * ic.x - ic.y - ic.z, 2.0 * ic.y - ic.x - ic.z, 2.0 * ic.z - ic.y - ic.x));
|
|
float lgt = dot(float3(1.0, 1.0, 1.0), ic);
|
|
|
|
float ff = dot(dir, normalize(ic));
|
|
|
|
const float dsp_str = 1.5;
|
|
ic += dsp_str * dir * sd * ff * lgt;
|
|
return saturate(ic);
|
|
}
|
|
|
|
|
|
half4 ComputeWeights(half4 iWeights, half h0, half h1, half h2, half h3, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return iWeights;
|
|
#else
|
|
// compute weight with height map
|
|
//half4 weights = half4(iWeights.x * h0, iWeights.y * h1, iWeights.z * h2, iWeights.w * h3);
|
|
half4 weights = half4(iWeights.x * max(h0,0.001), iWeights.y * max(h1,0.001), iWeights.z * max(h2,0.001), iWeights.w * max(h3,0.001));
|
|
|
|
// Contrast weights
|
|
half maxWeight = max(max(weights.x, max(weights.y, weights.z)), weights.w);
|
|
half transition = max(contrast * maxWeight, 0.0001);
|
|
half threshold = maxWeight - transition;
|
|
half scale = 1.0 / transition;
|
|
weights = saturate((weights - threshold) * scale);
|
|
|
|
weights = TotalOne(weights);
|
|
return weights;
|
|
#endif
|
|
}
|
|
|
|
half HeightBlend(half h1, half h2, half slope, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return slope;
|
|
#else
|
|
h2 = 1 - h2;
|
|
half tween = saturate((slope - min(h1, h2)) / max(abs(h1 - h2), 0.001));
|
|
half blend = saturate( ( tween - (1-contrast) ) / max(contrast, 0.001));
|
|
return blend;
|
|
#endif
|
|
}
|
|
|
|
#if _MAX4TEXTURES
|
|
#define TEXCOUNT 4
|
|
#elif _MAX8TEXTURES
|
|
#define TEXCOUNT 8
|
|
#elif _MAX12TEXTURES
|
|
#define TEXCOUNT 12
|
|
#elif _MAX20TEXTURES
|
|
#define TEXCOUNT 20
|
|
#elif _MAX24TEXTURES
|
|
#define TEXCOUNT 24
|
|
#elif _MAX28TEXTURES
|
|
#define TEXCOUNT 28
|
|
#elif _MAX32TEXTURES
|
|
#define TEXCOUNT 32
|
|
#else
|
|
#define TEXCOUNT 16
|
|
#endif
|
|
|
|
#if _DECAL_SPLAT
|
|
|
|
void DoMergeDecalSplats(half4 iWeights, half4 iIndexes, inout half4 indexes, inout half4 weights)
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
half w = iWeights[i];
|
|
half index = iIndexes[i];
|
|
if (w > weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = index;
|
|
}
|
|
else if (w > weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = index;
|
|
}
|
|
else if (w > weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = index;
|
|
}
|
|
else if (w > weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = index;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
void Setup(out half4 weights, float2 uv, out Config config, half4 w0, half4 w1, half4 w2, half4 w3, half4 w4, half4 w5, half4 w6, half4 w7, float3 worldPos, DecalOutput decalOutput)
|
|
{
|
|
config = (Config)0;
|
|
half4 indexes = 0;
|
|
|
|
config.uv = uv;
|
|
|
|
#if _WORLDUV
|
|
uv = worldPos.xz;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
float2 scaledUV = uv;
|
|
#else
|
|
float2 scaledUV = uv * _UVScale.xy + _UVScale.zw;
|
|
#endif
|
|
|
|
// if only 4 textures, and blending 4 textures, skip this whole thing..
|
|
// this saves about 25% of the ALU of the base shader on low end. However if
|
|
// we rely on sorted texture weights (distance resampling) we have to sort..
|
|
float4 defaultIndexes = float4(0,1,2,3);
|
|
#if _MESHSUBARRAY
|
|
defaultIndexes = _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
#if _MESHSUBARRAY && !_DECAL_SPLAT || (_MAX4TEXTURES && !_MAX3LAYER && !_MAX2LAYER && !_DISTANCERESAMPLE && !_POM && !_DECAL_SPLAT)
|
|
weights = w0;
|
|
config.uv0 = float3(scaledUV, defaultIndexes.x);
|
|
config.uv1 = float3(scaledUV, defaultIndexes.y);
|
|
config.uv2 = float3(scaledUV, defaultIndexes.z);
|
|
config.uv3 = float3(scaledUV, defaultIndexes.w);
|
|
return;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
weights = float4(1,0,0,0);
|
|
return;
|
|
#else
|
|
half splats[TEXCOUNT];
|
|
|
|
splats[0] = w0.x;
|
|
splats[1] = w0.y;
|
|
splats[2] = w0.z;
|
|
splats[3] = w0.w;
|
|
#if !_MAX4TEXTURES
|
|
splats[4] = w1.x;
|
|
splats[5] = w1.y;
|
|
splats[6] = w1.z;
|
|
splats[7] = w1.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
splats[8] = w2.x;
|
|
splats[9] = w2.y;
|
|
splats[10] = w2.z;
|
|
splats[11] = w2.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
splats[12] = w3.x;
|
|
splats[13] = w3.y;
|
|
splats[14] = w3.z;
|
|
splats[15] = w3.w;
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[16] = w4.x;
|
|
splats[17] = w4.y;
|
|
splats[18] = w4.z;
|
|
splats[19] = w4.w;
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[20] = w5.x;
|
|
splats[21] = w5.y;
|
|
splats[22] = w5.z;
|
|
splats[23] = w5.w;
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[24] = w6.x;
|
|
splats[25] = w6.y;
|
|
splats[26] = w6.z;
|
|
splats[27] = w6.w;
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
splats[28] = w7.x;
|
|
splats[29] = w7.y;
|
|
splats[30] = w7.z;
|
|
splats[31] = w7.w;
|
|
#endif
|
|
|
|
|
|
|
|
weights[0] = 0;
|
|
weights[1] = 0;
|
|
weights[2] = 0;
|
|
weights[3] = 0;
|
|
indexes[0] = 0;
|
|
indexes[1] = 0;
|
|
indexes[2] = 0;
|
|
indexes[3] = 0;
|
|
|
|
int i = 0;
|
|
for (i = 0; i < TEXCOUNT; ++i)
|
|
{
|
|
half w = splats[i];
|
|
if (w >= weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = i;
|
|
}
|
|
else if (w >= weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = i;
|
|
}
|
|
else if (w >= weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = i;
|
|
}
|
|
else if (w >= weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = i;
|
|
}
|
|
}
|
|
|
|
// NaN Prevention
|
|
if (weights.x <= 0)
|
|
weights = float4(1, 0, 0, 0);
|
|
|
|
#if _DECAL_SPLAT
|
|
DoMergeDecalSplats(decalOutput.Weights, decalOutput.Indexes, weights, indexes);
|
|
#endif
|
|
|
|
|
|
|
|
// clamp and renormalize
|
|
#if _MAX2LAYER
|
|
weights.zw = 0;
|
|
weights.xy = TotalOne(weights.xy);
|
|
#elif _MAX3LAYER
|
|
weights.w = 0;
|
|
weights.xyz = TotalOne(weights.xyz);
|
|
#elif !_DISABLEHEIGHTBLENDING || _NORMALIZEWEIGHTS // prevents black when painting, which the unity shader does not prevent.
|
|
weights = normalize(weights);
|
|
#endif
|
|
|
|
|
|
config.uv0 = float3(scaledUV, indexes.x);
|
|
config.uv1 = float3(scaledUV, indexes.y);
|
|
config.uv2 = float3(scaledUV, indexes.z);
|
|
config.uv3 = float3(scaledUV, indexes.w);
|
|
|
|
|
|
#endif //_DISABLESPLATMAPS
|
|
|
|
|
|
}
|
|
|
|
float3 HeightToNormal(float height, float3 worldPos)
|
|
{
|
|
float3 dx = ddx(worldPos);
|
|
float3 dy = ddy(worldPos);
|
|
float3 crossX = cross(float3(0,1,0), dx);
|
|
float3 crossY = cross(float3(0,1,0), dy);
|
|
float3 d = abs(dot(crossY, dx));
|
|
float3 n = ((((height + ddx(height)) - height) * crossY) + (((height + ddy(height)) - height) * crossX)) * sign(d);
|
|
n.z *= -1;
|
|
return normalize((d * float3(0,1,0)) - n).xzy;
|
|
}
|
|
|
|
float ComputeMipLevel(float2 uv, float2 textureSize)
|
|
{
|
|
uv *= textureSize;
|
|
float2 dx_vtc = ddx(uv);
|
|
float2 dy_vtc = ddy(uv);
|
|
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
|
|
return 0.5 * log2(delta_max_sqr);
|
|
}
|
|
|
|
inline half2 UnpackNormal2(half4 packednormal)
|
|
{
|
|
return packednormal.wy * 2 - 1;
|
|
|
|
}
|
|
|
|
half3 TriplanarHBlend(half h0, half h1, half h2, half3 pN, half contrast)
|
|
{
|
|
half3 blend = pN / dot(pN, half3(1,1,1));
|
|
float3 heights = float3(h0, h1, h2) + (blend * 3.0);
|
|
half height_start = max(max(heights.x, heights.y), heights.z) - contrast;
|
|
half3 h = max(heights - height_start.xxx, half3(0,0,0));
|
|
blend = h / dot(h, half3(1,1,1));
|
|
return blend;
|
|
}
|
|
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half3 display)
|
|
{
|
|
o.Albedo = display.rgb;
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half display)
|
|
{
|
|
o.Albedo = half3(display, display, display);
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
half MicroShadow(float3 lightDir, half3 normal, half ao, half strength)
|
|
{
|
|
half shadow = saturate(abs(dot(normal, lightDir)) + (ao * ao * 2.0) - 1.0);
|
|
return 1 - ((1-shadow) * strength);
|
|
}
|
|
|
|
|
|
void DoDebugOutput(inout MicroSplatLayer l)
|
|
{
|
|
#if _DEBUG_OUTPUT_ALBEDO
|
|
ClearAllButAlbedo(l, l.Albedo);
|
|
#elif _DEBUG_OUTPUT_NORMAL
|
|
// oh unit shader compiler normal stripping, how I hate you so..
|
|
// must multiply by albedo to stop the normal from being white. Why, fuck knows?
|
|
ClearAllButAlbedo(l, float3(l.Normal.xy * 0.5 + 0.5, l.Normal.z * saturate(l.Albedo.z+1)));
|
|
#elif _DEBUG_OUTPUT_SMOOTHNESS
|
|
ClearAllButAlbedo(l, l.Smoothness.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_METAL
|
|
ClearAllButAlbedo(l, l.Metallic.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_AO
|
|
ClearAllButAlbedo(l, l.Occlusion.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_EMISSION
|
|
ClearAllButAlbedo(l, l.Emission * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_HEIGHT
|
|
ClearAllButAlbedo(l, l.Height.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_SPECULAR && _USESPECULARWORKFLOW
|
|
ClearAllButAlbedo(l, l.Specular * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_BRANCHCOUNT_WEIGHT
|
|
ClearAllButAlbedo(l, _branchWeightCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TRIPLANAR
|
|
ClearAllButAlbedo(l, _branchTriplanarCount / 24 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_CLUSTER
|
|
ClearAllButAlbedo(l, _branchClusterCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_OTHER
|
|
ClearAllButAlbedo(l, _branchOtherCount / 8 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TOTAL
|
|
l.Albedo.r = _branchWeightCount / 12;
|
|
l.Albedo.g = _branchTriplanarCount / 24;
|
|
l.Albedo.b = _branchClusterCount / 12;
|
|
ClearAllButAlbedo(l, (l.Albedo.r + l.Albedo.g + l.Albedo.b + (_branchOtherCount / 8)) / 4);
|
|
#elif _DEBUG_OUTPUT_MICROSHADOWS
|
|
ClearAllButAlbedo(l,l.Albedo);
|
|
#elif _DEBUG_SAMPLECOUNT
|
|
float sdisp = (float)_sampleCount / max(_SampleCountDiv, 1);
|
|
half3 sdcolor = float3(sdisp, sdisp > 1 ? 1 : 0, 0);
|
|
ClearAllButAlbedo(l, sdcolor * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_PROCLAYERS
|
|
ClearAllButAlbedo(l, (float)_procLayerCount / (float)_PCLayerCount * saturate(l.Albedo.z + 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
// abstraction around sampler mode
|
|
#if _USELODMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_LOD(tex, sampler##tex, u, l.x)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u, l.x)
|
|
#elif _USEGRADMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_GRAD(tex, sampler##tex, u, l.xy, l.zw)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY_GRAD(tex, ss, u.xy, u.z, l.xy, l.zw)
|
|
#else
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, u.xy, u.z)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u.xy, y.z)
|
|
#endif
|
|
|
|
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE(u, cl, l) MICROSPLAT_SAMPLE(_Diffuse, u, l)
|
|
#define MICROSPLAT_SAMPLE_EMIS(u, cl, l) MICROSPLAT_SAMPLE(_EmissiveMetal, u, l)
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE_LOD(u, cl, l) UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, u, l)
|
|
|
|
|
|
#if _PACKINGHQ
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) half4(MICROSPLAT_SAMPLE(_NormalSAO, u, l).ga, MICROSPLAT_SAMPLE(_SmoothAO, u, l).ga).brag
|
|
#else
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) MICROSPLAT_SAMPLE(_NormalSAO, u, l)
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
#define MICROSPLAT_SAMPLE_SPECULAR(u, cl, l) MICROSPLAT_SAMPLE(_Specular, u, l)
|
|
#endif
|
|
|
|
struct SimpleTriplanarConfig
|
|
{
|
|
float3 pn;
|
|
float2 uv0;
|
|
float2 uv1;
|
|
float2 uv2;
|
|
};
|
|
|
|
void PrepSimpleTriplanarConfig(inout SimpleTriplanarConfig tc, float3 worldPos, float3 normal, float contrast)
|
|
{
|
|
tc.pn = pow(abs(normal), contrast);
|
|
tc.pn = tc.pn / (tc.pn.x + tc.pn.y + tc.pn.z);
|
|
|
|
half3 axisSign = sign(normal);
|
|
|
|
tc.uv0 = worldPos.zy * axisSign.x;
|
|
tc.uv1 = worldPos.xz * axisSign.y;
|
|
tc.uv2 = worldPos.xy * axisSign.z;
|
|
}
|
|
|
|
#define SimpleTriplanarSample(tex, tc, scale) (SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv0 * scale) * tc.pn.x + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv1 * scale) * tc.pn.y + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv2 * scale) * tc.pn.z)
|
|
#define SimpleTriplanarSampleLOD(tex, tc, scale, lod) (SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv0 * scale, lod) * tc.pn.x + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv1 * scale, lod) * tc.pn.y + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv2 * scale, lod) * tc.pn.z)
|
|
#define SimpleTriplanarSampleGrad(tex, tc, scale) (SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv0 * scale, ddx(tc.uv0) * scale, ddy(tc.uv0) * scale) * tc.pn.x + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv1 * scale, ddx(tc.uv1) * scale, ddy(tc.uv1) * scale) * tc.pn.y + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv2 * scale, ddx(tc.uv2) * scale, ddy(tc.uv2) * scale) * tc.pn.z)
|
|
|
|
|
|
inline half3 MicroSplatDiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
|
|
{
|
|
specColor = lerp (half3(0,0,0), albedo, metallic);
|
|
oneMinusReflectivity = (1-metallic);
|
|
return albedo * oneMinusReflectivity;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Input DescToInput(ShaderData IN)
|
|
{
|
|
Input s = (Input)0;
|
|
s.shaderData = IN;
|
|
s.TBN = IN.TBNMatrix;
|
|
s.worldNormal = IN.worldSpaceNormal;
|
|
s.worldPos = IN.worldSpacePosition;
|
|
s.viewDir = IN.tangentSpaceViewDir;
|
|
s.uv_Control0 = IN.texcoord0.xy;
|
|
|
|
s.worldUpVector = float3(0,1,0);
|
|
s.worldHeight = IN.worldSpacePosition.y;
|
|
|
|
#if _PLANETVECTORS
|
|
float3 rwp = mul(_PQSToLocal, float4(IN.worldSpacePosition, 1));
|
|
s.worldHeight = distance(rwp, float3(0,0,0));
|
|
s.worldUpVector = normalize(rwp);
|
|
#endif
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
s.uv2_Diffuse = IN.texcoord1.xy;
|
|
#endif
|
|
|
|
#if _MEGASPLAT
|
|
UnpackMegaSplat(s, IN);
|
|
#endif
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
UnpackVertexWorkflow(s, IN);
|
|
#endif
|
|
|
|
#if _PLANETVECTORS
|
|
DoPlanetDataInputCopy(s, IN);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
void SampleAlbedo(inout Config config, inout TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half4 contrasts = _Contrast.xxxx;
|
|
#if _PERTEXTRIPLANARCONTRAST
|
|
SAMPLE_PER_TEX(ptc, 9.5, config, half4(1,0.5,0,0));
|
|
contrasts = half4(ptc0.y, ptc1.y, ptc2.y, ptc3.y);
|
|
#endif
|
|
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
SAMPLE_PER_TEX(pttri, 9.5, config, half4(0,0,0,0));
|
|
#endif
|
|
|
|
{
|
|
// For per-texture triplanar, we modify the view based blending factor of the triplanar
|
|
// such that you get a pure blend of either top down projection, or with the top down projection
|
|
// removed and renormalized. This causes dynamic flow control optimizations to kick in and avoid
|
|
// the extra texture samples while keeping the code simple. Yay..
|
|
|
|
// We also only have to do this in the Albedo, because the pN values will be adjusted after the
|
|
// albedo is sampled, causing future samples to use this data.
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri0.x > 0.66)
|
|
{
|
|
tc.pN0 = half3(0,1,0);
|
|
}
|
|
else if (pttri0.x > 0.33)
|
|
{
|
|
tc.pN0.y = 0;
|
|
tc.pN0.xz = TotalOne(tc.pN0.xz);
|
|
}
|
|
#endif
|
|
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN0;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN0, contrasts.x);
|
|
tc.pN0 = bf;
|
|
#endif
|
|
|
|
s.albedo0 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri1.x > 0.66)
|
|
{
|
|
tc.pN1 = half3(0,1,0);
|
|
}
|
|
else if (pttri1.x > 0.33)
|
|
{
|
|
tc.pN1.y = 0;
|
|
tc.pN1.xz = TotalOne(tc.pN1.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
COUNTSAMPLE
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[2], config.cluster1, d2);
|
|
}
|
|
half3 bf = tc.pN1;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN1, contrasts.x);
|
|
tc.pN1 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo1 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri2.x > 0.66)
|
|
{
|
|
tc.pN2 = half3(0,1,0);
|
|
}
|
|
else if (pttri2.x > 0.33)
|
|
{
|
|
tc.pN2.y = 0;
|
|
tc.pN2.xz = TotalOne(tc.pN2.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN2;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN2, contrasts.x);
|
|
tc.pN2 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo2 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri3.x > 0.66)
|
|
{
|
|
tc.pN3 = half3(0,1,0);
|
|
}
|
|
else if (pttri3.x > 0.33)
|
|
{
|
|
tc.pN3.y = 0;
|
|
tc.pN3.xz = TotalOne(tc.pN3.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN3;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN3, contrasts.x);
|
|
tc.pN3 = bf;
|
|
#endif
|
|
|
|
s.albedo3 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.albedo0 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.albedo1 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.albedo2 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.albedo3 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXHEIGHTOFFSET || _PERTEXHEIGHTCONTRAST
|
|
SAMPLE_PER_TEX(ptHeight, 10.5, config, 1);
|
|
|
|
#if _PERTEXHEIGHTOFFSET
|
|
s.albedo0.a = saturate(s.albedo0.a + ptHeight0.b - 1);
|
|
s.albedo1.a = saturate(s.albedo1.a + ptHeight1.b - 1);
|
|
s.albedo2.a = saturate(s.albedo2.a + ptHeight2.b - 1);
|
|
s.albedo3.a = saturate(s.albedo3.a + ptHeight3.b - 1);
|
|
#endif
|
|
#if _PERTEXHEIGHTCONTRAST
|
|
s.albedo0.a = saturate(pow(s.albedo0.a + 0.5, abs(ptHeight0.a)) - 0.5);
|
|
s.albedo1.a = saturate(pow(s.albedo1.a + 0.5, abs(ptHeight1.a)) - 0.5);
|
|
s.albedo2.a = saturate(pow(s.albedo2.a + 0.5, abs(ptHeight2.a)) - 0.5);
|
|
s.albedo3.a = saturate(pow(s.albedo3.a + 0.5, abs(ptHeight3.a)) - 0.5);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void SampleNormal(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
|
|
#if _NONORMALMAP || _AUTONORMAL
|
|
s.normSAO0 = half4(0,0, 0, 1);
|
|
s.normSAO1 = half4(0,0, 0, 1);
|
|
s.normSAO2 = half4(0,0, 0, 1);
|
|
s.normSAO3 = half4(0,0, 0, 1);
|
|
return;
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half3 absVertNormal = abs(tc.IN.worldNormal);
|
|
float3x3 t2w = tc.IN.TBN;
|
|
|
|
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[0], config.cluster0, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[1], config.cluster0, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[2], config.cluster0, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = SurfgradFromTriplanarProjection(tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO0.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO0.zw = a0.zw * tc.pN0.x + a1.zw * tc.pN0.y + a2.zw * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[0], config.cluster1, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[1], config.cluster1, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[2], config.cluster1, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = SurfgradFromTriplanarProjection(tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO1.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO1.zw = a0.zw * tc.pN1.x + a1.zw * tc.pN1.y + a2.zw * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[0], config.cluster2, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[1], config.cluster2, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[2], config.cluster2, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf2 = SurfgradFromTriplanarProjection(tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO2.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO2.zw = a0.zw * tc.pN2.x + a1.zw * tc.pN2.y + a2.zw * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[0], config.cluster3, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[1], config.cluster3, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[2], config.cluster3, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf3 = SurfgradFromTriplanarProjection(tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO3.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO3.zw = a0.zw * tc.pN3.x + a1.zw * tc.pN3.y + a2.zw * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.normSAO0 = MICROSPLAT_SAMPLE_NORMAL(config.uv0, config.cluster0, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO0.xy = s.normSAO0.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = ConvertNormal2ToGradient(s.normSAO0.xy);
|
|
#endif
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.normSAO1 = MICROSPLAT_SAMPLE_NORMAL(config.uv1, config.cluster1, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO1.xy = s.normSAO1.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = ConvertNormal2ToGradient(s.normSAO1.xy);
|
|
#endif
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.normSAO2 = MICROSPLAT_SAMPLE_NORMAL(config.uv2, config.cluster2, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO2.xy = s.normSAO2.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf2 = ConvertNormal2ToGradient(s.normSAO2.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.normSAO3 = MICROSPLAT_SAMPLE_NORMAL(config.uv3, config.cluster3, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO3.xy = s.normSAO3.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf3 = ConvertNormal2ToGradient(s.normSAO3.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleEmis(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
s.emisMetal0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.emisMetal0 = MICROSPLAT_SAMPLE_EMIS(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.emisMetal1 = MICROSPLAT_SAMPLE_EMIS(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.emisMetal2 = MICROSPLAT_SAMPLE_EMIS(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.emisMetal3 = MICROSPLAT_SAMPLE_EMIS(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleSpecular(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.specular0 = MICROSPLAT_SAMPLE_SPECULAR(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.specular1 = MICROSPLAT_SAMPLE_SPECULAR(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.specular2 = MICROSPLAT_SAMPLE_SPECULAR(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.specular3 = MICROSPLAT_SAMPLE_SPECULAR(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
MicroSplatLayer Sample(Input i, half4 weights, inout Config config, float camDist, float3 worldNormalVertex, DecalOutput decalOutput)
|
|
{
|
|
MicroSplatLayer o = (MicroSplatLayer)0;
|
|
UNITY_INITIALIZE_OUTPUT(MicroSplatLayer,o);
|
|
|
|
RawSamples samples = (RawSamples)0;
|
|
InitRawSamples(samples);
|
|
|
|
half4 albedo = 0;
|
|
half4 normSAO = half4(0,0,0,1);
|
|
half3 surfGrad = half3(0,0,0);
|
|
half4 emisMetal = 0;
|
|
half3 specular = 0;
|
|
|
|
float worldHeight = i.worldPos.y;
|
|
float3 upVector = float3(0,1,0);
|
|
|
|
#if _GLOBALTINT || _GLOBALNORMALS || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _GLOBALSPECULAR
|
|
float globalSlopeFilter = 1;
|
|
#if _GLOBALSLOPEFILTER
|
|
float2 gfilterUV = float2(1 - saturate(dot(worldNormalVertex, upVector) * 0.5 + 0.49), 0.5);
|
|
globalSlopeFilter = SAMPLE_TEXTURE2D(_GlobalSlopeTex, sampler_Diffuse, gfilterUV).a;
|
|
#endif
|
|
#endif
|
|
|
|
// declare outside of branchy areas..
|
|
half4 fxLevels = half4(0,0,0,0);
|
|
half burnLevel = 0;
|
|
half wetLevel = 0;
|
|
half3 waterNormalFoam = half3(0, 0, 0);
|
|
half porosity = 0.4;
|
|
float streamFoam = 1.0f;
|
|
half pud = 0;
|
|
half snowCover = 0;
|
|
half SSSThickness = 0;
|
|
half3 SSSTint = half3(1,1,1);
|
|
float traxBuffer = 0;
|
|
float3 traxNormal = 0;
|
|
float2 noiseUV = 0;
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(1 - saturate(camDist - _SplatFade.y))
|
|
{
|
|
#endif
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE || _SNOWFOOTSTEPS
|
|
traxBuffer = SampleTraxBuffer(i.worldPos, worldNormalVertex, traxNormal);
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
#if _MICROMESH
|
|
fxLevels = SampleFXLevels(InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, config.uv), wetLevel, burnLevel, traxBuffer);
|
|
#elif _MICROVERTEXMESH || _MICRODIGGERMESH || _MEGASPLAT
|
|
fxLevels = ProcessFXLevels(i.fx, traxBuffer);
|
|
#else
|
|
fxLevels = SampleFXLevels(config.uv, wetLevel, burnLevel, traxBuffer);
|
|
#endif
|
|
#endif
|
|
|
|
#if _DECAL
|
|
fxLevels = max(fxLevels, decalOutput.fxLevels);
|
|
#endif
|
|
|
|
TriplanarConfig tc = (TriplanarConfig)0;
|
|
UNITY_INITIALIZE_OUTPUT(TriplanarConfig,tc);
|
|
|
|
|
|
MIPFORMAT albedoLOD = INITMIPFORMAT
|
|
MIPFORMAT normalLOD = INITMIPFORMAT
|
|
MIPFORMAT emisLOD = INITMIPFORMAT
|
|
MIPFORMAT specLOD = INITMIPFORMAT
|
|
MIPFORMAT origAlbedoLOD = INITMIPFORMAT;
|
|
|
|
#if _TRIPLANAR && !_DISABLESPLATMAPS
|
|
PrepTriplanar(i.shaderData.texcoord0, worldNormalVertex, i.worldPos, config, tc, weights, albedoLOD, normalLOD, emisLOD, origAlbedoLOD);
|
|
tc.IN = i;
|
|
#endif
|
|
|
|
|
|
#if !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
#if _USELODMIP
|
|
albedoLOD = ComputeMipLevel(config.uv0.xy, _Diffuse_TexelSize.zw);
|
|
normalLOD = ComputeMipLevel(config.uv0.xy, _NormalSAO_TexelSize.zw);
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = ComputeMipLevel(config.uv0.xy, _EmissiveMetal_TexelSize.zw);
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = ComputeMipLevel(config.uv0.xy, _Specular_TexelSize.zw);;
|
|
#endif
|
|
#elif _USEGRADMIP
|
|
albedoLOD = float4(ddx(config.uv0.xy), ddy(config.uv0.xy));
|
|
normalLOD = albedoLOD;
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
|
|
origAlbedoLOD = albedoLOD;
|
|
#endif
|
|
|
|
#if _PERTEXCURVEWEIGHT
|
|
SAMPLE_PER_TEX(ptCurveWeight, 19.5, config, half4(0.5,1,1,1));
|
|
weights.x = lerp(smoothstep(0.5 - ptCurveWeight0.r, 0.5 + ptCurveWeight0.r, weights.x), weights.x, ptCurveWeight0.r*2);
|
|
weights.y = lerp(smoothstep(0.5 - ptCurveWeight1.r, 0.5 + ptCurveWeight1.r, weights.y), weights.y, ptCurveWeight1.r*2);
|
|
weights.z = lerp(smoothstep(0.5 - ptCurveWeight2.r, 0.5 + ptCurveWeight2.r, weights.z), weights.z, ptCurveWeight2.r*2);
|
|
weights.w = lerp(smoothstep(0.5 - ptCurveWeight3.r, 0.5 + ptCurveWeight3.r, weights.w), weights.w, ptCurveWeight3.r*2);
|
|
weights = TotalOne(weights);
|
|
#endif
|
|
|
|
|
|
|
|
// uvScale before anything
|
|
#if _PERTEXUVSCALEOFFSET && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
config.uv0.xy = config.uv0.xy * ptUVScale0.rg + ptUVScale0.ba;
|
|
config.uv1.xy = config.uv1.xy * ptUVScale1.rg + ptUVScale1.ba;
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = config.uv2.xy * ptUVScale2.rg + ptUVScale2.ba;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = config.uv3.xy * ptUVScale3.rg + ptUVScale3.ba;
|
|
#endif
|
|
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = albedoLOD * ptUVScale0.rgrg * weights.x +
|
|
albedoLOD * ptUVScale1.rgrg * weights.y +
|
|
albedoLOD * ptUVScale2.rgrg * weights.z +
|
|
albedoLOD * ptUVScale3.rgrg * weights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXUVROTATION && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptUVRot, 16.5, config, half4(0,0,0,0));
|
|
config.uv0.xy = RotateUV(config.uv0.xy, ptUVRot0.x);
|
|
config.uv1.xy = RotateUV(config.uv1.xy, ptUVRot1.x);
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = RotateUV(config.uv2.xy, ptUVRot2.x);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = RotateUV(config.uv3.xy, ptUVRot0.x);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
o.Alpha = 1;
|
|
|
|
|
|
#if _POM && !_DISABLESPLATMAPS
|
|
DoPOM(i, config, tc, albedoLOD, weights, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
SampleAlbedo(config, tc, samples, albedoLOD, weights);
|
|
|
|
#if _NOISEHEIGHT
|
|
ApplyNoiseHeight(samples, config.uv, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STREAMS || (_PARALLAX && !_DISABLESPLATMAPS)
|
|
half earlyHeight = BlendWeights(samples.albedo0.w, samples.albedo1.w, samples.albedo2.w, samples.albedo3.w, weights);
|
|
#endif
|
|
|
|
|
|
#if _STREAMS
|
|
waterNormalFoam = GetWaterNormal(i, config.uv, worldNormalVertex);
|
|
DoStreamRefract(config, tc, waterNormalFoam, fxLevels.b, earlyHeight);
|
|
#endif
|
|
|
|
#if _PARALLAX && !_DISABLESPLATMAPS
|
|
DoParallax(i, earlyHeight, config, tc, samples, weights, camDist);
|
|
#endif
|
|
|
|
|
|
// Blend results
|
|
#if _PERTEXINTERPCONTRAST && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptContrasts, 1.5, config, 0.5);
|
|
half4 contrast = 0.5;
|
|
contrast.x = ptContrasts0.a;
|
|
contrast.y = ptContrasts1.a;
|
|
#if !_MAX2LAYER
|
|
contrast.z = ptContrasts2.a;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
contrast.w = ptContrasts3.a;
|
|
#endif
|
|
contrast = clamp(contrast + _Contrast, 0.0001, 1.0);
|
|
half cnt = contrast.x * weights.x + contrast.y * weights.y + contrast.z * weights.z + contrast.w * weights.w;
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, cnt);
|
|
#else
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, _Contrast);
|
|
#endif
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
heightWeights = lerp(heightWeights, TotalOne(weights), saturate(camDist/max(1.0, _HybridHeightBlendDistance)));
|
|
#endif
|
|
|
|
|
|
// rescale derivatives after height weighting. Basically, in gradmip mode we blend the mip levels,
|
|
// but this is before height mapping is sampled, so reblending them after alpha will make sure the other
|
|
// channels (normal, etc) are sharper, which likely matters most..
|
|
#if _PERTEXUVSCALEOFFSET && !_DISABLESPLATMAPS
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
|
|
albedoLOD.d0 = origAlbedoLOD.d0 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d0 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d0 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d0 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d1 = origAlbedoLOD.d1 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d1 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d1 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d1 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d2 = origAlbedoLOD.d2 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d2 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d2 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d2 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
normalLOD.d0 = albedoLOD.d0;
|
|
normalLOD.d1 = albedoLOD.d1;
|
|
normalLOD.d2 = albedoLOD.d2;
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD.d0 = albedoLOD.d0;
|
|
emisLOD.d1 = albedoLOD.d1;
|
|
emisLOD.d2 = albedoLOD.d2;
|
|
#endif
|
|
#endif // gradmip
|
|
#else // not triplanar
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = origAlbedoLOD * ptUVScale0.rgrg * heightWeights.x +
|
|
origAlbedoLOD * ptUVScale1.rgrg * heightWeights.y +
|
|
origAlbedoLOD * ptUVScale2.rgrg * heightWeights.z +
|
|
origAlbedoLOD * ptUVScale3.rgrg * heightWeights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _PARALLAX || _STREAMS
|
|
SampleAlbedo(config, tc, samples, albedoLOD, heightWeights);
|
|
#endif
|
|
|
|
|
|
SampleNormal(config, tc, samples, normalLOD, heightWeights);
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
SampleEmis(config, tc, samples, emisLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
SampleSpecular(config, tc, samples, specLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _DISTANCERESAMPLE && !_DISABLESPLATMAPS
|
|
DistanceResample(samples, config, tc, camDist, i.viewDir, fxLevels, albedoLOD, i.worldPos, heightWeights, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STARREACHFORMAT
|
|
samples.normSAO0.w = length(samples.normSAO0.xy);
|
|
samples.normSAO1.w = length(samples.normSAO1.xy);
|
|
samples.normSAO2.w = length(samples.normSAO2.xy);
|
|
samples.normSAO3.w = length(samples.normSAO3.xy);
|
|
#endif
|
|
|
|
// PerTexture sampling goes here, passing the samples structure
|
|
|
|
#if _PERTEXMICROSHADOWS || _PERTEXFUZZYSHADE
|
|
SAMPLE_PER_TEX(ptFuzz, 17.5, config, half4(0, 0, 1, 1));
|
|
#endif
|
|
|
|
#if _PERTEXMICROSHADOWS
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
{
|
|
half3 lightDir = GetGlobalLightDirTS(i);
|
|
half4 microShadows = half4(1,1,1,1);
|
|
microShadows.x = MicroShadow(lightDir, half3(samples.normSAO0.xy, 1), samples.normSAO0.a, ptFuzz0.a);
|
|
microShadows.y = MicroShadow(lightDir, half3(samples.normSAO1.xy, 1), samples.normSAO1.a, ptFuzz1.a);
|
|
microShadows.z = MicroShadow(lightDir, half3(samples.normSAO2.xy, 1), samples.normSAO2.a, ptFuzz2.a);
|
|
microShadows.w = MicroShadow(lightDir, half3(samples.normSAO3.xy, 1), samples.normSAO3.a, ptFuzz3.a);
|
|
samples.normSAO0.a *= microShadows.x;
|
|
samples.normSAO1.a *= microShadows.y;
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a *= microShadows.z;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a *= microShadows.w;
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_OUTPUT_MICROSHADOWS
|
|
o.Albedo = BlendWeights(microShadows.x, microShadows.y, microShadows.z, microShadows.a, heightWeights);
|
|
return o;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
#endif // _PERTEXMICROSHADOWS
|
|
|
|
|
|
#if _PERTEXFUZZYSHADE
|
|
samples.albedo0.rgb = FuzzyShade(samples.albedo0.rgb, half3(samples.normSAO0.rg, 1), ptFuzz0.r, ptFuzz0.g, ptFuzz0.b, i.viewDir);
|
|
samples.albedo1.rgb = FuzzyShade(samples.albedo1.rgb, half3(samples.normSAO1.rg, 1), ptFuzz1.r, ptFuzz1.g, ptFuzz1.b, i.viewDir);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = FuzzyShade(samples.albedo2.rgb, half3(samples.normSAO2.rg, 1), ptFuzz2.r, ptFuzz2.g, ptFuzz2.b, i.viewDir);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = FuzzyShade(samples.albedo3.rgb, half3(samples.normSAO3.rg, 1), ptFuzz3.r, ptFuzz3.g, ptFuzz3.b, i.viewDir);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSATURATION && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptSaturattion, 9.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = lerp(MSLuminance(samples.albedo0.rgb), samples.albedo0.rgb, ptSaturattion0.a);
|
|
samples.albedo1.rgb = lerp(MSLuminance(samples.albedo1.rgb), samples.albedo1.rgb, ptSaturattion1.a);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = lerp(MSLuminance(samples.albedo2.rgb), samples.albedo2.rgb, ptSaturattion2.a);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = lerp(MSLuminance(samples.albedo3.rgb), samples.albedo3.rgb, ptSaturattion3.a);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if _PERTEXTINT && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptTints, 1.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb *= ptTints0.rgb;
|
|
samples.albedo1.rgb *= ptTints1.rgb;
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb *= ptTints2.rgb;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb *= ptTints3.rgb;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PCHEIGHTGRADIENT || _PCHEIGHTHSV || _PCSLOPEGRADIENT || _PCSLOPEHSV
|
|
ProceduralGradients(i, samples, config, worldHeight, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS
|
|
porosity = _GlobalPorosity;
|
|
#endif
|
|
|
|
|
|
#if _PERTEXCOLORINTENSITY
|
|
SAMPLE_PER_TEX(ptCI, 23.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb * (1 + ptCI0.rrr));
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb * (1 + ptCI1.rrr));
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb * (1 + ptCI2.rrr));
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb * (1 + ptCI3.rrr));
|
|
#endif
|
|
#endif
|
|
|
|
#if (_PERTEXBRIGHTNESS || _PERTEXCONTRAST || _PERTEXPOROSITY || _PERTEXFOAM) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptBC, 3.5, config, half4(1, 1, 1, 1));
|
|
#if _PERTEXCONTRAST
|
|
samples.albedo0.rgb = saturate(((samples.albedo0.rgb - 0.5) * ptBC0.g) + 0.5);
|
|
samples.albedo1.rgb = saturate(((samples.albedo1.rgb - 0.5) * ptBC1.g) + 0.5);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(((samples.albedo2.rgb - 0.5) * ptBC2.g) + 0.5);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(((samples.albedo3.rgb - 0.5) * ptBC3.g) + 0.5);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXBRIGHTNESS
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb + ptBC0.rrr);
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb + ptBC1.rrr);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb + ptBC2.rrr);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb + ptBC3.rrr);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXPOROSITY
|
|
porosity = BlendWeights(ptBC0.b, ptBC1.b, ptBC2.b, ptBC3.b, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXFOAM
|
|
streamFoam = BlendWeights(ptBC0.a, ptBC1.a, ptBC2.a, ptBC3.a, heightWeights);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if (_PERTEXNORMSTR || _PERTEXAOSTR || _PERTEXSMOOTHSTR || _PERTEXMETALLIC) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(perTexMatSettings, 2.5, config, half4(1.0, 1.0, 1.0, 0.0));
|
|
#endif
|
|
|
|
#if _PERTEXNORMSTR && !_DISABLESPLATMAPS
|
|
#if _SURFACENORMALS
|
|
samples.surf0 *= perTexMatSettings0.r;
|
|
samples.surf1 *= perTexMatSettings1.r;
|
|
samples.surf2 *= perTexMatSettings2.r;
|
|
samples.surf3 *= perTexMatSettings3.r;
|
|
#else
|
|
samples.normSAO0.xy *= perTexMatSettings0.r;
|
|
samples.normSAO1.xy *= perTexMatSettings1.r;
|
|
samples.normSAO2.xy *= perTexMatSettings2.r;
|
|
samples.normSAO3.xy *= perTexMatSettings3.r;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXAOSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.a = pow(abs(samples.normSAO0.a), perTexMatSettings0.b);
|
|
samples.normSAO1.a = pow(abs(samples.normSAO1.a), perTexMatSettings1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a = pow(abs(samples.normSAO2.a), perTexMatSettings2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a = pow(abs(samples.normSAO3.a), perTexMatSettings3.b);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSMOOTHSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.b += perTexMatSettings0.g;
|
|
samples.normSAO1.b += perTexMatSettings1.g;
|
|
samples.normSAO0.b = saturate(samples.normSAO0.b);
|
|
samples.normSAO1.b = saturate(samples.normSAO1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.b += perTexMatSettings2.g;
|
|
samples.normSAO2.b = saturate(samples.normSAO2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.b += perTexMatSettings3.g;
|
|
samples.normSAO3.b = saturate(samples.normSAO3.b);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
#if _PERTEXSSS
|
|
{
|
|
SAMPLE_PER_TEX(ptSSS, 18.5, config, half4(1, 1, 1, 1)); // tint, thickness
|
|
half4 vals = ptSSS0 * heightWeights.x + ptSSS1 * heightWeights.y + ptSSS2 * heightWeights.z + ptSSS3 * heightWeights.w;
|
|
SSSThickness = vals.a;
|
|
SSSTint = vals.rgb;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXRIMLIGHT
|
|
{
|
|
SAMPLE_PER_TEX(ptRimA, 26.5, config, half4(1, 1, 1, 1));
|
|
SAMPLE_PER_TEX(ptRimB, 27.5, config, half4(1, 1, 1, 0));
|
|
samples.emisMetal0.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO0.xy, 1))), max(0.0001, ptRimA0.g)) * ptRimB0.rgb * ptRimB0.a;
|
|
samples.emisMetal1.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO1.xy, 1))), max(0.0001, ptRimA1.g)) * ptRimB1.rgb * ptRimB1.a;
|
|
samples.emisMetal2.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO2.xy, 1))), max(0.0001, ptRimA2.g)) * ptRimB2.rgb * ptRimB2.a;
|
|
samples.emisMetal3.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO3.xy, 1))), max(0.0001, ptRimA3.g)) * ptRimB3.rgb * ptRimB3.a;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#if (((_DETAILNOISE && _PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && _PERTEXDISTANCENOISESTRENGTH)) || (_NORMALNOISE && _PERTEXNORMALNOISESTRENGTH)) && !_DISABLESPLATMAPS
|
|
ApplyDetailDistanceNoisePerTex(samples, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALNOISEUV
|
|
// noise defaults so that a value of 1, 1 is 4 pixels in size and moves the uvs by 1 pixel max.
|
|
#if _CUSTOMSPLATTEXTURES
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#else
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE
|
|
ApplyTrax(samples, config, i.worldPos, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if (_ANTITILEARRAYDETAIL || _ANTITILEARRAYDISTANCE || _ANTITILEARRAYNORMAL) && !_DISABLESPLATMAPS
|
|
ApplyAntiTilePerTex(samples, config, camDist, i.worldPos, worldNormalVertex, heightWeights);
|
|
#endif
|
|
|
|
#if _GEOMAP && !_DISABLESPLATMAPS
|
|
GeoTexturePerTex(samples, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
#if _GLOBALTINT && _PERTEXGLOBALTINTSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalTintTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && _PERTEXGLOBALNORMALSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalNormalTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && _PERTEXGLOBALSAOMSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalSAOMTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && _PERTEXGLOBALEMISSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalEmisTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && _PERTEXGLOBALSPECULARSTRENGTH && !_DISABLESPLATMAPS && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _PERTEXMETALLIC && !_DISABLESPLATMAPS
|
|
half metallic = BlendWeights(perTexMatSettings0.a, perTexMatSettings1.a, perTexMatSettings2.a, perTexMatSettings3.a, heightWeights);
|
|
o.Metallic = metallic;
|
|
#endif
|
|
|
|
#if _GLITTER && !_DISABLESPLATMAPS
|
|
DoGlitter(i, samples, config, camDist, worldNormalVertex, i.worldPos);
|
|
#endif
|
|
|
|
// Blend em..
|
|
#if _DISABLESPLATMAPS
|
|
// If we don't sample from the _Diffuse, then the shader compiler will strip the sampler on
|
|
// some platforms, which will cause everything to break. So we sample from the lowest mip
|
|
// and saturate to 1 to keep the cost minimal. Annoying, but the compiler removes the texture
|
|
// and sampler, even though the sampler is still used.
|
|
albedo = saturate(UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, float3(0,0,0), 12) + 1);
|
|
albedo.a = 0.5; // make height something we can blend with for the combined mesh mode, since it still height blends.
|
|
normSAO = half4(0,0,0,1);
|
|
#else
|
|
albedo = BlendWeights(samples.albedo0, samples.albedo1, samples.albedo2, samples.albedo3, heightWeights);
|
|
normSAO = BlendWeights(samples.normSAO0, samples.normSAO1, samples.normSAO2, samples.normSAO3, heightWeights);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = BlendWeights(samples.surf0, samples.surf1, samples.surf2, samples.surf3, heightWeights);
|
|
#endif
|
|
|
|
#if (_USEEMISSIVEMETAL || _PERTEXRIMLIGHT) && !_DISABLESPLATMAPS
|
|
emisMetal = BlendWeights(samples.emisMetal0, samples.emisMetal1, samples.emisMetal2, samples.emisMetal3, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW && !_DISABLESPLATMAPS
|
|
specular = BlendWeights(samples.specular0, samples.specular1, samples.specular2, samples.specular3, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXOUTLINECOLOR
|
|
SAMPLE_PER_TEX(ptOutlineColor, 28.5, config, half4(0.5, 0.5, 0.5, 1));
|
|
half4 outlineColor = BlendWeights(ptOutlineColor0, ptOutlineColor1, ptOutlineColor2, ptOutlineColor3, heightWeights);
|
|
half4 tstr = saturate(abs(heightWeights - 0.5) * 2);
|
|
half transitionBlend = min(min(min(tstr.x, tstr.y), tstr.z), tstr.w);
|
|
albedo.rgb = lerp(albedo.rgb * outlineColor.rgb * 2, albedo.rgb, outlineColor.a * transitionBlend);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHOVERLAYSPLATS || _MESHCOMBINED
|
|
o.Alpha = 1.0;
|
|
if (config.uv0.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.x;
|
|
else if (config.uv1.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.y;
|
|
else if (config.uv2.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.z;
|
|
else if (config.uv3.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.w;
|
|
#endif
|
|
|
|
|
|
|
|
// effects which don't require per texture adjustments and are part of the splats sample go here.
|
|
// Often, as an optimization, you can compute the non-per tex version of above effects here..
|
|
|
|
|
|
#if ((_DETAILNOISE && !_PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && !_PERTEXDISTANCENOISESTRENGTH) || (_NORMALNOISE && !_PERTEXNORMALNOISESTRENGTH))
|
|
ApplyDetailDistanceNoise(albedo.rgb, normSAO, surfGrad, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
}
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
|
|
float2 sfDX = ddx(config.uv * _UVScale);
|
|
float2 sfDY = ddy(config.uv * _UVScale);
|
|
|
|
MSBRANCHOTHER(camDist - _SplatFade.x)
|
|
{
|
|
float falloff = saturate(InverseLerp(_SplatFade.x, _SplatFade.y, camDist));
|
|
half4 sfalb = SAMPLE_TEXTURE2D_ARRAY_GRAD(_Diffuse, sampler_Diffuse, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY);
|
|
COUNTSAMPLE
|
|
albedo.rgb = lerp(albedo.rgb, sfalb.rgb, falloff);
|
|
|
|
#if !_NONORMALMAP && !_AUTONORMAL
|
|
half4 sfnormSAO = SAMPLE_TEXTURE2D_ARRAY_GRAD(_NormalSAO, sampler_NormalSAO, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY).agrb;
|
|
COUNTSAMPLE
|
|
sfnormSAO.xy = sfnormSAO.xy * 2 - 1;
|
|
|
|
normSAO = lerp(normSAO, sfnormSAO, falloff);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = lerp(surfGrad, ConvertNormal2ToGradient(sfnormSAO.xy), falloff);
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
float3 autoNormal = HeightToNormal(albedo.a * _AutoNormalHeightScale, i.worldPos);
|
|
normSAO.xy = autoNormal;
|
|
normSAO.z = 0;
|
|
normSAO.w = (autoNormal.z * autoNormal.z);
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHCOMBINED
|
|
SampleMeshCombined(albedo, normSAO, surfGrad, emisMetal, specular, o.Alpha, SSSThickness, SSSTint, config, heightWeights);
|
|
#endif
|
|
|
|
#if _ISOBJECTSHADER
|
|
SampleObjectShader(i, albedo, normSAO, surfGrad, emisMetal, specular, config);
|
|
#endif
|
|
|
|
#if _GEOMAP
|
|
GeoTexture(albedo.rgb, normSAO, surfGrad, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
|
|
#if _SCATTER
|
|
ApplyScatter(
|
|
#if _MEGASPLAT
|
|
config,
|
|
#endif
|
|
i, albedo, normSAO, surfGrad, config.uv, camDist);
|
|
#endif
|
|
|
|
#if _DECAL
|
|
DoDecalBlend(decalOutput, albedo, normSAO, surfGrad, emisMetal, i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALTINT && !_PERTEXGLOBALTINTSTRENGTH
|
|
GlobalTintTexture(albedo.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _VSGRASSMAP
|
|
VSGrassTexture(albedo.rgb, config, camDist);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && !_PERTEXGLOBALNORMALSTRENGTH
|
|
GlobalNormalTexture(normSAO, surfGrad, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && !_PERTEXGLOBALSAOMSTRENGTH
|
|
GlobalSAOMTexture(normSAO, emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && !_PERTEXGLOBALEMISSTRENGTH
|
|
GlobalEmisTexture(emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && !_PERTEXGLOBALSPECULARSTRENGTH && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexture(specular.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
|
|
|
|
o.Albedo = albedo.rgb;
|
|
o.Height = albedo.a;
|
|
|
|
#if _NONORMALMAP
|
|
o.Normal = half3(0,0,1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#elif _SURFACENORMALS
|
|
o.Normal = ResolveNormalFromSurfaceGradient(surfGrad);
|
|
o.Normal = mul(GetTBN(i), o.Normal);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#else
|
|
o.Normal = half3(normSAO.xy, 1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _PERTEXRIMLIGHT
|
|
#if _USEEMISSIVEMETAL
|
|
emisMetal.rgb *= _EmissiveMult;
|
|
#endif
|
|
|
|
o.Emission += emisMetal.rgb;
|
|
o.Metallic = emisMetal.a;
|
|
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = specular;
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
pud = DoStreams(i, o, fxLevels, config.uv, porosity, waterNormalFoam, worldNormalVertex, streamFoam, wetLevel, burnLevel, i.worldPos);
|
|
#endif
|
|
|
|
|
|
#if _SNOW
|
|
snowCover = DoSnow(i, o, config.uv, WorldNormalVector(i, o.Normal), worldNormalVertex, i.worldPos, pud, porosity, camDist,
|
|
config, weights, SSSTint, SSSThickness, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if _PERTEXSSS || _MESHCOMBINEDUSESSS || (_SNOW && _SNOWSSS)
|
|
{
|
|
half3 worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
|
|
|
|
o.Emission += ComputeSSS(i, worldView, WorldNormalVector(i, o.Normal),
|
|
SSSTint, SSSThickness, _SSSDistance, _SSSScale, _SSSPower);
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWGLITTER
|
|
DoSnowGlitter(i, config, o, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
#if _WINDPARTICULATE || _SNOWPARTICULATE
|
|
DoWindParticulate(i, o, config, weights, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
o.Normal.z = sqrt(1 - saturate(dot(o.Normal.xy, o.Normal.xy)));
|
|
|
|
#if _SPECULARFADE
|
|
{
|
|
float specFade = saturate((i.worldPos.y - _SpecularFades.x) / max(_SpecularFades.y - _SpecularFades.x, 0.0001));
|
|
o.Metallic *= specFade;
|
|
o.Smoothness *= specFade;
|
|
}
|
|
#endif
|
|
|
|
#if _VSSHADOWMAP
|
|
VSShadowTexture(o, i, config, camDist);
|
|
#endif
|
|
|
|
#if _TOONWIREFRAME
|
|
ToonWireframe(config.uv, o.Albedo, camDist);
|
|
#endif
|
|
|
|
#if _SEETHROUGHSHADER
|
|
SeethroughShader(o.Albedo, o.Emission, o.Alpha, i.worldPos, o.Normal, i.worldNormal);
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_TRAXBUFFER
|
|
ClearAllButAlbedo(o, half3(traxBuffer, 0, 0) * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMALVERTEX
|
|
ClearAllButAlbedo(o, worldNormalVertex * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(o, WorldNormalVector(i, o.Normal) * saturate(o.Albedo.z+1));
|
|
#endif
|
|
|
|
#if _DEBUG_MEGABARY && _MEGASPLAT
|
|
o.Albedo = i.baryWeights.xyz;
|
|
#endif
|
|
|
|
|
|
return o;
|
|
}
|
|
|
|
void SampleSplats(float2 controlUV, inout half4 w0, inout half4 w1, inout half4 w2, inout half4 w3, inout half4 w4, inout half4 w5, inout half4 w6, inout half4 w7)
|
|
{
|
|
#if _CUSTOMSPLATTEXTURES
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_CustomControl0_TexelSize.zw - 1.0f) + 0.5f) * _CustomControl0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_CustomControl0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_CustomControl1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_CustomControl2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_CustomControl3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_CustomControl4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_CustomControl5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_CustomControl6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_CustomControl7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#else
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_Control0_TexelSize.zw - 1.0f) + 0.5f) * _Control0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_Control0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_Control1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_Control2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_Control3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_Control4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_Control5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_Control6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_Control7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
MicroSplatLayer SurfImpl(Input i, float3 worldNormalVertex)
|
|
{
|
|
#if _MEGANOUV
|
|
i.uv_Control0 = i.worldPos.xz;
|
|
#endif
|
|
|
|
float camDist = distance(_WorldSpaceCameraPos, i.worldPos);
|
|
|
|
#if _FORCELOCALSPACE
|
|
worldNormalVertex = mul((float3x3)GetWorldToObjectMatrix(), worldNormalVertex).xyz;
|
|
i.worldPos = i.worldPos - mul(GetObjectToWorldMatrix(), float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
i.worldPos = i.worldPos + mul(_GlobalOriginMTX, float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
i.worldPos = SAMPLE_TEXTURE2D(_DebugWorldPos, sampler_Diffuse, i.uv_Control0);
|
|
worldNormalVertex = SAMPLE_TEXTURE2D(_DebugWorldNormal, sampler_Diffuse, i.uv_Control0);
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ALPHABELOWHEIGHT && !_TBDISABLEALPHAHOLES
|
|
ClipWaterLevel(i.worldPos);
|
|
#endif
|
|
|
|
#if !_TBDISABLEALPHAHOLES && defined(_ALPHATEST_ON)
|
|
// UNITY 2019.3 holes
|
|
ClipHoles(i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
float2 origUV = i.uv_Control0;
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
float2 controlUV = i.uv2_Diffuse;
|
|
#else
|
|
float2 controlUV = i.uv_Control0;
|
|
#endif
|
|
|
|
|
|
#if _MICROMESH
|
|
controlUV = InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, controlUV);
|
|
#endif
|
|
|
|
half4 weights = half4(1,0,0,0);
|
|
|
|
Config config = (Config)0;
|
|
UNITY_INITIALIZE_OUTPUT(Config,config);
|
|
config.uv = origUV;
|
|
|
|
DecalOutput decalOutput = (DecalOutput)0;
|
|
#if _DECAL
|
|
decalOutput = DoDecals(i.uv_Control0, i.worldPos, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SURFACENORMALS
|
|
// Initialize the surface gradient basis vectors
|
|
ConstructSurfaceGradientTBN(i);
|
|
#endif
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(_SplatFade.y - camDist)
|
|
#endif // _SPLATFADE
|
|
{
|
|
#if !_DISABLESPLATMAPS
|
|
|
|
// Sample the splat data, from textures or vertices, and setup the config..
|
|
#if _MICRODIGGERMESH
|
|
DiggerSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLAT
|
|
MegaSplatVertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLATTEXTURE
|
|
MegaSplatTextureSetup(controlUV, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MICROVERTEXMESH
|
|
VertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif !_PROCEDURALTEXTURE || _PROCEDURALBLENDSPLATS
|
|
half4 w0 = 0; half4 w1 = 0; half4 w2 = 0; half4 w3 = 0; half4 w4 = 0; half4 w5 = 0; half4 w6 = 0; half4 w7 = 0;
|
|
SampleSplats(controlUV, w0, w1, w2, w3, w4, w5, w6, w7);
|
|
Setup(weights, origUV, config, w0, w1, w2, w3, w4, w5, w6, w7, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
float3 procNormal = worldNormalVertex;
|
|
float3 worldPos = i.worldPos;
|
|
ProceduralSetup(i, worldPos, i.worldHeight, procNormal, i.worldUpVector, weights, origUV, config, ddx(origUV), ddy(origUV), ddx(worldPos), ddy(worldPos), decalOutput);
|
|
#endif
|
|
#else // _DISABLESPLATMAPS
|
|
Setup(weights, origUV, config, half4(1,0,0,0), 0, 0, 0, 0, 0, 0, 0, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _SLOPETEXTURE
|
|
SlopeTexture(config, weights, worldNormalVertex);
|
|
#endif
|
|
} // _SPLATFADE else case
|
|
|
|
|
|
#if _TOONFLATTEXTURE
|
|
float2 quv = floor(origUV * _ToonTerrainSize);
|
|
float2 fuv = frac(origUV * _ToonTerrainSize);
|
|
#if !_TOONFLATTEXTUREQUAD
|
|
quv = Hash2D((fuv.x > fuv.y) ? quv : quv * 0.333);
|
|
#endif
|
|
float2 uvq = quv / _ToonTerrainSize;
|
|
config.uv0.xy = uvq;
|
|
config.uv1.xy = uvq;
|
|
config.uv2.xy = uvq;
|
|
config.uv3.xy = uvq;
|
|
#endif
|
|
|
|
#if (_TEXTURECLUSTER2 || _TEXTURECLUSTER3) && !_DISABLESPLATMAPS
|
|
PrepClusters(origUV, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if (_ALPHAHOLE || _ALPHAHOLETEXTURE) && !_DISABLESPLATMAPS && !_TBDISABLEALPHAHOLES
|
|
ClipAlphaHole(config, weights);
|
|
#endif
|
|
|
|
|
|
|
|
MicroSplatLayer l = Sample(i, weights, config, camDist, worldNormalVertex, decalOutput);
|
|
|
|
// On windows, sometimes the shared samplers gets stripped, so we have to do this crap.
|
|
// We sample from the lowest mip, so it shouldn't cost much, but still, I hate this, wtf..
|
|
float stripVal = saturate(SAMPLE_TEXTURE2D_LOD(_Diffuse, sampler_Diffuse, config.uv0, 11).r + 2);
|
|
stripVal *= saturate(SAMPLE_TEXTURE2D_LOD(_NormalSAO, sampler_NormalSAO, config.uv0, 11).r + 2);
|
|
l.Albedo *= stripVal;
|
|
l.Normal *= stripVal;
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
ProceduralTextureDebugOutput(l, weights, config);
|
|
#endif
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float4 ConstructTerrainTangent(float3 normal, float3 positiveZ)
|
|
{
|
|
// Consider a flat terrain. It should have tangent be (1, 0, 0) and bitangent be (0, 0, 1) as the UV of the terrain grid mesh is a scale of the world XZ position.
|
|
// In CreateTangentToWorld function (in SpaceTransform.hlsl), it is cross(normal, tangent) * sgn for the bitangent vector.
|
|
// It is not true in a left-handed coordinate system for the terrain bitangent, if we provide 1 as the tangent.w. It would produce (0, 0, -1) instead of (0, 0, 1).
|
|
// Also terrain's tangent calculation was wrong in a left handed system because cross((0,0,1), terrainNormalOS) points to the wrong direction as negative X.
|
|
// Therefore all the 4 xyzw components of the tangent needs to be flipped to correct the tangent frame.
|
|
// (See TerrainLitData.hlsl - GetSurfaceAndBuiltinData)
|
|
float3 tangent = normalize(cross(normal, positiveZ));
|
|
return float4(tangent, -1);
|
|
}
|
|
|
|
|
|
|
|
void TerrainInstancing(inout float4 vertex, inout float3 normal, inout float2 uv)
|
|
{
|
|
#if _MICROTERRAIN && defined(UNITY_INSTANCING_ENABLED) && !_TERRAINBLENDABLESHADER
|
|
|
|
float2 patchVertex = vertex.xy;
|
|
float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);
|
|
|
|
float2 sampleCoords = (patchVertex.xy + instanceData.xy) * instanceData.z; // (xy + float2(xBase,yBase)) * skipScale
|
|
uv = sampleCoords * _TerrainHeightmapRecipSize.zw;
|
|
|
|
float2 sampleUV = (uv / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleUV, 0));
|
|
|
|
vertex.xz = sampleCoords * _TerrainHeightmapScale.xz;
|
|
vertex.y = height * _TerrainHeightmapScale.y;
|
|
|
|
|
|
normal = float3(0, 1, 0);
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
void ApplyMeshModification(inout VertexData input)
|
|
{
|
|
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
|
|
float2 uv = input.texcoord0.xy;
|
|
TerrainInstancing(input.vertex, input.normal, uv);
|
|
input.texcoord0.xy = uv;
|
|
#endif
|
|
#if _PERPIXNORMAL && !_TERRAINBLENDABLESHADER
|
|
input.normal = float3(0,1,0);
|
|
#endif
|
|
|
|
#if _MICROVERSEPREVIEW
|
|
float4 recipSize = _TerrainHeightmapTexture_TexelSize;
|
|
recipSize.zw = (1.0f / (_TerrainHeightmapTexture_TexelSize.zw-1));
|
|
float2 sampleCoords = (input.texcoord0.xy / recipSize.zw + 0.5f) * recipSize.xy;
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleCoords, 0));
|
|
input.vertex.xyz += float3(0,1,0) * height * _TerrainHeight * 2;
|
|
#endif
|
|
|
|
}
|
|
|
|
// called by the template, so we can remove tangent from VertexData
|
|
void ApplyTerrainTangent(inout VertexToPixel input)
|
|
{
|
|
#if (_MICROTERRAIN || _PERPIXNORMAL) && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
|
|
// digger meshes ain't got no tangent either..
|
|
#if _MICRODIGGERMESH && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
void ModifyVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
ApplyMeshModification(v);
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
EncodeVertexWorkflow(v, d);
|
|
#elif _MEGASPLAT
|
|
EncodeMegaSplatVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void ModifyTessellatedVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
#if _MICROVERSEPREVIEW
|
|
v.vertex.y = OffsetVertex(v, d).y;
|
|
#elif _TESSDISTANCE || _TESSEDGE
|
|
v.vertex.xyz += OffsetVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
float3 GetTessFactors ()
|
|
{
|
|
#if _TESSEDGE
|
|
return float3(_TessData1.x, _TessData1.w, 0);
|
|
#endif
|
|
#if _TESSDISTANCE
|
|
return float3(_TessData2.x, _TessData2.y, _TessData1.x);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SurfaceFunction(inout Surface o, inout ShaderData d)
|
|
{
|
|
|
|
float3 worldNormalVertex = d.worldSpaceNormal;
|
|
#if _MICROVERSEPREVIEW
|
|
float2 sampleCoords = d.texcoord0.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif (defined(UNITY_INSTANCING_ENABLED) && _MICROTERRAIN && !_TERRAINBLENDABLESHADER)
|
|
float2 sampleCoords = (d.texcoord0.xy / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif _PERPIXNORMAL && (_MICROTERRAIN || _MICROMESHTERRAIN) && !_TERRAINBLENDABLESHADER
|
|
float2 sampleCoords = (d.texcoord0.xy * _PerPixelNormal_TexelSize.zw + 0.5f) * _PerPixelNormal_TexelSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_PerPixelNormal, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
|
|
float3 geomBitangent = normalize(cross(geomTangent, geomNormal)) * -1;
|
|
#if _MICROMESHTERRAIN
|
|
geomBitangent *= -1;
|
|
#endif
|
|
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#endif
|
|
|
|
#if _TOONPOLYEDGE
|
|
FlatShade(d);
|
|
#endif
|
|
|
|
Input i = DescToInput(d);
|
|
|
|
|
|
|
|
#if _SRPTERRAINBLEND
|
|
MicroSplatLayer l = BlendWithTerrain(d);
|
|
|
|
#if _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(l, normalize(TangentToWorldSpace(d, l.Normal)) * saturate(l.Albedo.z+1));
|
|
#endif
|
|
#else
|
|
MicroSplatLayer l = SurfImpl(i, worldNormalVertex);
|
|
#endif
|
|
|
|
DoDebugOutput(l);
|
|
|
|
|
|
|
|
|
|
o.Albedo = l.Albedo;
|
|
o.Normal = l.Normal;
|
|
o.Smoothness = l.Smoothness;
|
|
o.Occlusion = l.Occlusion;
|
|
o.Metallic = l.Metallic;
|
|
o.Emission = l.Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = l.Specular;
|
|
#endif
|
|
o.Height = l.Height;
|
|
o.Alpha = l.Alpha;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SHADERDESC
|
|
|
|
ShaderData CreateShaderData(VertexToPixel i)
|
|
{
|
|
ShaderData d = (ShaderData)0;
|
|
d.worldSpacePosition = i.worldPos;
|
|
|
|
d.worldSpaceNormal = i.worldNormal;
|
|
d.worldSpaceTangent = i.worldTangent.xyz;
|
|
float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * -1;
|
|
|
|
|
|
d.TBNMatrix = float3x3(d.worldSpaceTangent, bitangent, d.worldSpaceNormal);
|
|
d.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
d.texcoord0 = i.texcoord0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
d.texcoord1 = i.texcoord1;
|
|
// d.texcoord2 = i.texcoord2;
|
|
#endif
|
|
// d.texcoord3 = i.texcoord3;
|
|
// d.vertexColor = i.vertexColor;
|
|
|
|
// these rarely get used, so we back transform them. Usually will be stripped.
|
|
#if _HDRP
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(GetCameraRelativePositionWS(i.worldPos), 1));
|
|
#else
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(i.worldPos, 1));
|
|
#endif
|
|
// d.localSpaceNormal = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldNormal));
|
|
// d.localSpaceTangent = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldTangent.xyz));
|
|
|
|
// d.screenPos = i.screenPos;
|
|
// d.screenUV = i.screenPos.xy / i.screenPos.w;
|
|
|
|
// d.extraV2F0 = i.extraV2F0;
|
|
// d.extraV2F1 = i.extraV2F1;
|
|
// d.extraV2F2 = i.extraV2F2;
|
|
// d.extraV2F3 = i.extraV2F3;
|
|
// d.extraV2F4 = i.extraV2F4;
|
|
// d.extraV2F5 = i.extraV2F5;
|
|
// d.extraV2F6 = i.extraV2F6;
|
|
// d.extraV2F7 = i.extraV2F7;
|
|
|
|
return d;
|
|
}
|
|
// CHAINS
|
|
|
|
void ChainModifyVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
ModifyVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
void ChainModifyTessellatedVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
// d.extraV2F0 = v2p.extraV2F0;
|
|
// d.extraV2F1 = v2p.extraV2F1;
|
|
// d.extraV2F2 = v2p.extraV2F2;
|
|
// d.extraV2F3 = v2p.extraV2F3;
|
|
// d.extraV2F4 = v2p.extraV2F4;
|
|
// d.extraV2F5 = v2p.extraV2F5;
|
|
// d.extraV2F6 = v2p.extraV2F6;
|
|
// d.extraV2F7 = v2p.extraV2F7;
|
|
|
|
ModifyTessellatedVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
|
|
void ChainFinalColorForward(inout Surface l, inout ShaderData d, inout half4 color)
|
|
{
|
|
|
|
}
|
|
|
|
void ChainFinalGBufferStandard(inout Surface s, inout ShaderData d, inout half4 GBuffer0, inout half4 GBuffer1, inout half4 GBuffer2, inout half4 outEmission, inout half4 outShadowMask)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _PASSSHADOW
|
|
float3 _LightDirection;
|
|
float3 _LightPosition;
|
|
#endif
|
|
|
|
// vertex shader
|
|
VertexToPixel Vert (VertexData v)
|
|
{
|
|
|
|
VertexToPixel o = (VertexToPixel)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
|
|
|
|
|
#if !_TESSELLATION_ON
|
|
ChainModifyVertex(v, o);
|
|
#endif
|
|
|
|
o.texcoord0 = v.texcoord0;
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
o.texcoord1 = v.texcoord1;
|
|
// o.texcoord2 = v.texcoord2;
|
|
#endif
|
|
|
|
// o.texcoord3 = v.texcoord3;
|
|
// o.vertexColor = v.vertexColor;
|
|
|
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
|
|
o.worldPos = TransformObjectToWorld(v.vertex.xyz);
|
|
o.worldNormal = TransformObjectToWorldNormal(v.normal);
|
|
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float2 uv1 = v.texcoord1.xy;
|
|
float2 uv2 = v.texcoord2.xy;
|
|
o.worldTangent = float4(TransformObjectToWorldDir(v.tangent.xyz), v.tangent.w);
|
|
#else
|
|
float2 uv1 = v.texcoord0.xy;
|
|
float2 uv2 = uv1;
|
|
#endif
|
|
|
|
// MS Only
|
|
ApplyTerrainTangent(o);
|
|
|
|
|
|
#if _PASSSHADOW
|
|
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
float3 lightDirectionWS = normalize(_LightPosition - o.worldPos);
|
|
#else
|
|
float3 lightDirectionWS = _LightDirection;
|
|
#endif
|
|
// Define shadow pass specific clip position for Universal
|
|
o.pos = TransformWorldToHClip(ApplyShadowBias(o.worldPos, o.worldNormal, lightDirectionWS));
|
|
#if UNITY_REVERSED_Z
|
|
o.pos.z = min(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#else
|
|
o.pos.z = max(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#endif
|
|
#elif _PASSMETA
|
|
#if _MICROTERRAIN
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), v.texcoord0.xy, v.texcoord0.xy, unity_LightmapST, unity_DynamicLightmapST);
|
|
#else
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), uv1, uv2, unity_LightmapST, unity_DynamicLightmapST);
|
|
#endif
|
|
#else
|
|
o.pos = TransformWorldToHClip(o.worldPos);
|
|
#endif
|
|
|
|
|
|
|
|
// o.screenPos = ComputeScreenPos(o.pos, _ProjectionParams.x);
|
|
|
|
|
|
#if _PASSFORWARD || _PASSGBUFFER
|
|
#if _MICROTERRAIN
|
|
OUTPUT_LIGHTMAP_UV(v.texcoord0.xy, unity_LightmapST, o.lightmapUV);
|
|
#else
|
|
OUTPUT_LIGHTMAP_UV(uv1, unity_LightmapST, o.lightmapUV);
|
|
#endif
|
|
OUTPUT_SH(o.worldNormal, o.sh);
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
o.dynamicLightmapUV.xy = uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
|
|
half fogFactor = 0;
|
|
#if defined(_FOG_FRAGMENT)
|
|
fogFactor = ComputeFogFactor(o.pos.z);
|
|
#endif
|
|
#if _BAKEDLIT
|
|
half3 vertexLight = VertexLighting(o.worldPos, o.worldNormal);
|
|
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
|
|
#else
|
|
o.fogFactorAndVertexLight = half4(fogFactor, 0,0,0);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
|
|
o.shadowCoord = GetShadowCoord(vertexInput);
|
|
#endif
|
|
|
|
return o;
|
|
}
|
|
|
|
|
|
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UnityGBuffer.hlsl"
|
|
|
|
|
|
// fragment shader
|
|
FragmentOutput Frag (VertexToPixel IN
|
|
#ifdef _DEPTHOFFSET_ON
|
|
, out float outputDepth : SV_Depth
|
|
#endif
|
|
)
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
|
|
|
|
ShaderData d = CreateShaderData(IN);
|
|
Surface l = (Surface)0;
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
l.outputDepth = outputDepth;
|
|
#endif
|
|
|
|
l.Albedo = half3(0.5, 0.5, 0.5);
|
|
l.Normal = float3(0,0,1);
|
|
l.Occlusion = 1;
|
|
l.Alpha = 1;
|
|
|
|
SurfaceFunction(l, d);
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
outputDepth = l.outputDepth;
|
|
#endif
|
|
|
|
#if defined(_USESPECULAR) || _SIMPLELIT
|
|
float3 specular = l.Specular;
|
|
float metallic = 0;
|
|
#else
|
|
float3 specular = 0;
|
|
float metallic = l.Metallic;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
InputData inputData = (InputData)0;
|
|
|
|
inputData.positionWS = IN.worldPos;
|
|
inputData.normalWS = mul(l.Normal, d.TBNMatrix);
|
|
inputData.viewDirectionWS = SafeNormalize(d.worldSpaceViewDir);
|
|
|
|
|
|
#if defined(MAIN_LIGHT_CALCULATE_SHADOWS)
|
|
inputData.shadowCoord = TransformWorldToShadowCoord(inputData.positionWS);
|
|
#else
|
|
inputData.shadowCoord = float4(0, 0, 0, 0);
|
|
#endif
|
|
|
|
|
|
InitializeInputDataFog(float4(IN.worldPos, 1.0), IN.fogFactorAndVertexLight.x);
|
|
inputData.vertexLighting = IN.fogFactorAndVertexLight.yzw;
|
|
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
inputData.bakedGI = SAMPLE_GI(IN.lightmapUV, IN.dynamicLightmapUV.xy, IN.sh, inputData.normalWS);
|
|
#else
|
|
inputData.bakedGI = SAMPLE_GI(IN.lightmapUV, IN.sh, inputData.normalWS);
|
|
#endif
|
|
|
|
inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(IN.pos);
|
|
#if defined(LIGHTMAP_ON)
|
|
inputData.shadowMask = SAMPLE_SHADOWMASK(IN.lightmapUV);
|
|
#endif
|
|
|
|
#if defined(DEBUG_DISPLAY)
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
inputData.dynamicLightmapUV = IN.dynamicLightmapUV.xy;
|
|
#endif
|
|
#if defined(LIGHTMAP_ON)
|
|
inputData.staticLightmapUV = IN.lightmapUV;
|
|
#else
|
|
inputData.vertexSH = IN.sh;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _DBUFFER
|
|
ApplyDecal(IN.pos,
|
|
l.Albedo,
|
|
specular,
|
|
inputData.normalWS,
|
|
metallic,
|
|
l.Occlusion,
|
|
l.Smoothness);
|
|
#endif
|
|
|
|
BRDFData brdfData;
|
|
InitializeBRDFData(l.Albedo, metallic, specular, l.Smoothness, l.Alpha, brdfData);
|
|
Light mainLight = GetMainLight(inputData.shadowCoord, inputData.positionWS, inputData.shadowMask);
|
|
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, inputData.shadowMask);
|
|
half3 color = GlobalIllumination(brdfData, inputData.bakedGI, l.Occlusion, inputData.positionWS, inputData.normalWS, inputData.viewDirectionWS);
|
|
|
|
return BRDFDataToGbuffer(brdfData, inputData, l.Smoothness, l.Emission + color, l.Occlusion);
|
|
}
|
|
|
|
ENDHLSL
|
|
|
|
}
|
|
|
|
|
|
|
|
Pass
|
|
{
|
|
Name "ShadowCaster"
|
|
Tags
|
|
{
|
|
"LightMode" = "ShadowCaster"
|
|
}
|
|
|
|
// Render State
|
|
Blend One Zero, One Zero
|
|
Cull Back
|
|
ZTest LEqual
|
|
ZWrite On
|
|
// ColorMask: <None>
|
|
|
|
|
|
|
|
HLSLPROGRAM
|
|
|
|
#pragma vertex Vert
|
|
#pragma fragment Frag
|
|
|
|
#pragma target 3.5
|
|
|
|
#pragma prefer_hlslcc gles
|
|
#pragma exclude_renderers d3d11_9x
|
|
#pragma multi_compile_instancing
|
|
#pragma multi_compile_local _ _ALPHATEST_ON
|
|
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
|
|
|
|
#define _NORMAL_DROPOFF_TS 1
|
|
#define ATTRIBUTES_NEED_NORMAL
|
|
#define ATTRIBUTES_NEED_TANGENT
|
|
#define SHADERPASS_SHADOWCASTER
|
|
|
|
#define _PASSSHADOW 1
|
|
|
|
|
|
#define _MICROSPLAT 1
|
|
#define _MICROPOLARISMESH 1
|
|
#define _USEGRADMIP 1
|
|
#define _PERTEXUVSCALEOFFSET 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
#define _MSRENDERLOOP_UNITYLD 1
|
|
#define _MSRENDERLOOP_UNITYURP2020 1
|
|
#define _MSRENDERLOOP_UNITYURP2021 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
|
|
|
|
|
|
#define _URP 1
|
|
|
|
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
|
|
#include "Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariablesFunctions.hlsl"
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, float3x3(d.worldSpaceTangent, cross(d.worldSpaceTangent, d.worldSpaceNormal), d.worldSpaceNormal))
|
|
|
|
|
|
#define UnityObjectToWorldNormal(normal) mul(GetObjectToWorldMatrix(), normal)
|
|
|
|
#define _WorldSpaceLightPos0 _MainLightPosition
|
|
|
|
#define UNITY_DECLARE_TEX2D(name) TEXTURE2D(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2D_NOSAMPLER(name) TEXTURE2D(name);
|
|
#define UNITY_DECLARE_TEX2DARRAY(name) TEXTURE2D_ARRAY(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2DARRAY_NOSAMPLER(name) TEXTURE2D_ARRAY(name);
|
|
|
|
#define UNITY_SAMPLE_TEX2DARRAY(tex,coord) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, coord.xy, coord.z)
|
|
#define UNITY_SAMPLE_TEX2DARRAY_LOD(tex,coord,lod) SAMPLE_TEXTURE2D_ARRAY_LOD(tex, sampler##tex, coord.xy, coord.z, lod)
|
|
#define UNITY_SAMPLE_TEX2D(tex, coord) SAMPLE_TEXTURE2D(tex, sampler##tex, coord)
|
|
#define UNITY_SAMPLE_TEX2D_SAMPLER(tex, samp, coord) SAMPLE_TEXTURE2D(tex, sampler##samp, coord)
|
|
|
|
#if defined(UNITY_COMPILER_HLSL)
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
|
|
#else
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name)
|
|
#endif
|
|
|
|
#define sampler2D_float sampler2D
|
|
#define sampler2D_half sampler2D
|
|
|
|
|
|
|
|
// data across stages, stripped like the above.
|
|
struct VertexToPixel
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float3 worldPos : TEXCOORD0;
|
|
float3 worldNormal : TEXCOORD1;
|
|
float4 worldTangent : TEXCOORD2;
|
|
float4 texcoord0 : TEXCCOORD3;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 texcoord1 : TEXCCOORD4;
|
|
// float4 texcoord2 : TEXCCOORD5;
|
|
#endif
|
|
// float4 texcoord3 : TEXCCOORD6;
|
|
// float4 screenPos : TEXCOORD7;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
// float4 extraV2F0 : TEXCOORD13;
|
|
// float4 extraV2F1 : TEXCOORD14;
|
|
// float4 extraV2F2 : TEXCOORD15;
|
|
// float4 extraV2F3 : TEXCOORD16;
|
|
// float4 extraV2F4 : TEXCOORD17;
|
|
// float4 extraV2F5 : TEXCOORD18;
|
|
// float4 extraV2F6 : TEXCOORD19;
|
|
// float4 extraV2F7 : TEXCOORD20;
|
|
|
|
|
|
#if defined(LIGHTMAP_ON)
|
|
float2 lightmapUV : TEXCOORD8;
|
|
#endif
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
float2 dynamicLightmapUV : TEXCOORD9;
|
|
#endif
|
|
#if !defined(LIGHTMAP_ON)
|
|
float3 sh : TEXCOORD10;
|
|
#endif
|
|
|
|
float4 fogFactorAndVertexLight : TEXCOORD11;
|
|
float4 shadowCoord : TEXCOORD12;
|
|
|
|
#if UNITY_ANY_INSTANCING_ENABLED
|
|
uint instanceID : CUSTOM_INSTANCE_ID;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_MULTIVIEW_ENABLED)) || (defined(UNITY_STEREO_INSTANCING_ENABLED) && (defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)))
|
|
uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_INSTANCING_ENABLED))
|
|
uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex;
|
|
#endif
|
|
#if defined(SHADER_STAGE_FRAGMENT) && defined(VARYINGS_NEED_CULLFACE)
|
|
FRONT_FACE_TYPE cullFace : FRONT_FACE_SEMANTIC;
|
|
#endif
|
|
};
|
|
|
|
|
|
// TEMPLATE_SHARED
|
|
|
|
// data describing the user output of a pixel
|
|
struct Surface
|
|
{
|
|
half3 Albedo;
|
|
half Height;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half3 Emission;
|
|
half Metallic;
|
|
half3 Specular;
|
|
half Occlusion;
|
|
half Alpha;
|
|
// HDRP Only
|
|
half SpecularOcclusion;
|
|
half SubsurfaceMask;
|
|
half Thickness;
|
|
half CoatMask;
|
|
half Anisotropy;
|
|
half IridescenceMask;
|
|
half IridescenceThickness;
|
|
};
|
|
|
|
// data the user might need, this will grow to be big. But easy to strip
|
|
struct ShaderData
|
|
{
|
|
float3 localSpacePosition;
|
|
float3 localSpaceNormal;
|
|
float3 localSpaceTangent;
|
|
|
|
float3 worldSpacePosition;
|
|
float3 worldSpaceNormal;
|
|
float3 worldSpaceTangent;
|
|
|
|
float3 worldSpaceViewDir;
|
|
float3 tangentSpaceViewDir;
|
|
|
|
float4 texcoord0;
|
|
float4 texcoord1;
|
|
float4 texcoord2;
|
|
float4 texcoord3;
|
|
|
|
float2 screenUV;
|
|
float4 screenPos;
|
|
|
|
float4 vertexColor;
|
|
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
|
|
float3x3 TBNMatrix;
|
|
};
|
|
|
|
struct VertexData
|
|
{
|
|
#if SHADER_TARGET > 30 && _PLANETCOMPUTE
|
|
// // uint vertexID : SV_VertexID;
|
|
#endif
|
|
float4 vertex : POSITION;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD4; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD5; // Add Precomputed Velocity (Alembic computes velocities on runtime side).
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct TessVertex
|
|
{
|
|
float4 vertex : INTERNALTESSPOS;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
// float4 extraV2F0 : TEXCOORD4;
|
|
// float4 extraV2F1 : TEXCOORD5;
|
|
// float4 extraV2F2 : TEXCOORD6;
|
|
// float4 extraV2F3 : TEXCOORD7;
|
|
// float4 extraV2F4 : TEXCOORD8;
|
|
// float4 extraV2F5 : TEXCOORD9;
|
|
// float4 extraV2F6 : TEXCOORD10;
|
|
// float4 extraV2F7 : TEXCOORD11;
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD12; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD13;
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
struct ExtraV2F
|
|
{
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
};
|
|
|
|
|
|
float3 WorldToTangentSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(d.TBNMatrix, normal);
|
|
}
|
|
|
|
float3 TangentToWorldSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(normal, d.TBNMatrix);
|
|
}
|
|
|
|
// in this case, make standard more like SRPs, because we can't fix
|
|
// GetWorldToObjectMatrix() in HDRP, since it already does macro-fu there
|
|
|
|
#if _STANDARD
|
|
float3 TransformWorldToObject(float3 p) { return mul(GetWorldToObjectMatrix(), float4(p, 1)); };
|
|
float3 TransformObjectToWorld(float3 p) { return mul(GetObjectToWorldMatrix(), float4(p, 1)); };
|
|
float4 TransformWorldToObject(float4 p) { return mul(GetWorldToObjectMatrix(), p); };
|
|
float4 TransformObjectToWorld(float4 p) { return mul(GetObjectToWorldMatrix(), p); };
|
|
float4x4 GetWorldToObjectMatrix() { return GetWorldToObjectMatrix(); }
|
|
float4x4 GetObjectToWorldMatrix() { return GetObjectToWorldMatrix(); }
|
|
#endif
|
|
|
|
float3 GetCameraWorldPosition()
|
|
{
|
|
#if _HDRP
|
|
return GetCameraRelativePositionWS(_WorldSpaceCameraPos);
|
|
#else
|
|
return _WorldSpaceCameraPos;
|
|
#endif
|
|
}
|
|
|
|
|
|
#if _HDRP
|
|
|
|
half3 UnpackNormalmapRGorAG(half4 packednormal)
|
|
{
|
|
// This do the trick
|
|
packednormal.x *= packednormal.w;
|
|
|
|
half3 normal;
|
|
normal.xy = packednormal.xy * 2 - 1;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
half3 UnpackNormal(half4 packednormal)
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
return packednormal.xyz * 2 - 1;
|
|
#else
|
|
return UnpackNormalmapRGorAG(packednormal);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if _HDRP || _URP
|
|
|
|
half3 UnpackScaleNormal(half4 packednormal, half scale)
|
|
{
|
|
#ifndef UNITY_NO_DXT5nm
|
|
// Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
|
|
// Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
|
|
packednormal.x *= packednormal.w;
|
|
#endif
|
|
half3 normal;
|
|
normal.xy = (packednormal.xy * 2 - 1) * scale;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void GetSun(out float3 lightDir, out float3 color)
|
|
{
|
|
lightDir = float3(0.5, 0.5, 0);
|
|
color = 1;
|
|
#if _HDRP
|
|
if (_DirectionalLightCount > 0)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[0];
|
|
lightDir = -light.forward.xyz;
|
|
color = light.color;
|
|
}
|
|
#elif _STANDARD
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
color = _LightColor0.rgb;
|
|
#elif _URP
|
|
Light light = GetMainLight();
|
|
lightDir = light.direction;
|
|
color = light.color;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
|
|
|
|
|
|
#if _MESHSUBARRAY
|
|
half4 _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
float4 _Diffuse_TexelSize;
|
|
float4 _NormalSAO_TexelSize;
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
float _HybridHeightBlendDistance;
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
float4 _SmoothAO_TexelSize;
|
|
#endif
|
|
|
|
#ifdef _ALPHATEST_ON
|
|
float4 _TerrainHolesTexture_TexelSize;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
float4 _Specular_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
float4 _EmissiveMetal_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
half _EmissiveMult;
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
half _AutoNormalHeightScale;
|
|
#endif
|
|
|
|
float4 _UVScale; // scale and offset
|
|
|
|
half _Contrast;
|
|
|
|
|
|
|
|
#if _VSSHADOWMAP
|
|
float4 gVSSunDirection;
|
|
#endif
|
|
|
|
#if _FORCELOCALSPACE && _PLANETVECTORS
|
|
float4x4 _PQSToLocal;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
float4x4 _GlobalOriginMTX;
|
|
#endif
|
|
|
|
float4 _Control0_TexelSize;
|
|
#if _CUSTOMSPLATTEXTURES
|
|
float4 _CustomControl0_TexelSize;
|
|
#endif
|
|
float4 _PerPixelNormal_TexelSize;
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
float2 _NoiseUVParams;
|
|
#endif
|
|
|
|
float4 _PerTexProps_TexelSize;
|
|
|
|
#if _SURFACENORMALS
|
|
float3 surfTangent;
|
|
float3 surfBitangent;
|
|
float3 surfNormal;
|
|
#endif
|
|
|
|
|
|
|
|
CBUFFER_END
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, data.TBN)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// In Unity 2020.3LTS, Unity will spew tons of errors about missing this sampler in
|
|
// URP, even though it shouldn't be required.
|
|
TEXTURE2D(_MainTex);
|
|
|
|
// globals, outside of CBuffer, but used by more than one module
|
|
float3 _gGlitterLightDir;
|
|
float3 _gGlitterLightWorldPos;
|
|
half3 _gGlitterLightColor;
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
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)
|
|
float4 _TerrainNormalmapTexture_TexelSize;
|
|
#endif
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
TEXTURE2D(_TerrainHeightmapTexture);
|
|
float4 _TerrainHeightmapTexture_TexelSize;
|
|
TEXTURE2D(_TerrainNormalmapTexture);
|
|
#endif
|
|
|
|
UNITY_INSTANCING_BUFFER_START(Terrain)
|
|
UNITY_DEFINE_INSTANCED_PROP(float4, _TerrainPatchInstanceData) // float4(xBase, yBase, skipScale, ~)
|
|
UNITY_INSTANCING_BUFFER_END(Terrain)
|
|
|
|
|
|
|
|
|
|
// dynamic branching helpers, for regular and aggressive branching
|
|
// debug mode shows how many samples using branching will save us.
|
|
//
|
|
// These macros are always used instead of the UNITY_BRANCH macro
|
|
// to maintain debug displays and allow branching to be disabled
|
|
// on as granular level as we want.
|
|
|
|
#if _BRANCHSAMPLES
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++; if (w > 0)
|
|
#else
|
|
#define MSBRANCH(w) UNITY_BRANCH if (w > 0)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++;
|
|
#else
|
|
#define MSBRANCH(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _BRANCHSAMPLESAGR
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER ||_DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++; if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++; if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++; if (w > 0.001)
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) UNITY_BRANCH if (w > 0.001)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++;
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++;
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++;
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w)
|
|
#define MSBRANCHCLUSTER(w)
|
|
#define MSBRANCHOTHER(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _DEBUG_SAMPLECOUNT
|
|
int _sampleCount;
|
|
#define COUNTSAMPLE { _sampleCount++; }
|
|
#else
|
|
#define COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _DEBUG_PROCLAYERS
|
|
int _procLayerCount;
|
|
#define COUNTPROCLAYER { _procLayerCount++; }
|
|
#else
|
|
#define COUNTPROCLAYER
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
TEXTURE2D(_DebugWorldPos);
|
|
TEXTURE2D(_DebugWorldNormal);
|
|
#endif
|
|
|
|
|
|
// splat
|
|
UNITY_DECLARE_TEX2DARRAY(_Diffuse);
|
|
UNITY_DECLARE_TEX2DARRAY(_NormalSAO);
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
TEXTURE2D(_NoiseUV);
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
UNITY_DECLARE_TEX2DARRAY(_SmoothAO);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
UNITY_DECLARE_TEX2DARRAY(_Specular);
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
UNITY_DECLARE_TEX2DARRAY(_EmissiveMetal);
|
|
#endif
|
|
|
|
TEXTURE2D(_PerPixelNormal);
|
|
|
|
SamplerState shared_linear_clamp_sampler;
|
|
SamplerState shared_point_clamp_sampler;
|
|
|
|
TEXTURE2D(_Control0);
|
|
#if _CUSTOMSPLATTEXTURES
|
|
TEXTURE2D(_CustomControl0);
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_CustomControl1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_CustomControl2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_CustomControl3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl7);
|
|
#endif
|
|
#else
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_Control1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_Control2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_Control3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_Control7);
|
|
#endif
|
|
#endif
|
|
|
|
TEXTURE2D_FLOAT(_PerTexProps);
|
|
|
|
struct DecalLayer
|
|
{
|
|
float3 uv;
|
|
float2 dx;
|
|
float2 dy;
|
|
int decalIndex;
|
|
bool dynamic;
|
|
};
|
|
|
|
struct DecalOutput
|
|
{
|
|
DecalLayer l0;
|
|
DecalLayer l1;
|
|
DecalLayer l2;
|
|
DecalLayer l3;
|
|
|
|
half4 Weights;
|
|
half4 Indexes;
|
|
half4 fxLevels;
|
|
|
|
};
|
|
|
|
|
|
struct TriGradMipFormat
|
|
{
|
|
float4 d0;
|
|
float4 d1;
|
|
float4 d2;
|
|
};
|
|
|
|
float InverseLerp(float x, float y, float v) { return (v-x)/max(y-x, 0.001); }
|
|
float2 InverseLerp(float2 x, float2 y, float2 v) { return (v-x)/max(y-x, float2(0.001, 0.001)); }
|
|
float3 InverseLerp(float3 x, float3 y, float3 v) { return (v-x)/max(y-x, float3(0.001, 0.001, 0.001)); }
|
|
float4 InverseLerp(float4 x, float4 y, float4 v) { return (v-x)/max(y-x, float4(0.001, 0.001, 0.001, 0.001)); }
|
|
|
|
|
|
// 2019.3 holes
|
|
#ifdef _ALPHATEST_ON
|
|
TEXTURE2D(_TerrainHolesTexture);
|
|
|
|
void ClipHoles(float2 uv)
|
|
{
|
|
float hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, shared_linear_clamp_sampler, uv).r;
|
|
COUNTSAMPLE
|
|
clip(hole < 0.5f ? -1 : 1);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT TriGradMipFormat
|
|
#define INITMIPFORMAT (TriGradMipFormat)0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float3
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float3
|
|
#endif
|
|
#else
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT float4
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float
|
|
#endif
|
|
#endif
|
|
|
|
float2 TotalOne(float2 v) { return v * (1.0 / max(v.x + v.y, 0.001)); }
|
|
float3 TotalOne(float3 v) { return v * (1.0 / max(v.x + v.y + v.z, 0.001)); }
|
|
float4 TotalOne(float4 v) { return v * (1.0 / max(v.x + v.y + v.z + v.w, 0.001)); }
|
|
|
|
float2 RotateUV(float2 uv, float amt)
|
|
{
|
|
uv -=0.5;
|
|
float s = sin ( amt);
|
|
float c = cos ( amt );
|
|
float2x2 mtx = float2x2( c, -s, s, c);
|
|
mtx *= 0.5;
|
|
mtx += 0.5;
|
|
mtx = mtx * 2-1;
|
|
uv = mul ( uv, mtx );
|
|
uv += 0.5;
|
|
return uv;
|
|
}
|
|
|
|
float4 DecodeToFloat4(float v)
|
|
{
|
|
uint vi = (uint)(v * (256.0f * 256.0f * 256.0f * 256.0f));
|
|
int ex = (int)(vi / (256 * 256 * 256) % 256);
|
|
int ey = (int)((vi / (256 * 256)) % 256);
|
|
int ez = (int)((vi / (256)) % 256);
|
|
int ew = (int)(vi % 256);
|
|
float4 e = float4(ex / 255.0, ey / 255.0, ez / 255.0, ew / 255.0);
|
|
return e;
|
|
}
|
|
|
|
|
|
|
|
struct Input
|
|
{
|
|
ShaderData shaderData;
|
|
float2 uv_Control0;
|
|
float2 uv2_Diffuse;
|
|
|
|
float worldHeight;
|
|
float3 worldUpVector;
|
|
|
|
float3 viewDir;
|
|
float3 worldPos;
|
|
float3 worldNormal;
|
|
float4 color;
|
|
float3x3 TBN;
|
|
|
|
// vertex/digger workflow data
|
|
half4 w0;
|
|
half4 w1;
|
|
half4 w2;
|
|
half4 w3;
|
|
half4 w4;
|
|
half4 w5;
|
|
half4 w6;
|
|
|
|
// megasplat data
|
|
half4 layer0;
|
|
half4 layer1;
|
|
half3 baryWeights;
|
|
half4 scatter0;
|
|
half4 scatter1;
|
|
|
|
// wetness, puddles, streams, lava from vertex or megasplat
|
|
half4 fx;
|
|
// snow min, snow max
|
|
half4 fx2;
|
|
|
|
|
|
};
|
|
|
|
struct TriplanarConfig
|
|
{
|
|
float3x3 uv0;
|
|
float3x3 uv1;
|
|
float3x3 uv2;
|
|
float3x3 uv3;
|
|
half3 pN;
|
|
half3 pN0;
|
|
half3 pN1;
|
|
half3 pN2;
|
|
half3 pN3;
|
|
half3 axisSign;
|
|
Input IN;
|
|
};
|
|
|
|
|
|
struct Config
|
|
{
|
|
float2 uv;
|
|
float3 uv0;
|
|
float3 uv1;
|
|
float3 uv2;
|
|
float3 uv3;
|
|
|
|
half4 cluster0;
|
|
half4 cluster1;
|
|
half4 cluster2;
|
|
half4 cluster3;
|
|
|
|
};
|
|
|
|
|
|
struct MicroSplatLayer
|
|
{
|
|
half3 Albedo;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half Occlusion;
|
|
half Metallic;
|
|
half Height;
|
|
half3 Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
half3 Specular;
|
|
#endif
|
|
half Alpha;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// raw, unblended samples from arrays
|
|
struct RawSamples
|
|
{
|
|
half4 albedo0;
|
|
half4 albedo1;
|
|
half4 albedo2;
|
|
half4 albedo3;
|
|
#if _SURFACENORMALS
|
|
half3 surf0;
|
|
half3 surf1;
|
|
half3 surf2;
|
|
half3 surf3;
|
|
#endif
|
|
|
|
half4 normSAO0;
|
|
half4 normSAO1;
|
|
half4 normSAO2;
|
|
half4 normSAO3;
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALEMIS || _GLOBALSMOOTHAOMETAL || _PERTEXSSS || _PERTEXRIMLIGHT
|
|
half4 emisMetal0;
|
|
half4 emisMetal1;
|
|
half4 emisMetal2;
|
|
half4 emisMetal3;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
half3 specular0;
|
|
half3 specular1;
|
|
half3 specular2;
|
|
half3 specular3;
|
|
#endif
|
|
};
|
|
|
|
void InitRawSamples(inout RawSamples s)
|
|
{
|
|
s.normSAO0 = half4(0,0,0,1);
|
|
s.normSAO1 = half4(0,0,0,1);
|
|
s.normSAO2 = half4(0,0,0,1);
|
|
s.normSAO3 = half4(0,0,0,1);
|
|
#if _SURFACENORMALS
|
|
s.surf0 = half3(0,0,1);
|
|
s.surf1 = half3(0,0,1);
|
|
s.surf2 = half3(0,0,1);
|
|
s.surf3 = half3(0,0,1);
|
|
#endif
|
|
}
|
|
|
|
float3 GetGlobalLightDir(Input i)
|
|
{
|
|
float3 lightDir = float3(1,0,0);
|
|
|
|
#if _HDRP || PASS_DEFERRED
|
|
lightDir = normalize(_gGlitterLightDir.xyz);
|
|
#elif _URP
|
|
lightDir = GetMainLight().direction;
|
|
#else
|
|
#ifndef USING_DIRECTIONAL_LIGHT
|
|
lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
|
|
#else
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
#endif
|
|
#endif
|
|
return lightDir;
|
|
}
|
|
|
|
float3x3 GetTBN(Input i)
|
|
{
|
|
return i.TBN;
|
|
}
|
|
|
|
float3 GetGlobalLightDirTS(Input i)
|
|
{
|
|
float3 lightDirWS = GetGlobalLightDir(i);
|
|
return mul(GetTBN(i), lightDirWS);
|
|
}
|
|
|
|
half3 GetGlobalLightColor()
|
|
{
|
|
#if _HDRP || PASS_DEFERRED
|
|
return _gGlitterLightColor;
|
|
#elif _URP
|
|
return (GetMainLight().color);
|
|
#else
|
|
return _LightColor0.rgb;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 FuzzyShade(half3 color, half3 normal, half coreMult, half edgeMult, half power, float3 viewDir)
|
|
{
|
|
half dt = saturate(dot(viewDir, normal));
|
|
half dark = 1.0 - (coreMult * dt);
|
|
half edge = pow(1-dt, power) * edgeMult;
|
|
return color * (dark + edge);
|
|
}
|
|
|
|
half3 ComputeSSS(Input i, float3 V, float3 N, half3 tint, half thickness, half distortion, half scale, half power)
|
|
{
|
|
float3 L = GetGlobalLightDir(i);
|
|
half3 lightColor = GetGlobalLightColor();
|
|
float3 H = normalize(L + N * distortion);
|
|
float VdotH = pow(saturate(dot(V, -H)), power) * scale;
|
|
float3 I = (VdotH) * thickness;
|
|
return lightColor * I * tint;
|
|
}
|
|
|
|
|
|
#if _MAX2LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
#elif _MAX3LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
#else
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
#endif
|
|
|
|
|
|
#if _MAX3LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#elif _MAX2LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#else
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##3 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv3.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#endif
|
|
|
|
half2 BlendNormal2(half2 base, half2 blend) { return normalize(half3(base.xy + blend.xy, 1)).xy; }
|
|
half3 BlendOverlay(half3 base, half3 blend) { return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))); }
|
|
half3 BlendMult2X(half3 base, half3 blend) { return (base * (blend * 2)); }
|
|
half3 BlendLighterColor(half3 s, half3 d) { return (s.x + s.y + s.z > d.x + d.y + d.z) ? s : d; }
|
|
|
|
|
|
#if _SURFACENORMALS
|
|
|
|
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
|
|
|
|
|
|
|
|
void ConstructSurfaceGradientTBN(Input i)
|
|
{
|
|
float3x3 tbn = GetTBN(i);
|
|
float3 t = tbn[0];
|
|
float3 b = tbn[1];
|
|
float3 n = tbn[2];
|
|
|
|
surfNormal = n;//mul(GetWorldToObjectMatrix(), float4(n, 1)).xyz;
|
|
surfTangent = t;//mul(GetWorldToObjectMatrix(), float4(t, 1)).xyz;
|
|
surfBitangent = b;//cross(surfNormal, surfTangent);
|
|
|
|
float renormFactor = 1.0 / length(surfNormal);
|
|
surfNormal *= renormFactor;
|
|
surfTangent *= renormFactor;
|
|
surfBitangent *= renormFactor;
|
|
}
|
|
|
|
half3 SurfaceGradientFromTBN(half2 deriv)
|
|
{
|
|
return deriv.x * surfTangent + deriv.y * surfBitangent;
|
|
}
|
|
|
|
// Input: vM is tangent space normal in [-1;1].
|
|
// Output: convert vM to a derivative.
|
|
half2 TspaceNormalToDerivative(half3 vM)
|
|
{
|
|
const half scale = 1.0/128.0;
|
|
|
|
// Ensure vM delivers a positive third component using abs() and
|
|
// constrain vM.z so the range of the derivative is [-128; 128].
|
|
const half3 vMa = abs(vM);
|
|
const half z_ma = max(vMa.z, scale*max(vMa.x, vMa.y));
|
|
|
|
return -half2(vM.x, vM.y)/z_ma;
|
|
}
|
|
|
|
// Used to produce a surface gradient from the gradient of a volume
|
|
// bump function such as 3D Perlin noise. Equation 2 in [Mik10].
|
|
half3 SurfgradFromVolumeGradient(half3 grad)
|
|
{
|
|
return grad - dot(surfNormal, grad) * surfNormal;
|
|
}
|
|
|
|
half3 SurfgradFromTriplanarProjection(half3 pN, half2 xPlaneTN, half2 yPlaneTN, half2 zPlaneTN)
|
|
{
|
|
const half w0 = pN.x;
|
|
const half w1 = pN.y;
|
|
const half w2 = pN.z;
|
|
|
|
// X-plane tangent normal to gradient derivative
|
|
xPlaneTN = xPlaneTN * 2.0 - 1.0;
|
|
half xPlaneRcpZ = rsqrt(max(1 - dot(xPlaneTN.x, xPlaneTN.x) - dot(xPlaneTN.y, xPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_xplane = xPlaneTN * -xPlaneRcpZ;
|
|
|
|
// Y-plane tangent normal to gradient derivative
|
|
yPlaneTN = yPlaneTN * 2.0 - 1.0;
|
|
half yPlaneRcpZ = rsqrt(max(1 - dot(yPlaneTN.x, yPlaneTN.x) - dot(yPlaneTN.y, yPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_yplane = yPlaneTN * -yPlaneRcpZ;
|
|
|
|
// Z-plane tangent normal to gradient derivative
|
|
zPlaneTN = zPlaneTN * 2.0 - 1.0;
|
|
half zPlaneRcpZ = rsqrt(max(1 - dot(zPlaneTN.x, zPlaneTN.x) - dot(zPlaneTN.y, zPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_zplane = zPlaneTN * -zPlaneRcpZ;
|
|
|
|
// Assume deriv xplane, deriv yplane, and deriv zplane are
|
|
// sampled using (z,y), (x,z), and (x,y), respectively.
|
|
// Positive scales of the lookup coordinate will work
|
|
// as well, but for negative scales the derivative components
|
|
// will need to be negated accordingly.
|
|
float3 grad = float3(w2*d_zplane.x + w1*d_yplane.x,
|
|
w2*d_zplane.y + w0*d_xplane.y,
|
|
w0*d_xplane.x + w1*d_yplane.y);
|
|
|
|
return SurfgradFromVolumeGradient(grad);
|
|
}
|
|
|
|
half3 ConvertNormalToGradient(half3 normal)
|
|
{
|
|
half2 deriv = TspaceNormalToDerivative(normal);
|
|
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
half3 ConvertNormal2ToGradient(half2 packedNormal)
|
|
{
|
|
half2 tNormal = packedNormal;
|
|
half rcpZ = rsqrt(max(1 - dot(tNormal.x, tNormal.x) - dot(tNormal.y, tNormal.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
half2 deriv = tNormal * -rcpZ;
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
|
|
half3 ResolveNormalFromSurfaceGradient(half3 gradient)
|
|
{
|
|
return normalize(surfNormal - gradient);
|
|
}
|
|
|
|
|
|
#endif // _SURFACENORMALS
|
|
|
|
void BlendNormalPerTex(inout RawSamples o, half2 noise, float4 fades)
|
|
{
|
|
#if _SURFACENORMALS
|
|
float3 grad = ConvertNormal2ToGradient(noise.xy);
|
|
o.surf0 += grad * fades.x;
|
|
o.surf1 += grad * fades.y;
|
|
#if !_MAX2LAYER
|
|
o.surf2 += grad * fades.z;
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.surf3 += grad * fades.w;
|
|
#endif
|
|
#else
|
|
o.normSAO0.xy = lerp(o.normSAO0.xy, BlendNormal2(o.normSAO0.xy, noise.xy), fades.x);
|
|
o.normSAO1.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#if !_MAX2LAYER
|
|
o.normSAO2.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO2.xy, noise.xy), fades.y);
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.normSAO3.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 BlendNormal3(half3 n1, half3 n2)
|
|
{
|
|
n1 += float3( 0, 0, 1);
|
|
n2 *= float3(-1, -1, 1);
|
|
return n1*dot(n1, n2) / n1.z - n2;
|
|
}
|
|
|
|
half2 TransformTriplanarNormal(Input IN, float3x3 t2w, half3 axisSign, half3 absVertNormal,
|
|
half3 pN, half2 a0, half2 a1, half2 a2)
|
|
{
|
|
|
|
a0 = a0 * 2 - 1;
|
|
a1 = a1 * 2 - 1;
|
|
a2 = a2 * 2 - 1;
|
|
|
|
a0.x *= axisSign.x;
|
|
a1.x *= axisSign.y;
|
|
a2.x *= axisSign.z;
|
|
|
|
half3 n0 = half3(a0.xy, 1);
|
|
half3 n1 = half3(a1.xy, 1);
|
|
half3 n2 = half3(a2.xy, 1);
|
|
|
|
float3 wn = IN.worldNormal;
|
|
|
|
n0 = BlendNormal3(half3(wn.zy, absVertNormal.x), n0);
|
|
n1 = BlendNormal3(half3(wn.xz, absVertNormal.y), n1 * float3(-1, 1, 1));
|
|
n2 = BlendNormal3(half3(wn.xy, absVertNormal.z), n2);
|
|
|
|
n0.z *= axisSign.x;
|
|
n1.z *= axisSign.y;
|
|
n2.z *= -axisSign.z;
|
|
|
|
half3 worldNormal = (n0.zyx * pN.x + n1.xzy * pN.y + n2.xyz * pN.z);
|
|
return mul(t2w, worldNormal).xy;
|
|
|
|
}
|
|
|
|
// funcs
|
|
|
|
inline half MSLuminance(half3 rgb)
|
|
{
|
|
#ifdef UNITY_COLORSPACE_GAMMA
|
|
return dot(rgb, half3(0.22, 0.707, 0.071));
|
|
#else
|
|
return dot(rgb, half3(0.0396819152, 0.458021790, 0.00609653955));
|
|
#endif
|
|
}
|
|
|
|
|
|
float2 Hash2D( float2 x )
|
|
{
|
|
float2 k = float2( 0.3183099, 0.3678794 );
|
|
x = x*k + k.yx;
|
|
return -1.0 + 2.0*frac( 16.0 * k*frac( x.x*x.y*(x.x+x.y)) );
|
|
}
|
|
|
|
float Noise2D(float2 p )
|
|
{
|
|
float2 i = floor( p );
|
|
float2 f = frac( p );
|
|
|
|
float2 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( dot( Hash2D( i + float2(0.0,0.0) ), f - float2(0.0,0.0) ),
|
|
dot( Hash2D( i + float2(1.0,0.0) ), f - float2(1.0,0.0) ), u.x),
|
|
lerp( dot( Hash2D( i + float2(0.0,1.0) ), f - float2(0.0,1.0) ),
|
|
dot( Hash2D( i + float2(1.0,1.0) ), f - float2(1.0,1.0) ), u.x), u.y);
|
|
}
|
|
|
|
float FBM2D(float2 uv)
|
|
{
|
|
float f = 0.5000*Noise2D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise2D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise2D( uv );
|
|
return f;
|
|
}
|
|
|
|
float3 Hash3D( float3 p )
|
|
{
|
|
p = float3( dot(p,float3(127.1,311.7, 74.7)),
|
|
dot(p,float3(269.5,183.3,246.1)),
|
|
dot(p,float3(113.5,271.9,124.6)));
|
|
|
|
return -1.0 + 2.0*frac(sin(p)*437.5453123);
|
|
}
|
|
|
|
float Noise3D( float3 p )
|
|
{
|
|
float3 i = floor( p );
|
|
float3 f = frac( p );
|
|
|
|
float3 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,0.0) ), f - float3(0.0,0.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,0.0) ), f - float3(1.0,0.0,0.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,0.0) ), f - float3(0.0,1.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,0.0) ), f - float3(1.0,1.0,0.0) ), u.x), u.y),
|
|
lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,1.0) ), f - float3(0.0,0.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,1.0) ), f - float3(1.0,0.0,1.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,1.0) ), f - float3(0.0,1.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,1.0) ), f - float3(1.0,1.0,1.0) ), u.x), u.y), u.z );
|
|
}
|
|
|
|
float FBM3D(float3 uv)
|
|
{
|
|
float f = 0.5000*Noise3D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise3D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise3D( uv );
|
|
return f;
|
|
}
|
|
|
|
|
|
|
|
float GetSaturation(float3 c)
|
|
{
|
|
float mi = min(min(c.x, c.y), c.z);
|
|
float ma = max(max(c.x, c.y), c.z);
|
|
return (ma - mi)/(ma + 1e-7);
|
|
}
|
|
|
|
// Better Color Lerp, does not have darkening issue
|
|
float3 BetterColorLerp(float3 a, float3 b, float x)
|
|
{
|
|
float3 ic = lerp(a, b, x) + float3(1e-6,0.0,0.0);
|
|
float sd = abs(GetSaturation(ic) - lerp(GetSaturation(a), GetSaturation(b), x));
|
|
|
|
float3 dir = normalize(float3(2.0 * ic.x - ic.y - ic.z, 2.0 * ic.y - ic.x - ic.z, 2.0 * ic.z - ic.y - ic.x));
|
|
float lgt = dot(float3(1.0, 1.0, 1.0), ic);
|
|
|
|
float ff = dot(dir, normalize(ic));
|
|
|
|
const float dsp_str = 1.5;
|
|
ic += dsp_str * dir * sd * ff * lgt;
|
|
return saturate(ic);
|
|
}
|
|
|
|
|
|
half4 ComputeWeights(half4 iWeights, half h0, half h1, half h2, half h3, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return iWeights;
|
|
#else
|
|
// compute weight with height map
|
|
//half4 weights = half4(iWeights.x * h0, iWeights.y * h1, iWeights.z * h2, iWeights.w * h3);
|
|
half4 weights = half4(iWeights.x * max(h0,0.001), iWeights.y * max(h1,0.001), iWeights.z * max(h2,0.001), iWeights.w * max(h3,0.001));
|
|
|
|
// Contrast weights
|
|
half maxWeight = max(max(weights.x, max(weights.y, weights.z)), weights.w);
|
|
half transition = max(contrast * maxWeight, 0.0001);
|
|
half threshold = maxWeight - transition;
|
|
half scale = 1.0 / transition;
|
|
weights = saturate((weights - threshold) * scale);
|
|
|
|
weights = TotalOne(weights);
|
|
return weights;
|
|
#endif
|
|
}
|
|
|
|
half HeightBlend(half h1, half h2, half slope, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return slope;
|
|
#else
|
|
h2 = 1 - h2;
|
|
half tween = saturate((slope - min(h1, h2)) / max(abs(h1 - h2), 0.001));
|
|
half blend = saturate( ( tween - (1-contrast) ) / max(contrast, 0.001));
|
|
return blend;
|
|
#endif
|
|
}
|
|
|
|
#if _MAX4TEXTURES
|
|
#define TEXCOUNT 4
|
|
#elif _MAX8TEXTURES
|
|
#define TEXCOUNT 8
|
|
#elif _MAX12TEXTURES
|
|
#define TEXCOUNT 12
|
|
#elif _MAX20TEXTURES
|
|
#define TEXCOUNT 20
|
|
#elif _MAX24TEXTURES
|
|
#define TEXCOUNT 24
|
|
#elif _MAX28TEXTURES
|
|
#define TEXCOUNT 28
|
|
#elif _MAX32TEXTURES
|
|
#define TEXCOUNT 32
|
|
#else
|
|
#define TEXCOUNT 16
|
|
#endif
|
|
|
|
#if _DECAL_SPLAT
|
|
|
|
void DoMergeDecalSplats(half4 iWeights, half4 iIndexes, inout half4 indexes, inout half4 weights)
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
half w = iWeights[i];
|
|
half index = iIndexes[i];
|
|
if (w > weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = index;
|
|
}
|
|
else if (w > weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = index;
|
|
}
|
|
else if (w > weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = index;
|
|
}
|
|
else if (w > weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = index;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
void Setup(out half4 weights, float2 uv, out Config config, half4 w0, half4 w1, half4 w2, half4 w3, half4 w4, half4 w5, half4 w6, half4 w7, float3 worldPos, DecalOutput decalOutput)
|
|
{
|
|
config = (Config)0;
|
|
half4 indexes = 0;
|
|
|
|
config.uv = uv;
|
|
|
|
#if _WORLDUV
|
|
uv = worldPos.xz;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
float2 scaledUV = uv;
|
|
#else
|
|
float2 scaledUV = uv * _UVScale.xy + _UVScale.zw;
|
|
#endif
|
|
|
|
// if only 4 textures, and blending 4 textures, skip this whole thing..
|
|
// this saves about 25% of the ALU of the base shader on low end. However if
|
|
// we rely on sorted texture weights (distance resampling) we have to sort..
|
|
float4 defaultIndexes = float4(0,1,2,3);
|
|
#if _MESHSUBARRAY
|
|
defaultIndexes = _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
#if _MESHSUBARRAY && !_DECAL_SPLAT || (_MAX4TEXTURES && !_MAX3LAYER && !_MAX2LAYER && !_DISTANCERESAMPLE && !_POM && !_DECAL_SPLAT)
|
|
weights = w0;
|
|
config.uv0 = float3(scaledUV, defaultIndexes.x);
|
|
config.uv1 = float3(scaledUV, defaultIndexes.y);
|
|
config.uv2 = float3(scaledUV, defaultIndexes.z);
|
|
config.uv3 = float3(scaledUV, defaultIndexes.w);
|
|
return;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
weights = float4(1,0,0,0);
|
|
return;
|
|
#else
|
|
half splats[TEXCOUNT];
|
|
|
|
splats[0] = w0.x;
|
|
splats[1] = w0.y;
|
|
splats[2] = w0.z;
|
|
splats[3] = w0.w;
|
|
#if !_MAX4TEXTURES
|
|
splats[4] = w1.x;
|
|
splats[5] = w1.y;
|
|
splats[6] = w1.z;
|
|
splats[7] = w1.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
splats[8] = w2.x;
|
|
splats[9] = w2.y;
|
|
splats[10] = w2.z;
|
|
splats[11] = w2.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
splats[12] = w3.x;
|
|
splats[13] = w3.y;
|
|
splats[14] = w3.z;
|
|
splats[15] = w3.w;
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[16] = w4.x;
|
|
splats[17] = w4.y;
|
|
splats[18] = w4.z;
|
|
splats[19] = w4.w;
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[20] = w5.x;
|
|
splats[21] = w5.y;
|
|
splats[22] = w5.z;
|
|
splats[23] = w5.w;
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[24] = w6.x;
|
|
splats[25] = w6.y;
|
|
splats[26] = w6.z;
|
|
splats[27] = w6.w;
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
splats[28] = w7.x;
|
|
splats[29] = w7.y;
|
|
splats[30] = w7.z;
|
|
splats[31] = w7.w;
|
|
#endif
|
|
|
|
|
|
|
|
weights[0] = 0;
|
|
weights[1] = 0;
|
|
weights[2] = 0;
|
|
weights[3] = 0;
|
|
indexes[0] = 0;
|
|
indexes[1] = 0;
|
|
indexes[2] = 0;
|
|
indexes[3] = 0;
|
|
|
|
int i = 0;
|
|
for (i = 0; i < TEXCOUNT; ++i)
|
|
{
|
|
half w = splats[i];
|
|
if (w >= weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = i;
|
|
}
|
|
else if (w >= weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = i;
|
|
}
|
|
else if (w >= weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = i;
|
|
}
|
|
else if (w >= weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = i;
|
|
}
|
|
}
|
|
|
|
// NaN Prevention
|
|
if (weights.x <= 0)
|
|
weights = float4(1, 0, 0, 0);
|
|
|
|
#if _DECAL_SPLAT
|
|
DoMergeDecalSplats(decalOutput.Weights, decalOutput.Indexes, weights, indexes);
|
|
#endif
|
|
|
|
|
|
|
|
// clamp and renormalize
|
|
#if _MAX2LAYER
|
|
weights.zw = 0;
|
|
weights.xy = TotalOne(weights.xy);
|
|
#elif _MAX3LAYER
|
|
weights.w = 0;
|
|
weights.xyz = TotalOne(weights.xyz);
|
|
#elif !_DISABLEHEIGHTBLENDING || _NORMALIZEWEIGHTS // prevents black when painting, which the unity shader does not prevent.
|
|
weights = normalize(weights);
|
|
#endif
|
|
|
|
|
|
config.uv0 = float3(scaledUV, indexes.x);
|
|
config.uv1 = float3(scaledUV, indexes.y);
|
|
config.uv2 = float3(scaledUV, indexes.z);
|
|
config.uv3 = float3(scaledUV, indexes.w);
|
|
|
|
|
|
#endif //_DISABLESPLATMAPS
|
|
|
|
|
|
}
|
|
|
|
float3 HeightToNormal(float height, float3 worldPos)
|
|
{
|
|
float3 dx = ddx(worldPos);
|
|
float3 dy = ddy(worldPos);
|
|
float3 crossX = cross(float3(0,1,0), dx);
|
|
float3 crossY = cross(float3(0,1,0), dy);
|
|
float3 d = abs(dot(crossY, dx));
|
|
float3 n = ((((height + ddx(height)) - height) * crossY) + (((height + ddy(height)) - height) * crossX)) * sign(d);
|
|
n.z *= -1;
|
|
return normalize((d * float3(0,1,0)) - n).xzy;
|
|
}
|
|
|
|
float ComputeMipLevel(float2 uv, float2 textureSize)
|
|
{
|
|
uv *= textureSize;
|
|
float2 dx_vtc = ddx(uv);
|
|
float2 dy_vtc = ddy(uv);
|
|
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
|
|
return 0.5 * log2(delta_max_sqr);
|
|
}
|
|
|
|
inline half2 UnpackNormal2(half4 packednormal)
|
|
{
|
|
return packednormal.wy * 2 - 1;
|
|
|
|
}
|
|
|
|
half3 TriplanarHBlend(half h0, half h1, half h2, half3 pN, half contrast)
|
|
{
|
|
half3 blend = pN / dot(pN, half3(1,1,1));
|
|
float3 heights = float3(h0, h1, h2) + (blend * 3.0);
|
|
half height_start = max(max(heights.x, heights.y), heights.z) - contrast;
|
|
half3 h = max(heights - height_start.xxx, half3(0,0,0));
|
|
blend = h / dot(h, half3(1,1,1));
|
|
return blend;
|
|
}
|
|
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half3 display)
|
|
{
|
|
o.Albedo = display.rgb;
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half display)
|
|
{
|
|
o.Albedo = half3(display, display, display);
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
half MicroShadow(float3 lightDir, half3 normal, half ao, half strength)
|
|
{
|
|
half shadow = saturate(abs(dot(normal, lightDir)) + (ao * ao * 2.0) - 1.0);
|
|
return 1 - ((1-shadow) * strength);
|
|
}
|
|
|
|
|
|
void DoDebugOutput(inout MicroSplatLayer l)
|
|
{
|
|
#if _DEBUG_OUTPUT_ALBEDO
|
|
ClearAllButAlbedo(l, l.Albedo);
|
|
#elif _DEBUG_OUTPUT_NORMAL
|
|
// oh unit shader compiler normal stripping, how I hate you so..
|
|
// must multiply by albedo to stop the normal from being white. Why, fuck knows?
|
|
ClearAllButAlbedo(l, float3(l.Normal.xy * 0.5 + 0.5, l.Normal.z * saturate(l.Albedo.z+1)));
|
|
#elif _DEBUG_OUTPUT_SMOOTHNESS
|
|
ClearAllButAlbedo(l, l.Smoothness.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_METAL
|
|
ClearAllButAlbedo(l, l.Metallic.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_AO
|
|
ClearAllButAlbedo(l, l.Occlusion.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_EMISSION
|
|
ClearAllButAlbedo(l, l.Emission * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_HEIGHT
|
|
ClearAllButAlbedo(l, l.Height.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_SPECULAR && _USESPECULARWORKFLOW
|
|
ClearAllButAlbedo(l, l.Specular * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_BRANCHCOUNT_WEIGHT
|
|
ClearAllButAlbedo(l, _branchWeightCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TRIPLANAR
|
|
ClearAllButAlbedo(l, _branchTriplanarCount / 24 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_CLUSTER
|
|
ClearAllButAlbedo(l, _branchClusterCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_OTHER
|
|
ClearAllButAlbedo(l, _branchOtherCount / 8 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TOTAL
|
|
l.Albedo.r = _branchWeightCount / 12;
|
|
l.Albedo.g = _branchTriplanarCount / 24;
|
|
l.Albedo.b = _branchClusterCount / 12;
|
|
ClearAllButAlbedo(l, (l.Albedo.r + l.Albedo.g + l.Albedo.b + (_branchOtherCount / 8)) / 4);
|
|
#elif _DEBUG_OUTPUT_MICROSHADOWS
|
|
ClearAllButAlbedo(l,l.Albedo);
|
|
#elif _DEBUG_SAMPLECOUNT
|
|
float sdisp = (float)_sampleCount / max(_SampleCountDiv, 1);
|
|
half3 sdcolor = float3(sdisp, sdisp > 1 ? 1 : 0, 0);
|
|
ClearAllButAlbedo(l, sdcolor * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_PROCLAYERS
|
|
ClearAllButAlbedo(l, (float)_procLayerCount / (float)_PCLayerCount * saturate(l.Albedo.z + 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
// abstraction around sampler mode
|
|
#if _USELODMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_LOD(tex, sampler##tex, u, l.x)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u, l.x)
|
|
#elif _USEGRADMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_GRAD(tex, sampler##tex, u, l.xy, l.zw)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY_GRAD(tex, ss, u.xy, u.z, l.xy, l.zw)
|
|
#else
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, u.xy, u.z)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u.xy, y.z)
|
|
#endif
|
|
|
|
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE(u, cl, l) MICROSPLAT_SAMPLE(_Diffuse, u, l)
|
|
#define MICROSPLAT_SAMPLE_EMIS(u, cl, l) MICROSPLAT_SAMPLE(_EmissiveMetal, u, l)
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE_LOD(u, cl, l) UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, u, l)
|
|
|
|
|
|
#if _PACKINGHQ
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) half4(MICROSPLAT_SAMPLE(_NormalSAO, u, l).ga, MICROSPLAT_SAMPLE(_SmoothAO, u, l).ga).brag
|
|
#else
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) MICROSPLAT_SAMPLE(_NormalSAO, u, l)
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
#define MICROSPLAT_SAMPLE_SPECULAR(u, cl, l) MICROSPLAT_SAMPLE(_Specular, u, l)
|
|
#endif
|
|
|
|
struct SimpleTriplanarConfig
|
|
{
|
|
float3 pn;
|
|
float2 uv0;
|
|
float2 uv1;
|
|
float2 uv2;
|
|
};
|
|
|
|
void PrepSimpleTriplanarConfig(inout SimpleTriplanarConfig tc, float3 worldPos, float3 normal, float contrast)
|
|
{
|
|
tc.pn = pow(abs(normal), contrast);
|
|
tc.pn = tc.pn / (tc.pn.x + tc.pn.y + tc.pn.z);
|
|
|
|
half3 axisSign = sign(normal);
|
|
|
|
tc.uv0 = worldPos.zy * axisSign.x;
|
|
tc.uv1 = worldPos.xz * axisSign.y;
|
|
tc.uv2 = worldPos.xy * axisSign.z;
|
|
}
|
|
|
|
#define SimpleTriplanarSample(tex, tc, scale) (SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv0 * scale) * tc.pn.x + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv1 * scale) * tc.pn.y + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv2 * scale) * tc.pn.z)
|
|
#define SimpleTriplanarSampleLOD(tex, tc, scale, lod) (SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv0 * scale, lod) * tc.pn.x + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv1 * scale, lod) * tc.pn.y + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv2 * scale, lod) * tc.pn.z)
|
|
#define SimpleTriplanarSampleGrad(tex, tc, scale) (SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv0 * scale, ddx(tc.uv0) * scale, ddy(tc.uv0) * scale) * tc.pn.x + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv1 * scale, ddx(tc.uv1) * scale, ddy(tc.uv1) * scale) * tc.pn.y + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv2 * scale, ddx(tc.uv2) * scale, ddy(tc.uv2) * scale) * tc.pn.z)
|
|
|
|
|
|
inline half3 MicroSplatDiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
|
|
{
|
|
specColor = lerp (half3(0,0,0), albedo, metallic);
|
|
oneMinusReflectivity = (1-metallic);
|
|
return albedo * oneMinusReflectivity;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Input DescToInput(ShaderData IN)
|
|
{
|
|
Input s = (Input)0;
|
|
s.shaderData = IN;
|
|
s.TBN = IN.TBNMatrix;
|
|
s.worldNormal = IN.worldSpaceNormal;
|
|
s.worldPos = IN.worldSpacePosition;
|
|
s.viewDir = IN.tangentSpaceViewDir;
|
|
s.uv_Control0 = IN.texcoord0.xy;
|
|
|
|
s.worldUpVector = float3(0,1,0);
|
|
s.worldHeight = IN.worldSpacePosition.y;
|
|
|
|
#if _PLANETVECTORS
|
|
float3 rwp = mul(_PQSToLocal, float4(IN.worldSpacePosition, 1));
|
|
s.worldHeight = distance(rwp, float3(0,0,0));
|
|
s.worldUpVector = normalize(rwp);
|
|
#endif
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
s.uv2_Diffuse = IN.texcoord1.xy;
|
|
#endif
|
|
|
|
#if _MEGASPLAT
|
|
UnpackMegaSplat(s, IN);
|
|
#endif
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
UnpackVertexWorkflow(s, IN);
|
|
#endif
|
|
|
|
#if _PLANETVECTORS
|
|
DoPlanetDataInputCopy(s, IN);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
void SampleAlbedo(inout Config config, inout TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half4 contrasts = _Contrast.xxxx;
|
|
#if _PERTEXTRIPLANARCONTRAST
|
|
SAMPLE_PER_TEX(ptc, 9.5, config, half4(1,0.5,0,0));
|
|
contrasts = half4(ptc0.y, ptc1.y, ptc2.y, ptc3.y);
|
|
#endif
|
|
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
SAMPLE_PER_TEX(pttri, 9.5, config, half4(0,0,0,0));
|
|
#endif
|
|
|
|
{
|
|
// For per-texture triplanar, we modify the view based blending factor of the triplanar
|
|
// such that you get a pure blend of either top down projection, or with the top down projection
|
|
// removed and renormalized. This causes dynamic flow control optimizations to kick in and avoid
|
|
// the extra texture samples while keeping the code simple. Yay..
|
|
|
|
// We also only have to do this in the Albedo, because the pN values will be adjusted after the
|
|
// albedo is sampled, causing future samples to use this data.
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri0.x > 0.66)
|
|
{
|
|
tc.pN0 = half3(0,1,0);
|
|
}
|
|
else if (pttri0.x > 0.33)
|
|
{
|
|
tc.pN0.y = 0;
|
|
tc.pN0.xz = TotalOne(tc.pN0.xz);
|
|
}
|
|
#endif
|
|
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN0;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN0, contrasts.x);
|
|
tc.pN0 = bf;
|
|
#endif
|
|
|
|
s.albedo0 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri1.x > 0.66)
|
|
{
|
|
tc.pN1 = half3(0,1,0);
|
|
}
|
|
else if (pttri1.x > 0.33)
|
|
{
|
|
tc.pN1.y = 0;
|
|
tc.pN1.xz = TotalOne(tc.pN1.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
COUNTSAMPLE
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[2], config.cluster1, d2);
|
|
}
|
|
half3 bf = tc.pN1;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN1, contrasts.x);
|
|
tc.pN1 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo1 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri2.x > 0.66)
|
|
{
|
|
tc.pN2 = half3(0,1,0);
|
|
}
|
|
else if (pttri2.x > 0.33)
|
|
{
|
|
tc.pN2.y = 0;
|
|
tc.pN2.xz = TotalOne(tc.pN2.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN2;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN2, contrasts.x);
|
|
tc.pN2 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo2 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri3.x > 0.66)
|
|
{
|
|
tc.pN3 = half3(0,1,0);
|
|
}
|
|
else if (pttri3.x > 0.33)
|
|
{
|
|
tc.pN3.y = 0;
|
|
tc.pN3.xz = TotalOne(tc.pN3.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN3;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN3, contrasts.x);
|
|
tc.pN3 = bf;
|
|
#endif
|
|
|
|
s.albedo3 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.albedo0 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.albedo1 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.albedo2 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.albedo3 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXHEIGHTOFFSET || _PERTEXHEIGHTCONTRAST
|
|
SAMPLE_PER_TEX(ptHeight, 10.5, config, 1);
|
|
|
|
#if _PERTEXHEIGHTOFFSET
|
|
s.albedo0.a = saturate(s.albedo0.a + ptHeight0.b - 1);
|
|
s.albedo1.a = saturate(s.albedo1.a + ptHeight1.b - 1);
|
|
s.albedo2.a = saturate(s.albedo2.a + ptHeight2.b - 1);
|
|
s.albedo3.a = saturate(s.albedo3.a + ptHeight3.b - 1);
|
|
#endif
|
|
#if _PERTEXHEIGHTCONTRAST
|
|
s.albedo0.a = saturate(pow(s.albedo0.a + 0.5, abs(ptHeight0.a)) - 0.5);
|
|
s.albedo1.a = saturate(pow(s.albedo1.a + 0.5, abs(ptHeight1.a)) - 0.5);
|
|
s.albedo2.a = saturate(pow(s.albedo2.a + 0.5, abs(ptHeight2.a)) - 0.5);
|
|
s.albedo3.a = saturate(pow(s.albedo3.a + 0.5, abs(ptHeight3.a)) - 0.5);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void SampleNormal(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
|
|
#if _NONORMALMAP || _AUTONORMAL
|
|
s.normSAO0 = half4(0,0, 0, 1);
|
|
s.normSAO1 = half4(0,0, 0, 1);
|
|
s.normSAO2 = half4(0,0, 0, 1);
|
|
s.normSAO3 = half4(0,0, 0, 1);
|
|
return;
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half3 absVertNormal = abs(tc.IN.worldNormal);
|
|
float3x3 t2w = tc.IN.TBN;
|
|
|
|
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[0], config.cluster0, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[1], config.cluster0, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[2], config.cluster0, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = SurfgradFromTriplanarProjection(tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO0.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO0.zw = a0.zw * tc.pN0.x + a1.zw * tc.pN0.y + a2.zw * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[0], config.cluster1, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[1], config.cluster1, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[2], config.cluster1, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = SurfgradFromTriplanarProjection(tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO1.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO1.zw = a0.zw * tc.pN1.x + a1.zw * tc.pN1.y + a2.zw * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[0], config.cluster2, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[1], config.cluster2, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[2], config.cluster2, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf2 = SurfgradFromTriplanarProjection(tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO2.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO2.zw = a0.zw * tc.pN2.x + a1.zw * tc.pN2.y + a2.zw * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[0], config.cluster3, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[1], config.cluster3, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[2], config.cluster3, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf3 = SurfgradFromTriplanarProjection(tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO3.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO3.zw = a0.zw * tc.pN3.x + a1.zw * tc.pN3.y + a2.zw * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.normSAO0 = MICROSPLAT_SAMPLE_NORMAL(config.uv0, config.cluster0, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO0.xy = s.normSAO0.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = ConvertNormal2ToGradient(s.normSAO0.xy);
|
|
#endif
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.normSAO1 = MICROSPLAT_SAMPLE_NORMAL(config.uv1, config.cluster1, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO1.xy = s.normSAO1.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = ConvertNormal2ToGradient(s.normSAO1.xy);
|
|
#endif
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.normSAO2 = MICROSPLAT_SAMPLE_NORMAL(config.uv2, config.cluster2, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO2.xy = s.normSAO2.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf2 = ConvertNormal2ToGradient(s.normSAO2.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.normSAO3 = MICROSPLAT_SAMPLE_NORMAL(config.uv3, config.cluster3, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO3.xy = s.normSAO3.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf3 = ConvertNormal2ToGradient(s.normSAO3.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleEmis(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
s.emisMetal0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.emisMetal0 = MICROSPLAT_SAMPLE_EMIS(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.emisMetal1 = MICROSPLAT_SAMPLE_EMIS(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.emisMetal2 = MICROSPLAT_SAMPLE_EMIS(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.emisMetal3 = MICROSPLAT_SAMPLE_EMIS(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleSpecular(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.specular0 = MICROSPLAT_SAMPLE_SPECULAR(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.specular1 = MICROSPLAT_SAMPLE_SPECULAR(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.specular2 = MICROSPLAT_SAMPLE_SPECULAR(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.specular3 = MICROSPLAT_SAMPLE_SPECULAR(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
MicroSplatLayer Sample(Input i, half4 weights, inout Config config, float camDist, float3 worldNormalVertex, DecalOutput decalOutput)
|
|
{
|
|
MicroSplatLayer o = (MicroSplatLayer)0;
|
|
UNITY_INITIALIZE_OUTPUT(MicroSplatLayer,o);
|
|
|
|
RawSamples samples = (RawSamples)0;
|
|
InitRawSamples(samples);
|
|
|
|
half4 albedo = 0;
|
|
half4 normSAO = half4(0,0,0,1);
|
|
half3 surfGrad = half3(0,0,0);
|
|
half4 emisMetal = 0;
|
|
half3 specular = 0;
|
|
|
|
float worldHeight = i.worldPos.y;
|
|
float3 upVector = float3(0,1,0);
|
|
|
|
#if _GLOBALTINT || _GLOBALNORMALS || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _GLOBALSPECULAR
|
|
float globalSlopeFilter = 1;
|
|
#if _GLOBALSLOPEFILTER
|
|
float2 gfilterUV = float2(1 - saturate(dot(worldNormalVertex, upVector) * 0.5 + 0.49), 0.5);
|
|
globalSlopeFilter = SAMPLE_TEXTURE2D(_GlobalSlopeTex, sampler_Diffuse, gfilterUV).a;
|
|
#endif
|
|
#endif
|
|
|
|
// declare outside of branchy areas..
|
|
half4 fxLevels = half4(0,0,0,0);
|
|
half burnLevel = 0;
|
|
half wetLevel = 0;
|
|
half3 waterNormalFoam = half3(0, 0, 0);
|
|
half porosity = 0.4;
|
|
float streamFoam = 1.0f;
|
|
half pud = 0;
|
|
half snowCover = 0;
|
|
half SSSThickness = 0;
|
|
half3 SSSTint = half3(1,1,1);
|
|
float traxBuffer = 0;
|
|
float3 traxNormal = 0;
|
|
float2 noiseUV = 0;
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(1 - saturate(camDist - _SplatFade.y))
|
|
{
|
|
#endif
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE || _SNOWFOOTSTEPS
|
|
traxBuffer = SampleTraxBuffer(i.worldPos, worldNormalVertex, traxNormal);
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
#if _MICROMESH
|
|
fxLevels = SampleFXLevels(InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, config.uv), wetLevel, burnLevel, traxBuffer);
|
|
#elif _MICROVERTEXMESH || _MICRODIGGERMESH || _MEGASPLAT
|
|
fxLevels = ProcessFXLevels(i.fx, traxBuffer);
|
|
#else
|
|
fxLevels = SampleFXLevels(config.uv, wetLevel, burnLevel, traxBuffer);
|
|
#endif
|
|
#endif
|
|
|
|
#if _DECAL
|
|
fxLevels = max(fxLevels, decalOutput.fxLevels);
|
|
#endif
|
|
|
|
TriplanarConfig tc = (TriplanarConfig)0;
|
|
UNITY_INITIALIZE_OUTPUT(TriplanarConfig,tc);
|
|
|
|
|
|
MIPFORMAT albedoLOD = INITMIPFORMAT
|
|
MIPFORMAT normalLOD = INITMIPFORMAT
|
|
MIPFORMAT emisLOD = INITMIPFORMAT
|
|
MIPFORMAT specLOD = INITMIPFORMAT
|
|
MIPFORMAT origAlbedoLOD = INITMIPFORMAT;
|
|
|
|
#if _TRIPLANAR && !_DISABLESPLATMAPS
|
|
PrepTriplanar(i.shaderData.texcoord0, worldNormalVertex, i.worldPos, config, tc, weights, albedoLOD, normalLOD, emisLOD, origAlbedoLOD);
|
|
tc.IN = i;
|
|
#endif
|
|
|
|
|
|
#if !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
#if _USELODMIP
|
|
albedoLOD = ComputeMipLevel(config.uv0.xy, _Diffuse_TexelSize.zw);
|
|
normalLOD = ComputeMipLevel(config.uv0.xy, _NormalSAO_TexelSize.zw);
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = ComputeMipLevel(config.uv0.xy, _EmissiveMetal_TexelSize.zw);
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = ComputeMipLevel(config.uv0.xy, _Specular_TexelSize.zw);;
|
|
#endif
|
|
#elif _USEGRADMIP
|
|
albedoLOD = float4(ddx(config.uv0.xy), ddy(config.uv0.xy));
|
|
normalLOD = albedoLOD;
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
|
|
origAlbedoLOD = albedoLOD;
|
|
#endif
|
|
|
|
#if _PERTEXCURVEWEIGHT
|
|
SAMPLE_PER_TEX(ptCurveWeight, 19.5, config, half4(0.5,1,1,1));
|
|
weights.x = lerp(smoothstep(0.5 - ptCurveWeight0.r, 0.5 + ptCurveWeight0.r, weights.x), weights.x, ptCurveWeight0.r*2);
|
|
weights.y = lerp(smoothstep(0.5 - ptCurveWeight1.r, 0.5 + ptCurveWeight1.r, weights.y), weights.y, ptCurveWeight1.r*2);
|
|
weights.z = lerp(smoothstep(0.5 - ptCurveWeight2.r, 0.5 + ptCurveWeight2.r, weights.z), weights.z, ptCurveWeight2.r*2);
|
|
weights.w = lerp(smoothstep(0.5 - ptCurveWeight3.r, 0.5 + ptCurveWeight3.r, weights.w), weights.w, ptCurveWeight3.r*2);
|
|
weights = TotalOne(weights);
|
|
#endif
|
|
|
|
|
|
|
|
// uvScale before anything
|
|
#if _PERTEXUVSCALEOFFSET && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
config.uv0.xy = config.uv0.xy * ptUVScale0.rg + ptUVScale0.ba;
|
|
config.uv1.xy = config.uv1.xy * ptUVScale1.rg + ptUVScale1.ba;
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = config.uv2.xy * ptUVScale2.rg + ptUVScale2.ba;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = config.uv3.xy * ptUVScale3.rg + ptUVScale3.ba;
|
|
#endif
|
|
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = albedoLOD * ptUVScale0.rgrg * weights.x +
|
|
albedoLOD * ptUVScale1.rgrg * weights.y +
|
|
albedoLOD * ptUVScale2.rgrg * weights.z +
|
|
albedoLOD * ptUVScale3.rgrg * weights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXUVROTATION && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptUVRot, 16.5, config, half4(0,0,0,0));
|
|
config.uv0.xy = RotateUV(config.uv0.xy, ptUVRot0.x);
|
|
config.uv1.xy = RotateUV(config.uv1.xy, ptUVRot1.x);
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = RotateUV(config.uv2.xy, ptUVRot2.x);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = RotateUV(config.uv3.xy, ptUVRot0.x);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
o.Alpha = 1;
|
|
|
|
|
|
#if _POM && !_DISABLESPLATMAPS
|
|
DoPOM(i, config, tc, albedoLOD, weights, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
SampleAlbedo(config, tc, samples, albedoLOD, weights);
|
|
|
|
#if _NOISEHEIGHT
|
|
ApplyNoiseHeight(samples, config.uv, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STREAMS || (_PARALLAX && !_DISABLESPLATMAPS)
|
|
half earlyHeight = BlendWeights(samples.albedo0.w, samples.albedo1.w, samples.albedo2.w, samples.albedo3.w, weights);
|
|
#endif
|
|
|
|
|
|
#if _STREAMS
|
|
waterNormalFoam = GetWaterNormal(i, config.uv, worldNormalVertex);
|
|
DoStreamRefract(config, tc, waterNormalFoam, fxLevels.b, earlyHeight);
|
|
#endif
|
|
|
|
#if _PARALLAX && !_DISABLESPLATMAPS
|
|
DoParallax(i, earlyHeight, config, tc, samples, weights, camDist);
|
|
#endif
|
|
|
|
|
|
// Blend results
|
|
#if _PERTEXINTERPCONTRAST && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptContrasts, 1.5, config, 0.5);
|
|
half4 contrast = 0.5;
|
|
contrast.x = ptContrasts0.a;
|
|
contrast.y = ptContrasts1.a;
|
|
#if !_MAX2LAYER
|
|
contrast.z = ptContrasts2.a;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
contrast.w = ptContrasts3.a;
|
|
#endif
|
|
contrast = clamp(contrast + _Contrast, 0.0001, 1.0);
|
|
half cnt = contrast.x * weights.x + contrast.y * weights.y + contrast.z * weights.z + contrast.w * weights.w;
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, cnt);
|
|
#else
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, _Contrast);
|
|
#endif
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
heightWeights = lerp(heightWeights, TotalOne(weights), saturate(camDist/max(1.0, _HybridHeightBlendDistance)));
|
|
#endif
|
|
|
|
|
|
// rescale derivatives after height weighting. Basically, in gradmip mode we blend the mip levels,
|
|
// but this is before height mapping is sampled, so reblending them after alpha will make sure the other
|
|
// channels (normal, etc) are sharper, which likely matters most..
|
|
#if _PERTEXUVSCALEOFFSET && !_DISABLESPLATMAPS
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
|
|
albedoLOD.d0 = origAlbedoLOD.d0 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d0 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d0 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d0 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d1 = origAlbedoLOD.d1 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d1 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d1 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d1 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d2 = origAlbedoLOD.d2 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d2 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d2 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d2 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
normalLOD.d0 = albedoLOD.d0;
|
|
normalLOD.d1 = albedoLOD.d1;
|
|
normalLOD.d2 = albedoLOD.d2;
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD.d0 = albedoLOD.d0;
|
|
emisLOD.d1 = albedoLOD.d1;
|
|
emisLOD.d2 = albedoLOD.d2;
|
|
#endif
|
|
#endif // gradmip
|
|
#else // not triplanar
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = origAlbedoLOD * ptUVScale0.rgrg * heightWeights.x +
|
|
origAlbedoLOD * ptUVScale1.rgrg * heightWeights.y +
|
|
origAlbedoLOD * ptUVScale2.rgrg * heightWeights.z +
|
|
origAlbedoLOD * ptUVScale3.rgrg * heightWeights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _PARALLAX || _STREAMS
|
|
SampleAlbedo(config, tc, samples, albedoLOD, heightWeights);
|
|
#endif
|
|
|
|
|
|
SampleNormal(config, tc, samples, normalLOD, heightWeights);
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
SampleEmis(config, tc, samples, emisLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
SampleSpecular(config, tc, samples, specLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _DISTANCERESAMPLE && !_DISABLESPLATMAPS
|
|
DistanceResample(samples, config, tc, camDist, i.viewDir, fxLevels, albedoLOD, i.worldPos, heightWeights, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STARREACHFORMAT
|
|
samples.normSAO0.w = length(samples.normSAO0.xy);
|
|
samples.normSAO1.w = length(samples.normSAO1.xy);
|
|
samples.normSAO2.w = length(samples.normSAO2.xy);
|
|
samples.normSAO3.w = length(samples.normSAO3.xy);
|
|
#endif
|
|
|
|
// PerTexture sampling goes here, passing the samples structure
|
|
|
|
#if _PERTEXMICROSHADOWS || _PERTEXFUZZYSHADE
|
|
SAMPLE_PER_TEX(ptFuzz, 17.5, config, half4(0, 0, 1, 1));
|
|
#endif
|
|
|
|
#if _PERTEXMICROSHADOWS
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
{
|
|
half3 lightDir = GetGlobalLightDirTS(i);
|
|
half4 microShadows = half4(1,1,1,1);
|
|
microShadows.x = MicroShadow(lightDir, half3(samples.normSAO0.xy, 1), samples.normSAO0.a, ptFuzz0.a);
|
|
microShadows.y = MicroShadow(lightDir, half3(samples.normSAO1.xy, 1), samples.normSAO1.a, ptFuzz1.a);
|
|
microShadows.z = MicroShadow(lightDir, half3(samples.normSAO2.xy, 1), samples.normSAO2.a, ptFuzz2.a);
|
|
microShadows.w = MicroShadow(lightDir, half3(samples.normSAO3.xy, 1), samples.normSAO3.a, ptFuzz3.a);
|
|
samples.normSAO0.a *= microShadows.x;
|
|
samples.normSAO1.a *= microShadows.y;
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a *= microShadows.z;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a *= microShadows.w;
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_OUTPUT_MICROSHADOWS
|
|
o.Albedo = BlendWeights(microShadows.x, microShadows.y, microShadows.z, microShadows.a, heightWeights);
|
|
return o;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
#endif // _PERTEXMICROSHADOWS
|
|
|
|
|
|
#if _PERTEXFUZZYSHADE
|
|
samples.albedo0.rgb = FuzzyShade(samples.albedo0.rgb, half3(samples.normSAO0.rg, 1), ptFuzz0.r, ptFuzz0.g, ptFuzz0.b, i.viewDir);
|
|
samples.albedo1.rgb = FuzzyShade(samples.albedo1.rgb, half3(samples.normSAO1.rg, 1), ptFuzz1.r, ptFuzz1.g, ptFuzz1.b, i.viewDir);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = FuzzyShade(samples.albedo2.rgb, half3(samples.normSAO2.rg, 1), ptFuzz2.r, ptFuzz2.g, ptFuzz2.b, i.viewDir);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = FuzzyShade(samples.albedo3.rgb, half3(samples.normSAO3.rg, 1), ptFuzz3.r, ptFuzz3.g, ptFuzz3.b, i.viewDir);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSATURATION && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptSaturattion, 9.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = lerp(MSLuminance(samples.albedo0.rgb), samples.albedo0.rgb, ptSaturattion0.a);
|
|
samples.albedo1.rgb = lerp(MSLuminance(samples.albedo1.rgb), samples.albedo1.rgb, ptSaturattion1.a);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = lerp(MSLuminance(samples.albedo2.rgb), samples.albedo2.rgb, ptSaturattion2.a);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = lerp(MSLuminance(samples.albedo3.rgb), samples.albedo3.rgb, ptSaturattion3.a);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if _PERTEXTINT && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptTints, 1.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb *= ptTints0.rgb;
|
|
samples.albedo1.rgb *= ptTints1.rgb;
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb *= ptTints2.rgb;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb *= ptTints3.rgb;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PCHEIGHTGRADIENT || _PCHEIGHTHSV || _PCSLOPEGRADIENT || _PCSLOPEHSV
|
|
ProceduralGradients(i, samples, config, worldHeight, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS
|
|
porosity = _GlobalPorosity;
|
|
#endif
|
|
|
|
|
|
#if _PERTEXCOLORINTENSITY
|
|
SAMPLE_PER_TEX(ptCI, 23.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb * (1 + ptCI0.rrr));
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb * (1 + ptCI1.rrr));
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb * (1 + ptCI2.rrr));
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb * (1 + ptCI3.rrr));
|
|
#endif
|
|
#endif
|
|
|
|
#if (_PERTEXBRIGHTNESS || _PERTEXCONTRAST || _PERTEXPOROSITY || _PERTEXFOAM) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptBC, 3.5, config, half4(1, 1, 1, 1));
|
|
#if _PERTEXCONTRAST
|
|
samples.albedo0.rgb = saturate(((samples.albedo0.rgb - 0.5) * ptBC0.g) + 0.5);
|
|
samples.albedo1.rgb = saturate(((samples.albedo1.rgb - 0.5) * ptBC1.g) + 0.5);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(((samples.albedo2.rgb - 0.5) * ptBC2.g) + 0.5);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(((samples.albedo3.rgb - 0.5) * ptBC3.g) + 0.5);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXBRIGHTNESS
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb + ptBC0.rrr);
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb + ptBC1.rrr);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb + ptBC2.rrr);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb + ptBC3.rrr);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXPOROSITY
|
|
porosity = BlendWeights(ptBC0.b, ptBC1.b, ptBC2.b, ptBC3.b, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXFOAM
|
|
streamFoam = BlendWeights(ptBC0.a, ptBC1.a, ptBC2.a, ptBC3.a, heightWeights);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if (_PERTEXNORMSTR || _PERTEXAOSTR || _PERTEXSMOOTHSTR || _PERTEXMETALLIC) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(perTexMatSettings, 2.5, config, half4(1.0, 1.0, 1.0, 0.0));
|
|
#endif
|
|
|
|
#if _PERTEXNORMSTR && !_DISABLESPLATMAPS
|
|
#if _SURFACENORMALS
|
|
samples.surf0 *= perTexMatSettings0.r;
|
|
samples.surf1 *= perTexMatSettings1.r;
|
|
samples.surf2 *= perTexMatSettings2.r;
|
|
samples.surf3 *= perTexMatSettings3.r;
|
|
#else
|
|
samples.normSAO0.xy *= perTexMatSettings0.r;
|
|
samples.normSAO1.xy *= perTexMatSettings1.r;
|
|
samples.normSAO2.xy *= perTexMatSettings2.r;
|
|
samples.normSAO3.xy *= perTexMatSettings3.r;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXAOSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.a = pow(abs(samples.normSAO0.a), perTexMatSettings0.b);
|
|
samples.normSAO1.a = pow(abs(samples.normSAO1.a), perTexMatSettings1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a = pow(abs(samples.normSAO2.a), perTexMatSettings2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a = pow(abs(samples.normSAO3.a), perTexMatSettings3.b);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSMOOTHSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.b += perTexMatSettings0.g;
|
|
samples.normSAO1.b += perTexMatSettings1.g;
|
|
samples.normSAO0.b = saturate(samples.normSAO0.b);
|
|
samples.normSAO1.b = saturate(samples.normSAO1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.b += perTexMatSettings2.g;
|
|
samples.normSAO2.b = saturate(samples.normSAO2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.b += perTexMatSettings3.g;
|
|
samples.normSAO3.b = saturate(samples.normSAO3.b);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
#if _PERTEXSSS
|
|
{
|
|
SAMPLE_PER_TEX(ptSSS, 18.5, config, half4(1, 1, 1, 1)); // tint, thickness
|
|
half4 vals = ptSSS0 * heightWeights.x + ptSSS1 * heightWeights.y + ptSSS2 * heightWeights.z + ptSSS3 * heightWeights.w;
|
|
SSSThickness = vals.a;
|
|
SSSTint = vals.rgb;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXRIMLIGHT
|
|
{
|
|
SAMPLE_PER_TEX(ptRimA, 26.5, config, half4(1, 1, 1, 1));
|
|
SAMPLE_PER_TEX(ptRimB, 27.5, config, half4(1, 1, 1, 0));
|
|
samples.emisMetal0.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO0.xy, 1))), max(0.0001, ptRimA0.g)) * ptRimB0.rgb * ptRimB0.a;
|
|
samples.emisMetal1.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO1.xy, 1))), max(0.0001, ptRimA1.g)) * ptRimB1.rgb * ptRimB1.a;
|
|
samples.emisMetal2.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO2.xy, 1))), max(0.0001, ptRimA2.g)) * ptRimB2.rgb * ptRimB2.a;
|
|
samples.emisMetal3.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO3.xy, 1))), max(0.0001, ptRimA3.g)) * ptRimB3.rgb * ptRimB3.a;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#if (((_DETAILNOISE && _PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && _PERTEXDISTANCENOISESTRENGTH)) || (_NORMALNOISE && _PERTEXNORMALNOISESTRENGTH)) && !_DISABLESPLATMAPS
|
|
ApplyDetailDistanceNoisePerTex(samples, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALNOISEUV
|
|
// noise defaults so that a value of 1, 1 is 4 pixels in size and moves the uvs by 1 pixel max.
|
|
#if _CUSTOMSPLATTEXTURES
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#else
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE
|
|
ApplyTrax(samples, config, i.worldPos, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if (_ANTITILEARRAYDETAIL || _ANTITILEARRAYDISTANCE || _ANTITILEARRAYNORMAL) && !_DISABLESPLATMAPS
|
|
ApplyAntiTilePerTex(samples, config, camDist, i.worldPos, worldNormalVertex, heightWeights);
|
|
#endif
|
|
|
|
#if _GEOMAP && !_DISABLESPLATMAPS
|
|
GeoTexturePerTex(samples, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
#if _GLOBALTINT && _PERTEXGLOBALTINTSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalTintTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && _PERTEXGLOBALNORMALSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalNormalTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && _PERTEXGLOBALSAOMSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalSAOMTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && _PERTEXGLOBALEMISSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalEmisTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && _PERTEXGLOBALSPECULARSTRENGTH && !_DISABLESPLATMAPS && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _PERTEXMETALLIC && !_DISABLESPLATMAPS
|
|
half metallic = BlendWeights(perTexMatSettings0.a, perTexMatSettings1.a, perTexMatSettings2.a, perTexMatSettings3.a, heightWeights);
|
|
o.Metallic = metallic;
|
|
#endif
|
|
|
|
#if _GLITTER && !_DISABLESPLATMAPS
|
|
DoGlitter(i, samples, config, camDist, worldNormalVertex, i.worldPos);
|
|
#endif
|
|
|
|
// Blend em..
|
|
#if _DISABLESPLATMAPS
|
|
// If we don't sample from the _Diffuse, then the shader compiler will strip the sampler on
|
|
// some platforms, which will cause everything to break. So we sample from the lowest mip
|
|
// and saturate to 1 to keep the cost minimal. Annoying, but the compiler removes the texture
|
|
// and sampler, even though the sampler is still used.
|
|
albedo = saturate(UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, float3(0,0,0), 12) + 1);
|
|
albedo.a = 0.5; // make height something we can blend with for the combined mesh mode, since it still height blends.
|
|
normSAO = half4(0,0,0,1);
|
|
#else
|
|
albedo = BlendWeights(samples.albedo0, samples.albedo1, samples.albedo2, samples.albedo3, heightWeights);
|
|
normSAO = BlendWeights(samples.normSAO0, samples.normSAO1, samples.normSAO2, samples.normSAO3, heightWeights);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = BlendWeights(samples.surf0, samples.surf1, samples.surf2, samples.surf3, heightWeights);
|
|
#endif
|
|
|
|
#if (_USEEMISSIVEMETAL || _PERTEXRIMLIGHT) && !_DISABLESPLATMAPS
|
|
emisMetal = BlendWeights(samples.emisMetal0, samples.emisMetal1, samples.emisMetal2, samples.emisMetal3, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW && !_DISABLESPLATMAPS
|
|
specular = BlendWeights(samples.specular0, samples.specular1, samples.specular2, samples.specular3, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXOUTLINECOLOR
|
|
SAMPLE_PER_TEX(ptOutlineColor, 28.5, config, half4(0.5, 0.5, 0.5, 1));
|
|
half4 outlineColor = BlendWeights(ptOutlineColor0, ptOutlineColor1, ptOutlineColor2, ptOutlineColor3, heightWeights);
|
|
half4 tstr = saturate(abs(heightWeights - 0.5) * 2);
|
|
half transitionBlend = min(min(min(tstr.x, tstr.y), tstr.z), tstr.w);
|
|
albedo.rgb = lerp(albedo.rgb * outlineColor.rgb * 2, albedo.rgb, outlineColor.a * transitionBlend);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHOVERLAYSPLATS || _MESHCOMBINED
|
|
o.Alpha = 1.0;
|
|
if (config.uv0.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.x;
|
|
else if (config.uv1.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.y;
|
|
else if (config.uv2.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.z;
|
|
else if (config.uv3.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.w;
|
|
#endif
|
|
|
|
|
|
|
|
// effects which don't require per texture adjustments and are part of the splats sample go here.
|
|
// Often, as an optimization, you can compute the non-per tex version of above effects here..
|
|
|
|
|
|
#if ((_DETAILNOISE && !_PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && !_PERTEXDISTANCENOISESTRENGTH) || (_NORMALNOISE && !_PERTEXNORMALNOISESTRENGTH))
|
|
ApplyDetailDistanceNoise(albedo.rgb, normSAO, surfGrad, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
}
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
|
|
float2 sfDX = ddx(config.uv * _UVScale);
|
|
float2 sfDY = ddy(config.uv * _UVScale);
|
|
|
|
MSBRANCHOTHER(camDist - _SplatFade.x)
|
|
{
|
|
float falloff = saturate(InverseLerp(_SplatFade.x, _SplatFade.y, camDist));
|
|
half4 sfalb = SAMPLE_TEXTURE2D_ARRAY_GRAD(_Diffuse, sampler_Diffuse, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY);
|
|
COUNTSAMPLE
|
|
albedo.rgb = lerp(albedo.rgb, sfalb.rgb, falloff);
|
|
|
|
#if !_NONORMALMAP && !_AUTONORMAL
|
|
half4 sfnormSAO = SAMPLE_TEXTURE2D_ARRAY_GRAD(_NormalSAO, sampler_NormalSAO, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY).agrb;
|
|
COUNTSAMPLE
|
|
sfnormSAO.xy = sfnormSAO.xy * 2 - 1;
|
|
|
|
normSAO = lerp(normSAO, sfnormSAO, falloff);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = lerp(surfGrad, ConvertNormal2ToGradient(sfnormSAO.xy), falloff);
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
float3 autoNormal = HeightToNormal(albedo.a * _AutoNormalHeightScale, i.worldPos);
|
|
normSAO.xy = autoNormal;
|
|
normSAO.z = 0;
|
|
normSAO.w = (autoNormal.z * autoNormal.z);
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHCOMBINED
|
|
SampleMeshCombined(albedo, normSAO, surfGrad, emisMetal, specular, o.Alpha, SSSThickness, SSSTint, config, heightWeights);
|
|
#endif
|
|
|
|
#if _ISOBJECTSHADER
|
|
SampleObjectShader(i, albedo, normSAO, surfGrad, emisMetal, specular, config);
|
|
#endif
|
|
|
|
#if _GEOMAP
|
|
GeoTexture(albedo.rgb, normSAO, surfGrad, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
|
|
#if _SCATTER
|
|
ApplyScatter(
|
|
#if _MEGASPLAT
|
|
config,
|
|
#endif
|
|
i, albedo, normSAO, surfGrad, config.uv, camDist);
|
|
#endif
|
|
|
|
#if _DECAL
|
|
DoDecalBlend(decalOutput, albedo, normSAO, surfGrad, emisMetal, i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALTINT && !_PERTEXGLOBALTINTSTRENGTH
|
|
GlobalTintTexture(albedo.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _VSGRASSMAP
|
|
VSGrassTexture(albedo.rgb, config, camDist);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && !_PERTEXGLOBALNORMALSTRENGTH
|
|
GlobalNormalTexture(normSAO, surfGrad, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && !_PERTEXGLOBALSAOMSTRENGTH
|
|
GlobalSAOMTexture(normSAO, emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && !_PERTEXGLOBALEMISSTRENGTH
|
|
GlobalEmisTexture(emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && !_PERTEXGLOBALSPECULARSTRENGTH && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexture(specular.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
|
|
|
|
o.Albedo = albedo.rgb;
|
|
o.Height = albedo.a;
|
|
|
|
#if _NONORMALMAP
|
|
o.Normal = half3(0,0,1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#elif _SURFACENORMALS
|
|
o.Normal = ResolveNormalFromSurfaceGradient(surfGrad);
|
|
o.Normal = mul(GetTBN(i), o.Normal);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#else
|
|
o.Normal = half3(normSAO.xy, 1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _PERTEXRIMLIGHT
|
|
#if _USEEMISSIVEMETAL
|
|
emisMetal.rgb *= _EmissiveMult;
|
|
#endif
|
|
|
|
o.Emission += emisMetal.rgb;
|
|
o.Metallic = emisMetal.a;
|
|
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = specular;
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
pud = DoStreams(i, o, fxLevels, config.uv, porosity, waterNormalFoam, worldNormalVertex, streamFoam, wetLevel, burnLevel, i.worldPos);
|
|
#endif
|
|
|
|
|
|
#if _SNOW
|
|
snowCover = DoSnow(i, o, config.uv, WorldNormalVector(i, o.Normal), worldNormalVertex, i.worldPos, pud, porosity, camDist,
|
|
config, weights, SSSTint, SSSThickness, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if _PERTEXSSS || _MESHCOMBINEDUSESSS || (_SNOW && _SNOWSSS)
|
|
{
|
|
half3 worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
|
|
|
|
o.Emission += ComputeSSS(i, worldView, WorldNormalVector(i, o.Normal),
|
|
SSSTint, SSSThickness, _SSSDistance, _SSSScale, _SSSPower);
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWGLITTER
|
|
DoSnowGlitter(i, config, o, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
#if _WINDPARTICULATE || _SNOWPARTICULATE
|
|
DoWindParticulate(i, o, config, weights, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
o.Normal.z = sqrt(1 - saturate(dot(o.Normal.xy, o.Normal.xy)));
|
|
|
|
#if _SPECULARFADE
|
|
{
|
|
float specFade = saturate((i.worldPos.y - _SpecularFades.x) / max(_SpecularFades.y - _SpecularFades.x, 0.0001));
|
|
o.Metallic *= specFade;
|
|
o.Smoothness *= specFade;
|
|
}
|
|
#endif
|
|
|
|
#if _VSSHADOWMAP
|
|
VSShadowTexture(o, i, config, camDist);
|
|
#endif
|
|
|
|
#if _TOONWIREFRAME
|
|
ToonWireframe(config.uv, o.Albedo, camDist);
|
|
#endif
|
|
|
|
#if _SEETHROUGHSHADER
|
|
SeethroughShader(o.Albedo, o.Emission, o.Alpha, i.worldPos, o.Normal, i.worldNormal);
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_TRAXBUFFER
|
|
ClearAllButAlbedo(o, half3(traxBuffer, 0, 0) * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMALVERTEX
|
|
ClearAllButAlbedo(o, worldNormalVertex * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(o, WorldNormalVector(i, o.Normal) * saturate(o.Albedo.z+1));
|
|
#endif
|
|
|
|
#if _DEBUG_MEGABARY && _MEGASPLAT
|
|
o.Albedo = i.baryWeights.xyz;
|
|
#endif
|
|
|
|
|
|
return o;
|
|
}
|
|
|
|
void SampleSplats(float2 controlUV, inout half4 w0, inout half4 w1, inout half4 w2, inout half4 w3, inout half4 w4, inout half4 w5, inout half4 w6, inout half4 w7)
|
|
{
|
|
#if _CUSTOMSPLATTEXTURES
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_CustomControl0_TexelSize.zw - 1.0f) + 0.5f) * _CustomControl0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_CustomControl0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_CustomControl1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_CustomControl2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_CustomControl3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_CustomControl4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_CustomControl5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_CustomControl6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_CustomControl7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#else
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_Control0_TexelSize.zw - 1.0f) + 0.5f) * _Control0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_Control0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_Control1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_Control2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_Control3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_Control4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_Control5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_Control6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_Control7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
MicroSplatLayer SurfImpl(Input i, float3 worldNormalVertex)
|
|
{
|
|
#if _MEGANOUV
|
|
i.uv_Control0 = i.worldPos.xz;
|
|
#endif
|
|
|
|
float camDist = distance(_WorldSpaceCameraPos, i.worldPos);
|
|
|
|
#if _FORCELOCALSPACE
|
|
worldNormalVertex = mul((float3x3)GetWorldToObjectMatrix(), worldNormalVertex).xyz;
|
|
i.worldPos = i.worldPos - mul(GetObjectToWorldMatrix(), float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
i.worldPos = i.worldPos + mul(_GlobalOriginMTX, float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
i.worldPos = SAMPLE_TEXTURE2D(_DebugWorldPos, sampler_Diffuse, i.uv_Control0);
|
|
worldNormalVertex = SAMPLE_TEXTURE2D(_DebugWorldNormal, sampler_Diffuse, i.uv_Control0);
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ALPHABELOWHEIGHT && !_TBDISABLEALPHAHOLES
|
|
ClipWaterLevel(i.worldPos);
|
|
#endif
|
|
|
|
#if !_TBDISABLEALPHAHOLES && defined(_ALPHATEST_ON)
|
|
// UNITY 2019.3 holes
|
|
ClipHoles(i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
float2 origUV = i.uv_Control0;
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
float2 controlUV = i.uv2_Diffuse;
|
|
#else
|
|
float2 controlUV = i.uv_Control0;
|
|
#endif
|
|
|
|
|
|
#if _MICROMESH
|
|
controlUV = InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, controlUV);
|
|
#endif
|
|
|
|
half4 weights = half4(1,0,0,0);
|
|
|
|
Config config = (Config)0;
|
|
UNITY_INITIALIZE_OUTPUT(Config,config);
|
|
config.uv = origUV;
|
|
|
|
DecalOutput decalOutput = (DecalOutput)0;
|
|
#if _DECAL
|
|
decalOutput = DoDecals(i.uv_Control0, i.worldPos, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SURFACENORMALS
|
|
// Initialize the surface gradient basis vectors
|
|
ConstructSurfaceGradientTBN(i);
|
|
#endif
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(_SplatFade.y - camDist)
|
|
#endif // _SPLATFADE
|
|
{
|
|
#if !_DISABLESPLATMAPS
|
|
|
|
// Sample the splat data, from textures or vertices, and setup the config..
|
|
#if _MICRODIGGERMESH
|
|
DiggerSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLAT
|
|
MegaSplatVertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLATTEXTURE
|
|
MegaSplatTextureSetup(controlUV, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MICROVERTEXMESH
|
|
VertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif !_PROCEDURALTEXTURE || _PROCEDURALBLENDSPLATS
|
|
half4 w0 = 0; half4 w1 = 0; half4 w2 = 0; half4 w3 = 0; half4 w4 = 0; half4 w5 = 0; half4 w6 = 0; half4 w7 = 0;
|
|
SampleSplats(controlUV, w0, w1, w2, w3, w4, w5, w6, w7);
|
|
Setup(weights, origUV, config, w0, w1, w2, w3, w4, w5, w6, w7, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
float3 procNormal = worldNormalVertex;
|
|
float3 worldPos = i.worldPos;
|
|
ProceduralSetup(i, worldPos, i.worldHeight, procNormal, i.worldUpVector, weights, origUV, config, ddx(origUV), ddy(origUV), ddx(worldPos), ddy(worldPos), decalOutput);
|
|
#endif
|
|
#else // _DISABLESPLATMAPS
|
|
Setup(weights, origUV, config, half4(1,0,0,0), 0, 0, 0, 0, 0, 0, 0, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _SLOPETEXTURE
|
|
SlopeTexture(config, weights, worldNormalVertex);
|
|
#endif
|
|
} // _SPLATFADE else case
|
|
|
|
|
|
#if _TOONFLATTEXTURE
|
|
float2 quv = floor(origUV * _ToonTerrainSize);
|
|
float2 fuv = frac(origUV * _ToonTerrainSize);
|
|
#if !_TOONFLATTEXTUREQUAD
|
|
quv = Hash2D((fuv.x > fuv.y) ? quv : quv * 0.333);
|
|
#endif
|
|
float2 uvq = quv / _ToonTerrainSize;
|
|
config.uv0.xy = uvq;
|
|
config.uv1.xy = uvq;
|
|
config.uv2.xy = uvq;
|
|
config.uv3.xy = uvq;
|
|
#endif
|
|
|
|
#if (_TEXTURECLUSTER2 || _TEXTURECLUSTER3) && !_DISABLESPLATMAPS
|
|
PrepClusters(origUV, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if (_ALPHAHOLE || _ALPHAHOLETEXTURE) && !_DISABLESPLATMAPS && !_TBDISABLEALPHAHOLES
|
|
ClipAlphaHole(config, weights);
|
|
#endif
|
|
|
|
|
|
|
|
MicroSplatLayer l = Sample(i, weights, config, camDist, worldNormalVertex, decalOutput);
|
|
|
|
// On windows, sometimes the shared samplers gets stripped, so we have to do this crap.
|
|
// We sample from the lowest mip, so it shouldn't cost much, but still, I hate this, wtf..
|
|
float stripVal = saturate(SAMPLE_TEXTURE2D_LOD(_Diffuse, sampler_Diffuse, config.uv0, 11).r + 2);
|
|
stripVal *= saturate(SAMPLE_TEXTURE2D_LOD(_NormalSAO, sampler_NormalSAO, config.uv0, 11).r + 2);
|
|
l.Albedo *= stripVal;
|
|
l.Normal *= stripVal;
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
ProceduralTextureDebugOutput(l, weights, config);
|
|
#endif
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float4 ConstructTerrainTangent(float3 normal, float3 positiveZ)
|
|
{
|
|
// Consider a flat terrain. It should have tangent be (1, 0, 0) and bitangent be (0, 0, 1) as the UV of the terrain grid mesh is a scale of the world XZ position.
|
|
// In CreateTangentToWorld function (in SpaceTransform.hlsl), it is cross(normal, tangent) * sgn for the bitangent vector.
|
|
// It is not true in a left-handed coordinate system for the terrain bitangent, if we provide 1 as the tangent.w. It would produce (0, 0, -1) instead of (0, 0, 1).
|
|
// Also terrain's tangent calculation was wrong in a left handed system because cross((0,0,1), terrainNormalOS) points to the wrong direction as negative X.
|
|
// Therefore all the 4 xyzw components of the tangent needs to be flipped to correct the tangent frame.
|
|
// (See TerrainLitData.hlsl - GetSurfaceAndBuiltinData)
|
|
float3 tangent = normalize(cross(normal, positiveZ));
|
|
return float4(tangent, -1);
|
|
}
|
|
|
|
|
|
|
|
void TerrainInstancing(inout float4 vertex, inout float3 normal, inout float2 uv)
|
|
{
|
|
#if _MICROTERRAIN && defined(UNITY_INSTANCING_ENABLED) && !_TERRAINBLENDABLESHADER
|
|
|
|
float2 patchVertex = vertex.xy;
|
|
float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);
|
|
|
|
float2 sampleCoords = (patchVertex.xy + instanceData.xy) * instanceData.z; // (xy + float2(xBase,yBase)) * skipScale
|
|
uv = sampleCoords * _TerrainHeightmapRecipSize.zw;
|
|
|
|
float2 sampleUV = (uv / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleUV, 0));
|
|
|
|
vertex.xz = sampleCoords * _TerrainHeightmapScale.xz;
|
|
vertex.y = height * _TerrainHeightmapScale.y;
|
|
|
|
|
|
normal = float3(0, 1, 0);
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
void ApplyMeshModification(inout VertexData input)
|
|
{
|
|
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
|
|
float2 uv = input.texcoord0.xy;
|
|
TerrainInstancing(input.vertex, input.normal, uv);
|
|
input.texcoord0.xy = uv;
|
|
#endif
|
|
#if _PERPIXNORMAL && !_TERRAINBLENDABLESHADER
|
|
input.normal = float3(0,1,0);
|
|
#endif
|
|
|
|
#if _MICROVERSEPREVIEW
|
|
float4 recipSize = _TerrainHeightmapTexture_TexelSize;
|
|
recipSize.zw = (1.0f / (_TerrainHeightmapTexture_TexelSize.zw-1));
|
|
float2 sampleCoords = (input.texcoord0.xy / recipSize.zw + 0.5f) * recipSize.xy;
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleCoords, 0));
|
|
input.vertex.xyz += float3(0,1,0) * height * _TerrainHeight * 2;
|
|
#endif
|
|
|
|
}
|
|
|
|
// called by the template, so we can remove tangent from VertexData
|
|
void ApplyTerrainTangent(inout VertexToPixel input)
|
|
{
|
|
#if (_MICROTERRAIN || _PERPIXNORMAL) && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
|
|
// digger meshes ain't got no tangent either..
|
|
#if _MICRODIGGERMESH && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
void ModifyVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
ApplyMeshModification(v);
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
EncodeVertexWorkflow(v, d);
|
|
#elif _MEGASPLAT
|
|
EncodeMegaSplatVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void ModifyTessellatedVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
#if _MICROVERSEPREVIEW
|
|
v.vertex.y = OffsetVertex(v, d).y;
|
|
#elif _TESSDISTANCE || _TESSEDGE
|
|
v.vertex.xyz += OffsetVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
float3 GetTessFactors ()
|
|
{
|
|
#if _TESSEDGE
|
|
return float3(_TessData1.x, _TessData1.w, 0);
|
|
#endif
|
|
#if _TESSDISTANCE
|
|
return float3(_TessData2.x, _TessData2.y, _TessData1.x);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SurfaceFunction(inout Surface o, inout ShaderData d)
|
|
{
|
|
|
|
float3 worldNormalVertex = d.worldSpaceNormal;
|
|
#if _MICROVERSEPREVIEW
|
|
float2 sampleCoords = d.texcoord0.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif (defined(UNITY_INSTANCING_ENABLED) && _MICROTERRAIN && !_TERRAINBLENDABLESHADER)
|
|
float2 sampleCoords = (d.texcoord0.xy / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif _PERPIXNORMAL && (_MICROTERRAIN || _MICROMESHTERRAIN) && !_TERRAINBLENDABLESHADER
|
|
float2 sampleCoords = (d.texcoord0.xy * _PerPixelNormal_TexelSize.zw + 0.5f) * _PerPixelNormal_TexelSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_PerPixelNormal, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
|
|
float3 geomBitangent = normalize(cross(geomTangent, geomNormal)) * -1;
|
|
#if _MICROMESHTERRAIN
|
|
geomBitangent *= -1;
|
|
#endif
|
|
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#endif
|
|
|
|
#if _TOONPOLYEDGE
|
|
FlatShade(d);
|
|
#endif
|
|
|
|
Input i = DescToInput(d);
|
|
|
|
|
|
|
|
#if _SRPTERRAINBLEND
|
|
MicroSplatLayer l = BlendWithTerrain(d);
|
|
|
|
#if _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(l, normalize(TangentToWorldSpace(d, l.Normal)) * saturate(l.Albedo.z+1));
|
|
#endif
|
|
#else
|
|
MicroSplatLayer l = SurfImpl(i, worldNormalVertex);
|
|
#endif
|
|
|
|
DoDebugOutput(l);
|
|
|
|
|
|
|
|
|
|
o.Albedo = l.Albedo;
|
|
o.Normal = l.Normal;
|
|
o.Smoothness = l.Smoothness;
|
|
o.Occlusion = l.Occlusion;
|
|
o.Metallic = l.Metallic;
|
|
o.Emission = l.Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = l.Specular;
|
|
#endif
|
|
o.Height = l.Height;
|
|
o.Alpha = l.Alpha;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SHADERDESC
|
|
|
|
ShaderData CreateShaderData(VertexToPixel i)
|
|
{
|
|
ShaderData d = (ShaderData)0;
|
|
d.worldSpacePosition = i.worldPos;
|
|
|
|
d.worldSpaceNormal = i.worldNormal;
|
|
d.worldSpaceTangent = i.worldTangent.xyz;
|
|
float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * -1;
|
|
|
|
|
|
d.TBNMatrix = float3x3(d.worldSpaceTangent, bitangent, d.worldSpaceNormal);
|
|
d.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
d.texcoord0 = i.texcoord0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
d.texcoord1 = i.texcoord1;
|
|
// d.texcoord2 = i.texcoord2;
|
|
#endif
|
|
// d.texcoord3 = i.texcoord3;
|
|
// d.vertexColor = i.vertexColor;
|
|
|
|
// these rarely get used, so we back transform them. Usually will be stripped.
|
|
#if _HDRP
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(GetCameraRelativePositionWS(i.worldPos), 1));
|
|
#else
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(i.worldPos, 1));
|
|
#endif
|
|
// d.localSpaceNormal = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldNormal));
|
|
// d.localSpaceTangent = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldTangent.xyz));
|
|
|
|
// d.screenPos = i.screenPos;
|
|
// d.screenUV = i.screenPos.xy / i.screenPos.w;
|
|
|
|
// d.extraV2F0 = i.extraV2F0;
|
|
// d.extraV2F1 = i.extraV2F1;
|
|
// d.extraV2F2 = i.extraV2F2;
|
|
// d.extraV2F3 = i.extraV2F3;
|
|
// d.extraV2F4 = i.extraV2F4;
|
|
// d.extraV2F5 = i.extraV2F5;
|
|
// d.extraV2F6 = i.extraV2F6;
|
|
// d.extraV2F7 = i.extraV2F7;
|
|
|
|
return d;
|
|
}
|
|
// CHAINS
|
|
|
|
void ChainModifyVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
ModifyVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
void ChainModifyTessellatedVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
// d.extraV2F0 = v2p.extraV2F0;
|
|
// d.extraV2F1 = v2p.extraV2F1;
|
|
// d.extraV2F2 = v2p.extraV2F2;
|
|
// d.extraV2F3 = v2p.extraV2F3;
|
|
// d.extraV2F4 = v2p.extraV2F4;
|
|
// d.extraV2F5 = v2p.extraV2F5;
|
|
// d.extraV2F6 = v2p.extraV2F6;
|
|
// d.extraV2F7 = v2p.extraV2F7;
|
|
|
|
ModifyTessellatedVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
|
|
void ChainFinalColorForward(inout Surface l, inout ShaderData d, inout half4 color)
|
|
{
|
|
|
|
}
|
|
|
|
void ChainFinalGBufferStandard(inout Surface s, inout ShaderData d, inout half4 GBuffer0, inout half4 GBuffer1, inout half4 GBuffer2, inout half4 outEmission, inout half4 outShadowMask)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _PASSSHADOW
|
|
float3 _LightDirection;
|
|
float3 _LightPosition;
|
|
#endif
|
|
|
|
// vertex shader
|
|
VertexToPixel Vert (VertexData v)
|
|
{
|
|
|
|
VertexToPixel o = (VertexToPixel)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
|
|
|
|
|
#if !_TESSELLATION_ON
|
|
ChainModifyVertex(v, o);
|
|
#endif
|
|
|
|
o.texcoord0 = v.texcoord0;
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
o.texcoord1 = v.texcoord1;
|
|
// o.texcoord2 = v.texcoord2;
|
|
#endif
|
|
|
|
// o.texcoord3 = v.texcoord3;
|
|
// o.vertexColor = v.vertexColor;
|
|
|
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
|
|
o.worldPos = TransformObjectToWorld(v.vertex.xyz);
|
|
o.worldNormal = TransformObjectToWorldNormal(v.normal);
|
|
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float2 uv1 = v.texcoord1.xy;
|
|
float2 uv2 = v.texcoord2.xy;
|
|
o.worldTangent = float4(TransformObjectToWorldDir(v.tangent.xyz), v.tangent.w);
|
|
#else
|
|
float2 uv1 = v.texcoord0.xy;
|
|
float2 uv2 = uv1;
|
|
#endif
|
|
|
|
// MS Only
|
|
ApplyTerrainTangent(o);
|
|
|
|
|
|
#if _PASSSHADOW
|
|
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
float3 lightDirectionWS = normalize(_LightPosition - o.worldPos);
|
|
#else
|
|
float3 lightDirectionWS = _LightDirection;
|
|
#endif
|
|
// Define shadow pass specific clip position for Universal
|
|
o.pos = TransformWorldToHClip(ApplyShadowBias(o.worldPos, o.worldNormal, lightDirectionWS));
|
|
#if UNITY_REVERSED_Z
|
|
o.pos.z = min(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#else
|
|
o.pos.z = max(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#endif
|
|
#elif _PASSMETA
|
|
#if _MICROTERRAIN
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), v.texcoord0.xy, v.texcoord0.xy, unity_LightmapST, unity_DynamicLightmapST);
|
|
#else
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), uv1, uv2, unity_LightmapST, unity_DynamicLightmapST);
|
|
#endif
|
|
#else
|
|
o.pos = TransformWorldToHClip(o.worldPos);
|
|
#endif
|
|
|
|
|
|
|
|
// o.screenPos = ComputeScreenPos(o.pos, _ProjectionParams.x);
|
|
|
|
|
|
#if _PASSFORWARD || _PASSGBUFFER
|
|
#if _MICROTERRAIN
|
|
OUTPUT_LIGHTMAP_UV(v.texcoord0.xy, unity_LightmapST, o.lightmapUV);
|
|
#else
|
|
OUTPUT_LIGHTMAP_UV(uv1, unity_LightmapST, o.lightmapUV);
|
|
#endif
|
|
OUTPUT_SH(o.worldNormal, o.sh);
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
o.dynamicLightmapUV.xy = uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
|
|
half fogFactor = 0;
|
|
#if defined(_FOG_FRAGMENT)
|
|
fogFactor = ComputeFogFactor(o.pos.z);
|
|
#endif
|
|
#if _BAKEDLIT
|
|
half3 vertexLight = VertexLighting(o.worldPos, o.worldNormal);
|
|
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
|
|
#else
|
|
o.fogFactorAndVertexLight = half4(fogFactor, 0,0,0);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
|
|
o.shadowCoord = GetShadowCoord(vertexInput);
|
|
#endif
|
|
|
|
return o;
|
|
}
|
|
|
|
|
|
|
|
|
|
// fragment shader
|
|
half4 Frag (VertexToPixel IN
|
|
#ifdef _DEPTHOFFSET_ON
|
|
, out float outputDepth : SV_Depth
|
|
#endif
|
|
) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
|
|
ShaderData d = CreateShaderData(IN);
|
|
Surface l = (Surface)0;
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
l.outputDepth = outputDepth;
|
|
#endif
|
|
|
|
l.Albedo = half3(0.5, 0.5, 0.5);
|
|
l.Normal = float3(0,0,1);
|
|
l.Occlusion = 1;
|
|
l.Alpha = 1;
|
|
|
|
SurfaceFunction(l, d);
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
outputDepth = l.outputDepth;
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ENDHLSL
|
|
|
|
}
|
|
|
|
|
|
|
|
Pass
|
|
{
|
|
Name "DepthOnly"
|
|
Tags
|
|
{
|
|
"LightMode" = "DepthOnly"
|
|
}
|
|
|
|
// Render State
|
|
Blend One Zero, One Zero
|
|
Cull Back
|
|
ZTest LEqual
|
|
ZWrite On
|
|
ColorMask 0
|
|
|
|
|
|
|
|
HLSLPROGRAM
|
|
|
|
#pragma vertex Vert
|
|
#pragma fragment Frag
|
|
|
|
|
|
#define SHADERPASS SHADERPASS_DEPTHNORMALSONLY
|
|
#define _PASSDEPTH 1
|
|
#define _PASSDEPTHNORMALS 1
|
|
|
|
#pragma target 3.5
|
|
#pragma prefer_hlslcc gles
|
|
#pragma exclude_renderers d3d11_9x
|
|
#pragma multi_compile_instancing
|
|
#pragma multi_compile _ DOTS_INSTANCING_ON
|
|
#pragma multi_compile_local _ _ALPHATEST_ON
|
|
|
|
|
|
#define _MICROSPLAT 1
|
|
#define _MICROPOLARISMESH 1
|
|
#define _USEGRADMIP 1
|
|
#define _PERTEXUVSCALEOFFSET 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
#define _MSRENDERLOOP_UNITYLD 1
|
|
#define _MSRENDERLOOP_UNITYURP2020 1
|
|
#define _MSRENDERLOOP_UNITYURP2021 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
|
|
|
|
|
|
#define _URP 1
|
|
|
|
|
|
// Includes
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
|
|
#include "Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariablesFunctions.hlsl"
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, float3x3(d.worldSpaceTangent, cross(d.worldSpaceTangent, d.worldSpaceNormal), d.worldSpaceNormal))
|
|
|
|
|
|
#define UnityObjectToWorldNormal(normal) mul(GetObjectToWorldMatrix(), normal)
|
|
|
|
#define _WorldSpaceLightPos0 _MainLightPosition
|
|
|
|
#define UNITY_DECLARE_TEX2D(name) TEXTURE2D(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2D_NOSAMPLER(name) TEXTURE2D(name);
|
|
#define UNITY_DECLARE_TEX2DARRAY(name) TEXTURE2D_ARRAY(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2DARRAY_NOSAMPLER(name) TEXTURE2D_ARRAY(name);
|
|
|
|
#define UNITY_SAMPLE_TEX2DARRAY(tex,coord) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, coord.xy, coord.z)
|
|
#define UNITY_SAMPLE_TEX2DARRAY_LOD(tex,coord,lod) SAMPLE_TEXTURE2D_ARRAY_LOD(tex, sampler##tex, coord.xy, coord.z, lod)
|
|
#define UNITY_SAMPLE_TEX2D(tex, coord) SAMPLE_TEXTURE2D(tex, sampler##tex, coord)
|
|
#define UNITY_SAMPLE_TEX2D_SAMPLER(tex, samp, coord) SAMPLE_TEXTURE2D(tex, sampler##samp, coord)
|
|
|
|
#if defined(UNITY_COMPILER_HLSL)
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
|
|
#else
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name)
|
|
#endif
|
|
|
|
#define sampler2D_float sampler2D
|
|
#define sampler2D_half sampler2D
|
|
|
|
|
|
|
|
// data across stages, stripped like the above.
|
|
struct VertexToPixel
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float3 worldPos : TEXCOORD0;
|
|
float3 worldNormal : TEXCOORD1;
|
|
float4 worldTangent : TEXCOORD2;
|
|
float4 texcoord0 : TEXCCOORD3;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 texcoord1 : TEXCCOORD4;
|
|
// float4 texcoord2 : TEXCCOORD5;
|
|
#endif
|
|
// float4 texcoord3 : TEXCCOORD6;
|
|
// float4 screenPos : TEXCOORD7;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
// float4 extraV2F0 : TEXCOORD13;
|
|
// float4 extraV2F1 : TEXCOORD14;
|
|
// float4 extraV2F2 : TEXCOORD15;
|
|
// float4 extraV2F3 : TEXCOORD16;
|
|
// float4 extraV2F4 : TEXCOORD17;
|
|
// float4 extraV2F5 : TEXCOORD18;
|
|
// float4 extraV2F6 : TEXCOORD19;
|
|
// float4 extraV2F7 : TEXCOORD20;
|
|
|
|
|
|
#if defined(LIGHTMAP_ON)
|
|
float2 lightmapUV : TEXCOORD8;
|
|
#endif
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
float2 dynamicLightmapUV : TEXCOORD9;
|
|
#endif
|
|
#if !defined(LIGHTMAP_ON)
|
|
float3 sh : TEXCOORD10;
|
|
#endif
|
|
|
|
float4 fogFactorAndVertexLight : TEXCOORD11;
|
|
float4 shadowCoord : TEXCOORD12;
|
|
|
|
#if UNITY_ANY_INSTANCING_ENABLED
|
|
uint instanceID : CUSTOM_INSTANCE_ID;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_MULTIVIEW_ENABLED)) || (defined(UNITY_STEREO_INSTANCING_ENABLED) && (defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)))
|
|
uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_INSTANCING_ENABLED))
|
|
uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex;
|
|
#endif
|
|
#if defined(SHADER_STAGE_FRAGMENT) && defined(VARYINGS_NEED_CULLFACE)
|
|
FRONT_FACE_TYPE cullFace : FRONT_FACE_SEMANTIC;
|
|
#endif
|
|
};
|
|
|
|
|
|
// TEMPLATE_SHARED
|
|
|
|
// data describing the user output of a pixel
|
|
struct Surface
|
|
{
|
|
half3 Albedo;
|
|
half Height;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half3 Emission;
|
|
half Metallic;
|
|
half3 Specular;
|
|
half Occlusion;
|
|
half Alpha;
|
|
// HDRP Only
|
|
half SpecularOcclusion;
|
|
half SubsurfaceMask;
|
|
half Thickness;
|
|
half CoatMask;
|
|
half Anisotropy;
|
|
half IridescenceMask;
|
|
half IridescenceThickness;
|
|
};
|
|
|
|
// data the user might need, this will grow to be big. But easy to strip
|
|
struct ShaderData
|
|
{
|
|
float3 localSpacePosition;
|
|
float3 localSpaceNormal;
|
|
float3 localSpaceTangent;
|
|
|
|
float3 worldSpacePosition;
|
|
float3 worldSpaceNormal;
|
|
float3 worldSpaceTangent;
|
|
|
|
float3 worldSpaceViewDir;
|
|
float3 tangentSpaceViewDir;
|
|
|
|
float4 texcoord0;
|
|
float4 texcoord1;
|
|
float4 texcoord2;
|
|
float4 texcoord3;
|
|
|
|
float2 screenUV;
|
|
float4 screenPos;
|
|
|
|
float4 vertexColor;
|
|
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
|
|
float3x3 TBNMatrix;
|
|
};
|
|
|
|
struct VertexData
|
|
{
|
|
#if SHADER_TARGET > 30 && _PLANETCOMPUTE
|
|
// // uint vertexID : SV_VertexID;
|
|
#endif
|
|
float4 vertex : POSITION;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD4; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD5; // Add Precomputed Velocity (Alembic computes velocities on runtime side).
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct TessVertex
|
|
{
|
|
float4 vertex : INTERNALTESSPOS;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
// float4 extraV2F0 : TEXCOORD4;
|
|
// float4 extraV2F1 : TEXCOORD5;
|
|
// float4 extraV2F2 : TEXCOORD6;
|
|
// float4 extraV2F3 : TEXCOORD7;
|
|
// float4 extraV2F4 : TEXCOORD8;
|
|
// float4 extraV2F5 : TEXCOORD9;
|
|
// float4 extraV2F6 : TEXCOORD10;
|
|
// float4 extraV2F7 : TEXCOORD11;
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD12; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD13;
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
struct ExtraV2F
|
|
{
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
};
|
|
|
|
|
|
float3 WorldToTangentSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(d.TBNMatrix, normal);
|
|
}
|
|
|
|
float3 TangentToWorldSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(normal, d.TBNMatrix);
|
|
}
|
|
|
|
// in this case, make standard more like SRPs, because we can't fix
|
|
// GetWorldToObjectMatrix() in HDRP, since it already does macro-fu there
|
|
|
|
#if _STANDARD
|
|
float3 TransformWorldToObject(float3 p) { return mul(GetWorldToObjectMatrix(), float4(p, 1)); };
|
|
float3 TransformObjectToWorld(float3 p) { return mul(GetObjectToWorldMatrix(), float4(p, 1)); };
|
|
float4 TransformWorldToObject(float4 p) { return mul(GetWorldToObjectMatrix(), p); };
|
|
float4 TransformObjectToWorld(float4 p) { return mul(GetObjectToWorldMatrix(), p); };
|
|
float4x4 GetWorldToObjectMatrix() { return GetWorldToObjectMatrix(); }
|
|
float4x4 GetObjectToWorldMatrix() { return GetObjectToWorldMatrix(); }
|
|
#endif
|
|
|
|
float3 GetCameraWorldPosition()
|
|
{
|
|
#if _HDRP
|
|
return GetCameraRelativePositionWS(_WorldSpaceCameraPos);
|
|
#else
|
|
return _WorldSpaceCameraPos;
|
|
#endif
|
|
}
|
|
|
|
|
|
#if _HDRP
|
|
|
|
half3 UnpackNormalmapRGorAG(half4 packednormal)
|
|
{
|
|
// This do the trick
|
|
packednormal.x *= packednormal.w;
|
|
|
|
half3 normal;
|
|
normal.xy = packednormal.xy * 2 - 1;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
half3 UnpackNormal(half4 packednormal)
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
return packednormal.xyz * 2 - 1;
|
|
#else
|
|
return UnpackNormalmapRGorAG(packednormal);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if _HDRP || _URP
|
|
|
|
half3 UnpackScaleNormal(half4 packednormal, half scale)
|
|
{
|
|
#ifndef UNITY_NO_DXT5nm
|
|
// Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
|
|
// Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
|
|
packednormal.x *= packednormal.w;
|
|
#endif
|
|
half3 normal;
|
|
normal.xy = (packednormal.xy * 2 - 1) * scale;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void GetSun(out float3 lightDir, out float3 color)
|
|
{
|
|
lightDir = float3(0.5, 0.5, 0);
|
|
color = 1;
|
|
#if _HDRP
|
|
if (_DirectionalLightCount > 0)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[0];
|
|
lightDir = -light.forward.xyz;
|
|
color = light.color;
|
|
}
|
|
#elif _STANDARD
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
color = _LightColor0.rgb;
|
|
#elif _URP
|
|
Light light = GetMainLight();
|
|
lightDir = light.direction;
|
|
color = light.color;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
|
|
|
|
|
|
#if _MESHSUBARRAY
|
|
half4 _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
float4 _Diffuse_TexelSize;
|
|
float4 _NormalSAO_TexelSize;
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
float _HybridHeightBlendDistance;
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
float4 _SmoothAO_TexelSize;
|
|
#endif
|
|
|
|
#ifdef _ALPHATEST_ON
|
|
float4 _TerrainHolesTexture_TexelSize;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
float4 _Specular_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
float4 _EmissiveMetal_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
half _EmissiveMult;
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
half _AutoNormalHeightScale;
|
|
#endif
|
|
|
|
float4 _UVScale; // scale and offset
|
|
|
|
half _Contrast;
|
|
|
|
|
|
|
|
#if _VSSHADOWMAP
|
|
float4 gVSSunDirection;
|
|
#endif
|
|
|
|
#if _FORCELOCALSPACE && _PLANETVECTORS
|
|
float4x4 _PQSToLocal;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
float4x4 _GlobalOriginMTX;
|
|
#endif
|
|
|
|
float4 _Control0_TexelSize;
|
|
#if _CUSTOMSPLATTEXTURES
|
|
float4 _CustomControl0_TexelSize;
|
|
#endif
|
|
float4 _PerPixelNormal_TexelSize;
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
float2 _NoiseUVParams;
|
|
#endif
|
|
|
|
float4 _PerTexProps_TexelSize;
|
|
|
|
#if _SURFACENORMALS
|
|
float3 surfTangent;
|
|
float3 surfBitangent;
|
|
float3 surfNormal;
|
|
#endif
|
|
|
|
|
|
|
|
CBUFFER_END
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, data.TBN)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// In Unity 2020.3LTS, Unity will spew tons of errors about missing this sampler in
|
|
// URP, even though it shouldn't be required.
|
|
TEXTURE2D(_MainTex);
|
|
|
|
// globals, outside of CBuffer, but used by more than one module
|
|
float3 _gGlitterLightDir;
|
|
float3 _gGlitterLightWorldPos;
|
|
half3 _gGlitterLightColor;
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
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)
|
|
float4 _TerrainNormalmapTexture_TexelSize;
|
|
#endif
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
TEXTURE2D(_TerrainHeightmapTexture);
|
|
float4 _TerrainHeightmapTexture_TexelSize;
|
|
TEXTURE2D(_TerrainNormalmapTexture);
|
|
#endif
|
|
|
|
UNITY_INSTANCING_BUFFER_START(Terrain)
|
|
UNITY_DEFINE_INSTANCED_PROP(float4, _TerrainPatchInstanceData) // float4(xBase, yBase, skipScale, ~)
|
|
UNITY_INSTANCING_BUFFER_END(Terrain)
|
|
|
|
|
|
|
|
|
|
// dynamic branching helpers, for regular and aggressive branching
|
|
// debug mode shows how many samples using branching will save us.
|
|
//
|
|
// These macros are always used instead of the UNITY_BRANCH macro
|
|
// to maintain debug displays and allow branching to be disabled
|
|
// on as granular level as we want.
|
|
|
|
#if _BRANCHSAMPLES
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++; if (w > 0)
|
|
#else
|
|
#define MSBRANCH(w) UNITY_BRANCH if (w > 0)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++;
|
|
#else
|
|
#define MSBRANCH(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _BRANCHSAMPLESAGR
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER ||_DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++; if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++; if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++; if (w > 0.001)
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) UNITY_BRANCH if (w > 0.001)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++;
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++;
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++;
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w)
|
|
#define MSBRANCHCLUSTER(w)
|
|
#define MSBRANCHOTHER(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _DEBUG_SAMPLECOUNT
|
|
int _sampleCount;
|
|
#define COUNTSAMPLE { _sampleCount++; }
|
|
#else
|
|
#define COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _DEBUG_PROCLAYERS
|
|
int _procLayerCount;
|
|
#define COUNTPROCLAYER { _procLayerCount++; }
|
|
#else
|
|
#define COUNTPROCLAYER
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
TEXTURE2D(_DebugWorldPos);
|
|
TEXTURE2D(_DebugWorldNormal);
|
|
#endif
|
|
|
|
|
|
// splat
|
|
UNITY_DECLARE_TEX2DARRAY(_Diffuse);
|
|
UNITY_DECLARE_TEX2DARRAY(_NormalSAO);
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
TEXTURE2D(_NoiseUV);
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
UNITY_DECLARE_TEX2DARRAY(_SmoothAO);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
UNITY_DECLARE_TEX2DARRAY(_Specular);
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
UNITY_DECLARE_TEX2DARRAY(_EmissiveMetal);
|
|
#endif
|
|
|
|
TEXTURE2D(_PerPixelNormal);
|
|
|
|
SamplerState shared_linear_clamp_sampler;
|
|
SamplerState shared_point_clamp_sampler;
|
|
|
|
TEXTURE2D(_Control0);
|
|
#if _CUSTOMSPLATTEXTURES
|
|
TEXTURE2D(_CustomControl0);
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_CustomControl1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_CustomControl2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_CustomControl3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl7);
|
|
#endif
|
|
#else
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_Control1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_Control2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_Control3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_Control7);
|
|
#endif
|
|
#endif
|
|
|
|
TEXTURE2D_FLOAT(_PerTexProps);
|
|
|
|
struct DecalLayer
|
|
{
|
|
float3 uv;
|
|
float2 dx;
|
|
float2 dy;
|
|
int decalIndex;
|
|
bool dynamic;
|
|
};
|
|
|
|
struct DecalOutput
|
|
{
|
|
DecalLayer l0;
|
|
DecalLayer l1;
|
|
DecalLayer l2;
|
|
DecalLayer l3;
|
|
|
|
half4 Weights;
|
|
half4 Indexes;
|
|
half4 fxLevels;
|
|
|
|
};
|
|
|
|
|
|
struct TriGradMipFormat
|
|
{
|
|
float4 d0;
|
|
float4 d1;
|
|
float4 d2;
|
|
};
|
|
|
|
float InverseLerp(float x, float y, float v) { return (v-x)/max(y-x, 0.001); }
|
|
float2 InverseLerp(float2 x, float2 y, float2 v) { return (v-x)/max(y-x, float2(0.001, 0.001)); }
|
|
float3 InverseLerp(float3 x, float3 y, float3 v) { return (v-x)/max(y-x, float3(0.001, 0.001, 0.001)); }
|
|
float4 InverseLerp(float4 x, float4 y, float4 v) { return (v-x)/max(y-x, float4(0.001, 0.001, 0.001, 0.001)); }
|
|
|
|
|
|
// 2019.3 holes
|
|
#ifdef _ALPHATEST_ON
|
|
TEXTURE2D(_TerrainHolesTexture);
|
|
|
|
void ClipHoles(float2 uv)
|
|
{
|
|
float hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, shared_linear_clamp_sampler, uv).r;
|
|
COUNTSAMPLE
|
|
clip(hole < 0.5f ? -1 : 1);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT TriGradMipFormat
|
|
#define INITMIPFORMAT (TriGradMipFormat)0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float3
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float3
|
|
#endif
|
|
#else
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT float4
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float
|
|
#endif
|
|
#endif
|
|
|
|
float2 TotalOne(float2 v) { return v * (1.0 / max(v.x + v.y, 0.001)); }
|
|
float3 TotalOne(float3 v) { return v * (1.0 / max(v.x + v.y + v.z, 0.001)); }
|
|
float4 TotalOne(float4 v) { return v * (1.0 / max(v.x + v.y + v.z + v.w, 0.001)); }
|
|
|
|
float2 RotateUV(float2 uv, float amt)
|
|
{
|
|
uv -=0.5;
|
|
float s = sin ( amt);
|
|
float c = cos ( amt );
|
|
float2x2 mtx = float2x2( c, -s, s, c);
|
|
mtx *= 0.5;
|
|
mtx += 0.5;
|
|
mtx = mtx * 2-1;
|
|
uv = mul ( uv, mtx );
|
|
uv += 0.5;
|
|
return uv;
|
|
}
|
|
|
|
float4 DecodeToFloat4(float v)
|
|
{
|
|
uint vi = (uint)(v * (256.0f * 256.0f * 256.0f * 256.0f));
|
|
int ex = (int)(vi / (256 * 256 * 256) % 256);
|
|
int ey = (int)((vi / (256 * 256)) % 256);
|
|
int ez = (int)((vi / (256)) % 256);
|
|
int ew = (int)(vi % 256);
|
|
float4 e = float4(ex / 255.0, ey / 255.0, ez / 255.0, ew / 255.0);
|
|
return e;
|
|
}
|
|
|
|
|
|
|
|
struct Input
|
|
{
|
|
ShaderData shaderData;
|
|
float2 uv_Control0;
|
|
float2 uv2_Diffuse;
|
|
|
|
float worldHeight;
|
|
float3 worldUpVector;
|
|
|
|
float3 viewDir;
|
|
float3 worldPos;
|
|
float3 worldNormal;
|
|
float4 color;
|
|
float3x3 TBN;
|
|
|
|
// vertex/digger workflow data
|
|
half4 w0;
|
|
half4 w1;
|
|
half4 w2;
|
|
half4 w3;
|
|
half4 w4;
|
|
half4 w5;
|
|
half4 w6;
|
|
|
|
// megasplat data
|
|
half4 layer0;
|
|
half4 layer1;
|
|
half3 baryWeights;
|
|
half4 scatter0;
|
|
half4 scatter1;
|
|
|
|
// wetness, puddles, streams, lava from vertex or megasplat
|
|
half4 fx;
|
|
// snow min, snow max
|
|
half4 fx2;
|
|
|
|
|
|
};
|
|
|
|
struct TriplanarConfig
|
|
{
|
|
float3x3 uv0;
|
|
float3x3 uv1;
|
|
float3x3 uv2;
|
|
float3x3 uv3;
|
|
half3 pN;
|
|
half3 pN0;
|
|
half3 pN1;
|
|
half3 pN2;
|
|
half3 pN3;
|
|
half3 axisSign;
|
|
Input IN;
|
|
};
|
|
|
|
|
|
struct Config
|
|
{
|
|
float2 uv;
|
|
float3 uv0;
|
|
float3 uv1;
|
|
float3 uv2;
|
|
float3 uv3;
|
|
|
|
half4 cluster0;
|
|
half4 cluster1;
|
|
half4 cluster2;
|
|
half4 cluster3;
|
|
|
|
};
|
|
|
|
|
|
struct MicroSplatLayer
|
|
{
|
|
half3 Albedo;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half Occlusion;
|
|
half Metallic;
|
|
half Height;
|
|
half3 Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
half3 Specular;
|
|
#endif
|
|
half Alpha;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// raw, unblended samples from arrays
|
|
struct RawSamples
|
|
{
|
|
half4 albedo0;
|
|
half4 albedo1;
|
|
half4 albedo2;
|
|
half4 albedo3;
|
|
#if _SURFACENORMALS
|
|
half3 surf0;
|
|
half3 surf1;
|
|
half3 surf2;
|
|
half3 surf3;
|
|
#endif
|
|
|
|
half4 normSAO0;
|
|
half4 normSAO1;
|
|
half4 normSAO2;
|
|
half4 normSAO3;
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALEMIS || _GLOBALSMOOTHAOMETAL || _PERTEXSSS || _PERTEXRIMLIGHT
|
|
half4 emisMetal0;
|
|
half4 emisMetal1;
|
|
half4 emisMetal2;
|
|
half4 emisMetal3;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
half3 specular0;
|
|
half3 specular1;
|
|
half3 specular2;
|
|
half3 specular3;
|
|
#endif
|
|
};
|
|
|
|
void InitRawSamples(inout RawSamples s)
|
|
{
|
|
s.normSAO0 = half4(0,0,0,1);
|
|
s.normSAO1 = half4(0,0,0,1);
|
|
s.normSAO2 = half4(0,0,0,1);
|
|
s.normSAO3 = half4(0,0,0,1);
|
|
#if _SURFACENORMALS
|
|
s.surf0 = half3(0,0,1);
|
|
s.surf1 = half3(0,0,1);
|
|
s.surf2 = half3(0,0,1);
|
|
s.surf3 = half3(0,0,1);
|
|
#endif
|
|
}
|
|
|
|
float3 GetGlobalLightDir(Input i)
|
|
{
|
|
float3 lightDir = float3(1,0,0);
|
|
|
|
#if _HDRP || PASS_DEFERRED
|
|
lightDir = normalize(_gGlitterLightDir.xyz);
|
|
#elif _URP
|
|
lightDir = GetMainLight().direction;
|
|
#else
|
|
#ifndef USING_DIRECTIONAL_LIGHT
|
|
lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
|
|
#else
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
#endif
|
|
#endif
|
|
return lightDir;
|
|
}
|
|
|
|
float3x3 GetTBN(Input i)
|
|
{
|
|
return i.TBN;
|
|
}
|
|
|
|
float3 GetGlobalLightDirTS(Input i)
|
|
{
|
|
float3 lightDirWS = GetGlobalLightDir(i);
|
|
return mul(GetTBN(i), lightDirWS);
|
|
}
|
|
|
|
half3 GetGlobalLightColor()
|
|
{
|
|
#if _HDRP || PASS_DEFERRED
|
|
return _gGlitterLightColor;
|
|
#elif _URP
|
|
return (GetMainLight().color);
|
|
#else
|
|
return _LightColor0.rgb;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 FuzzyShade(half3 color, half3 normal, half coreMult, half edgeMult, half power, float3 viewDir)
|
|
{
|
|
half dt = saturate(dot(viewDir, normal));
|
|
half dark = 1.0 - (coreMult * dt);
|
|
half edge = pow(1-dt, power) * edgeMult;
|
|
return color * (dark + edge);
|
|
}
|
|
|
|
half3 ComputeSSS(Input i, float3 V, float3 N, half3 tint, half thickness, half distortion, half scale, half power)
|
|
{
|
|
float3 L = GetGlobalLightDir(i);
|
|
half3 lightColor = GetGlobalLightColor();
|
|
float3 H = normalize(L + N * distortion);
|
|
float VdotH = pow(saturate(dot(V, -H)), power) * scale;
|
|
float3 I = (VdotH) * thickness;
|
|
return lightColor * I * tint;
|
|
}
|
|
|
|
|
|
#if _MAX2LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
#elif _MAX3LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
#else
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
#endif
|
|
|
|
|
|
#if _MAX3LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#elif _MAX2LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#else
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##3 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv3.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#endif
|
|
|
|
half2 BlendNormal2(half2 base, half2 blend) { return normalize(half3(base.xy + blend.xy, 1)).xy; }
|
|
half3 BlendOverlay(half3 base, half3 blend) { return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))); }
|
|
half3 BlendMult2X(half3 base, half3 blend) { return (base * (blend * 2)); }
|
|
half3 BlendLighterColor(half3 s, half3 d) { return (s.x + s.y + s.z > d.x + d.y + d.z) ? s : d; }
|
|
|
|
|
|
#if _SURFACENORMALS
|
|
|
|
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
|
|
|
|
|
|
|
|
void ConstructSurfaceGradientTBN(Input i)
|
|
{
|
|
float3x3 tbn = GetTBN(i);
|
|
float3 t = tbn[0];
|
|
float3 b = tbn[1];
|
|
float3 n = tbn[2];
|
|
|
|
surfNormal = n;//mul(GetWorldToObjectMatrix(), float4(n, 1)).xyz;
|
|
surfTangent = t;//mul(GetWorldToObjectMatrix(), float4(t, 1)).xyz;
|
|
surfBitangent = b;//cross(surfNormal, surfTangent);
|
|
|
|
float renormFactor = 1.0 / length(surfNormal);
|
|
surfNormal *= renormFactor;
|
|
surfTangent *= renormFactor;
|
|
surfBitangent *= renormFactor;
|
|
}
|
|
|
|
half3 SurfaceGradientFromTBN(half2 deriv)
|
|
{
|
|
return deriv.x * surfTangent + deriv.y * surfBitangent;
|
|
}
|
|
|
|
// Input: vM is tangent space normal in [-1;1].
|
|
// Output: convert vM to a derivative.
|
|
half2 TspaceNormalToDerivative(half3 vM)
|
|
{
|
|
const half scale = 1.0/128.0;
|
|
|
|
// Ensure vM delivers a positive third component using abs() and
|
|
// constrain vM.z so the range of the derivative is [-128; 128].
|
|
const half3 vMa = abs(vM);
|
|
const half z_ma = max(vMa.z, scale*max(vMa.x, vMa.y));
|
|
|
|
return -half2(vM.x, vM.y)/z_ma;
|
|
}
|
|
|
|
// Used to produce a surface gradient from the gradient of a volume
|
|
// bump function such as 3D Perlin noise. Equation 2 in [Mik10].
|
|
half3 SurfgradFromVolumeGradient(half3 grad)
|
|
{
|
|
return grad - dot(surfNormal, grad) * surfNormal;
|
|
}
|
|
|
|
half3 SurfgradFromTriplanarProjection(half3 pN, half2 xPlaneTN, half2 yPlaneTN, half2 zPlaneTN)
|
|
{
|
|
const half w0 = pN.x;
|
|
const half w1 = pN.y;
|
|
const half w2 = pN.z;
|
|
|
|
// X-plane tangent normal to gradient derivative
|
|
xPlaneTN = xPlaneTN * 2.0 - 1.0;
|
|
half xPlaneRcpZ = rsqrt(max(1 - dot(xPlaneTN.x, xPlaneTN.x) - dot(xPlaneTN.y, xPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_xplane = xPlaneTN * -xPlaneRcpZ;
|
|
|
|
// Y-plane tangent normal to gradient derivative
|
|
yPlaneTN = yPlaneTN * 2.0 - 1.0;
|
|
half yPlaneRcpZ = rsqrt(max(1 - dot(yPlaneTN.x, yPlaneTN.x) - dot(yPlaneTN.y, yPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_yplane = yPlaneTN * -yPlaneRcpZ;
|
|
|
|
// Z-plane tangent normal to gradient derivative
|
|
zPlaneTN = zPlaneTN * 2.0 - 1.0;
|
|
half zPlaneRcpZ = rsqrt(max(1 - dot(zPlaneTN.x, zPlaneTN.x) - dot(zPlaneTN.y, zPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_zplane = zPlaneTN * -zPlaneRcpZ;
|
|
|
|
// Assume deriv xplane, deriv yplane, and deriv zplane are
|
|
// sampled using (z,y), (x,z), and (x,y), respectively.
|
|
// Positive scales of the lookup coordinate will work
|
|
// as well, but for negative scales the derivative components
|
|
// will need to be negated accordingly.
|
|
float3 grad = float3(w2*d_zplane.x + w1*d_yplane.x,
|
|
w2*d_zplane.y + w0*d_xplane.y,
|
|
w0*d_xplane.x + w1*d_yplane.y);
|
|
|
|
return SurfgradFromVolumeGradient(grad);
|
|
}
|
|
|
|
half3 ConvertNormalToGradient(half3 normal)
|
|
{
|
|
half2 deriv = TspaceNormalToDerivative(normal);
|
|
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
half3 ConvertNormal2ToGradient(half2 packedNormal)
|
|
{
|
|
half2 tNormal = packedNormal;
|
|
half rcpZ = rsqrt(max(1 - dot(tNormal.x, tNormal.x) - dot(tNormal.y, tNormal.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
half2 deriv = tNormal * -rcpZ;
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
|
|
half3 ResolveNormalFromSurfaceGradient(half3 gradient)
|
|
{
|
|
return normalize(surfNormal - gradient);
|
|
}
|
|
|
|
|
|
#endif // _SURFACENORMALS
|
|
|
|
void BlendNormalPerTex(inout RawSamples o, half2 noise, float4 fades)
|
|
{
|
|
#if _SURFACENORMALS
|
|
float3 grad = ConvertNormal2ToGradient(noise.xy);
|
|
o.surf0 += grad * fades.x;
|
|
o.surf1 += grad * fades.y;
|
|
#if !_MAX2LAYER
|
|
o.surf2 += grad * fades.z;
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.surf3 += grad * fades.w;
|
|
#endif
|
|
#else
|
|
o.normSAO0.xy = lerp(o.normSAO0.xy, BlendNormal2(o.normSAO0.xy, noise.xy), fades.x);
|
|
o.normSAO1.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#if !_MAX2LAYER
|
|
o.normSAO2.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO2.xy, noise.xy), fades.y);
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.normSAO3.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 BlendNormal3(half3 n1, half3 n2)
|
|
{
|
|
n1 += float3( 0, 0, 1);
|
|
n2 *= float3(-1, -1, 1);
|
|
return n1*dot(n1, n2) / n1.z - n2;
|
|
}
|
|
|
|
half2 TransformTriplanarNormal(Input IN, float3x3 t2w, half3 axisSign, half3 absVertNormal,
|
|
half3 pN, half2 a0, half2 a1, half2 a2)
|
|
{
|
|
|
|
a0 = a0 * 2 - 1;
|
|
a1 = a1 * 2 - 1;
|
|
a2 = a2 * 2 - 1;
|
|
|
|
a0.x *= axisSign.x;
|
|
a1.x *= axisSign.y;
|
|
a2.x *= axisSign.z;
|
|
|
|
half3 n0 = half3(a0.xy, 1);
|
|
half3 n1 = half3(a1.xy, 1);
|
|
half3 n2 = half3(a2.xy, 1);
|
|
|
|
float3 wn = IN.worldNormal;
|
|
|
|
n0 = BlendNormal3(half3(wn.zy, absVertNormal.x), n0);
|
|
n1 = BlendNormal3(half3(wn.xz, absVertNormal.y), n1 * float3(-1, 1, 1));
|
|
n2 = BlendNormal3(half3(wn.xy, absVertNormal.z), n2);
|
|
|
|
n0.z *= axisSign.x;
|
|
n1.z *= axisSign.y;
|
|
n2.z *= -axisSign.z;
|
|
|
|
half3 worldNormal = (n0.zyx * pN.x + n1.xzy * pN.y + n2.xyz * pN.z);
|
|
return mul(t2w, worldNormal).xy;
|
|
|
|
}
|
|
|
|
// funcs
|
|
|
|
inline half MSLuminance(half3 rgb)
|
|
{
|
|
#ifdef UNITY_COLORSPACE_GAMMA
|
|
return dot(rgb, half3(0.22, 0.707, 0.071));
|
|
#else
|
|
return dot(rgb, half3(0.0396819152, 0.458021790, 0.00609653955));
|
|
#endif
|
|
}
|
|
|
|
|
|
float2 Hash2D( float2 x )
|
|
{
|
|
float2 k = float2( 0.3183099, 0.3678794 );
|
|
x = x*k + k.yx;
|
|
return -1.0 + 2.0*frac( 16.0 * k*frac( x.x*x.y*(x.x+x.y)) );
|
|
}
|
|
|
|
float Noise2D(float2 p )
|
|
{
|
|
float2 i = floor( p );
|
|
float2 f = frac( p );
|
|
|
|
float2 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( dot( Hash2D( i + float2(0.0,0.0) ), f - float2(0.0,0.0) ),
|
|
dot( Hash2D( i + float2(1.0,0.0) ), f - float2(1.0,0.0) ), u.x),
|
|
lerp( dot( Hash2D( i + float2(0.0,1.0) ), f - float2(0.0,1.0) ),
|
|
dot( Hash2D( i + float2(1.0,1.0) ), f - float2(1.0,1.0) ), u.x), u.y);
|
|
}
|
|
|
|
float FBM2D(float2 uv)
|
|
{
|
|
float f = 0.5000*Noise2D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise2D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise2D( uv );
|
|
return f;
|
|
}
|
|
|
|
float3 Hash3D( float3 p )
|
|
{
|
|
p = float3( dot(p,float3(127.1,311.7, 74.7)),
|
|
dot(p,float3(269.5,183.3,246.1)),
|
|
dot(p,float3(113.5,271.9,124.6)));
|
|
|
|
return -1.0 + 2.0*frac(sin(p)*437.5453123);
|
|
}
|
|
|
|
float Noise3D( float3 p )
|
|
{
|
|
float3 i = floor( p );
|
|
float3 f = frac( p );
|
|
|
|
float3 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,0.0) ), f - float3(0.0,0.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,0.0) ), f - float3(1.0,0.0,0.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,0.0) ), f - float3(0.0,1.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,0.0) ), f - float3(1.0,1.0,0.0) ), u.x), u.y),
|
|
lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,1.0) ), f - float3(0.0,0.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,1.0) ), f - float3(1.0,0.0,1.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,1.0) ), f - float3(0.0,1.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,1.0) ), f - float3(1.0,1.0,1.0) ), u.x), u.y), u.z );
|
|
}
|
|
|
|
float FBM3D(float3 uv)
|
|
{
|
|
float f = 0.5000*Noise3D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise3D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise3D( uv );
|
|
return f;
|
|
}
|
|
|
|
|
|
|
|
float GetSaturation(float3 c)
|
|
{
|
|
float mi = min(min(c.x, c.y), c.z);
|
|
float ma = max(max(c.x, c.y), c.z);
|
|
return (ma - mi)/(ma + 1e-7);
|
|
}
|
|
|
|
// Better Color Lerp, does not have darkening issue
|
|
float3 BetterColorLerp(float3 a, float3 b, float x)
|
|
{
|
|
float3 ic = lerp(a, b, x) + float3(1e-6,0.0,0.0);
|
|
float sd = abs(GetSaturation(ic) - lerp(GetSaturation(a), GetSaturation(b), x));
|
|
|
|
float3 dir = normalize(float3(2.0 * ic.x - ic.y - ic.z, 2.0 * ic.y - ic.x - ic.z, 2.0 * ic.z - ic.y - ic.x));
|
|
float lgt = dot(float3(1.0, 1.0, 1.0), ic);
|
|
|
|
float ff = dot(dir, normalize(ic));
|
|
|
|
const float dsp_str = 1.5;
|
|
ic += dsp_str * dir * sd * ff * lgt;
|
|
return saturate(ic);
|
|
}
|
|
|
|
|
|
half4 ComputeWeights(half4 iWeights, half h0, half h1, half h2, half h3, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return iWeights;
|
|
#else
|
|
// compute weight with height map
|
|
//half4 weights = half4(iWeights.x * h0, iWeights.y * h1, iWeights.z * h2, iWeights.w * h3);
|
|
half4 weights = half4(iWeights.x * max(h0,0.001), iWeights.y * max(h1,0.001), iWeights.z * max(h2,0.001), iWeights.w * max(h3,0.001));
|
|
|
|
// Contrast weights
|
|
half maxWeight = max(max(weights.x, max(weights.y, weights.z)), weights.w);
|
|
half transition = max(contrast * maxWeight, 0.0001);
|
|
half threshold = maxWeight - transition;
|
|
half scale = 1.0 / transition;
|
|
weights = saturate((weights - threshold) * scale);
|
|
|
|
weights = TotalOne(weights);
|
|
return weights;
|
|
#endif
|
|
}
|
|
|
|
half HeightBlend(half h1, half h2, half slope, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return slope;
|
|
#else
|
|
h2 = 1 - h2;
|
|
half tween = saturate((slope - min(h1, h2)) / max(abs(h1 - h2), 0.001));
|
|
half blend = saturate( ( tween - (1-contrast) ) / max(contrast, 0.001));
|
|
return blend;
|
|
#endif
|
|
}
|
|
|
|
#if _MAX4TEXTURES
|
|
#define TEXCOUNT 4
|
|
#elif _MAX8TEXTURES
|
|
#define TEXCOUNT 8
|
|
#elif _MAX12TEXTURES
|
|
#define TEXCOUNT 12
|
|
#elif _MAX20TEXTURES
|
|
#define TEXCOUNT 20
|
|
#elif _MAX24TEXTURES
|
|
#define TEXCOUNT 24
|
|
#elif _MAX28TEXTURES
|
|
#define TEXCOUNT 28
|
|
#elif _MAX32TEXTURES
|
|
#define TEXCOUNT 32
|
|
#else
|
|
#define TEXCOUNT 16
|
|
#endif
|
|
|
|
#if _DECAL_SPLAT
|
|
|
|
void DoMergeDecalSplats(half4 iWeights, half4 iIndexes, inout half4 indexes, inout half4 weights)
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
half w = iWeights[i];
|
|
half index = iIndexes[i];
|
|
if (w > weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = index;
|
|
}
|
|
else if (w > weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = index;
|
|
}
|
|
else if (w > weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = index;
|
|
}
|
|
else if (w > weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = index;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
void Setup(out half4 weights, float2 uv, out Config config, half4 w0, half4 w1, half4 w2, half4 w3, half4 w4, half4 w5, half4 w6, half4 w7, float3 worldPos, DecalOutput decalOutput)
|
|
{
|
|
config = (Config)0;
|
|
half4 indexes = 0;
|
|
|
|
config.uv = uv;
|
|
|
|
#if _WORLDUV
|
|
uv = worldPos.xz;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
float2 scaledUV = uv;
|
|
#else
|
|
float2 scaledUV = uv * _UVScale.xy + _UVScale.zw;
|
|
#endif
|
|
|
|
// if only 4 textures, and blending 4 textures, skip this whole thing..
|
|
// this saves about 25% of the ALU of the base shader on low end. However if
|
|
// we rely on sorted texture weights (distance resampling) we have to sort..
|
|
float4 defaultIndexes = float4(0,1,2,3);
|
|
#if _MESHSUBARRAY
|
|
defaultIndexes = _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
#if _MESHSUBARRAY && !_DECAL_SPLAT || (_MAX4TEXTURES && !_MAX3LAYER && !_MAX2LAYER && !_DISTANCERESAMPLE && !_POM && !_DECAL_SPLAT)
|
|
weights = w0;
|
|
config.uv0 = float3(scaledUV, defaultIndexes.x);
|
|
config.uv1 = float3(scaledUV, defaultIndexes.y);
|
|
config.uv2 = float3(scaledUV, defaultIndexes.z);
|
|
config.uv3 = float3(scaledUV, defaultIndexes.w);
|
|
return;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
weights = float4(1,0,0,0);
|
|
return;
|
|
#else
|
|
half splats[TEXCOUNT];
|
|
|
|
splats[0] = w0.x;
|
|
splats[1] = w0.y;
|
|
splats[2] = w0.z;
|
|
splats[3] = w0.w;
|
|
#if !_MAX4TEXTURES
|
|
splats[4] = w1.x;
|
|
splats[5] = w1.y;
|
|
splats[6] = w1.z;
|
|
splats[7] = w1.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
splats[8] = w2.x;
|
|
splats[9] = w2.y;
|
|
splats[10] = w2.z;
|
|
splats[11] = w2.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
splats[12] = w3.x;
|
|
splats[13] = w3.y;
|
|
splats[14] = w3.z;
|
|
splats[15] = w3.w;
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[16] = w4.x;
|
|
splats[17] = w4.y;
|
|
splats[18] = w4.z;
|
|
splats[19] = w4.w;
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[20] = w5.x;
|
|
splats[21] = w5.y;
|
|
splats[22] = w5.z;
|
|
splats[23] = w5.w;
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[24] = w6.x;
|
|
splats[25] = w6.y;
|
|
splats[26] = w6.z;
|
|
splats[27] = w6.w;
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
splats[28] = w7.x;
|
|
splats[29] = w7.y;
|
|
splats[30] = w7.z;
|
|
splats[31] = w7.w;
|
|
#endif
|
|
|
|
|
|
|
|
weights[0] = 0;
|
|
weights[1] = 0;
|
|
weights[2] = 0;
|
|
weights[3] = 0;
|
|
indexes[0] = 0;
|
|
indexes[1] = 0;
|
|
indexes[2] = 0;
|
|
indexes[3] = 0;
|
|
|
|
int i = 0;
|
|
for (i = 0; i < TEXCOUNT; ++i)
|
|
{
|
|
half w = splats[i];
|
|
if (w >= weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = i;
|
|
}
|
|
else if (w >= weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = i;
|
|
}
|
|
else if (w >= weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = i;
|
|
}
|
|
else if (w >= weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = i;
|
|
}
|
|
}
|
|
|
|
// NaN Prevention
|
|
if (weights.x <= 0)
|
|
weights = float4(1, 0, 0, 0);
|
|
|
|
#if _DECAL_SPLAT
|
|
DoMergeDecalSplats(decalOutput.Weights, decalOutput.Indexes, weights, indexes);
|
|
#endif
|
|
|
|
|
|
|
|
// clamp and renormalize
|
|
#if _MAX2LAYER
|
|
weights.zw = 0;
|
|
weights.xy = TotalOne(weights.xy);
|
|
#elif _MAX3LAYER
|
|
weights.w = 0;
|
|
weights.xyz = TotalOne(weights.xyz);
|
|
#elif !_DISABLEHEIGHTBLENDING || _NORMALIZEWEIGHTS // prevents black when painting, which the unity shader does not prevent.
|
|
weights = normalize(weights);
|
|
#endif
|
|
|
|
|
|
config.uv0 = float3(scaledUV, indexes.x);
|
|
config.uv1 = float3(scaledUV, indexes.y);
|
|
config.uv2 = float3(scaledUV, indexes.z);
|
|
config.uv3 = float3(scaledUV, indexes.w);
|
|
|
|
|
|
#endif //_DISABLESPLATMAPS
|
|
|
|
|
|
}
|
|
|
|
float3 HeightToNormal(float height, float3 worldPos)
|
|
{
|
|
float3 dx = ddx(worldPos);
|
|
float3 dy = ddy(worldPos);
|
|
float3 crossX = cross(float3(0,1,0), dx);
|
|
float3 crossY = cross(float3(0,1,0), dy);
|
|
float3 d = abs(dot(crossY, dx));
|
|
float3 n = ((((height + ddx(height)) - height) * crossY) + (((height + ddy(height)) - height) * crossX)) * sign(d);
|
|
n.z *= -1;
|
|
return normalize((d * float3(0,1,0)) - n).xzy;
|
|
}
|
|
|
|
float ComputeMipLevel(float2 uv, float2 textureSize)
|
|
{
|
|
uv *= textureSize;
|
|
float2 dx_vtc = ddx(uv);
|
|
float2 dy_vtc = ddy(uv);
|
|
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
|
|
return 0.5 * log2(delta_max_sqr);
|
|
}
|
|
|
|
inline half2 UnpackNormal2(half4 packednormal)
|
|
{
|
|
return packednormal.wy * 2 - 1;
|
|
|
|
}
|
|
|
|
half3 TriplanarHBlend(half h0, half h1, half h2, half3 pN, half contrast)
|
|
{
|
|
half3 blend = pN / dot(pN, half3(1,1,1));
|
|
float3 heights = float3(h0, h1, h2) + (blend * 3.0);
|
|
half height_start = max(max(heights.x, heights.y), heights.z) - contrast;
|
|
half3 h = max(heights - height_start.xxx, half3(0,0,0));
|
|
blend = h / dot(h, half3(1,1,1));
|
|
return blend;
|
|
}
|
|
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half3 display)
|
|
{
|
|
o.Albedo = display.rgb;
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half display)
|
|
{
|
|
o.Albedo = half3(display, display, display);
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
half MicroShadow(float3 lightDir, half3 normal, half ao, half strength)
|
|
{
|
|
half shadow = saturate(abs(dot(normal, lightDir)) + (ao * ao * 2.0) - 1.0);
|
|
return 1 - ((1-shadow) * strength);
|
|
}
|
|
|
|
|
|
void DoDebugOutput(inout MicroSplatLayer l)
|
|
{
|
|
#if _DEBUG_OUTPUT_ALBEDO
|
|
ClearAllButAlbedo(l, l.Albedo);
|
|
#elif _DEBUG_OUTPUT_NORMAL
|
|
// oh unit shader compiler normal stripping, how I hate you so..
|
|
// must multiply by albedo to stop the normal from being white. Why, fuck knows?
|
|
ClearAllButAlbedo(l, float3(l.Normal.xy * 0.5 + 0.5, l.Normal.z * saturate(l.Albedo.z+1)));
|
|
#elif _DEBUG_OUTPUT_SMOOTHNESS
|
|
ClearAllButAlbedo(l, l.Smoothness.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_METAL
|
|
ClearAllButAlbedo(l, l.Metallic.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_AO
|
|
ClearAllButAlbedo(l, l.Occlusion.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_EMISSION
|
|
ClearAllButAlbedo(l, l.Emission * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_HEIGHT
|
|
ClearAllButAlbedo(l, l.Height.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_SPECULAR && _USESPECULARWORKFLOW
|
|
ClearAllButAlbedo(l, l.Specular * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_BRANCHCOUNT_WEIGHT
|
|
ClearAllButAlbedo(l, _branchWeightCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TRIPLANAR
|
|
ClearAllButAlbedo(l, _branchTriplanarCount / 24 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_CLUSTER
|
|
ClearAllButAlbedo(l, _branchClusterCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_OTHER
|
|
ClearAllButAlbedo(l, _branchOtherCount / 8 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TOTAL
|
|
l.Albedo.r = _branchWeightCount / 12;
|
|
l.Albedo.g = _branchTriplanarCount / 24;
|
|
l.Albedo.b = _branchClusterCount / 12;
|
|
ClearAllButAlbedo(l, (l.Albedo.r + l.Albedo.g + l.Albedo.b + (_branchOtherCount / 8)) / 4);
|
|
#elif _DEBUG_OUTPUT_MICROSHADOWS
|
|
ClearAllButAlbedo(l,l.Albedo);
|
|
#elif _DEBUG_SAMPLECOUNT
|
|
float sdisp = (float)_sampleCount / max(_SampleCountDiv, 1);
|
|
half3 sdcolor = float3(sdisp, sdisp > 1 ? 1 : 0, 0);
|
|
ClearAllButAlbedo(l, sdcolor * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_PROCLAYERS
|
|
ClearAllButAlbedo(l, (float)_procLayerCount / (float)_PCLayerCount * saturate(l.Albedo.z + 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
// abstraction around sampler mode
|
|
#if _USELODMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_LOD(tex, sampler##tex, u, l.x)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u, l.x)
|
|
#elif _USEGRADMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_GRAD(tex, sampler##tex, u, l.xy, l.zw)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY_GRAD(tex, ss, u.xy, u.z, l.xy, l.zw)
|
|
#else
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, u.xy, u.z)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u.xy, y.z)
|
|
#endif
|
|
|
|
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE(u, cl, l) MICROSPLAT_SAMPLE(_Diffuse, u, l)
|
|
#define MICROSPLAT_SAMPLE_EMIS(u, cl, l) MICROSPLAT_SAMPLE(_EmissiveMetal, u, l)
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE_LOD(u, cl, l) UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, u, l)
|
|
|
|
|
|
#if _PACKINGHQ
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) half4(MICROSPLAT_SAMPLE(_NormalSAO, u, l).ga, MICROSPLAT_SAMPLE(_SmoothAO, u, l).ga).brag
|
|
#else
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) MICROSPLAT_SAMPLE(_NormalSAO, u, l)
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
#define MICROSPLAT_SAMPLE_SPECULAR(u, cl, l) MICROSPLAT_SAMPLE(_Specular, u, l)
|
|
#endif
|
|
|
|
struct SimpleTriplanarConfig
|
|
{
|
|
float3 pn;
|
|
float2 uv0;
|
|
float2 uv1;
|
|
float2 uv2;
|
|
};
|
|
|
|
void PrepSimpleTriplanarConfig(inout SimpleTriplanarConfig tc, float3 worldPos, float3 normal, float contrast)
|
|
{
|
|
tc.pn = pow(abs(normal), contrast);
|
|
tc.pn = tc.pn / (tc.pn.x + tc.pn.y + tc.pn.z);
|
|
|
|
half3 axisSign = sign(normal);
|
|
|
|
tc.uv0 = worldPos.zy * axisSign.x;
|
|
tc.uv1 = worldPos.xz * axisSign.y;
|
|
tc.uv2 = worldPos.xy * axisSign.z;
|
|
}
|
|
|
|
#define SimpleTriplanarSample(tex, tc, scale) (SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv0 * scale) * tc.pn.x + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv1 * scale) * tc.pn.y + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv2 * scale) * tc.pn.z)
|
|
#define SimpleTriplanarSampleLOD(tex, tc, scale, lod) (SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv0 * scale, lod) * tc.pn.x + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv1 * scale, lod) * tc.pn.y + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv2 * scale, lod) * tc.pn.z)
|
|
#define SimpleTriplanarSampleGrad(tex, tc, scale) (SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv0 * scale, ddx(tc.uv0) * scale, ddy(tc.uv0) * scale) * tc.pn.x + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv1 * scale, ddx(tc.uv1) * scale, ddy(tc.uv1) * scale) * tc.pn.y + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv2 * scale, ddx(tc.uv2) * scale, ddy(tc.uv2) * scale) * tc.pn.z)
|
|
|
|
|
|
inline half3 MicroSplatDiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
|
|
{
|
|
specColor = lerp (half3(0,0,0), albedo, metallic);
|
|
oneMinusReflectivity = (1-metallic);
|
|
return albedo * oneMinusReflectivity;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Input DescToInput(ShaderData IN)
|
|
{
|
|
Input s = (Input)0;
|
|
s.shaderData = IN;
|
|
s.TBN = IN.TBNMatrix;
|
|
s.worldNormal = IN.worldSpaceNormal;
|
|
s.worldPos = IN.worldSpacePosition;
|
|
s.viewDir = IN.tangentSpaceViewDir;
|
|
s.uv_Control0 = IN.texcoord0.xy;
|
|
|
|
s.worldUpVector = float3(0,1,0);
|
|
s.worldHeight = IN.worldSpacePosition.y;
|
|
|
|
#if _PLANETVECTORS
|
|
float3 rwp = mul(_PQSToLocal, float4(IN.worldSpacePosition, 1));
|
|
s.worldHeight = distance(rwp, float3(0,0,0));
|
|
s.worldUpVector = normalize(rwp);
|
|
#endif
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
s.uv2_Diffuse = IN.texcoord1.xy;
|
|
#endif
|
|
|
|
#if _MEGASPLAT
|
|
UnpackMegaSplat(s, IN);
|
|
#endif
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
UnpackVertexWorkflow(s, IN);
|
|
#endif
|
|
|
|
#if _PLANETVECTORS
|
|
DoPlanetDataInputCopy(s, IN);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
void SampleAlbedo(inout Config config, inout TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half4 contrasts = _Contrast.xxxx;
|
|
#if _PERTEXTRIPLANARCONTRAST
|
|
SAMPLE_PER_TEX(ptc, 9.5, config, half4(1,0.5,0,0));
|
|
contrasts = half4(ptc0.y, ptc1.y, ptc2.y, ptc3.y);
|
|
#endif
|
|
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
SAMPLE_PER_TEX(pttri, 9.5, config, half4(0,0,0,0));
|
|
#endif
|
|
|
|
{
|
|
// For per-texture triplanar, we modify the view based blending factor of the triplanar
|
|
// such that you get a pure blend of either top down projection, or with the top down projection
|
|
// removed and renormalized. This causes dynamic flow control optimizations to kick in and avoid
|
|
// the extra texture samples while keeping the code simple. Yay..
|
|
|
|
// We also only have to do this in the Albedo, because the pN values will be adjusted after the
|
|
// albedo is sampled, causing future samples to use this data.
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri0.x > 0.66)
|
|
{
|
|
tc.pN0 = half3(0,1,0);
|
|
}
|
|
else if (pttri0.x > 0.33)
|
|
{
|
|
tc.pN0.y = 0;
|
|
tc.pN0.xz = TotalOne(tc.pN0.xz);
|
|
}
|
|
#endif
|
|
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN0;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN0, contrasts.x);
|
|
tc.pN0 = bf;
|
|
#endif
|
|
|
|
s.albedo0 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri1.x > 0.66)
|
|
{
|
|
tc.pN1 = half3(0,1,0);
|
|
}
|
|
else if (pttri1.x > 0.33)
|
|
{
|
|
tc.pN1.y = 0;
|
|
tc.pN1.xz = TotalOne(tc.pN1.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
COUNTSAMPLE
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[2], config.cluster1, d2);
|
|
}
|
|
half3 bf = tc.pN1;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN1, contrasts.x);
|
|
tc.pN1 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo1 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri2.x > 0.66)
|
|
{
|
|
tc.pN2 = half3(0,1,0);
|
|
}
|
|
else if (pttri2.x > 0.33)
|
|
{
|
|
tc.pN2.y = 0;
|
|
tc.pN2.xz = TotalOne(tc.pN2.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN2;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN2, contrasts.x);
|
|
tc.pN2 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo2 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri3.x > 0.66)
|
|
{
|
|
tc.pN3 = half3(0,1,0);
|
|
}
|
|
else if (pttri3.x > 0.33)
|
|
{
|
|
tc.pN3.y = 0;
|
|
tc.pN3.xz = TotalOne(tc.pN3.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN3;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN3, contrasts.x);
|
|
tc.pN3 = bf;
|
|
#endif
|
|
|
|
s.albedo3 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.albedo0 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.albedo1 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.albedo2 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.albedo3 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXHEIGHTOFFSET || _PERTEXHEIGHTCONTRAST
|
|
SAMPLE_PER_TEX(ptHeight, 10.5, config, 1);
|
|
|
|
#if _PERTEXHEIGHTOFFSET
|
|
s.albedo0.a = saturate(s.albedo0.a + ptHeight0.b - 1);
|
|
s.albedo1.a = saturate(s.albedo1.a + ptHeight1.b - 1);
|
|
s.albedo2.a = saturate(s.albedo2.a + ptHeight2.b - 1);
|
|
s.albedo3.a = saturate(s.albedo3.a + ptHeight3.b - 1);
|
|
#endif
|
|
#if _PERTEXHEIGHTCONTRAST
|
|
s.albedo0.a = saturate(pow(s.albedo0.a + 0.5, abs(ptHeight0.a)) - 0.5);
|
|
s.albedo1.a = saturate(pow(s.albedo1.a + 0.5, abs(ptHeight1.a)) - 0.5);
|
|
s.albedo2.a = saturate(pow(s.albedo2.a + 0.5, abs(ptHeight2.a)) - 0.5);
|
|
s.albedo3.a = saturate(pow(s.albedo3.a + 0.5, abs(ptHeight3.a)) - 0.5);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void SampleNormal(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
|
|
#if _NONORMALMAP || _AUTONORMAL
|
|
s.normSAO0 = half4(0,0, 0, 1);
|
|
s.normSAO1 = half4(0,0, 0, 1);
|
|
s.normSAO2 = half4(0,0, 0, 1);
|
|
s.normSAO3 = half4(0,0, 0, 1);
|
|
return;
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half3 absVertNormal = abs(tc.IN.worldNormal);
|
|
float3x3 t2w = tc.IN.TBN;
|
|
|
|
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[0], config.cluster0, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[1], config.cluster0, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[2], config.cluster0, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = SurfgradFromTriplanarProjection(tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO0.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO0.zw = a0.zw * tc.pN0.x + a1.zw * tc.pN0.y + a2.zw * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[0], config.cluster1, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[1], config.cluster1, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[2], config.cluster1, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = SurfgradFromTriplanarProjection(tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO1.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO1.zw = a0.zw * tc.pN1.x + a1.zw * tc.pN1.y + a2.zw * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[0], config.cluster2, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[1], config.cluster2, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[2], config.cluster2, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf2 = SurfgradFromTriplanarProjection(tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO2.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO2.zw = a0.zw * tc.pN2.x + a1.zw * tc.pN2.y + a2.zw * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[0], config.cluster3, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[1], config.cluster3, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[2], config.cluster3, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf3 = SurfgradFromTriplanarProjection(tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO3.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO3.zw = a0.zw * tc.pN3.x + a1.zw * tc.pN3.y + a2.zw * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.normSAO0 = MICROSPLAT_SAMPLE_NORMAL(config.uv0, config.cluster0, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO0.xy = s.normSAO0.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = ConvertNormal2ToGradient(s.normSAO0.xy);
|
|
#endif
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.normSAO1 = MICROSPLAT_SAMPLE_NORMAL(config.uv1, config.cluster1, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO1.xy = s.normSAO1.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = ConvertNormal2ToGradient(s.normSAO1.xy);
|
|
#endif
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.normSAO2 = MICROSPLAT_SAMPLE_NORMAL(config.uv2, config.cluster2, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO2.xy = s.normSAO2.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf2 = ConvertNormal2ToGradient(s.normSAO2.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.normSAO3 = MICROSPLAT_SAMPLE_NORMAL(config.uv3, config.cluster3, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO3.xy = s.normSAO3.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf3 = ConvertNormal2ToGradient(s.normSAO3.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleEmis(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
s.emisMetal0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.emisMetal0 = MICROSPLAT_SAMPLE_EMIS(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.emisMetal1 = MICROSPLAT_SAMPLE_EMIS(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.emisMetal2 = MICROSPLAT_SAMPLE_EMIS(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.emisMetal3 = MICROSPLAT_SAMPLE_EMIS(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleSpecular(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.specular0 = MICROSPLAT_SAMPLE_SPECULAR(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.specular1 = MICROSPLAT_SAMPLE_SPECULAR(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.specular2 = MICROSPLAT_SAMPLE_SPECULAR(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.specular3 = MICROSPLAT_SAMPLE_SPECULAR(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
MicroSplatLayer Sample(Input i, half4 weights, inout Config config, float camDist, float3 worldNormalVertex, DecalOutput decalOutput)
|
|
{
|
|
MicroSplatLayer o = (MicroSplatLayer)0;
|
|
UNITY_INITIALIZE_OUTPUT(MicroSplatLayer,o);
|
|
|
|
RawSamples samples = (RawSamples)0;
|
|
InitRawSamples(samples);
|
|
|
|
half4 albedo = 0;
|
|
half4 normSAO = half4(0,0,0,1);
|
|
half3 surfGrad = half3(0,0,0);
|
|
half4 emisMetal = 0;
|
|
half3 specular = 0;
|
|
|
|
float worldHeight = i.worldPos.y;
|
|
float3 upVector = float3(0,1,0);
|
|
|
|
#if _GLOBALTINT || _GLOBALNORMALS || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _GLOBALSPECULAR
|
|
float globalSlopeFilter = 1;
|
|
#if _GLOBALSLOPEFILTER
|
|
float2 gfilterUV = float2(1 - saturate(dot(worldNormalVertex, upVector) * 0.5 + 0.49), 0.5);
|
|
globalSlopeFilter = SAMPLE_TEXTURE2D(_GlobalSlopeTex, sampler_Diffuse, gfilterUV).a;
|
|
#endif
|
|
#endif
|
|
|
|
// declare outside of branchy areas..
|
|
half4 fxLevels = half4(0,0,0,0);
|
|
half burnLevel = 0;
|
|
half wetLevel = 0;
|
|
half3 waterNormalFoam = half3(0, 0, 0);
|
|
half porosity = 0.4;
|
|
float streamFoam = 1.0f;
|
|
half pud = 0;
|
|
half snowCover = 0;
|
|
half SSSThickness = 0;
|
|
half3 SSSTint = half3(1,1,1);
|
|
float traxBuffer = 0;
|
|
float3 traxNormal = 0;
|
|
float2 noiseUV = 0;
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(1 - saturate(camDist - _SplatFade.y))
|
|
{
|
|
#endif
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE || _SNOWFOOTSTEPS
|
|
traxBuffer = SampleTraxBuffer(i.worldPos, worldNormalVertex, traxNormal);
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
#if _MICROMESH
|
|
fxLevels = SampleFXLevels(InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, config.uv), wetLevel, burnLevel, traxBuffer);
|
|
#elif _MICROVERTEXMESH || _MICRODIGGERMESH || _MEGASPLAT
|
|
fxLevels = ProcessFXLevels(i.fx, traxBuffer);
|
|
#else
|
|
fxLevels = SampleFXLevels(config.uv, wetLevel, burnLevel, traxBuffer);
|
|
#endif
|
|
#endif
|
|
|
|
#if _DECAL
|
|
fxLevels = max(fxLevels, decalOutput.fxLevels);
|
|
#endif
|
|
|
|
TriplanarConfig tc = (TriplanarConfig)0;
|
|
UNITY_INITIALIZE_OUTPUT(TriplanarConfig,tc);
|
|
|
|
|
|
MIPFORMAT albedoLOD = INITMIPFORMAT
|
|
MIPFORMAT normalLOD = INITMIPFORMAT
|
|
MIPFORMAT emisLOD = INITMIPFORMAT
|
|
MIPFORMAT specLOD = INITMIPFORMAT
|
|
MIPFORMAT origAlbedoLOD = INITMIPFORMAT;
|
|
|
|
#if _TRIPLANAR && !_DISABLESPLATMAPS
|
|
PrepTriplanar(i.shaderData.texcoord0, worldNormalVertex, i.worldPos, config, tc, weights, albedoLOD, normalLOD, emisLOD, origAlbedoLOD);
|
|
tc.IN = i;
|
|
#endif
|
|
|
|
|
|
#if !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
#if _USELODMIP
|
|
albedoLOD = ComputeMipLevel(config.uv0.xy, _Diffuse_TexelSize.zw);
|
|
normalLOD = ComputeMipLevel(config.uv0.xy, _NormalSAO_TexelSize.zw);
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = ComputeMipLevel(config.uv0.xy, _EmissiveMetal_TexelSize.zw);
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = ComputeMipLevel(config.uv0.xy, _Specular_TexelSize.zw);;
|
|
#endif
|
|
#elif _USEGRADMIP
|
|
albedoLOD = float4(ddx(config.uv0.xy), ddy(config.uv0.xy));
|
|
normalLOD = albedoLOD;
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
|
|
origAlbedoLOD = albedoLOD;
|
|
#endif
|
|
|
|
#if _PERTEXCURVEWEIGHT
|
|
SAMPLE_PER_TEX(ptCurveWeight, 19.5, config, half4(0.5,1,1,1));
|
|
weights.x = lerp(smoothstep(0.5 - ptCurveWeight0.r, 0.5 + ptCurveWeight0.r, weights.x), weights.x, ptCurveWeight0.r*2);
|
|
weights.y = lerp(smoothstep(0.5 - ptCurveWeight1.r, 0.5 + ptCurveWeight1.r, weights.y), weights.y, ptCurveWeight1.r*2);
|
|
weights.z = lerp(smoothstep(0.5 - ptCurveWeight2.r, 0.5 + ptCurveWeight2.r, weights.z), weights.z, ptCurveWeight2.r*2);
|
|
weights.w = lerp(smoothstep(0.5 - ptCurveWeight3.r, 0.5 + ptCurveWeight3.r, weights.w), weights.w, ptCurveWeight3.r*2);
|
|
weights = TotalOne(weights);
|
|
#endif
|
|
|
|
|
|
|
|
// uvScale before anything
|
|
#if _PERTEXUVSCALEOFFSET && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
config.uv0.xy = config.uv0.xy * ptUVScale0.rg + ptUVScale0.ba;
|
|
config.uv1.xy = config.uv1.xy * ptUVScale1.rg + ptUVScale1.ba;
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = config.uv2.xy * ptUVScale2.rg + ptUVScale2.ba;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = config.uv3.xy * ptUVScale3.rg + ptUVScale3.ba;
|
|
#endif
|
|
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = albedoLOD * ptUVScale0.rgrg * weights.x +
|
|
albedoLOD * ptUVScale1.rgrg * weights.y +
|
|
albedoLOD * ptUVScale2.rgrg * weights.z +
|
|
albedoLOD * ptUVScale3.rgrg * weights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXUVROTATION && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptUVRot, 16.5, config, half4(0,0,0,0));
|
|
config.uv0.xy = RotateUV(config.uv0.xy, ptUVRot0.x);
|
|
config.uv1.xy = RotateUV(config.uv1.xy, ptUVRot1.x);
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = RotateUV(config.uv2.xy, ptUVRot2.x);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = RotateUV(config.uv3.xy, ptUVRot0.x);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
o.Alpha = 1;
|
|
|
|
|
|
#if _POM && !_DISABLESPLATMAPS
|
|
DoPOM(i, config, tc, albedoLOD, weights, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
SampleAlbedo(config, tc, samples, albedoLOD, weights);
|
|
|
|
#if _NOISEHEIGHT
|
|
ApplyNoiseHeight(samples, config.uv, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STREAMS || (_PARALLAX && !_DISABLESPLATMAPS)
|
|
half earlyHeight = BlendWeights(samples.albedo0.w, samples.albedo1.w, samples.albedo2.w, samples.albedo3.w, weights);
|
|
#endif
|
|
|
|
|
|
#if _STREAMS
|
|
waterNormalFoam = GetWaterNormal(i, config.uv, worldNormalVertex);
|
|
DoStreamRefract(config, tc, waterNormalFoam, fxLevels.b, earlyHeight);
|
|
#endif
|
|
|
|
#if _PARALLAX && !_DISABLESPLATMAPS
|
|
DoParallax(i, earlyHeight, config, tc, samples, weights, camDist);
|
|
#endif
|
|
|
|
|
|
// Blend results
|
|
#if _PERTEXINTERPCONTRAST && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptContrasts, 1.5, config, 0.5);
|
|
half4 contrast = 0.5;
|
|
contrast.x = ptContrasts0.a;
|
|
contrast.y = ptContrasts1.a;
|
|
#if !_MAX2LAYER
|
|
contrast.z = ptContrasts2.a;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
contrast.w = ptContrasts3.a;
|
|
#endif
|
|
contrast = clamp(contrast + _Contrast, 0.0001, 1.0);
|
|
half cnt = contrast.x * weights.x + contrast.y * weights.y + contrast.z * weights.z + contrast.w * weights.w;
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, cnt);
|
|
#else
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, _Contrast);
|
|
#endif
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
heightWeights = lerp(heightWeights, TotalOne(weights), saturate(camDist/max(1.0, _HybridHeightBlendDistance)));
|
|
#endif
|
|
|
|
|
|
// rescale derivatives after height weighting. Basically, in gradmip mode we blend the mip levels,
|
|
// but this is before height mapping is sampled, so reblending them after alpha will make sure the other
|
|
// channels (normal, etc) are sharper, which likely matters most..
|
|
#if _PERTEXUVSCALEOFFSET && !_DISABLESPLATMAPS
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
|
|
albedoLOD.d0 = origAlbedoLOD.d0 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d0 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d0 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d0 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d1 = origAlbedoLOD.d1 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d1 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d1 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d1 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d2 = origAlbedoLOD.d2 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d2 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d2 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d2 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
normalLOD.d0 = albedoLOD.d0;
|
|
normalLOD.d1 = albedoLOD.d1;
|
|
normalLOD.d2 = albedoLOD.d2;
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD.d0 = albedoLOD.d0;
|
|
emisLOD.d1 = albedoLOD.d1;
|
|
emisLOD.d2 = albedoLOD.d2;
|
|
#endif
|
|
#endif // gradmip
|
|
#else // not triplanar
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = origAlbedoLOD * ptUVScale0.rgrg * heightWeights.x +
|
|
origAlbedoLOD * ptUVScale1.rgrg * heightWeights.y +
|
|
origAlbedoLOD * ptUVScale2.rgrg * heightWeights.z +
|
|
origAlbedoLOD * ptUVScale3.rgrg * heightWeights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _PARALLAX || _STREAMS
|
|
SampleAlbedo(config, tc, samples, albedoLOD, heightWeights);
|
|
#endif
|
|
|
|
|
|
SampleNormal(config, tc, samples, normalLOD, heightWeights);
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
SampleEmis(config, tc, samples, emisLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
SampleSpecular(config, tc, samples, specLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _DISTANCERESAMPLE && !_DISABLESPLATMAPS
|
|
DistanceResample(samples, config, tc, camDist, i.viewDir, fxLevels, albedoLOD, i.worldPos, heightWeights, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STARREACHFORMAT
|
|
samples.normSAO0.w = length(samples.normSAO0.xy);
|
|
samples.normSAO1.w = length(samples.normSAO1.xy);
|
|
samples.normSAO2.w = length(samples.normSAO2.xy);
|
|
samples.normSAO3.w = length(samples.normSAO3.xy);
|
|
#endif
|
|
|
|
// PerTexture sampling goes here, passing the samples structure
|
|
|
|
#if _PERTEXMICROSHADOWS || _PERTEXFUZZYSHADE
|
|
SAMPLE_PER_TEX(ptFuzz, 17.5, config, half4(0, 0, 1, 1));
|
|
#endif
|
|
|
|
#if _PERTEXMICROSHADOWS
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
{
|
|
half3 lightDir = GetGlobalLightDirTS(i);
|
|
half4 microShadows = half4(1,1,1,1);
|
|
microShadows.x = MicroShadow(lightDir, half3(samples.normSAO0.xy, 1), samples.normSAO0.a, ptFuzz0.a);
|
|
microShadows.y = MicroShadow(lightDir, half3(samples.normSAO1.xy, 1), samples.normSAO1.a, ptFuzz1.a);
|
|
microShadows.z = MicroShadow(lightDir, half3(samples.normSAO2.xy, 1), samples.normSAO2.a, ptFuzz2.a);
|
|
microShadows.w = MicroShadow(lightDir, half3(samples.normSAO3.xy, 1), samples.normSAO3.a, ptFuzz3.a);
|
|
samples.normSAO0.a *= microShadows.x;
|
|
samples.normSAO1.a *= microShadows.y;
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a *= microShadows.z;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a *= microShadows.w;
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_OUTPUT_MICROSHADOWS
|
|
o.Albedo = BlendWeights(microShadows.x, microShadows.y, microShadows.z, microShadows.a, heightWeights);
|
|
return o;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
#endif // _PERTEXMICROSHADOWS
|
|
|
|
|
|
#if _PERTEXFUZZYSHADE
|
|
samples.albedo0.rgb = FuzzyShade(samples.albedo0.rgb, half3(samples.normSAO0.rg, 1), ptFuzz0.r, ptFuzz0.g, ptFuzz0.b, i.viewDir);
|
|
samples.albedo1.rgb = FuzzyShade(samples.albedo1.rgb, half3(samples.normSAO1.rg, 1), ptFuzz1.r, ptFuzz1.g, ptFuzz1.b, i.viewDir);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = FuzzyShade(samples.albedo2.rgb, half3(samples.normSAO2.rg, 1), ptFuzz2.r, ptFuzz2.g, ptFuzz2.b, i.viewDir);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = FuzzyShade(samples.albedo3.rgb, half3(samples.normSAO3.rg, 1), ptFuzz3.r, ptFuzz3.g, ptFuzz3.b, i.viewDir);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSATURATION && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptSaturattion, 9.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = lerp(MSLuminance(samples.albedo0.rgb), samples.albedo0.rgb, ptSaturattion0.a);
|
|
samples.albedo1.rgb = lerp(MSLuminance(samples.albedo1.rgb), samples.albedo1.rgb, ptSaturattion1.a);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = lerp(MSLuminance(samples.albedo2.rgb), samples.albedo2.rgb, ptSaturattion2.a);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = lerp(MSLuminance(samples.albedo3.rgb), samples.albedo3.rgb, ptSaturattion3.a);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if _PERTEXTINT && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptTints, 1.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb *= ptTints0.rgb;
|
|
samples.albedo1.rgb *= ptTints1.rgb;
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb *= ptTints2.rgb;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb *= ptTints3.rgb;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PCHEIGHTGRADIENT || _PCHEIGHTHSV || _PCSLOPEGRADIENT || _PCSLOPEHSV
|
|
ProceduralGradients(i, samples, config, worldHeight, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS
|
|
porosity = _GlobalPorosity;
|
|
#endif
|
|
|
|
|
|
#if _PERTEXCOLORINTENSITY
|
|
SAMPLE_PER_TEX(ptCI, 23.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb * (1 + ptCI0.rrr));
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb * (1 + ptCI1.rrr));
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb * (1 + ptCI2.rrr));
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb * (1 + ptCI3.rrr));
|
|
#endif
|
|
#endif
|
|
|
|
#if (_PERTEXBRIGHTNESS || _PERTEXCONTRAST || _PERTEXPOROSITY || _PERTEXFOAM) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptBC, 3.5, config, half4(1, 1, 1, 1));
|
|
#if _PERTEXCONTRAST
|
|
samples.albedo0.rgb = saturate(((samples.albedo0.rgb - 0.5) * ptBC0.g) + 0.5);
|
|
samples.albedo1.rgb = saturate(((samples.albedo1.rgb - 0.5) * ptBC1.g) + 0.5);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(((samples.albedo2.rgb - 0.5) * ptBC2.g) + 0.5);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(((samples.albedo3.rgb - 0.5) * ptBC3.g) + 0.5);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXBRIGHTNESS
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb + ptBC0.rrr);
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb + ptBC1.rrr);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb + ptBC2.rrr);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb + ptBC3.rrr);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXPOROSITY
|
|
porosity = BlendWeights(ptBC0.b, ptBC1.b, ptBC2.b, ptBC3.b, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXFOAM
|
|
streamFoam = BlendWeights(ptBC0.a, ptBC1.a, ptBC2.a, ptBC3.a, heightWeights);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if (_PERTEXNORMSTR || _PERTEXAOSTR || _PERTEXSMOOTHSTR || _PERTEXMETALLIC) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(perTexMatSettings, 2.5, config, half4(1.0, 1.0, 1.0, 0.0));
|
|
#endif
|
|
|
|
#if _PERTEXNORMSTR && !_DISABLESPLATMAPS
|
|
#if _SURFACENORMALS
|
|
samples.surf0 *= perTexMatSettings0.r;
|
|
samples.surf1 *= perTexMatSettings1.r;
|
|
samples.surf2 *= perTexMatSettings2.r;
|
|
samples.surf3 *= perTexMatSettings3.r;
|
|
#else
|
|
samples.normSAO0.xy *= perTexMatSettings0.r;
|
|
samples.normSAO1.xy *= perTexMatSettings1.r;
|
|
samples.normSAO2.xy *= perTexMatSettings2.r;
|
|
samples.normSAO3.xy *= perTexMatSettings3.r;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXAOSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.a = pow(abs(samples.normSAO0.a), perTexMatSettings0.b);
|
|
samples.normSAO1.a = pow(abs(samples.normSAO1.a), perTexMatSettings1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a = pow(abs(samples.normSAO2.a), perTexMatSettings2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a = pow(abs(samples.normSAO3.a), perTexMatSettings3.b);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSMOOTHSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.b += perTexMatSettings0.g;
|
|
samples.normSAO1.b += perTexMatSettings1.g;
|
|
samples.normSAO0.b = saturate(samples.normSAO0.b);
|
|
samples.normSAO1.b = saturate(samples.normSAO1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.b += perTexMatSettings2.g;
|
|
samples.normSAO2.b = saturate(samples.normSAO2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.b += perTexMatSettings3.g;
|
|
samples.normSAO3.b = saturate(samples.normSAO3.b);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
#if _PERTEXSSS
|
|
{
|
|
SAMPLE_PER_TEX(ptSSS, 18.5, config, half4(1, 1, 1, 1)); // tint, thickness
|
|
half4 vals = ptSSS0 * heightWeights.x + ptSSS1 * heightWeights.y + ptSSS2 * heightWeights.z + ptSSS3 * heightWeights.w;
|
|
SSSThickness = vals.a;
|
|
SSSTint = vals.rgb;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXRIMLIGHT
|
|
{
|
|
SAMPLE_PER_TEX(ptRimA, 26.5, config, half4(1, 1, 1, 1));
|
|
SAMPLE_PER_TEX(ptRimB, 27.5, config, half4(1, 1, 1, 0));
|
|
samples.emisMetal0.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO0.xy, 1))), max(0.0001, ptRimA0.g)) * ptRimB0.rgb * ptRimB0.a;
|
|
samples.emisMetal1.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO1.xy, 1))), max(0.0001, ptRimA1.g)) * ptRimB1.rgb * ptRimB1.a;
|
|
samples.emisMetal2.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO2.xy, 1))), max(0.0001, ptRimA2.g)) * ptRimB2.rgb * ptRimB2.a;
|
|
samples.emisMetal3.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO3.xy, 1))), max(0.0001, ptRimA3.g)) * ptRimB3.rgb * ptRimB3.a;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#if (((_DETAILNOISE && _PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && _PERTEXDISTANCENOISESTRENGTH)) || (_NORMALNOISE && _PERTEXNORMALNOISESTRENGTH)) && !_DISABLESPLATMAPS
|
|
ApplyDetailDistanceNoisePerTex(samples, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALNOISEUV
|
|
// noise defaults so that a value of 1, 1 is 4 pixels in size and moves the uvs by 1 pixel max.
|
|
#if _CUSTOMSPLATTEXTURES
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#else
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE
|
|
ApplyTrax(samples, config, i.worldPos, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if (_ANTITILEARRAYDETAIL || _ANTITILEARRAYDISTANCE || _ANTITILEARRAYNORMAL) && !_DISABLESPLATMAPS
|
|
ApplyAntiTilePerTex(samples, config, camDist, i.worldPos, worldNormalVertex, heightWeights);
|
|
#endif
|
|
|
|
#if _GEOMAP && !_DISABLESPLATMAPS
|
|
GeoTexturePerTex(samples, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
#if _GLOBALTINT && _PERTEXGLOBALTINTSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalTintTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && _PERTEXGLOBALNORMALSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalNormalTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && _PERTEXGLOBALSAOMSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalSAOMTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && _PERTEXGLOBALEMISSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalEmisTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && _PERTEXGLOBALSPECULARSTRENGTH && !_DISABLESPLATMAPS && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _PERTEXMETALLIC && !_DISABLESPLATMAPS
|
|
half metallic = BlendWeights(perTexMatSettings0.a, perTexMatSettings1.a, perTexMatSettings2.a, perTexMatSettings3.a, heightWeights);
|
|
o.Metallic = metallic;
|
|
#endif
|
|
|
|
#if _GLITTER && !_DISABLESPLATMAPS
|
|
DoGlitter(i, samples, config, camDist, worldNormalVertex, i.worldPos);
|
|
#endif
|
|
|
|
// Blend em..
|
|
#if _DISABLESPLATMAPS
|
|
// If we don't sample from the _Diffuse, then the shader compiler will strip the sampler on
|
|
// some platforms, which will cause everything to break. So we sample from the lowest mip
|
|
// and saturate to 1 to keep the cost minimal. Annoying, but the compiler removes the texture
|
|
// and sampler, even though the sampler is still used.
|
|
albedo = saturate(UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, float3(0,0,0), 12) + 1);
|
|
albedo.a = 0.5; // make height something we can blend with for the combined mesh mode, since it still height blends.
|
|
normSAO = half4(0,0,0,1);
|
|
#else
|
|
albedo = BlendWeights(samples.albedo0, samples.albedo1, samples.albedo2, samples.albedo3, heightWeights);
|
|
normSAO = BlendWeights(samples.normSAO0, samples.normSAO1, samples.normSAO2, samples.normSAO3, heightWeights);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = BlendWeights(samples.surf0, samples.surf1, samples.surf2, samples.surf3, heightWeights);
|
|
#endif
|
|
|
|
#if (_USEEMISSIVEMETAL || _PERTEXRIMLIGHT) && !_DISABLESPLATMAPS
|
|
emisMetal = BlendWeights(samples.emisMetal0, samples.emisMetal1, samples.emisMetal2, samples.emisMetal3, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW && !_DISABLESPLATMAPS
|
|
specular = BlendWeights(samples.specular0, samples.specular1, samples.specular2, samples.specular3, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXOUTLINECOLOR
|
|
SAMPLE_PER_TEX(ptOutlineColor, 28.5, config, half4(0.5, 0.5, 0.5, 1));
|
|
half4 outlineColor = BlendWeights(ptOutlineColor0, ptOutlineColor1, ptOutlineColor2, ptOutlineColor3, heightWeights);
|
|
half4 tstr = saturate(abs(heightWeights - 0.5) * 2);
|
|
half transitionBlend = min(min(min(tstr.x, tstr.y), tstr.z), tstr.w);
|
|
albedo.rgb = lerp(albedo.rgb * outlineColor.rgb * 2, albedo.rgb, outlineColor.a * transitionBlend);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHOVERLAYSPLATS || _MESHCOMBINED
|
|
o.Alpha = 1.0;
|
|
if (config.uv0.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.x;
|
|
else if (config.uv1.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.y;
|
|
else if (config.uv2.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.z;
|
|
else if (config.uv3.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.w;
|
|
#endif
|
|
|
|
|
|
|
|
// effects which don't require per texture adjustments and are part of the splats sample go here.
|
|
// Often, as an optimization, you can compute the non-per tex version of above effects here..
|
|
|
|
|
|
#if ((_DETAILNOISE && !_PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && !_PERTEXDISTANCENOISESTRENGTH) || (_NORMALNOISE && !_PERTEXNORMALNOISESTRENGTH))
|
|
ApplyDetailDistanceNoise(albedo.rgb, normSAO, surfGrad, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
}
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
|
|
float2 sfDX = ddx(config.uv * _UVScale);
|
|
float2 sfDY = ddy(config.uv * _UVScale);
|
|
|
|
MSBRANCHOTHER(camDist - _SplatFade.x)
|
|
{
|
|
float falloff = saturate(InverseLerp(_SplatFade.x, _SplatFade.y, camDist));
|
|
half4 sfalb = SAMPLE_TEXTURE2D_ARRAY_GRAD(_Diffuse, sampler_Diffuse, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY);
|
|
COUNTSAMPLE
|
|
albedo.rgb = lerp(albedo.rgb, sfalb.rgb, falloff);
|
|
|
|
#if !_NONORMALMAP && !_AUTONORMAL
|
|
half4 sfnormSAO = SAMPLE_TEXTURE2D_ARRAY_GRAD(_NormalSAO, sampler_NormalSAO, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY).agrb;
|
|
COUNTSAMPLE
|
|
sfnormSAO.xy = sfnormSAO.xy * 2 - 1;
|
|
|
|
normSAO = lerp(normSAO, sfnormSAO, falloff);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = lerp(surfGrad, ConvertNormal2ToGradient(sfnormSAO.xy), falloff);
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
float3 autoNormal = HeightToNormal(albedo.a * _AutoNormalHeightScale, i.worldPos);
|
|
normSAO.xy = autoNormal;
|
|
normSAO.z = 0;
|
|
normSAO.w = (autoNormal.z * autoNormal.z);
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHCOMBINED
|
|
SampleMeshCombined(albedo, normSAO, surfGrad, emisMetal, specular, o.Alpha, SSSThickness, SSSTint, config, heightWeights);
|
|
#endif
|
|
|
|
#if _ISOBJECTSHADER
|
|
SampleObjectShader(i, albedo, normSAO, surfGrad, emisMetal, specular, config);
|
|
#endif
|
|
|
|
#if _GEOMAP
|
|
GeoTexture(albedo.rgb, normSAO, surfGrad, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
|
|
#if _SCATTER
|
|
ApplyScatter(
|
|
#if _MEGASPLAT
|
|
config,
|
|
#endif
|
|
i, albedo, normSAO, surfGrad, config.uv, camDist);
|
|
#endif
|
|
|
|
#if _DECAL
|
|
DoDecalBlend(decalOutput, albedo, normSAO, surfGrad, emisMetal, i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALTINT && !_PERTEXGLOBALTINTSTRENGTH
|
|
GlobalTintTexture(albedo.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _VSGRASSMAP
|
|
VSGrassTexture(albedo.rgb, config, camDist);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && !_PERTEXGLOBALNORMALSTRENGTH
|
|
GlobalNormalTexture(normSAO, surfGrad, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && !_PERTEXGLOBALSAOMSTRENGTH
|
|
GlobalSAOMTexture(normSAO, emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && !_PERTEXGLOBALEMISSTRENGTH
|
|
GlobalEmisTexture(emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && !_PERTEXGLOBALSPECULARSTRENGTH && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexture(specular.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
|
|
|
|
o.Albedo = albedo.rgb;
|
|
o.Height = albedo.a;
|
|
|
|
#if _NONORMALMAP
|
|
o.Normal = half3(0,0,1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#elif _SURFACENORMALS
|
|
o.Normal = ResolveNormalFromSurfaceGradient(surfGrad);
|
|
o.Normal = mul(GetTBN(i), o.Normal);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#else
|
|
o.Normal = half3(normSAO.xy, 1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _PERTEXRIMLIGHT
|
|
#if _USEEMISSIVEMETAL
|
|
emisMetal.rgb *= _EmissiveMult;
|
|
#endif
|
|
|
|
o.Emission += emisMetal.rgb;
|
|
o.Metallic = emisMetal.a;
|
|
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = specular;
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
pud = DoStreams(i, o, fxLevels, config.uv, porosity, waterNormalFoam, worldNormalVertex, streamFoam, wetLevel, burnLevel, i.worldPos);
|
|
#endif
|
|
|
|
|
|
#if _SNOW
|
|
snowCover = DoSnow(i, o, config.uv, WorldNormalVector(i, o.Normal), worldNormalVertex, i.worldPos, pud, porosity, camDist,
|
|
config, weights, SSSTint, SSSThickness, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if _PERTEXSSS || _MESHCOMBINEDUSESSS || (_SNOW && _SNOWSSS)
|
|
{
|
|
half3 worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
|
|
|
|
o.Emission += ComputeSSS(i, worldView, WorldNormalVector(i, o.Normal),
|
|
SSSTint, SSSThickness, _SSSDistance, _SSSScale, _SSSPower);
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWGLITTER
|
|
DoSnowGlitter(i, config, o, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
#if _WINDPARTICULATE || _SNOWPARTICULATE
|
|
DoWindParticulate(i, o, config, weights, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
o.Normal.z = sqrt(1 - saturate(dot(o.Normal.xy, o.Normal.xy)));
|
|
|
|
#if _SPECULARFADE
|
|
{
|
|
float specFade = saturate((i.worldPos.y - _SpecularFades.x) / max(_SpecularFades.y - _SpecularFades.x, 0.0001));
|
|
o.Metallic *= specFade;
|
|
o.Smoothness *= specFade;
|
|
}
|
|
#endif
|
|
|
|
#if _VSSHADOWMAP
|
|
VSShadowTexture(o, i, config, camDist);
|
|
#endif
|
|
|
|
#if _TOONWIREFRAME
|
|
ToonWireframe(config.uv, o.Albedo, camDist);
|
|
#endif
|
|
|
|
#if _SEETHROUGHSHADER
|
|
SeethroughShader(o.Albedo, o.Emission, o.Alpha, i.worldPos, o.Normal, i.worldNormal);
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_TRAXBUFFER
|
|
ClearAllButAlbedo(o, half3(traxBuffer, 0, 0) * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMALVERTEX
|
|
ClearAllButAlbedo(o, worldNormalVertex * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(o, WorldNormalVector(i, o.Normal) * saturate(o.Albedo.z+1));
|
|
#endif
|
|
|
|
#if _DEBUG_MEGABARY && _MEGASPLAT
|
|
o.Albedo = i.baryWeights.xyz;
|
|
#endif
|
|
|
|
|
|
return o;
|
|
}
|
|
|
|
void SampleSplats(float2 controlUV, inout half4 w0, inout half4 w1, inout half4 w2, inout half4 w3, inout half4 w4, inout half4 w5, inout half4 w6, inout half4 w7)
|
|
{
|
|
#if _CUSTOMSPLATTEXTURES
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_CustomControl0_TexelSize.zw - 1.0f) + 0.5f) * _CustomControl0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_CustomControl0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_CustomControl1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_CustomControl2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_CustomControl3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_CustomControl4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_CustomControl5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_CustomControl6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_CustomControl7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#else
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_Control0_TexelSize.zw - 1.0f) + 0.5f) * _Control0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_Control0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_Control1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_Control2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_Control3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_Control4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_Control5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_Control6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_Control7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
MicroSplatLayer SurfImpl(Input i, float3 worldNormalVertex)
|
|
{
|
|
#if _MEGANOUV
|
|
i.uv_Control0 = i.worldPos.xz;
|
|
#endif
|
|
|
|
float camDist = distance(_WorldSpaceCameraPos, i.worldPos);
|
|
|
|
#if _FORCELOCALSPACE
|
|
worldNormalVertex = mul((float3x3)GetWorldToObjectMatrix(), worldNormalVertex).xyz;
|
|
i.worldPos = i.worldPos - mul(GetObjectToWorldMatrix(), float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
i.worldPos = i.worldPos + mul(_GlobalOriginMTX, float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
i.worldPos = SAMPLE_TEXTURE2D(_DebugWorldPos, sampler_Diffuse, i.uv_Control0);
|
|
worldNormalVertex = SAMPLE_TEXTURE2D(_DebugWorldNormal, sampler_Diffuse, i.uv_Control0);
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ALPHABELOWHEIGHT && !_TBDISABLEALPHAHOLES
|
|
ClipWaterLevel(i.worldPos);
|
|
#endif
|
|
|
|
#if !_TBDISABLEALPHAHOLES && defined(_ALPHATEST_ON)
|
|
// UNITY 2019.3 holes
|
|
ClipHoles(i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
float2 origUV = i.uv_Control0;
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
float2 controlUV = i.uv2_Diffuse;
|
|
#else
|
|
float2 controlUV = i.uv_Control0;
|
|
#endif
|
|
|
|
|
|
#if _MICROMESH
|
|
controlUV = InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, controlUV);
|
|
#endif
|
|
|
|
half4 weights = half4(1,0,0,0);
|
|
|
|
Config config = (Config)0;
|
|
UNITY_INITIALIZE_OUTPUT(Config,config);
|
|
config.uv = origUV;
|
|
|
|
DecalOutput decalOutput = (DecalOutput)0;
|
|
#if _DECAL
|
|
decalOutput = DoDecals(i.uv_Control0, i.worldPos, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SURFACENORMALS
|
|
// Initialize the surface gradient basis vectors
|
|
ConstructSurfaceGradientTBN(i);
|
|
#endif
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(_SplatFade.y - camDist)
|
|
#endif // _SPLATFADE
|
|
{
|
|
#if !_DISABLESPLATMAPS
|
|
|
|
// Sample the splat data, from textures or vertices, and setup the config..
|
|
#if _MICRODIGGERMESH
|
|
DiggerSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLAT
|
|
MegaSplatVertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLATTEXTURE
|
|
MegaSplatTextureSetup(controlUV, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MICROVERTEXMESH
|
|
VertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif !_PROCEDURALTEXTURE || _PROCEDURALBLENDSPLATS
|
|
half4 w0 = 0; half4 w1 = 0; half4 w2 = 0; half4 w3 = 0; half4 w4 = 0; half4 w5 = 0; half4 w6 = 0; half4 w7 = 0;
|
|
SampleSplats(controlUV, w0, w1, w2, w3, w4, w5, w6, w7);
|
|
Setup(weights, origUV, config, w0, w1, w2, w3, w4, w5, w6, w7, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
float3 procNormal = worldNormalVertex;
|
|
float3 worldPos = i.worldPos;
|
|
ProceduralSetup(i, worldPos, i.worldHeight, procNormal, i.worldUpVector, weights, origUV, config, ddx(origUV), ddy(origUV), ddx(worldPos), ddy(worldPos), decalOutput);
|
|
#endif
|
|
#else // _DISABLESPLATMAPS
|
|
Setup(weights, origUV, config, half4(1,0,0,0), 0, 0, 0, 0, 0, 0, 0, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _SLOPETEXTURE
|
|
SlopeTexture(config, weights, worldNormalVertex);
|
|
#endif
|
|
} // _SPLATFADE else case
|
|
|
|
|
|
#if _TOONFLATTEXTURE
|
|
float2 quv = floor(origUV * _ToonTerrainSize);
|
|
float2 fuv = frac(origUV * _ToonTerrainSize);
|
|
#if !_TOONFLATTEXTUREQUAD
|
|
quv = Hash2D((fuv.x > fuv.y) ? quv : quv * 0.333);
|
|
#endif
|
|
float2 uvq = quv / _ToonTerrainSize;
|
|
config.uv0.xy = uvq;
|
|
config.uv1.xy = uvq;
|
|
config.uv2.xy = uvq;
|
|
config.uv3.xy = uvq;
|
|
#endif
|
|
|
|
#if (_TEXTURECLUSTER2 || _TEXTURECLUSTER3) && !_DISABLESPLATMAPS
|
|
PrepClusters(origUV, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if (_ALPHAHOLE || _ALPHAHOLETEXTURE) && !_DISABLESPLATMAPS && !_TBDISABLEALPHAHOLES
|
|
ClipAlphaHole(config, weights);
|
|
#endif
|
|
|
|
|
|
|
|
MicroSplatLayer l = Sample(i, weights, config, camDist, worldNormalVertex, decalOutput);
|
|
|
|
// On windows, sometimes the shared samplers gets stripped, so we have to do this crap.
|
|
// We sample from the lowest mip, so it shouldn't cost much, but still, I hate this, wtf..
|
|
float stripVal = saturate(SAMPLE_TEXTURE2D_LOD(_Diffuse, sampler_Diffuse, config.uv0, 11).r + 2);
|
|
stripVal *= saturate(SAMPLE_TEXTURE2D_LOD(_NormalSAO, sampler_NormalSAO, config.uv0, 11).r + 2);
|
|
l.Albedo *= stripVal;
|
|
l.Normal *= stripVal;
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
ProceduralTextureDebugOutput(l, weights, config);
|
|
#endif
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float4 ConstructTerrainTangent(float3 normal, float3 positiveZ)
|
|
{
|
|
// Consider a flat terrain. It should have tangent be (1, 0, 0) and bitangent be (0, 0, 1) as the UV of the terrain grid mesh is a scale of the world XZ position.
|
|
// In CreateTangentToWorld function (in SpaceTransform.hlsl), it is cross(normal, tangent) * sgn for the bitangent vector.
|
|
// It is not true in a left-handed coordinate system for the terrain bitangent, if we provide 1 as the tangent.w. It would produce (0, 0, -1) instead of (0, 0, 1).
|
|
// Also terrain's tangent calculation was wrong in a left handed system because cross((0,0,1), terrainNormalOS) points to the wrong direction as negative X.
|
|
// Therefore all the 4 xyzw components of the tangent needs to be flipped to correct the tangent frame.
|
|
// (See TerrainLitData.hlsl - GetSurfaceAndBuiltinData)
|
|
float3 tangent = normalize(cross(normal, positiveZ));
|
|
return float4(tangent, -1);
|
|
}
|
|
|
|
|
|
|
|
void TerrainInstancing(inout float4 vertex, inout float3 normal, inout float2 uv)
|
|
{
|
|
#if _MICROTERRAIN && defined(UNITY_INSTANCING_ENABLED) && !_TERRAINBLENDABLESHADER
|
|
|
|
float2 patchVertex = vertex.xy;
|
|
float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);
|
|
|
|
float2 sampleCoords = (patchVertex.xy + instanceData.xy) * instanceData.z; // (xy + float2(xBase,yBase)) * skipScale
|
|
uv = sampleCoords * _TerrainHeightmapRecipSize.zw;
|
|
|
|
float2 sampleUV = (uv / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleUV, 0));
|
|
|
|
vertex.xz = sampleCoords * _TerrainHeightmapScale.xz;
|
|
vertex.y = height * _TerrainHeightmapScale.y;
|
|
|
|
|
|
normal = float3(0, 1, 0);
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
void ApplyMeshModification(inout VertexData input)
|
|
{
|
|
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
|
|
float2 uv = input.texcoord0.xy;
|
|
TerrainInstancing(input.vertex, input.normal, uv);
|
|
input.texcoord0.xy = uv;
|
|
#endif
|
|
#if _PERPIXNORMAL && !_TERRAINBLENDABLESHADER
|
|
input.normal = float3(0,1,0);
|
|
#endif
|
|
|
|
#if _MICROVERSEPREVIEW
|
|
float4 recipSize = _TerrainHeightmapTexture_TexelSize;
|
|
recipSize.zw = (1.0f / (_TerrainHeightmapTexture_TexelSize.zw-1));
|
|
float2 sampleCoords = (input.texcoord0.xy / recipSize.zw + 0.5f) * recipSize.xy;
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleCoords, 0));
|
|
input.vertex.xyz += float3(0,1,0) * height * _TerrainHeight * 2;
|
|
#endif
|
|
|
|
}
|
|
|
|
// called by the template, so we can remove tangent from VertexData
|
|
void ApplyTerrainTangent(inout VertexToPixel input)
|
|
{
|
|
#if (_MICROTERRAIN || _PERPIXNORMAL) && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
|
|
// digger meshes ain't got no tangent either..
|
|
#if _MICRODIGGERMESH && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
void ModifyVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
ApplyMeshModification(v);
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
EncodeVertexWorkflow(v, d);
|
|
#elif _MEGASPLAT
|
|
EncodeMegaSplatVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void ModifyTessellatedVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
#if _MICROVERSEPREVIEW
|
|
v.vertex.y = OffsetVertex(v, d).y;
|
|
#elif _TESSDISTANCE || _TESSEDGE
|
|
v.vertex.xyz += OffsetVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
float3 GetTessFactors ()
|
|
{
|
|
#if _TESSEDGE
|
|
return float3(_TessData1.x, _TessData1.w, 0);
|
|
#endif
|
|
#if _TESSDISTANCE
|
|
return float3(_TessData2.x, _TessData2.y, _TessData1.x);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SurfaceFunction(inout Surface o, inout ShaderData d)
|
|
{
|
|
|
|
float3 worldNormalVertex = d.worldSpaceNormal;
|
|
#if _MICROVERSEPREVIEW
|
|
float2 sampleCoords = d.texcoord0.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif (defined(UNITY_INSTANCING_ENABLED) && _MICROTERRAIN && !_TERRAINBLENDABLESHADER)
|
|
float2 sampleCoords = (d.texcoord0.xy / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif _PERPIXNORMAL && (_MICROTERRAIN || _MICROMESHTERRAIN) && !_TERRAINBLENDABLESHADER
|
|
float2 sampleCoords = (d.texcoord0.xy * _PerPixelNormal_TexelSize.zw + 0.5f) * _PerPixelNormal_TexelSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_PerPixelNormal, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
|
|
float3 geomBitangent = normalize(cross(geomTangent, geomNormal)) * -1;
|
|
#if _MICROMESHTERRAIN
|
|
geomBitangent *= -1;
|
|
#endif
|
|
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#endif
|
|
|
|
#if _TOONPOLYEDGE
|
|
FlatShade(d);
|
|
#endif
|
|
|
|
Input i = DescToInput(d);
|
|
|
|
|
|
|
|
#if _SRPTERRAINBLEND
|
|
MicroSplatLayer l = BlendWithTerrain(d);
|
|
|
|
#if _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(l, normalize(TangentToWorldSpace(d, l.Normal)) * saturate(l.Albedo.z+1));
|
|
#endif
|
|
#else
|
|
MicroSplatLayer l = SurfImpl(i, worldNormalVertex);
|
|
#endif
|
|
|
|
DoDebugOutput(l);
|
|
|
|
|
|
|
|
|
|
o.Albedo = l.Albedo;
|
|
o.Normal = l.Normal;
|
|
o.Smoothness = l.Smoothness;
|
|
o.Occlusion = l.Occlusion;
|
|
o.Metallic = l.Metallic;
|
|
o.Emission = l.Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = l.Specular;
|
|
#endif
|
|
o.Height = l.Height;
|
|
o.Alpha = l.Alpha;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SHADERDESC
|
|
|
|
ShaderData CreateShaderData(VertexToPixel i)
|
|
{
|
|
ShaderData d = (ShaderData)0;
|
|
d.worldSpacePosition = i.worldPos;
|
|
|
|
d.worldSpaceNormal = i.worldNormal;
|
|
d.worldSpaceTangent = i.worldTangent.xyz;
|
|
float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * -1;
|
|
|
|
|
|
d.TBNMatrix = float3x3(d.worldSpaceTangent, bitangent, d.worldSpaceNormal);
|
|
d.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
d.texcoord0 = i.texcoord0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
d.texcoord1 = i.texcoord1;
|
|
// d.texcoord2 = i.texcoord2;
|
|
#endif
|
|
// d.texcoord3 = i.texcoord3;
|
|
// d.vertexColor = i.vertexColor;
|
|
|
|
// these rarely get used, so we back transform them. Usually will be stripped.
|
|
#if _HDRP
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(GetCameraRelativePositionWS(i.worldPos), 1));
|
|
#else
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(i.worldPos, 1));
|
|
#endif
|
|
// d.localSpaceNormal = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldNormal));
|
|
// d.localSpaceTangent = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldTangent.xyz));
|
|
|
|
// d.screenPos = i.screenPos;
|
|
// d.screenUV = i.screenPos.xy / i.screenPos.w;
|
|
|
|
// d.extraV2F0 = i.extraV2F0;
|
|
// d.extraV2F1 = i.extraV2F1;
|
|
// d.extraV2F2 = i.extraV2F2;
|
|
// d.extraV2F3 = i.extraV2F3;
|
|
// d.extraV2F4 = i.extraV2F4;
|
|
// d.extraV2F5 = i.extraV2F5;
|
|
// d.extraV2F6 = i.extraV2F6;
|
|
// d.extraV2F7 = i.extraV2F7;
|
|
|
|
return d;
|
|
}
|
|
// CHAINS
|
|
|
|
void ChainModifyVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
ModifyVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
void ChainModifyTessellatedVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
// d.extraV2F0 = v2p.extraV2F0;
|
|
// d.extraV2F1 = v2p.extraV2F1;
|
|
// d.extraV2F2 = v2p.extraV2F2;
|
|
// d.extraV2F3 = v2p.extraV2F3;
|
|
// d.extraV2F4 = v2p.extraV2F4;
|
|
// d.extraV2F5 = v2p.extraV2F5;
|
|
// d.extraV2F6 = v2p.extraV2F6;
|
|
// d.extraV2F7 = v2p.extraV2F7;
|
|
|
|
ModifyTessellatedVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
|
|
void ChainFinalColorForward(inout Surface l, inout ShaderData d, inout half4 color)
|
|
{
|
|
|
|
}
|
|
|
|
void ChainFinalGBufferStandard(inout Surface s, inout ShaderData d, inout half4 GBuffer0, inout half4 GBuffer1, inout half4 GBuffer2, inout half4 outEmission, inout half4 outShadowMask)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _PASSSHADOW
|
|
float3 _LightDirection;
|
|
float3 _LightPosition;
|
|
#endif
|
|
|
|
// vertex shader
|
|
VertexToPixel Vert (VertexData v)
|
|
{
|
|
|
|
VertexToPixel o = (VertexToPixel)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
|
|
|
|
|
#if !_TESSELLATION_ON
|
|
ChainModifyVertex(v, o);
|
|
#endif
|
|
|
|
o.texcoord0 = v.texcoord0;
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
o.texcoord1 = v.texcoord1;
|
|
// o.texcoord2 = v.texcoord2;
|
|
#endif
|
|
|
|
// o.texcoord3 = v.texcoord3;
|
|
// o.vertexColor = v.vertexColor;
|
|
|
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
|
|
o.worldPos = TransformObjectToWorld(v.vertex.xyz);
|
|
o.worldNormal = TransformObjectToWorldNormal(v.normal);
|
|
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float2 uv1 = v.texcoord1.xy;
|
|
float2 uv2 = v.texcoord2.xy;
|
|
o.worldTangent = float4(TransformObjectToWorldDir(v.tangent.xyz), v.tangent.w);
|
|
#else
|
|
float2 uv1 = v.texcoord0.xy;
|
|
float2 uv2 = uv1;
|
|
#endif
|
|
|
|
// MS Only
|
|
ApplyTerrainTangent(o);
|
|
|
|
|
|
#if _PASSSHADOW
|
|
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
float3 lightDirectionWS = normalize(_LightPosition - o.worldPos);
|
|
#else
|
|
float3 lightDirectionWS = _LightDirection;
|
|
#endif
|
|
// Define shadow pass specific clip position for Universal
|
|
o.pos = TransformWorldToHClip(ApplyShadowBias(o.worldPos, o.worldNormal, lightDirectionWS));
|
|
#if UNITY_REVERSED_Z
|
|
o.pos.z = min(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#else
|
|
o.pos.z = max(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#endif
|
|
#elif _PASSMETA
|
|
#if _MICROTERRAIN
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), v.texcoord0.xy, v.texcoord0.xy, unity_LightmapST, unity_DynamicLightmapST);
|
|
#else
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), uv1, uv2, unity_LightmapST, unity_DynamicLightmapST);
|
|
#endif
|
|
#else
|
|
o.pos = TransformWorldToHClip(o.worldPos);
|
|
#endif
|
|
|
|
|
|
|
|
// o.screenPos = ComputeScreenPos(o.pos, _ProjectionParams.x);
|
|
|
|
|
|
#if _PASSFORWARD || _PASSGBUFFER
|
|
#if _MICROTERRAIN
|
|
OUTPUT_LIGHTMAP_UV(v.texcoord0.xy, unity_LightmapST, o.lightmapUV);
|
|
#else
|
|
OUTPUT_LIGHTMAP_UV(uv1, unity_LightmapST, o.lightmapUV);
|
|
#endif
|
|
OUTPUT_SH(o.worldNormal, o.sh);
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
o.dynamicLightmapUV.xy = uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
|
|
half fogFactor = 0;
|
|
#if defined(_FOG_FRAGMENT)
|
|
fogFactor = ComputeFogFactor(o.pos.z);
|
|
#endif
|
|
#if _BAKEDLIT
|
|
half3 vertexLight = VertexLighting(o.worldPos, o.worldNormal);
|
|
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
|
|
#else
|
|
o.fogFactorAndVertexLight = half4(fogFactor, 0,0,0);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
|
|
o.shadowCoord = GetShadowCoord(vertexInput);
|
|
#endif
|
|
|
|
return o;
|
|
}
|
|
|
|
|
|
|
|
|
|
// fragment shader
|
|
half4 Frag (VertexToPixel IN
|
|
#ifdef _DEPTHOFFSET_ON
|
|
, out float outputDepth : SV_Depth
|
|
#endif
|
|
) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
|
|
|
|
ShaderData d = CreateShaderData(IN);
|
|
Surface l = (Surface)0;
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
l.outputDepth = outputDepth;
|
|
#endif
|
|
|
|
l.Albedo = half3(0.5, 0.5, 0.5);
|
|
l.Normal = float3(0,0,1);
|
|
l.Occlusion = 1;
|
|
l.Alpha = 1;
|
|
|
|
SurfaceFunction(l, d);
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
outputDepth = l.outputDepth;
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ENDHLSL
|
|
|
|
}
|
|
|
|
|
|
|
|
Pass
|
|
{
|
|
Name "Meta"
|
|
Tags
|
|
{
|
|
"LightMode" = "Meta"
|
|
}
|
|
|
|
// Render State
|
|
Cull Off
|
|
|
|
|
|
|
|
HLSLPROGRAM
|
|
|
|
#pragma vertex Vert
|
|
#pragma fragment Frag
|
|
|
|
#pragma target 3.5
|
|
|
|
#pragma prefer_hlslcc gles
|
|
#pragma exclude_renderers d3d11_9x
|
|
#pragma multi_compile_local _ _ALPHATEST_ON
|
|
|
|
#define SHADERPASS SHADERPASS_META
|
|
#define _PASSMETA 1
|
|
|
|
|
|
#define _MICROSPLAT 1
|
|
#define _MICROPOLARISMESH 1
|
|
#define _USEGRADMIP 1
|
|
#define _PERTEXUVSCALEOFFSET 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
#define _MSRENDERLOOP_UNITYLD 1
|
|
#define _MSRENDERLOOP_UNITYURP2020 1
|
|
#define _MSRENDERLOOP_UNITYURP2021 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
|
|
|
|
|
|
#define _URP 1
|
|
|
|
|
|
|
|
|
|
// Includes
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/MetaInput.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
|
|
#include "Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariablesFunctions.hlsl"
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, float3x3(d.worldSpaceTangent, cross(d.worldSpaceTangent, d.worldSpaceNormal), d.worldSpaceNormal))
|
|
|
|
|
|
#define UnityObjectToWorldNormal(normal) mul(GetObjectToWorldMatrix(), normal)
|
|
|
|
#define _WorldSpaceLightPos0 _MainLightPosition
|
|
|
|
#define UNITY_DECLARE_TEX2D(name) TEXTURE2D(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2D_NOSAMPLER(name) TEXTURE2D(name);
|
|
#define UNITY_DECLARE_TEX2DARRAY(name) TEXTURE2D_ARRAY(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2DARRAY_NOSAMPLER(name) TEXTURE2D_ARRAY(name);
|
|
|
|
#define UNITY_SAMPLE_TEX2DARRAY(tex,coord) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, coord.xy, coord.z)
|
|
#define UNITY_SAMPLE_TEX2DARRAY_LOD(tex,coord,lod) SAMPLE_TEXTURE2D_ARRAY_LOD(tex, sampler##tex, coord.xy, coord.z, lod)
|
|
#define UNITY_SAMPLE_TEX2D(tex, coord) SAMPLE_TEXTURE2D(tex, sampler##tex, coord)
|
|
#define UNITY_SAMPLE_TEX2D_SAMPLER(tex, samp, coord) SAMPLE_TEXTURE2D(tex, sampler##samp, coord)
|
|
|
|
#if defined(UNITY_COMPILER_HLSL)
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
|
|
#else
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name)
|
|
#endif
|
|
|
|
#define sampler2D_float sampler2D
|
|
#define sampler2D_half sampler2D
|
|
|
|
|
|
|
|
// data across stages, stripped like the above.
|
|
struct VertexToPixel
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float3 worldPos : TEXCOORD0;
|
|
float3 worldNormal : TEXCOORD1;
|
|
float4 worldTangent : TEXCOORD2;
|
|
float4 texcoord0 : TEXCCOORD3;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 texcoord1 : TEXCCOORD4;
|
|
// float4 texcoord2 : TEXCCOORD5;
|
|
#endif
|
|
// float4 texcoord3 : TEXCCOORD6;
|
|
// float4 screenPos : TEXCOORD7;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
// float4 extraV2F0 : TEXCOORD13;
|
|
// float4 extraV2F1 : TEXCOORD14;
|
|
// float4 extraV2F2 : TEXCOORD15;
|
|
// float4 extraV2F3 : TEXCOORD16;
|
|
// float4 extraV2F4 : TEXCOORD17;
|
|
// float4 extraV2F5 : TEXCOORD18;
|
|
// float4 extraV2F6 : TEXCOORD19;
|
|
// float4 extraV2F7 : TEXCOORD20;
|
|
|
|
|
|
#if defined(LIGHTMAP_ON)
|
|
float2 lightmapUV : TEXCOORD8;
|
|
#endif
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
float2 dynamicLightmapUV : TEXCOORD9;
|
|
#endif
|
|
#if !defined(LIGHTMAP_ON)
|
|
float3 sh : TEXCOORD10;
|
|
#endif
|
|
|
|
float4 fogFactorAndVertexLight : TEXCOORD11;
|
|
float4 shadowCoord : TEXCOORD12;
|
|
|
|
#if UNITY_ANY_INSTANCING_ENABLED
|
|
uint instanceID : CUSTOM_INSTANCE_ID;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_MULTIVIEW_ENABLED)) || (defined(UNITY_STEREO_INSTANCING_ENABLED) && (defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)))
|
|
uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_INSTANCING_ENABLED))
|
|
uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex;
|
|
#endif
|
|
#if defined(SHADER_STAGE_FRAGMENT) && defined(VARYINGS_NEED_CULLFACE)
|
|
FRONT_FACE_TYPE cullFace : FRONT_FACE_SEMANTIC;
|
|
#endif
|
|
};
|
|
|
|
|
|
// TEMPLATE_SHARED
|
|
|
|
// data describing the user output of a pixel
|
|
struct Surface
|
|
{
|
|
half3 Albedo;
|
|
half Height;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half3 Emission;
|
|
half Metallic;
|
|
half3 Specular;
|
|
half Occlusion;
|
|
half Alpha;
|
|
// HDRP Only
|
|
half SpecularOcclusion;
|
|
half SubsurfaceMask;
|
|
half Thickness;
|
|
half CoatMask;
|
|
half Anisotropy;
|
|
half IridescenceMask;
|
|
half IridescenceThickness;
|
|
};
|
|
|
|
// data the user might need, this will grow to be big. But easy to strip
|
|
struct ShaderData
|
|
{
|
|
float3 localSpacePosition;
|
|
float3 localSpaceNormal;
|
|
float3 localSpaceTangent;
|
|
|
|
float3 worldSpacePosition;
|
|
float3 worldSpaceNormal;
|
|
float3 worldSpaceTangent;
|
|
|
|
float3 worldSpaceViewDir;
|
|
float3 tangentSpaceViewDir;
|
|
|
|
float4 texcoord0;
|
|
float4 texcoord1;
|
|
float4 texcoord2;
|
|
float4 texcoord3;
|
|
|
|
float2 screenUV;
|
|
float4 screenPos;
|
|
|
|
float4 vertexColor;
|
|
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
|
|
float3x3 TBNMatrix;
|
|
};
|
|
|
|
struct VertexData
|
|
{
|
|
#if SHADER_TARGET > 30 && _PLANETCOMPUTE
|
|
// // uint vertexID : SV_VertexID;
|
|
#endif
|
|
float4 vertex : POSITION;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD4; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD5; // Add Precomputed Velocity (Alembic computes velocities on runtime side).
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct TessVertex
|
|
{
|
|
float4 vertex : INTERNALTESSPOS;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
// float4 extraV2F0 : TEXCOORD4;
|
|
// float4 extraV2F1 : TEXCOORD5;
|
|
// float4 extraV2F2 : TEXCOORD6;
|
|
// float4 extraV2F3 : TEXCOORD7;
|
|
// float4 extraV2F4 : TEXCOORD8;
|
|
// float4 extraV2F5 : TEXCOORD9;
|
|
// float4 extraV2F6 : TEXCOORD10;
|
|
// float4 extraV2F7 : TEXCOORD11;
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD12; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD13;
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
struct ExtraV2F
|
|
{
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
};
|
|
|
|
|
|
float3 WorldToTangentSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(d.TBNMatrix, normal);
|
|
}
|
|
|
|
float3 TangentToWorldSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(normal, d.TBNMatrix);
|
|
}
|
|
|
|
// in this case, make standard more like SRPs, because we can't fix
|
|
// GetWorldToObjectMatrix() in HDRP, since it already does macro-fu there
|
|
|
|
#if _STANDARD
|
|
float3 TransformWorldToObject(float3 p) { return mul(GetWorldToObjectMatrix(), float4(p, 1)); };
|
|
float3 TransformObjectToWorld(float3 p) { return mul(GetObjectToWorldMatrix(), float4(p, 1)); };
|
|
float4 TransformWorldToObject(float4 p) { return mul(GetWorldToObjectMatrix(), p); };
|
|
float4 TransformObjectToWorld(float4 p) { return mul(GetObjectToWorldMatrix(), p); };
|
|
float4x4 GetWorldToObjectMatrix() { return GetWorldToObjectMatrix(); }
|
|
float4x4 GetObjectToWorldMatrix() { return GetObjectToWorldMatrix(); }
|
|
#endif
|
|
|
|
float3 GetCameraWorldPosition()
|
|
{
|
|
#if _HDRP
|
|
return GetCameraRelativePositionWS(_WorldSpaceCameraPos);
|
|
#else
|
|
return _WorldSpaceCameraPos;
|
|
#endif
|
|
}
|
|
|
|
|
|
#if _HDRP
|
|
|
|
half3 UnpackNormalmapRGorAG(half4 packednormal)
|
|
{
|
|
// This do the trick
|
|
packednormal.x *= packednormal.w;
|
|
|
|
half3 normal;
|
|
normal.xy = packednormal.xy * 2 - 1;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
half3 UnpackNormal(half4 packednormal)
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
return packednormal.xyz * 2 - 1;
|
|
#else
|
|
return UnpackNormalmapRGorAG(packednormal);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if _HDRP || _URP
|
|
|
|
half3 UnpackScaleNormal(half4 packednormal, half scale)
|
|
{
|
|
#ifndef UNITY_NO_DXT5nm
|
|
// Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
|
|
// Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
|
|
packednormal.x *= packednormal.w;
|
|
#endif
|
|
half3 normal;
|
|
normal.xy = (packednormal.xy * 2 - 1) * scale;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void GetSun(out float3 lightDir, out float3 color)
|
|
{
|
|
lightDir = float3(0.5, 0.5, 0);
|
|
color = 1;
|
|
#if _HDRP
|
|
if (_DirectionalLightCount > 0)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[0];
|
|
lightDir = -light.forward.xyz;
|
|
color = light.color;
|
|
}
|
|
#elif _STANDARD
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
color = _LightColor0.rgb;
|
|
#elif _URP
|
|
Light light = GetMainLight();
|
|
lightDir = light.direction;
|
|
color = light.color;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
|
|
|
|
|
|
#if _MESHSUBARRAY
|
|
half4 _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
float4 _Diffuse_TexelSize;
|
|
float4 _NormalSAO_TexelSize;
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
float _HybridHeightBlendDistance;
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
float4 _SmoothAO_TexelSize;
|
|
#endif
|
|
|
|
#ifdef _ALPHATEST_ON
|
|
float4 _TerrainHolesTexture_TexelSize;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
float4 _Specular_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
float4 _EmissiveMetal_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
half _EmissiveMult;
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
half _AutoNormalHeightScale;
|
|
#endif
|
|
|
|
float4 _UVScale; // scale and offset
|
|
|
|
half _Contrast;
|
|
|
|
|
|
|
|
#if _VSSHADOWMAP
|
|
float4 gVSSunDirection;
|
|
#endif
|
|
|
|
#if _FORCELOCALSPACE && _PLANETVECTORS
|
|
float4x4 _PQSToLocal;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
float4x4 _GlobalOriginMTX;
|
|
#endif
|
|
|
|
float4 _Control0_TexelSize;
|
|
#if _CUSTOMSPLATTEXTURES
|
|
float4 _CustomControl0_TexelSize;
|
|
#endif
|
|
float4 _PerPixelNormal_TexelSize;
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
float2 _NoiseUVParams;
|
|
#endif
|
|
|
|
float4 _PerTexProps_TexelSize;
|
|
|
|
#if _SURFACENORMALS
|
|
float3 surfTangent;
|
|
float3 surfBitangent;
|
|
float3 surfNormal;
|
|
#endif
|
|
|
|
|
|
|
|
CBUFFER_END
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, data.TBN)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// In Unity 2020.3LTS, Unity will spew tons of errors about missing this sampler in
|
|
// URP, even though it shouldn't be required.
|
|
TEXTURE2D(_MainTex);
|
|
|
|
// globals, outside of CBuffer, but used by more than one module
|
|
float3 _gGlitterLightDir;
|
|
float3 _gGlitterLightWorldPos;
|
|
half3 _gGlitterLightColor;
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
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)
|
|
float4 _TerrainNormalmapTexture_TexelSize;
|
|
#endif
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
TEXTURE2D(_TerrainHeightmapTexture);
|
|
float4 _TerrainHeightmapTexture_TexelSize;
|
|
TEXTURE2D(_TerrainNormalmapTexture);
|
|
#endif
|
|
|
|
UNITY_INSTANCING_BUFFER_START(Terrain)
|
|
UNITY_DEFINE_INSTANCED_PROP(float4, _TerrainPatchInstanceData) // float4(xBase, yBase, skipScale, ~)
|
|
UNITY_INSTANCING_BUFFER_END(Terrain)
|
|
|
|
|
|
|
|
|
|
// dynamic branching helpers, for regular and aggressive branching
|
|
// debug mode shows how many samples using branching will save us.
|
|
//
|
|
// These macros are always used instead of the UNITY_BRANCH macro
|
|
// to maintain debug displays and allow branching to be disabled
|
|
// on as granular level as we want.
|
|
|
|
#if _BRANCHSAMPLES
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++; if (w > 0)
|
|
#else
|
|
#define MSBRANCH(w) UNITY_BRANCH if (w > 0)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++;
|
|
#else
|
|
#define MSBRANCH(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _BRANCHSAMPLESAGR
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER ||_DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++; if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++; if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++; if (w > 0.001)
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) UNITY_BRANCH if (w > 0.001)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++;
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++;
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++;
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w)
|
|
#define MSBRANCHCLUSTER(w)
|
|
#define MSBRANCHOTHER(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _DEBUG_SAMPLECOUNT
|
|
int _sampleCount;
|
|
#define COUNTSAMPLE { _sampleCount++; }
|
|
#else
|
|
#define COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _DEBUG_PROCLAYERS
|
|
int _procLayerCount;
|
|
#define COUNTPROCLAYER { _procLayerCount++; }
|
|
#else
|
|
#define COUNTPROCLAYER
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
TEXTURE2D(_DebugWorldPos);
|
|
TEXTURE2D(_DebugWorldNormal);
|
|
#endif
|
|
|
|
|
|
// splat
|
|
UNITY_DECLARE_TEX2DARRAY(_Diffuse);
|
|
UNITY_DECLARE_TEX2DARRAY(_NormalSAO);
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
TEXTURE2D(_NoiseUV);
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
UNITY_DECLARE_TEX2DARRAY(_SmoothAO);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
UNITY_DECLARE_TEX2DARRAY(_Specular);
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
UNITY_DECLARE_TEX2DARRAY(_EmissiveMetal);
|
|
#endif
|
|
|
|
TEXTURE2D(_PerPixelNormal);
|
|
|
|
SamplerState shared_linear_clamp_sampler;
|
|
SamplerState shared_point_clamp_sampler;
|
|
|
|
TEXTURE2D(_Control0);
|
|
#if _CUSTOMSPLATTEXTURES
|
|
TEXTURE2D(_CustomControl0);
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_CustomControl1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_CustomControl2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_CustomControl3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl7);
|
|
#endif
|
|
#else
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_Control1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_Control2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_Control3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_Control7);
|
|
#endif
|
|
#endif
|
|
|
|
TEXTURE2D_FLOAT(_PerTexProps);
|
|
|
|
struct DecalLayer
|
|
{
|
|
float3 uv;
|
|
float2 dx;
|
|
float2 dy;
|
|
int decalIndex;
|
|
bool dynamic;
|
|
};
|
|
|
|
struct DecalOutput
|
|
{
|
|
DecalLayer l0;
|
|
DecalLayer l1;
|
|
DecalLayer l2;
|
|
DecalLayer l3;
|
|
|
|
half4 Weights;
|
|
half4 Indexes;
|
|
half4 fxLevels;
|
|
|
|
};
|
|
|
|
|
|
struct TriGradMipFormat
|
|
{
|
|
float4 d0;
|
|
float4 d1;
|
|
float4 d2;
|
|
};
|
|
|
|
float InverseLerp(float x, float y, float v) { return (v-x)/max(y-x, 0.001); }
|
|
float2 InverseLerp(float2 x, float2 y, float2 v) { return (v-x)/max(y-x, float2(0.001, 0.001)); }
|
|
float3 InverseLerp(float3 x, float3 y, float3 v) { return (v-x)/max(y-x, float3(0.001, 0.001, 0.001)); }
|
|
float4 InverseLerp(float4 x, float4 y, float4 v) { return (v-x)/max(y-x, float4(0.001, 0.001, 0.001, 0.001)); }
|
|
|
|
|
|
// 2019.3 holes
|
|
#ifdef _ALPHATEST_ON
|
|
TEXTURE2D(_TerrainHolesTexture);
|
|
|
|
void ClipHoles(float2 uv)
|
|
{
|
|
float hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, shared_linear_clamp_sampler, uv).r;
|
|
COUNTSAMPLE
|
|
clip(hole < 0.5f ? -1 : 1);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT TriGradMipFormat
|
|
#define INITMIPFORMAT (TriGradMipFormat)0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float3
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float3
|
|
#endif
|
|
#else
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT float4
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float
|
|
#endif
|
|
#endif
|
|
|
|
float2 TotalOne(float2 v) { return v * (1.0 / max(v.x + v.y, 0.001)); }
|
|
float3 TotalOne(float3 v) { return v * (1.0 / max(v.x + v.y + v.z, 0.001)); }
|
|
float4 TotalOne(float4 v) { return v * (1.0 / max(v.x + v.y + v.z + v.w, 0.001)); }
|
|
|
|
float2 RotateUV(float2 uv, float amt)
|
|
{
|
|
uv -=0.5;
|
|
float s = sin ( amt);
|
|
float c = cos ( amt );
|
|
float2x2 mtx = float2x2( c, -s, s, c);
|
|
mtx *= 0.5;
|
|
mtx += 0.5;
|
|
mtx = mtx * 2-1;
|
|
uv = mul ( uv, mtx );
|
|
uv += 0.5;
|
|
return uv;
|
|
}
|
|
|
|
float4 DecodeToFloat4(float v)
|
|
{
|
|
uint vi = (uint)(v * (256.0f * 256.0f * 256.0f * 256.0f));
|
|
int ex = (int)(vi / (256 * 256 * 256) % 256);
|
|
int ey = (int)((vi / (256 * 256)) % 256);
|
|
int ez = (int)((vi / (256)) % 256);
|
|
int ew = (int)(vi % 256);
|
|
float4 e = float4(ex / 255.0, ey / 255.0, ez / 255.0, ew / 255.0);
|
|
return e;
|
|
}
|
|
|
|
|
|
|
|
struct Input
|
|
{
|
|
ShaderData shaderData;
|
|
float2 uv_Control0;
|
|
float2 uv2_Diffuse;
|
|
|
|
float worldHeight;
|
|
float3 worldUpVector;
|
|
|
|
float3 viewDir;
|
|
float3 worldPos;
|
|
float3 worldNormal;
|
|
float4 color;
|
|
float3x3 TBN;
|
|
|
|
// vertex/digger workflow data
|
|
half4 w0;
|
|
half4 w1;
|
|
half4 w2;
|
|
half4 w3;
|
|
half4 w4;
|
|
half4 w5;
|
|
half4 w6;
|
|
|
|
// megasplat data
|
|
half4 layer0;
|
|
half4 layer1;
|
|
half3 baryWeights;
|
|
half4 scatter0;
|
|
half4 scatter1;
|
|
|
|
// wetness, puddles, streams, lava from vertex or megasplat
|
|
half4 fx;
|
|
// snow min, snow max
|
|
half4 fx2;
|
|
|
|
|
|
};
|
|
|
|
struct TriplanarConfig
|
|
{
|
|
float3x3 uv0;
|
|
float3x3 uv1;
|
|
float3x3 uv2;
|
|
float3x3 uv3;
|
|
half3 pN;
|
|
half3 pN0;
|
|
half3 pN1;
|
|
half3 pN2;
|
|
half3 pN3;
|
|
half3 axisSign;
|
|
Input IN;
|
|
};
|
|
|
|
|
|
struct Config
|
|
{
|
|
float2 uv;
|
|
float3 uv0;
|
|
float3 uv1;
|
|
float3 uv2;
|
|
float3 uv3;
|
|
|
|
half4 cluster0;
|
|
half4 cluster1;
|
|
half4 cluster2;
|
|
half4 cluster3;
|
|
|
|
};
|
|
|
|
|
|
struct MicroSplatLayer
|
|
{
|
|
half3 Albedo;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half Occlusion;
|
|
half Metallic;
|
|
half Height;
|
|
half3 Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
half3 Specular;
|
|
#endif
|
|
half Alpha;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// raw, unblended samples from arrays
|
|
struct RawSamples
|
|
{
|
|
half4 albedo0;
|
|
half4 albedo1;
|
|
half4 albedo2;
|
|
half4 albedo3;
|
|
#if _SURFACENORMALS
|
|
half3 surf0;
|
|
half3 surf1;
|
|
half3 surf2;
|
|
half3 surf3;
|
|
#endif
|
|
|
|
half4 normSAO0;
|
|
half4 normSAO1;
|
|
half4 normSAO2;
|
|
half4 normSAO3;
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALEMIS || _GLOBALSMOOTHAOMETAL || _PERTEXSSS || _PERTEXRIMLIGHT
|
|
half4 emisMetal0;
|
|
half4 emisMetal1;
|
|
half4 emisMetal2;
|
|
half4 emisMetal3;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
half3 specular0;
|
|
half3 specular1;
|
|
half3 specular2;
|
|
half3 specular3;
|
|
#endif
|
|
};
|
|
|
|
void InitRawSamples(inout RawSamples s)
|
|
{
|
|
s.normSAO0 = half4(0,0,0,1);
|
|
s.normSAO1 = half4(0,0,0,1);
|
|
s.normSAO2 = half4(0,0,0,1);
|
|
s.normSAO3 = half4(0,0,0,1);
|
|
#if _SURFACENORMALS
|
|
s.surf0 = half3(0,0,1);
|
|
s.surf1 = half3(0,0,1);
|
|
s.surf2 = half3(0,0,1);
|
|
s.surf3 = half3(0,0,1);
|
|
#endif
|
|
}
|
|
|
|
float3 GetGlobalLightDir(Input i)
|
|
{
|
|
float3 lightDir = float3(1,0,0);
|
|
|
|
#if _HDRP || PASS_DEFERRED
|
|
lightDir = normalize(_gGlitterLightDir.xyz);
|
|
#elif _URP
|
|
lightDir = GetMainLight().direction;
|
|
#else
|
|
#ifndef USING_DIRECTIONAL_LIGHT
|
|
lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
|
|
#else
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
#endif
|
|
#endif
|
|
return lightDir;
|
|
}
|
|
|
|
float3x3 GetTBN(Input i)
|
|
{
|
|
return i.TBN;
|
|
}
|
|
|
|
float3 GetGlobalLightDirTS(Input i)
|
|
{
|
|
float3 lightDirWS = GetGlobalLightDir(i);
|
|
return mul(GetTBN(i), lightDirWS);
|
|
}
|
|
|
|
half3 GetGlobalLightColor()
|
|
{
|
|
#if _HDRP || PASS_DEFERRED
|
|
return _gGlitterLightColor;
|
|
#elif _URP
|
|
return (GetMainLight().color);
|
|
#else
|
|
return _LightColor0.rgb;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 FuzzyShade(half3 color, half3 normal, half coreMult, half edgeMult, half power, float3 viewDir)
|
|
{
|
|
half dt = saturate(dot(viewDir, normal));
|
|
half dark = 1.0 - (coreMult * dt);
|
|
half edge = pow(1-dt, power) * edgeMult;
|
|
return color * (dark + edge);
|
|
}
|
|
|
|
half3 ComputeSSS(Input i, float3 V, float3 N, half3 tint, half thickness, half distortion, half scale, half power)
|
|
{
|
|
float3 L = GetGlobalLightDir(i);
|
|
half3 lightColor = GetGlobalLightColor();
|
|
float3 H = normalize(L + N * distortion);
|
|
float VdotH = pow(saturate(dot(V, -H)), power) * scale;
|
|
float3 I = (VdotH) * thickness;
|
|
return lightColor * I * tint;
|
|
}
|
|
|
|
|
|
#if _MAX2LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
#elif _MAX3LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
#else
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
#endif
|
|
|
|
|
|
#if _MAX3LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#elif _MAX2LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#else
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##3 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv3.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#endif
|
|
|
|
half2 BlendNormal2(half2 base, half2 blend) { return normalize(half3(base.xy + blend.xy, 1)).xy; }
|
|
half3 BlendOverlay(half3 base, half3 blend) { return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))); }
|
|
half3 BlendMult2X(half3 base, half3 blend) { return (base * (blend * 2)); }
|
|
half3 BlendLighterColor(half3 s, half3 d) { return (s.x + s.y + s.z > d.x + d.y + d.z) ? s : d; }
|
|
|
|
|
|
#if _SURFACENORMALS
|
|
|
|
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
|
|
|
|
|
|
|
|
void ConstructSurfaceGradientTBN(Input i)
|
|
{
|
|
float3x3 tbn = GetTBN(i);
|
|
float3 t = tbn[0];
|
|
float3 b = tbn[1];
|
|
float3 n = tbn[2];
|
|
|
|
surfNormal = n;//mul(GetWorldToObjectMatrix(), float4(n, 1)).xyz;
|
|
surfTangent = t;//mul(GetWorldToObjectMatrix(), float4(t, 1)).xyz;
|
|
surfBitangent = b;//cross(surfNormal, surfTangent);
|
|
|
|
float renormFactor = 1.0 / length(surfNormal);
|
|
surfNormal *= renormFactor;
|
|
surfTangent *= renormFactor;
|
|
surfBitangent *= renormFactor;
|
|
}
|
|
|
|
half3 SurfaceGradientFromTBN(half2 deriv)
|
|
{
|
|
return deriv.x * surfTangent + deriv.y * surfBitangent;
|
|
}
|
|
|
|
// Input: vM is tangent space normal in [-1;1].
|
|
// Output: convert vM to a derivative.
|
|
half2 TspaceNormalToDerivative(half3 vM)
|
|
{
|
|
const half scale = 1.0/128.0;
|
|
|
|
// Ensure vM delivers a positive third component using abs() and
|
|
// constrain vM.z so the range of the derivative is [-128; 128].
|
|
const half3 vMa = abs(vM);
|
|
const half z_ma = max(vMa.z, scale*max(vMa.x, vMa.y));
|
|
|
|
return -half2(vM.x, vM.y)/z_ma;
|
|
}
|
|
|
|
// Used to produce a surface gradient from the gradient of a volume
|
|
// bump function such as 3D Perlin noise. Equation 2 in [Mik10].
|
|
half3 SurfgradFromVolumeGradient(half3 grad)
|
|
{
|
|
return grad - dot(surfNormal, grad) * surfNormal;
|
|
}
|
|
|
|
half3 SurfgradFromTriplanarProjection(half3 pN, half2 xPlaneTN, half2 yPlaneTN, half2 zPlaneTN)
|
|
{
|
|
const half w0 = pN.x;
|
|
const half w1 = pN.y;
|
|
const half w2 = pN.z;
|
|
|
|
// X-plane tangent normal to gradient derivative
|
|
xPlaneTN = xPlaneTN * 2.0 - 1.0;
|
|
half xPlaneRcpZ = rsqrt(max(1 - dot(xPlaneTN.x, xPlaneTN.x) - dot(xPlaneTN.y, xPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_xplane = xPlaneTN * -xPlaneRcpZ;
|
|
|
|
// Y-plane tangent normal to gradient derivative
|
|
yPlaneTN = yPlaneTN * 2.0 - 1.0;
|
|
half yPlaneRcpZ = rsqrt(max(1 - dot(yPlaneTN.x, yPlaneTN.x) - dot(yPlaneTN.y, yPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_yplane = yPlaneTN * -yPlaneRcpZ;
|
|
|
|
// Z-plane tangent normal to gradient derivative
|
|
zPlaneTN = zPlaneTN * 2.0 - 1.0;
|
|
half zPlaneRcpZ = rsqrt(max(1 - dot(zPlaneTN.x, zPlaneTN.x) - dot(zPlaneTN.y, zPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_zplane = zPlaneTN * -zPlaneRcpZ;
|
|
|
|
// Assume deriv xplane, deriv yplane, and deriv zplane are
|
|
// sampled using (z,y), (x,z), and (x,y), respectively.
|
|
// Positive scales of the lookup coordinate will work
|
|
// as well, but for negative scales the derivative components
|
|
// will need to be negated accordingly.
|
|
float3 grad = float3(w2*d_zplane.x + w1*d_yplane.x,
|
|
w2*d_zplane.y + w0*d_xplane.y,
|
|
w0*d_xplane.x + w1*d_yplane.y);
|
|
|
|
return SurfgradFromVolumeGradient(grad);
|
|
}
|
|
|
|
half3 ConvertNormalToGradient(half3 normal)
|
|
{
|
|
half2 deriv = TspaceNormalToDerivative(normal);
|
|
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
half3 ConvertNormal2ToGradient(half2 packedNormal)
|
|
{
|
|
half2 tNormal = packedNormal;
|
|
half rcpZ = rsqrt(max(1 - dot(tNormal.x, tNormal.x) - dot(tNormal.y, tNormal.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
half2 deriv = tNormal * -rcpZ;
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
|
|
half3 ResolveNormalFromSurfaceGradient(half3 gradient)
|
|
{
|
|
return normalize(surfNormal - gradient);
|
|
}
|
|
|
|
|
|
#endif // _SURFACENORMALS
|
|
|
|
void BlendNormalPerTex(inout RawSamples o, half2 noise, float4 fades)
|
|
{
|
|
#if _SURFACENORMALS
|
|
float3 grad = ConvertNormal2ToGradient(noise.xy);
|
|
o.surf0 += grad * fades.x;
|
|
o.surf1 += grad * fades.y;
|
|
#if !_MAX2LAYER
|
|
o.surf2 += grad * fades.z;
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.surf3 += grad * fades.w;
|
|
#endif
|
|
#else
|
|
o.normSAO0.xy = lerp(o.normSAO0.xy, BlendNormal2(o.normSAO0.xy, noise.xy), fades.x);
|
|
o.normSAO1.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#if !_MAX2LAYER
|
|
o.normSAO2.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO2.xy, noise.xy), fades.y);
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.normSAO3.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 BlendNormal3(half3 n1, half3 n2)
|
|
{
|
|
n1 += float3( 0, 0, 1);
|
|
n2 *= float3(-1, -1, 1);
|
|
return n1*dot(n1, n2) / n1.z - n2;
|
|
}
|
|
|
|
half2 TransformTriplanarNormal(Input IN, float3x3 t2w, half3 axisSign, half3 absVertNormal,
|
|
half3 pN, half2 a0, half2 a1, half2 a2)
|
|
{
|
|
|
|
a0 = a0 * 2 - 1;
|
|
a1 = a1 * 2 - 1;
|
|
a2 = a2 * 2 - 1;
|
|
|
|
a0.x *= axisSign.x;
|
|
a1.x *= axisSign.y;
|
|
a2.x *= axisSign.z;
|
|
|
|
half3 n0 = half3(a0.xy, 1);
|
|
half3 n1 = half3(a1.xy, 1);
|
|
half3 n2 = half3(a2.xy, 1);
|
|
|
|
float3 wn = IN.worldNormal;
|
|
|
|
n0 = BlendNormal3(half3(wn.zy, absVertNormal.x), n0);
|
|
n1 = BlendNormal3(half3(wn.xz, absVertNormal.y), n1 * float3(-1, 1, 1));
|
|
n2 = BlendNormal3(half3(wn.xy, absVertNormal.z), n2);
|
|
|
|
n0.z *= axisSign.x;
|
|
n1.z *= axisSign.y;
|
|
n2.z *= -axisSign.z;
|
|
|
|
half3 worldNormal = (n0.zyx * pN.x + n1.xzy * pN.y + n2.xyz * pN.z);
|
|
return mul(t2w, worldNormal).xy;
|
|
|
|
}
|
|
|
|
// funcs
|
|
|
|
inline half MSLuminance(half3 rgb)
|
|
{
|
|
#ifdef UNITY_COLORSPACE_GAMMA
|
|
return dot(rgb, half3(0.22, 0.707, 0.071));
|
|
#else
|
|
return dot(rgb, half3(0.0396819152, 0.458021790, 0.00609653955));
|
|
#endif
|
|
}
|
|
|
|
|
|
float2 Hash2D( float2 x )
|
|
{
|
|
float2 k = float2( 0.3183099, 0.3678794 );
|
|
x = x*k + k.yx;
|
|
return -1.0 + 2.0*frac( 16.0 * k*frac( x.x*x.y*(x.x+x.y)) );
|
|
}
|
|
|
|
float Noise2D(float2 p )
|
|
{
|
|
float2 i = floor( p );
|
|
float2 f = frac( p );
|
|
|
|
float2 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( dot( Hash2D( i + float2(0.0,0.0) ), f - float2(0.0,0.0) ),
|
|
dot( Hash2D( i + float2(1.0,0.0) ), f - float2(1.0,0.0) ), u.x),
|
|
lerp( dot( Hash2D( i + float2(0.0,1.0) ), f - float2(0.0,1.0) ),
|
|
dot( Hash2D( i + float2(1.0,1.0) ), f - float2(1.0,1.0) ), u.x), u.y);
|
|
}
|
|
|
|
float FBM2D(float2 uv)
|
|
{
|
|
float f = 0.5000*Noise2D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise2D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise2D( uv );
|
|
return f;
|
|
}
|
|
|
|
float3 Hash3D( float3 p )
|
|
{
|
|
p = float3( dot(p,float3(127.1,311.7, 74.7)),
|
|
dot(p,float3(269.5,183.3,246.1)),
|
|
dot(p,float3(113.5,271.9,124.6)));
|
|
|
|
return -1.0 + 2.0*frac(sin(p)*437.5453123);
|
|
}
|
|
|
|
float Noise3D( float3 p )
|
|
{
|
|
float3 i = floor( p );
|
|
float3 f = frac( p );
|
|
|
|
float3 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,0.0) ), f - float3(0.0,0.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,0.0) ), f - float3(1.0,0.0,0.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,0.0) ), f - float3(0.0,1.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,0.0) ), f - float3(1.0,1.0,0.0) ), u.x), u.y),
|
|
lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,1.0) ), f - float3(0.0,0.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,1.0) ), f - float3(1.0,0.0,1.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,1.0) ), f - float3(0.0,1.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,1.0) ), f - float3(1.0,1.0,1.0) ), u.x), u.y), u.z );
|
|
}
|
|
|
|
float FBM3D(float3 uv)
|
|
{
|
|
float f = 0.5000*Noise3D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise3D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise3D( uv );
|
|
return f;
|
|
}
|
|
|
|
|
|
|
|
float GetSaturation(float3 c)
|
|
{
|
|
float mi = min(min(c.x, c.y), c.z);
|
|
float ma = max(max(c.x, c.y), c.z);
|
|
return (ma - mi)/(ma + 1e-7);
|
|
}
|
|
|
|
// Better Color Lerp, does not have darkening issue
|
|
float3 BetterColorLerp(float3 a, float3 b, float x)
|
|
{
|
|
float3 ic = lerp(a, b, x) + float3(1e-6,0.0,0.0);
|
|
float sd = abs(GetSaturation(ic) - lerp(GetSaturation(a), GetSaturation(b), x));
|
|
|
|
float3 dir = normalize(float3(2.0 * ic.x - ic.y - ic.z, 2.0 * ic.y - ic.x - ic.z, 2.0 * ic.z - ic.y - ic.x));
|
|
float lgt = dot(float3(1.0, 1.0, 1.0), ic);
|
|
|
|
float ff = dot(dir, normalize(ic));
|
|
|
|
const float dsp_str = 1.5;
|
|
ic += dsp_str * dir * sd * ff * lgt;
|
|
return saturate(ic);
|
|
}
|
|
|
|
|
|
half4 ComputeWeights(half4 iWeights, half h0, half h1, half h2, half h3, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return iWeights;
|
|
#else
|
|
// compute weight with height map
|
|
//half4 weights = half4(iWeights.x * h0, iWeights.y * h1, iWeights.z * h2, iWeights.w * h3);
|
|
half4 weights = half4(iWeights.x * max(h0,0.001), iWeights.y * max(h1,0.001), iWeights.z * max(h2,0.001), iWeights.w * max(h3,0.001));
|
|
|
|
// Contrast weights
|
|
half maxWeight = max(max(weights.x, max(weights.y, weights.z)), weights.w);
|
|
half transition = max(contrast * maxWeight, 0.0001);
|
|
half threshold = maxWeight - transition;
|
|
half scale = 1.0 / transition;
|
|
weights = saturate((weights - threshold) * scale);
|
|
|
|
weights = TotalOne(weights);
|
|
return weights;
|
|
#endif
|
|
}
|
|
|
|
half HeightBlend(half h1, half h2, half slope, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return slope;
|
|
#else
|
|
h2 = 1 - h2;
|
|
half tween = saturate((slope - min(h1, h2)) / max(abs(h1 - h2), 0.001));
|
|
half blend = saturate( ( tween - (1-contrast) ) / max(contrast, 0.001));
|
|
return blend;
|
|
#endif
|
|
}
|
|
|
|
#if _MAX4TEXTURES
|
|
#define TEXCOUNT 4
|
|
#elif _MAX8TEXTURES
|
|
#define TEXCOUNT 8
|
|
#elif _MAX12TEXTURES
|
|
#define TEXCOUNT 12
|
|
#elif _MAX20TEXTURES
|
|
#define TEXCOUNT 20
|
|
#elif _MAX24TEXTURES
|
|
#define TEXCOUNT 24
|
|
#elif _MAX28TEXTURES
|
|
#define TEXCOUNT 28
|
|
#elif _MAX32TEXTURES
|
|
#define TEXCOUNT 32
|
|
#else
|
|
#define TEXCOUNT 16
|
|
#endif
|
|
|
|
#if _DECAL_SPLAT
|
|
|
|
void DoMergeDecalSplats(half4 iWeights, half4 iIndexes, inout half4 indexes, inout half4 weights)
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
half w = iWeights[i];
|
|
half index = iIndexes[i];
|
|
if (w > weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = index;
|
|
}
|
|
else if (w > weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = index;
|
|
}
|
|
else if (w > weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = index;
|
|
}
|
|
else if (w > weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = index;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
void Setup(out half4 weights, float2 uv, out Config config, half4 w0, half4 w1, half4 w2, half4 w3, half4 w4, half4 w5, half4 w6, half4 w7, float3 worldPos, DecalOutput decalOutput)
|
|
{
|
|
config = (Config)0;
|
|
half4 indexes = 0;
|
|
|
|
config.uv = uv;
|
|
|
|
#if _WORLDUV
|
|
uv = worldPos.xz;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
float2 scaledUV = uv;
|
|
#else
|
|
float2 scaledUV = uv * _UVScale.xy + _UVScale.zw;
|
|
#endif
|
|
|
|
// if only 4 textures, and blending 4 textures, skip this whole thing..
|
|
// this saves about 25% of the ALU of the base shader on low end. However if
|
|
// we rely on sorted texture weights (distance resampling) we have to sort..
|
|
float4 defaultIndexes = float4(0,1,2,3);
|
|
#if _MESHSUBARRAY
|
|
defaultIndexes = _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
#if _MESHSUBARRAY && !_DECAL_SPLAT || (_MAX4TEXTURES && !_MAX3LAYER && !_MAX2LAYER && !_DISTANCERESAMPLE && !_POM && !_DECAL_SPLAT)
|
|
weights = w0;
|
|
config.uv0 = float3(scaledUV, defaultIndexes.x);
|
|
config.uv1 = float3(scaledUV, defaultIndexes.y);
|
|
config.uv2 = float3(scaledUV, defaultIndexes.z);
|
|
config.uv3 = float3(scaledUV, defaultIndexes.w);
|
|
return;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
weights = float4(1,0,0,0);
|
|
return;
|
|
#else
|
|
half splats[TEXCOUNT];
|
|
|
|
splats[0] = w0.x;
|
|
splats[1] = w0.y;
|
|
splats[2] = w0.z;
|
|
splats[3] = w0.w;
|
|
#if !_MAX4TEXTURES
|
|
splats[4] = w1.x;
|
|
splats[5] = w1.y;
|
|
splats[6] = w1.z;
|
|
splats[7] = w1.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
splats[8] = w2.x;
|
|
splats[9] = w2.y;
|
|
splats[10] = w2.z;
|
|
splats[11] = w2.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
splats[12] = w3.x;
|
|
splats[13] = w3.y;
|
|
splats[14] = w3.z;
|
|
splats[15] = w3.w;
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[16] = w4.x;
|
|
splats[17] = w4.y;
|
|
splats[18] = w4.z;
|
|
splats[19] = w4.w;
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[20] = w5.x;
|
|
splats[21] = w5.y;
|
|
splats[22] = w5.z;
|
|
splats[23] = w5.w;
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[24] = w6.x;
|
|
splats[25] = w6.y;
|
|
splats[26] = w6.z;
|
|
splats[27] = w6.w;
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
splats[28] = w7.x;
|
|
splats[29] = w7.y;
|
|
splats[30] = w7.z;
|
|
splats[31] = w7.w;
|
|
#endif
|
|
|
|
|
|
|
|
weights[0] = 0;
|
|
weights[1] = 0;
|
|
weights[2] = 0;
|
|
weights[3] = 0;
|
|
indexes[0] = 0;
|
|
indexes[1] = 0;
|
|
indexes[2] = 0;
|
|
indexes[3] = 0;
|
|
|
|
int i = 0;
|
|
for (i = 0; i < TEXCOUNT; ++i)
|
|
{
|
|
half w = splats[i];
|
|
if (w >= weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = i;
|
|
}
|
|
else if (w >= weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = i;
|
|
}
|
|
else if (w >= weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = i;
|
|
}
|
|
else if (w >= weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = i;
|
|
}
|
|
}
|
|
|
|
// NaN Prevention
|
|
if (weights.x <= 0)
|
|
weights = float4(1, 0, 0, 0);
|
|
|
|
#if _DECAL_SPLAT
|
|
DoMergeDecalSplats(decalOutput.Weights, decalOutput.Indexes, weights, indexes);
|
|
#endif
|
|
|
|
|
|
|
|
// clamp and renormalize
|
|
#if _MAX2LAYER
|
|
weights.zw = 0;
|
|
weights.xy = TotalOne(weights.xy);
|
|
#elif _MAX3LAYER
|
|
weights.w = 0;
|
|
weights.xyz = TotalOne(weights.xyz);
|
|
#elif !_DISABLEHEIGHTBLENDING || _NORMALIZEWEIGHTS // prevents black when painting, which the unity shader does not prevent.
|
|
weights = normalize(weights);
|
|
#endif
|
|
|
|
|
|
config.uv0 = float3(scaledUV, indexes.x);
|
|
config.uv1 = float3(scaledUV, indexes.y);
|
|
config.uv2 = float3(scaledUV, indexes.z);
|
|
config.uv3 = float3(scaledUV, indexes.w);
|
|
|
|
|
|
#endif //_DISABLESPLATMAPS
|
|
|
|
|
|
}
|
|
|
|
float3 HeightToNormal(float height, float3 worldPos)
|
|
{
|
|
float3 dx = ddx(worldPos);
|
|
float3 dy = ddy(worldPos);
|
|
float3 crossX = cross(float3(0,1,0), dx);
|
|
float3 crossY = cross(float3(0,1,0), dy);
|
|
float3 d = abs(dot(crossY, dx));
|
|
float3 n = ((((height + ddx(height)) - height) * crossY) + (((height + ddy(height)) - height) * crossX)) * sign(d);
|
|
n.z *= -1;
|
|
return normalize((d * float3(0,1,0)) - n).xzy;
|
|
}
|
|
|
|
float ComputeMipLevel(float2 uv, float2 textureSize)
|
|
{
|
|
uv *= textureSize;
|
|
float2 dx_vtc = ddx(uv);
|
|
float2 dy_vtc = ddy(uv);
|
|
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
|
|
return 0.5 * log2(delta_max_sqr);
|
|
}
|
|
|
|
inline half2 UnpackNormal2(half4 packednormal)
|
|
{
|
|
return packednormal.wy * 2 - 1;
|
|
|
|
}
|
|
|
|
half3 TriplanarHBlend(half h0, half h1, half h2, half3 pN, half contrast)
|
|
{
|
|
half3 blend = pN / dot(pN, half3(1,1,1));
|
|
float3 heights = float3(h0, h1, h2) + (blend * 3.0);
|
|
half height_start = max(max(heights.x, heights.y), heights.z) - contrast;
|
|
half3 h = max(heights - height_start.xxx, half3(0,0,0));
|
|
blend = h / dot(h, half3(1,1,1));
|
|
return blend;
|
|
}
|
|
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half3 display)
|
|
{
|
|
o.Albedo = display.rgb;
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half display)
|
|
{
|
|
o.Albedo = half3(display, display, display);
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
half MicroShadow(float3 lightDir, half3 normal, half ao, half strength)
|
|
{
|
|
half shadow = saturate(abs(dot(normal, lightDir)) + (ao * ao * 2.0) - 1.0);
|
|
return 1 - ((1-shadow) * strength);
|
|
}
|
|
|
|
|
|
void DoDebugOutput(inout MicroSplatLayer l)
|
|
{
|
|
#if _DEBUG_OUTPUT_ALBEDO
|
|
ClearAllButAlbedo(l, l.Albedo);
|
|
#elif _DEBUG_OUTPUT_NORMAL
|
|
// oh unit shader compiler normal stripping, how I hate you so..
|
|
// must multiply by albedo to stop the normal from being white. Why, fuck knows?
|
|
ClearAllButAlbedo(l, float3(l.Normal.xy * 0.5 + 0.5, l.Normal.z * saturate(l.Albedo.z+1)));
|
|
#elif _DEBUG_OUTPUT_SMOOTHNESS
|
|
ClearAllButAlbedo(l, l.Smoothness.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_METAL
|
|
ClearAllButAlbedo(l, l.Metallic.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_AO
|
|
ClearAllButAlbedo(l, l.Occlusion.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_EMISSION
|
|
ClearAllButAlbedo(l, l.Emission * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_HEIGHT
|
|
ClearAllButAlbedo(l, l.Height.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_SPECULAR && _USESPECULARWORKFLOW
|
|
ClearAllButAlbedo(l, l.Specular * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_BRANCHCOUNT_WEIGHT
|
|
ClearAllButAlbedo(l, _branchWeightCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TRIPLANAR
|
|
ClearAllButAlbedo(l, _branchTriplanarCount / 24 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_CLUSTER
|
|
ClearAllButAlbedo(l, _branchClusterCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_OTHER
|
|
ClearAllButAlbedo(l, _branchOtherCount / 8 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TOTAL
|
|
l.Albedo.r = _branchWeightCount / 12;
|
|
l.Albedo.g = _branchTriplanarCount / 24;
|
|
l.Albedo.b = _branchClusterCount / 12;
|
|
ClearAllButAlbedo(l, (l.Albedo.r + l.Albedo.g + l.Albedo.b + (_branchOtherCount / 8)) / 4);
|
|
#elif _DEBUG_OUTPUT_MICROSHADOWS
|
|
ClearAllButAlbedo(l,l.Albedo);
|
|
#elif _DEBUG_SAMPLECOUNT
|
|
float sdisp = (float)_sampleCount / max(_SampleCountDiv, 1);
|
|
half3 sdcolor = float3(sdisp, sdisp > 1 ? 1 : 0, 0);
|
|
ClearAllButAlbedo(l, sdcolor * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_PROCLAYERS
|
|
ClearAllButAlbedo(l, (float)_procLayerCount / (float)_PCLayerCount * saturate(l.Albedo.z + 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
// abstraction around sampler mode
|
|
#if _USELODMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_LOD(tex, sampler##tex, u, l.x)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u, l.x)
|
|
#elif _USEGRADMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_GRAD(tex, sampler##tex, u, l.xy, l.zw)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY_GRAD(tex, ss, u.xy, u.z, l.xy, l.zw)
|
|
#else
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, u.xy, u.z)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u.xy, y.z)
|
|
#endif
|
|
|
|
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE(u, cl, l) MICROSPLAT_SAMPLE(_Diffuse, u, l)
|
|
#define MICROSPLAT_SAMPLE_EMIS(u, cl, l) MICROSPLAT_SAMPLE(_EmissiveMetal, u, l)
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE_LOD(u, cl, l) UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, u, l)
|
|
|
|
|
|
#if _PACKINGHQ
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) half4(MICROSPLAT_SAMPLE(_NormalSAO, u, l).ga, MICROSPLAT_SAMPLE(_SmoothAO, u, l).ga).brag
|
|
#else
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) MICROSPLAT_SAMPLE(_NormalSAO, u, l)
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
#define MICROSPLAT_SAMPLE_SPECULAR(u, cl, l) MICROSPLAT_SAMPLE(_Specular, u, l)
|
|
#endif
|
|
|
|
struct SimpleTriplanarConfig
|
|
{
|
|
float3 pn;
|
|
float2 uv0;
|
|
float2 uv1;
|
|
float2 uv2;
|
|
};
|
|
|
|
void PrepSimpleTriplanarConfig(inout SimpleTriplanarConfig tc, float3 worldPos, float3 normal, float contrast)
|
|
{
|
|
tc.pn = pow(abs(normal), contrast);
|
|
tc.pn = tc.pn / (tc.pn.x + tc.pn.y + tc.pn.z);
|
|
|
|
half3 axisSign = sign(normal);
|
|
|
|
tc.uv0 = worldPos.zy * axisSign.x;
|
|
tc.uv1 = worldPos.xz * axisSign.y;
|
|
tc.uv2 = worldPos.xy * axisSign.z;
|
|
}
|
|
|
|
#define SimpleTriplanarSample(tex, tc, scale) (SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv0 * scale) * tc.pn.x + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv1 * scale) * tc.pn.y + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv2 * scale) * tc.pn.z)
|
|
#define SimpleTriplanarSampleLOD(tex, tc, scale, lod) (SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv0 * scale, lod) * tc.pn.x + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv1 * scale, lod) * tc.pn.y + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv2 * scale, lod) * tc.pn.z)
|
|
#define SimpleTriplanarSampleGrad(tex, tc, scale) (SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv0 * scale, ddx(tc.uv0) * scale, ddy(tc.uv0) * scale) * tc.pn.x + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv1 * scale, ddx(tc.uv1) * scale, ddy(tc.uv1) * scale) * tc.pn.y + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv2 * scale, ddx(tc.uv2) * scale, ddy(tc.uv2) * scale) * tc.pn.z)
|
|
|
|
|
|
inline half3 MicroSplatDiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
|
|
{
|
|
specColor = lerp (half3(0,0,0), albedo, metallic);
|
|
oneMinusReflectivity = (1-metallic);
|
|
return albedo * oneMinusReflectivity;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Input DescToInput(ShaderData IN)
|
|
{
|
|
Input s = (Input)0;
|
|
s.shaderData = IN;
|
|
s.TBN = IN.TBNMatrix;
|
|
s.worldNormal = IN.worldSpaceNormal;
|
|
s.worldPos = IN.worldSpacePosition;
|
|
s.viewDir = IN.tangentSpaceViewDir;
|
|
s.uv_Control0 = IN.texcoord0.xy;
|
|
|
|
s.worldUpVector = float3(0,1,0);
|
|
s.worldHeight = IN.worldSpacePosition.y;
|
|
|
|
#if _PLANETVECTORS
|
|
float3 rwp = mul(_PQSToLocal, float4(IN.worldSpacePosition, 1));
|
|
s.worldHeight = distance(rwp, float3(0,0,0));
|
|
s.worldUpVector = normalize(rwp);
|
|
#endif
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
s.uv2_Diffuse = IN.texcoord1.xy;
|
|
#endif
|
|
|
|
#if _MEGASPLAT
|
|
UnpackMegaSplat(s, IN);
|
|
#endif
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
UnpackVertexWorkflow(s, IN);
|
|
#endif
|
|
|
|
#if _PLANETVECTORS
|
|
DoPlanetDataInputCopy(s, IN);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
void SampleAlbedo(inout Config config, inout TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half4 contrasts = _Contrast.xxxx;
|
|
#if _PERTEXTRIPLANARCONTRAST
|
|
SAMPLE_PER_TEX(ptc, 9.5, config, half4(1,0.5,0,0));
|
|
contrasts = half4(ptc0.y, ptc1.y, ptc2.y, ptc3.y);
|
|
#endif
|
|
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
SAMPLE_PER_TEX(pttri, 9.5, config, half4(0,0,0,0));
|
|
#endif
|
|
|
|
{
|
|
// For per-texture triplanar, we modify the view based blending factor of the triplanar
|
|
// such that you get a pure blend of either top down projection, or with the top down projection
|
|
// removed and renormalized. This causes dynamic flow control optimizations to kick in and avoid
|
|
// the extra texture samples while keeping the code simple. Yay..
|
|
|
|
// We also only have to do this in the Albedo, because the pN values will be adjusted after the
|
|
// albedo is sampled, causing future samples to use this data.
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri0.x > 0.66)
|
|
{
|
|
tc.pN0 = half3(0,1,0);
|
|
}
|
|
else if (pttri0.x > 0.33)
|
|
{
|
|
tc.pN0.y = 0;
|
|
tc.pN0.xz = TotalOne(tc.pN0.xz);
|
|
}
|
|
#endif
|
|
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN0;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN0, contrasts.x);
|
|
tc.pN0 = bf;
|
|
#endif
|
|
|
|
s.albedo0 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri1.x > 0.66)
|
|
{
|
|
tc.pN1 = half3(0,1,0);
|
|
}
|
|
else if (pttri1.x > 0.33)
|
|
{
|
|
tc.pN1.y = 0;
|
|
tc.pN1.xz = TotalOne(tc.pN1.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
COUNTSAMPLE
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[2], config.cluster1, d2);
|
|
}
|
|
half3 bf = tc.pN1;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN1, contrasts.x);
|
|
tc.pN1 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo1 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri2.x > 0.66)
|
|
{
|
|
tc.pN2 = half3(0,1,0);
|
|
}
|
|
else if (pttri2.x > 0.33)
|
|
{
|
|
tc.pN2.y = 0;
|
|
tc.pN2.xz = TotalOne(tc.pN2.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN2;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN2, contrasts.x);
|
|
tc.pN2 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo2 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri3.x > 0.66)
|
|
{
|
|
tc.pN3 = half3(0,1,0);
|
|
}
|
|
else if (pttri3.x > 0.33)
|
|
{
|
|
tc.pN3.y = 0;
|
|
tc.pN3.xz = TotalOne(tc.pN3.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN3;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN3, contrasts.x);
|
|
tc.pN3 = bf;
|
|
#endif
|
|
|
|
s.albedo3 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.albedo0 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.albedo1 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.albedo2 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.albedo3 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXHEIGHTOFFSET || _PERTEXHEIGHTCONTRAST
|
|
SAMPLE_PER_TEX(ptHeight, 10.5, config, 1);
|
|
|
|
#if _PERTEXHEIGHTOFFSET
|
|
s.albedo0.a = saturate(s.albedo0.a + ptHeight0.b - 1);
|
|
s.albedo1.a = saturate(s.albedo1.a + ptHeight1.b - 1);
|
|
s.albedo2.a = saturate(s.albedo2.a + ptHeight2.b - 1);
|
|
s.albedo3.a = saturate(s.albedo3.a + ptHeight3.b - 1);
|
|
#endif
|
|
#if _PERTEXHEIGHTCONTRAST
|
|
s.albedo0.a = saturate(pow(s.albedo0.a + 0.5, abs(ptHeight0.a)) - 0.5);
|
|
s.albedo1.a = saturate(pow(s.albedo1.a + 0.5, abs(ptHeight1.a)) - 0.5);
|
|
s.albedo2.a = saturate(pow(s.albedo2.a + 0.5, abs(ptHeight2.a)) - 0.5);
|
|
s.albedo3.a = saturate(pow(s.albedo3.a + 0.5, abs(ptHeight3.a)) - 0.5);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void SampleNormal(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
|
|
#if _NONORMALMAP || _AUTONORMAL
|
|
s.normSAO0 = half4(0,0, 0, 1);
|
|
s.normSAO1 = half4(0,0, 0, 1);
|
|
s.normSAO2 = half4(0,0, 0, 1);
|
|
s.normSAO3 = half4(0,0, 0, 1);
|
|
return;
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half3 absVertNormal = abs(tc.IN.worldNormal);
|
|
float3x3 t2w = tc.IN.TBN;
|
|
|
|
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[0], config.cluster0, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[1], config.cluster0, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[2], config.cluster0, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = SurfgradFromTriplanarProjection(tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO0.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO0.zw = a0.zw * tc.pN0.x + a1.zw * tc.pN0.y + a2.zw * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[0], config.cluster1, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[1], config.cluster1, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[2], config.cluster1, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = SurfgradFromTriplanarProjection(tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO1.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO1.zw = a0.zw * tc.pN1.x + a1.zw * tc.pN1.y + a2.zw * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[0], config.cluster2, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[1], config.cluster2, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[2], config.cluster2, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf2 = SurfgradFromTriplanarProjection(tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO2.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO2.zw = a0.zw * tc.pN2.x + a1.zw * tc.pN2.y + a2.zw * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[0], config.cluster3, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[1], config.cluster3, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[2], config.cluster3, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf3 = SurfgradFromTriplanarProjection(tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO3.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO3.zw = a0.zw * tc.pN3.x + a1.zw * tc.pN3.y + a2.zw * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.normSAO0 = MICROSPLAT_SAMPLE_NORMAL(config.uv0, config.cluster0, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO0.xy = s.normSAO0.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = ConvertNormal2ToGradient(s.normSAO0.xy);
|
|
#endif
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.normSAO1 = MICROSPLAT_SAMPLE_NORMAL(config.uv1, config.cluster1, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO1.xy = s.normSAO1.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = ConvertNormal2ToGradient(s.normSAO1.xy);
|
|
#endif
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.normSAO2 = MICROSPLAT_SAMPLE_NORMAL(config.uv2, config.cluster2, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO2.xy = s.normSAO2.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf2 = ConvertNormal2ToGradient(s.normSAO2.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.normSAO3 = MICROSPLAT_SAMPLE_NORMAL(config.uv3, config.cluster3, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO3.xy = s.normSAO3.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf3 = ConvertNormal2ToGradient(s.normSAO3.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleEmis(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
s.emisMetal0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.emisMetal0 = MICROSPLAT_SAMPLE_EMIS(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.emisMetal1 = MICROSPLAT_SAMPLE_EMIS(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.emisMetal2 = MICROSPLAT_SAMPLE_EMIS(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.emisMetal3 = MICROSPLAT_SAMPLE_EMIS(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleSpecular(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.specular0 = MICROSPLAT_SAMPLE_SPECULAR(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.specular1 = MICROSPLAT_SAMPLE_SPECULAR(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.specular2 = MICROSPLAT_SAMPLE_SPECULAR(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.specular3 = MICROSPLAT_SAMPLE_SPECULAR(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
MicroSplatLayer Sample(Input i, half4 weights, inout Config config, float camDist, float3 worldNormalVertex, DecalOutput decalOutput)
|
|
{
|
|
MicroSplatLayer o = (MicroSplatLayer)0;
|
|
UNITY_INITIALIZE_OUTPUT(MicroSplatLayer,o);
|
|
|
|
RawSamples samples = (RawSamples)0;
|
|
InitRawSamples(samples);
|
|
|
|
half4 albedo = 0;
|
|
half4 normSAO = half4(0,0,0,1);
|
|
half3 surfGrad = half3(0,0,0);
|
|
half4 emisMetal = 0;
|
|
half3 specular = 0;
|
|
|
|
float worldHeight = i.worldPos.y;
|
|
float3 upVector = float3(0,1,0);
|
|
|
|
#if _GLOBALTINT || _GLOBALNORMALS || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _GLOBALSPECULAR
|
|
float globalSlopeFilter = 1;
|
|
#if _GLOBALSLOPEFILTER
|
|
float2 gfilterUV = float2(1 - saturate(dot(worldNormalVertex, upVector) * 0.5 + 0.49), 0.5);
|
|
globalSlopeFilter = SAMPLE_TEXTURE2D(_GlobalSlopeTex, sampler_Diffuse, gfilterUV).a;
|
|
#endif
|
|
#endif
|
|
|
|
// declare outside of branchy areas..
|
|
half4 fxLevels = half4(0,0,0,0);
|
|
half burnLevel = 0;
|
|
half wetLevel = 0;
|
|
half3 waterNormalFoam = half3(0, 0, 0);
|
|
half porosity = 0.4;
|
|
float streamFoam = 1.0f;
|
|
half pud = 0;
|
|
half snowCover = 0;
|
|
half SSSThickness = 0;
|
|
half3 SSSTint = half3(1,1,1);
|
|
float traxBuffer = 0;
|
|
float3 traxNormal = 0;
|
|
float2 noiseUV = 0;
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(1 - saturate(camDist - _SplatFade.y))
|
|
{
|
|
#endif
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE || _SNOWFOOTSTEPS
|
|
traxBuffer = SampleTraxBuffer(i.worldPos, worldNormalVertex, traxNormal);
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
#if _MICROMESH
|
|
fxLevels = SampleFXLevels(InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, config.uv), wetLevel, burnLevel, traxBuffer);
|
|
#elif _MICROVERTEXMESH || _MICRODIGGERMESH || _MEGASPLAT
|
|
fxLevels = ProcessFXLevels(i.fx, traxBuffer);
|
|
#else
|
|
fxLevels = SampleFXLevels(config.uv, wetLevel, burnLevel, traxBuffer);
|
|
#endif
|
|
#endif
|
|
|
|
#if _DECAL
|
|
fxLevels = max(fxLevels, decalOutput.fxLevels);
|
|
#endif
|
|
|
|
TriplanarConfig tc = (TriplanarConfig)0;
|
|
UNITY_INITIALIZE_OUTPUT(TriplanarConfig,tc);
|
|
|
|
|
|
MIPFORMAT albedoLOD = INITMIPFORMAT
|
|
MIPFORMAT normalLOD = INITMIPFORMAT
|
|
MIPFORMAT emisLOD = INITMIPFORMAT
|
|
MIPFORMAT specLOD = INITMIPFORMAT
|
|
MIPFORMAT origAlbedoLOD = INITMIPFORMAT;
|
|
|
|
#if _TRIPLANAR && !_DISABLESPLATMAPS
|
|
PrepTriplanar(i.shaderData.texcoord0, worldNormalVertex, i.worldPos, config, tc, weights, albedoLOD, normalLOD, emisLOD, origAlbedoLOD);
|
|
tc.IN = i;
|
|
#endif
|
|
|
|
|
|
#if !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
#if _USELODMIP
|
|
albedoLOD = ComputeMipLevel(config.uv0.xy, _Diffuse_TexelSize.zw);
|
|
normalLOD = ComputeMipLevel(config.uv0.xy, _NormalSAO_TexelSize.zw);
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = ComputeMipLevel(config.uv0.xy, _EmissiveMetal_TexelSize.zw);
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = ComputeMipLevel(config.uv0.xy, _Specular_TexelSize.zw);;
|
|
#endif
|
|
#elif _USEGRADMIP
|
|
albedoLOD = float4(ddx(config.uv0.xy), ddy(config.uv0.xy));
|
|
normalLOD = albedoLOD;
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
|
|
origAlbedoLOD = albedoLOD;
|
|
#endif
|
|
|
|
#if _PERTEXCURVEWEIGHT
|
|
SAMPLE_PER_TEX(ptCurveWeight, 19.5, config, half4(0.5,1,1,1));
|
|
weights.x = lerp(smoothstep(0.5 - ptCurveWeight0.r, 0.5 + ptCurveWeight0.r, weights.x), weights.x, ptCurveWeight0.r*2);
|
|
weights.y = lerp(smoothstep(0.5 - ptCurveWeight1.r, 0.5 + ptCurveWeight1.r, weights.y), weights.y, ptCurveWeight1.r*2);
|
|
weights.z = lerp(smoothstep(0.5 - ptCurveWeight2.r, 0.5 + ptCurveWeight2.r, weights.z), weights.z, ptCurveWeight2.r*2);
|
|
weights.w = lerp(smoothstep(0.5 - ptCurveWeight3.r, 0.5 + ptCurveWeight3.r, weights.w), weights.w, ptCurveWeight3.r*2);
|
|
weights = TotalOne(weights);
|
|
#endif
|
|
|
|
|
|
|
|
// uvScale before anything
|
|
#if _PERTEXUVSCALEOFFSET && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
config.uv0.xy = config.uv0.xy * ptUVScale0.rg + ptUVScale0.ba;
|
|
config.uv1.xy = config.uv1.xy * ptUVScale1.rg + ptUVScale1.ba;
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = config.uv2.xy * ptUVScale2.rg + ptUVScale2.ba;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = config.uv3.xy * ptUVScale3.rg + ptUVScale3.ba;
|
|
#endif
|
|
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = albedoLOD * ptUVScale0.rgrg * weights.x +
|
|
albedoLOD * ptUVScale1.rgrg * weights.y +
|
|
albedoLOD * ptUVScale2.rgrg * weights.z +
|
|
albedoLOD * ptUVScale3.rgrg * weights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXUVROTATION && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptUVRot, 16.5, config, half4(0,0,0,0));
|
|
config.uv0.xy = RotateUV(config.uv0.xy, ptUVRot0.x);
|
|
config.uv1.xy = RotateUV(config.uv1.xy, ptUVRot1.x);
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = RotateUV(config.uv2.xy, ptUVRot2.x);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = RotateUV(config.uv3.xy, ptUVRot0.x);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
o.Alpha = 1;
|
|
|
|
|
|
#if _POM && !_DISABLESPLATMAPS
|
|
DoPOM(i, config, tc, albedoLOD, weights, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
SampleAlbedo(config, tc, samples, albedoLOD, weights);
|
|
|
|
#if _NOISEHEIGHT
|
|
ApplyNoiseHeight(samples, config.uv, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STREAMS || (_PARALLAX && !_DISABLESPLATMAPS)
|
|
half earlyHeight = BlendWeights(samples.albedo0.w, samples.albedo1.w, samples.albedo2.w, samples.albedo3.w, weights);
|
|
#endif
|
|
|
|
|
|
#if _STREAMS
|
|
waterNormalFoam = GetWaterNormal(i, config.uv, worldNormalVertex);
|
|
DoStreamRefract(config, tc, waterNormalFoam, fxLevels.b, earlyHeight);
|
|
#endif
|
|
|
|
#if _PARALLAX && !_DISABLESPLATMAPS
|
|
DoParallax(i, earlyHeight, config, tc, samples, weights, camDist);
|
|
#endif
|
|
|
|
|
|
// Blend results
|
|
#if _PERTEXINTERPCONTRAST && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptContrasts, 1.5, config, 0.5);
|
|
half4 contrast = 0.5;
|
|
contrast.x = ptContrasts0.a;
|
|
contrast.y = ptContrasts1.a;
|
|
#if !_MAX2LAYER
|
|
contrast.z = ptContrasts2.a;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
contrast.w = ptContrasts3.a;
|
|
#endif
|
|
contrast = clamp(contrast + _Contrast, 0.0001, 1.0);
|
|
half cnt = contrast.x * weights.x + contrast.y * weights.y + contrast.z * weights.z + contrast.w * weights.w;
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, cnt);
|
|
#else
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, _Contrast);
|
|
#endif
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
heightWeights = lerp(heightWeights, TotalOne(weights), saturate(camDist/max(1.0, _HybridHeightBlendDistance)));
|
|
#endif
|
|
|
|
|
|
// rescale derivatives after height weighting. Basically, in gradmip mode we blend the mip levels,
|
|
// but this is before height mapping is sampled, so reblending them after alpha will make sure the other
|
|
// channels (normal, etc) are sharper, which likely matters most..
|
|
#if _PERTEXUVSCALEOFFSET && !_DISABLESPLATMAPS
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
|
|
albedoLOD.d0 = origAlbedoLOD.d0 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d0 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d0 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d0 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d1 = origAlbedoLOD.d1 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d1 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d1 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d1 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d2 = origAlbedoLOD.d2 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d2 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d2 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d2 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
normalLOD.d0 = albedoLOD.d0;
|
|
normalLOD.d1 = albedoLOD.d1;
|
|
normalLOD.d2 = albedoLOD.d2;
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD.d0 = albedoLOD.d0;
|
|
emisLOD.d1 = albedoLOD.d1;
|
|
emisLOD.d2 = albedoLOD.d2;
|
|
#endif
|
|
#endif // gradmip
|
|
#else // not triplanar
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = origAlbedoLOD * ptUVScale0.rgrg * heightWeights.x +
|
|
origAlbedoLOD * ptUVScale1.rgrg * heightWeights.y +
|
|
origAlbedoLOD * ptUVScale2.rgrg * heightWeights.z +
|
|
origAlbedoLOD * ptUVScale3.rgrg * heightWeights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _PARALLAX || _STREAMS
|
|
SampleAlbedo(config, tc, samples, albedoLOD, heightWeights);
|
|
#endif
|
|
|
|
|
|
SampleNormal(config, tc, samples, normalLOD, heightWeights);
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
SampleEmis(config, tc, samples, emisLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
SampleSpecular(config, tc, samples, specLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _DISTANCERESAMPLE && !_DISABLESPLATMAPS
|
|
DistanceResample(samples, config, tc, camDist, i.viewDir, fxLevels, albedoLOD, i.worldPos, heightWeights, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STARREACHFORMAT
|
|
samples.normSAO0.w = length(samples.normSAO0.xy);
|
|
samples.normSAO1.w = length(samples.normSAO1.xy);
|
|
samples.normSAO2.w = length(samples.normSAO2.xy);
|
|
samples.normSAO3.w = length(samples.normSAO3.xy);
|
|
#endif
|
|
|
|
// PerTexture sampling goes here, passing the samples structure
|
|
|
|
#if _PERTEXMICROSHADOWS || _PERTEXFUZZYSHADE
|
|
SAMPLE_PER_TEX(ptFuzz, 17.5, config, half4(0, 0, 1, 1));
|
|
#endif
|
|
|
|
#if _PERTEXMICROSHADOWS
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
{
|
|
half3 lightDir = GetGlobalLightDirTS(i);
|
|
half4 microShadows = half4(1,1,1,1);
|
|
microShadows.x = MicroShadow(lightDir, half3(samples.normSAO0.xy, 1), samples.normSAO0.a, ptFuzz0.a);
|
|
microShadows.y = MicroShadow(lightDir, half3(samples.normSAO1.xy, 1), samples.normSAO1.a, ptFuzz1.a);
|
|
microShadows.z = MicroShadow(lightDir, half3(samples.normSAO2.xy, 1), samples.normSAO2.a, ptFuzz2.a);
|
|
microShadows.w = MicroShadow(lightDir, half3(samples.normSAO3.xy, 1), samples.normSAO3.a, ptFuzz3.a);
|
|
samples.normSAO0.a *= microShadows.x;
|
|
samples.normSAO1.a *= microShadows.y;
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a *= microShadows.z;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a *= microShadows.w;
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_OUTPUT_MICROSHADOWS
|
|
o.Albedo = BlendWeights(microShadows.x, microShadows.y, microShadows.z, microShadows.a, heightWeights);
|
|
return o;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
#endif // _PERTEXMICROSHADOWS
|
|
|
|
|
|
#if _PERTEXFUZZYSHADE
|
|
samples.albedo0.rgb = FuzzyShade(samples.albedo0.rgb, half3(samples.normSAO0.rg, 1), ptFuzz0.r, ptFuzz0.g, ptFuzz0.b, i.viewDir);
|
|
samples.albedo1.rgb = FuzzyShade(samples.albedo1.rgb, half3(samples.normSAO1.rg, 1), ptFuzz1.r, ptFuzz1.g, ptFuzz1.b, i.viewDir);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = FuzzyShade(samples.albedo2.rgb, half3(samples.normSAO2.rg, 1), ptFuzz2.r, ptFuzz2.g, ptFuzz2.b, i.viewDir);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = FuzzyShade(samples.albedo3.rgb, half3(samples.normSAO3.rg, 1), ptFuzz3.r, ptFuzz3.g, ptFuzz3.b, i.viewDir);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSATURATION && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptSaturattion, 9.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = lerp(MSLuminance(samples.albedo0.rgb), samples.albedo0.rgb, ptSaturattion0.a);
|
|
samples.albedo1.rgb = lerp(MSLuminance(samples.albedo1.rgb), samples.albedo1.rgb, ptSaturattion1.a);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = lerp(MSLuminance(samples.albedo2.rgb), samples.albedo2.rgb, ptSaturattion2.a);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = lerp(MSLuminance(samples.albedo3.rgb), samples.albedo3.rgb, ptSaturattion3.a);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if _PERTEXTINT && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptTints, 1.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb *= ptTints0.rgb;
|
|
samples.albedo1.rgb *= ptTints1.rgb;
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb *= ptTints2.rgb;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb *= ptTints3.rgb;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PCHEIGHTGRADIENT || _PCHEIGHTHSV || _PCSLOPEGRADIENT || _PCSLOPEHSV
|
|
ProceduralGradients(i, samples, config, worldHeight, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS
|
|
porosity = _GlobalPorosity;
|
|
#endif
|
|
|
|
|
|
#if _PERTEXCOLORINTENSITY
|
|
SAMPLE_PER_TEX(ptCI, 23.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb * (1 + ptCI0.rrr));
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb * (1 + ptCI1.rrr));
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb * (1 + ptCI2.rrr));
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb * (1 + ptCI3.rrr));
|
|
#endif
|
|
#endif
|
|
|
|
#if (_PERTEXBRIGHTNESS || _PERTEXCONTRAST || _PERTEXPOROSITY || _PERTEXFOAM) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptBC, 3.5, config, half4(1, 1, 1, 1));
|
|
#if _PERTEXCONTRAST
|
|
samples.albedo0.rgb = saturate(((samples.albedo0.rgb - 0.5) * ptBC0.g) + 0.5);
|
|
samples.albedo1.rgb = saturate(((samples.albedo1.rgb - 0.5) * ptBC1.g) + 0.5);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(((samples.albedo2.rgb - 0.5) * ptBC2.g) + 0.5);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(((samples.albedo3.rgb - 0.5) * ptBC3.g) + 0.5);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXBRIGHTNESS
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb + ptBC0.rrr);
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb + ptBC1.rrr);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb + ptBC2.rrr);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb + ptBC3.rrr);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXPOROSITY
|
|
porosity = BlendWeights(ptBC0.b, ptBC1.b, ptBC2.b, ptBC3.b, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXFOAM
|
|
streamFoam = BlendWeights(ptBC0.a, ptBC1.a, ptBC2.a, ptBC3.a, heightWeights);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if (_PERTEXNORMSTR || _PERTEXAOSTR || _PERTEXSMOOTHSTR || _PERTEXMETALLIC) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(perTexMatSettings, 2.5, config, half4(1.0, 1.0, 1.0, 0.0));
|
|
#endif
|
|
|
|
#if _PERTEXNORMSTR && !_DISABLESPLATMAPS
|
|
#if _SURFACENORMALS
|
|
samples.surf0 *= perTexMatSettings0.r;
|
|
samples.surf1 *= perTexMatSettings1.r;
|
|
samples.surf2 *= perTexMatSettings2.r;
|
|
samples.surf3 *= perTexMatSettings3.r;
|
|
#else
|
|
samples.normSAO0.xy *= perTexMatSettings0.r;
|
|
samples.normSAO1.xy *= perTexMatSettings1.r;
|
|
samples.normSAO2.xy *= perTexMatSettings2.r;
|
|
samples.normSAO3.xy *= perTexMatSettings3.r;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXAOSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.a = pow(abs(samples.normSAO0.a), perTexMatSettings0.b);
|
|
samples.normSAO1.a = pow(abs(samples.normSAO1.a), perTexMatSettings1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a = pow(abs(samples.normSAO2.a), perTexMatSettings2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a = pow(abs(samples.normSAO3.a), perTexMatSettings3.b);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSMOOTHSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.b += perTexMatSettings0.g;
|
|
samples.normSAO1.b += perTexMatSettings1.g;
|
|
samples.normSAO0.b = saturate(samples.normSAO0.b);
|
|
samples.normSAO1.b = saturate(samples.normSAO1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.b += perTexMatSettings2.g;
|
|
samples.normSAO2.b = saturate(samples.normSAO2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.b += perTexMatSettings3.g;
|
|
samples.normSAO3.b = saturate(samples.normSAO3.b);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
#if _PERTEXSSS
|
|
{
|
|
SAMPLE_PER_TEX(ptSSS, 18.5, config, half4(1, 1, 1, 1)); // tint, thickness
|
|
half4 vals = ptSSS0 * heightWeights.x + ptSSS1 * heightWeights.y + ptSSS2 * heightWeights.z + ptSSS3 * heightWeights.w;
|
|
SSSThickness = vals.a;
|
|
SSSTint = vals.rgb;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXRIMLIGHT
|
|
{
|
|
SAMPLE_PER_TEX(ptRimA, 26.5, config, half4(1, 1, 1, 1));
|
|
SAMPLE_PER_TEX(ptRimB, 27.5, config, half4(1, 1, 1, 0));
|
|
samples.emisMetal0.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO0.xy, 1))), max(0.0001, ptRimA0.g)) * ptRimB0.rgb * ptRimB0.a;
|
|
samples.emisMetal1.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO1.xy, 1))), max(0.0001, ptRimA1.g)) * ptRimB1.rgb * ptRimB1.a;
|
|
samples.emisMetal2.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO2.xy, 1))), max(0.0001, ptRimA2.g)) * ptRimB2.rgb * ptRimB2.a;
|
|
samples.emisMetal3.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO3.xy, 1))), max(0.0001, ptRimA3.g)) * ptRimB3.rgb * ptRimB3.a;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#if (((_DETAILNOISE && _PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && _PERTEXDISTANCENOISESTRENGTH)) || (_NORMALNOISE && _PERTEXNORMALNOISESTRENGTH)) && !_DISABLESPLATMAPS
|
|
ApplyDetailDistanceNoisePerTex(samples, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALNOISEUV
|
|
// noise defaults so that a value of 1, 1 is 4 pixels in size and moves the uvs by 1 pixel max.
|
|
#if _CUSTOMSPLATTEXTURES
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#else
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE
|
|
ApplyTrax(samples, config, i.worldPos, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if (_ANTITILEARRAYDETAIL || _ANTITILEARRAYDISTANCE || _ANTITILEARRAYNORMAL) && !_DISABLESPLATMAPS
|
|
ApplyAntiTilePerTex(samples, config, camDist, i.worldPos, worldNormalVertex, heightWeights);
|
|
#endif
|
|
|
|
#if _GEOMAP && !_DISABLESPLATMAPS
|
|
GeoTexturePerTex(samples, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
#if _GLOBALTINT && _PERTEXGLOBALTINTSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalTintTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && _PERTEXGLOBALNORMALSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalNormalTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && _PERTEXGLOBALSAOMSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalSAOMTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && _PERTEXGLOBALEMISSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalEmisTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && _PERTEXGLOBALSPECULARSTRENGTH && !_DISABLESPLATMAPS && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _PERTEXMETALLIC && !_DISABLESPLATMAPS
|
|
half metallic = BlendWeights(perTexMatSettings0.a, perTexMatSettings1.a, perTexMatSettings2.a, perTexMatSettings3.a, heightWeights);
|
|
o.Metallic = metallic;
|
|
#endif
|
|
|
|
#if _GLITTER && !_DISABLESPLATMAPS
|
|
DoGlitter(i, samples, config, camDist, worldNormalVertex, i.worldPos);
|
|
#endif
|
|
|
|
// Blend em..
|
|
#if _DISABLESPLATMAPS
|
|
// If we don't sample from the _Diffuse, then the shader compiler will strip the sampler on
|
|
// some platforms, which will cause everything to break. So we sample from the lowest mip
|
|
// and saturate to 1 to keep the cost minimal. Annoying, but the compiler removes the texture
|
|
// and sampler, even though the sampler is still used.
|
|
albedo = saturate(UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, float3(0,0,0), 12) + 1);
|
|
albedo.a = 0.5; // make height something we can blend with for the combined mesh mode, since it still height blends.
|
|
normSAO = half4(0,0,0,1);
|
|
#else
|
|
albedo = BlendWeights(samples.albedo0, samples.albedo1, samples.albedo2, samples.albedo3, heightWeights);
|
|
normSAO = BlendWeights(samples.normSAO0, samples.normSAO1, samples.normSAO2, samples.normSAO3, heightWeights);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = BlendWeights(samples.surf0, samples.surf1, samples.surf2, samples.surf3, heightWeights);
|
|
#endif
|
|
|
|
#if (_USEEMISSIVEMETAL || _PERTEXRIMLIGHT) && !_DISABLESPLATMAPS
|
|
emisMetal = BlendWeights(samples.emisMetal0, samples.emisMetal1, samples.emisMetal2, samples.emisMetal3, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW && !_DISABLESPLATMAPS
|
|
specular = BlendWeights(samples.specular0, samples.specular1, samples.specular2, samples.specular3, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXOUTLINECOLOR
|
|
SAMPLE_PER_TEX(ptOutlineColor, 28.5, config, half4(0.5, 0.5, 0.5, 1));
|
|
half4 outlineColor = BlendWeights(ptOutlineColor0, ptOutlineColor1, ptOutlineColor2, ptOutlineColor3, heightWeights);
|
|
half4 tstr = saturate(abs(heightWeights - 0.5) * 2);
|
|
half transitionBlend = min(min(min(tstr.x, tstr.y), tstr.z), tstr.w);
|
|
albedo.rgb = lerp(albedo.rgb * outlineColor.rgb * 2, albedo.rgb, outlineColor.a * transitionBlend);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHOVERLAYSPLATS || _MESHCOMBINED
|
|
o.Alpha = 1.0;
|
|
if (config.uv0.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.x;
|
|
else if (config.uv1.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.y;
|
|
else if (config.uv2.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.z;
|
|
else if (config.uv3.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.w;
|
|
#endif
|
|
|
|
|
|
|
|
// effects which don't require per texture adjustments and are part of the splats sample go here.
|
|
// Often, as an optimization, you can compute the non-per tex version of above effects here..
|
|
|
|
|
|
#if ((_DETAILNOISE && !_PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && !_PERTEXDISTANCENOISESTRENGTH) || (_NORMALNOISE && !_PERTEXNORMALNOISESTRENGTH))
|
|
ApplyDetailDistanceNoise(albedo.rgb, normSAO, surfGrad, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
}
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
|
|
float2 sfDX = ddx(config.uv * _UVScale);
|
|
float2 sfDY = ddy(config.uv * _UVScale);
|
|
|
|
MSBRANCHOTHER(camDist - _SplatFade.x)
|
|
{
|
|
float falloff = saturate(InverseLerp(_SplatFade.x, _SplatFade.y, camDist));
|
|
half4 sfalb = SAMPLE_TEXTURE2D_ARRAY_GRAD(_Diffuse, sampler_Diffuse, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY);
|
|
COUNTSAMPLE
|
|
albedo.rgb = lerp(albedo.rgb, sfalb.rgb, falloff);
|
|
|
|
#if !_NONORMALMAP && !_AUTONORMAL
|
|
half4 sfnormSAO = SAMPLE_TEXTURE2D_ARRAY_GRAD(_NormalSAO, sampler_NormalSAO, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY).agrb;
|
|
COUNTSAMPLE
|
|
sfnormSAO.xy = sfnormSAO.xy * 2 - 1;
|
|
|
|
normSAO = lerp(normSAO, sfnormSAO, falloff);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = lerp(surfGrad, ConvertNormal2ToGradient(sfnormSAO.xy), falloff);
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
float3 autoNormal = HeightToNormal(albedo.a * _AutoNormalHeightScale, i.worldPos);
|
|
normSAO.xy = autoNormal;
|
|
normSAO.z = 0;
|
|
normSAO.w = (autoNormal.z * autoNormal.z);
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHCOMBINED
|
|
SampleMeshCombined(albedo, normSAO, surfGrad, emisMetal, specular, o.Alpha, SSSThickness, SSSTint, config, heightWeights);
|
|
#endif
|
|
|
|
#if _ISOBJECTSHADER
|
|
SampleObjectShader(i, albedo, normSAO, surfGrad, emisMetal, specular, config);
|
|
#endif
|
|
|
|
#if _GEOMAP
|
|
GeoTexture(albedo.rgb, normSAO, surfGrad, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
|
|
#if _SCATTER
|
|
ApplyScatter(
|
|
#if _MEGASPLAT
|
|
config,
|
|
#endif
|
|
i, albedo, normSAO, surfGrad, config.uv, camDist);
|
|
#endif
|
|
|
|
#if _DECAL
|
|
DoDecalBlend(decalOutput, albedo, normSAO, surfGrad, emisMetal, i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALTINT && !_PERTEXGLOBALTINTSTRENGTH
|
|
GlobalTintTexture(albedo.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _VSGRASSMAP
|
|
VSGrassTexture(albedo.rgb, config, camDist);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && !_PERTEXGLOBALNORMALSTRENGTH
|
|
GlobalNormalTexture(normSAO, surfGrad, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && !_PERTEXGLOBALSAOMSTRENGTH
|
|
GlobalSAOMTexture(normSAO, emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && !_PERTEXGLOBALEMISSTRENGTH
|
|
GlobalEmisTexture(emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && !_PERTEXGLOBALSPECULARSTRENGTH && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexture(specular.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
|
|
|
|
o.Albedo = albedo.rgb;
|
|
o.Height = albedo.a;
|
|
|
|
#if _NONORMALMAP
|
|
o.Normal = half3(0,0,1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#elif _SURFACENORMALS
|
|
o.Normal = ResolveNormalFromSurfaceGradient(surfGrad);
|
|
o.Normal = mul(GetTBN(i), o.Normal);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#else
|
|
o.Normal = half3(normSAO.xy, 1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _PERTEXRIMLIGHT
|
|
#if _USEEMISSIVEMETAL
|
|
emisMetal.rgb *= _EmissiveMult;
|
|
#endif
|
|
|
|
o.Emission += emisMetal.rgb;
|
|
o.Metallic = emisMetal.a;
|
|
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = specular;
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
pud = DoStreams(i, o, fxLevels, config.uv, porosity, waterNormalFoam, worldNormalVertex, streamFoam, wetLevel, burnLevel, i.worldPos);
|
|
#endif
|
|
|
|
|
|
#if _SNOW
|
|
snowCover = DoSnow(i, o, config.uv, WorldNormalVector(i, o.Normal), worldNormalVertex, i.worldPos, pud, porosity, camDist,
|
|
config, weights, SSSTint, SSSThickness, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if _PERTEXSSS || _MESHCOMBINEDUSESSS || (_SNOW && _SNOWSSS)
|
|
{
|
|
half3 worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
|
|
|
|
o.Emission += ComputeSSS(i, worldView, WorldNormalVector(i, o.Normal),
|
|
SSSTint, SSSThickness, _SSSDistance, _SSSScale, _SSSPower);
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWGLITTER
|
|
DoSnowGlitter(i, config, o, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
#if _WINDPARTICULATE || _SNOWPARTICULATE
|
|
DoWindParticulate(i, o, config, weights, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
o.Normal.z = sqrt(1 - saturate(dot(o.Normal.xy, o.Normal.xy)));
|
|
|
|
#if _SPECULARFADE
|
|
{
|
|
float specFade = saturate((i.worldPos.y - _SpecularFades.x) / max(_SpecularFades.y - _SpecularFades.x, 0.0001));
|
|
o.Metallic *= specFade;
|
|
o.Smoothness *= specFade;
|
|
}
|
|
#endif
|
|
|
|
#if _VSSHADOWMAP
|
|
VSShadowTexture(o, i, config, camDist);
|
|
#endif
|
|
|
|
#if _TOONWIREFRAME
|
|
ToonWireframe(config.uv, o.Albedo, camDist);
|
|
#endif
|
|
|
|
#if _SEETHROUGHSHADER
|
|
SeethroughShader(o.Albedo, o.Emission, o.Alpha, i.worldPos, o.Normal, i.worldNormal);
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_TRAXBUFFER
|
|
ClearAllButAlbedo(o, half3(traxBuffer, 0, 0) * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMALVERTEX
|
|
ClearAllButAlbedo(o, worldNormalVertex * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(o, WorldNormalVector(i, o.Normal) * saturate(o.Albedo.z+1));
|
|
#endif
|
|
|
|
#if _DEBUG_MEGABARY && _MEGASPLAT
|
|
o.Albedo = i.baryWeights.xyz;
|
|
#endif
|
|
|
|
|
|
return o;
|
|
}
|
|
|
|
void SampleSplats(float2 controlUV, inout half4 w0, inout half4 w1, inout half4 w2, inout half4 w3, inout half4 w4, inout half4 w5, inout half4 w6, inout half4 w7)
|
|
{
|
|
#if _CUSTOMSPLATTEXTURES
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_CustomControl0_TexelSize.zw - 1.0f) + 0.5f) * _CustomControl0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_CustomControl0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_CustomControl1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_CustomControl2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_CustomControl3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_CustomControl4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_CustomControl5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_CustomControl6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_CustomControl7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#else
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_Control0_TexelSize.zw - 1.0f) + 0.5f) * _Control0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_Control0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_Control1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_Control2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_Control3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_Control4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_Control5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_Control6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_Control7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
MicroSplatLayer SurfImpl(Input i, float3 worldNormalVertex)
|
|
{
|
|
#if _MEGANOUV
|
|
i.uv_Control0 = i.worldPos.xz;
|
|
#endif
|
|
|
|
float camDist = distance(_WorldSpaceCameraPos, i.worldPos);
|
|
|
|
#if _FORCELOCALSPACE
|
|
worldNormalVertex = mul((float3x3)GetWorldToObjectMatrix(), worldNormalVertex).xyz;
|
|
i.worldPos = i.worldPos - mul(GetObjectToWorldMatrix(), float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
i.worldPos = i.worldPos + mul(_GlobalOriginMTX, float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
i.worldPos = SAMPLE_TEXTURE2D(_DebugWorldPos, sampler_Diffuse, i.uv_Control0);
|
|
worldNormalVertex = SAMPLE_TEXTURE2D(_DebugWorldNormal, sampler_Diffuse, i.uv_Control0);
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ALPHABELOWHEIGHT && !_TBDISABLEALPHAHOLES
|
|
ClipWaterLevel(i.worldPos);
|
|
#endif
|
|
|
|
#if !_TBDISABLEALPHAHOLES && defined(_ALPHATEST_ON)
|
|
// UNITY 2019.3 holes
|
|
ClipHoles(i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
float2 origUV = i.uv_Control0;
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
float2 controlUV = i.uv2_Diffuse;
|
|
#else
|
|
float2 controlUV = i.uv_Control0;
|
|
#endif
|
|
|
|
|
|
#if _MICROMESH
|
|
controlUV = InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, controlUV);
|
|
#endif
|
|
|
|
half4 weights = half4(1,0,0,0);
|
|
|
|
Config config = (Config)0;
|
|
UNITY_INITIALIZE_OUTPUT(Config,config);
|
|
config.uv = origUV;
|
|
|
|
DecalOutput decalOutput = (DecalOutput)0;
|
|
#if _DECAL
|
|
decalOutput = DoDecals(i.uv_Control0, i.worldPos, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SURFACENORMALS
|
|
// Initialize the surface gradient basis vectors
|
|
ConstructSurfaceGradientTBN(i);
|
|
#endif
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(_SplatFade.y - camDist)
|
|
#endif // _SPLATFADE
|
|
{
|
|
#if !_DISABLESPLATMAPS
|
|
|
|
// Sample the splat data, from textures or vertices, and setup the config..
|
|
#if _MICRODIGGERMESH
|
|
DiggerSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLAT
|
|
MegaSplatVertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLATTEXTURE
|
|
MegaSplatTextureSetup(controlUV, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MICROVERTEXMESH
|
|
VertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif !_PROCEDURALTEXTURE || _PROCEDURALBLENDSPLATS
|
|
half4 w0 = 0; half4 w1 = 0; half4 w2 = 0; half4 w3 = 0; half4 w4 = 0; half4 w5 = 0; half4 w6 = 0; half4 w7 = 0;
|
|
SampleSplats(controlUV, w0, w1, w2, w3, w4, w5, w6, w7);
|
|
Setup(weights, origUV, config, w0, w1, w2, w3, w4, w5, w6, w7, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
float3 procNormal = worldNormalVertex;
|
|
float3 worldPos = i.worldPos;
|
|
ProceduralSetup(i, worldPos, i.worldHeight, procNormal, i.worldUpVector, weights, origUV, config, ddx(origUV), ddy(origUV), ddx(worldPos), ddy(worldPos), decalOutput);
|
|
#endif
|
|
#else // _DISABLESPLATMAPS
|
|
Setup(weights, origUV, config, half4(1,0,0,0), 0, 0, 0, 0, 0, 0, 0, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _SLOPETEXTURE
|
|
SlopeTexture(config, weights, worldNormalVertex);
|
|
#endif
|
|
} // _SPLATFADE else case
|
|
|
|
|
|
#if _TOONFLATTEXTURE
|
|
float2 quv = floor(origUV * _ToonTerrainSize);
|
|
float2 fuv = frac(origUV * _ToonTerrainSize);
|
|
#if !_TOONFLATTEXTUREQUAD
|
|
quv = Hash2D((fuv.x > fuv.y) ? quv : quv * 0.333);
|
|
#endif
|
|
float2 uvq = quv / _ToonTerrainSize;
|
|
config.uv0.xy = uvq;
|
|
config.uv1.xy = uvq;
|
|
config.uv2.xy = uvq;
|
|
config.uv3.xy = uvq;
|
|
#endif
|
|
|
|
#if (_TEXTURECLUSTER2 || _TEXTURECLUSTER3) && !_DISABLESPLATMAPS
|
|
PrepClusters(origUV, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if (_ALPHAHOLE || _ALPHAHOLETEXTURE) && !_DISABLESPLATMAPS && !_TBDISABLEALPHAHOLES
|
|
ClipAlphaHole(config, weights);
|
|
#endif
|
|
|
|
|
|
|
|
MicroSplatLayer l = Sample(i, weights, config, camDist, worldNormalVertex, decalOutput);
|
|
|
|
// On windows, sometimes the shared samplers gets stripped, so we have to do this crap.
|
|
// We sample from the lowest mip, so it shouldn't cost much, but still, I hate this, wtf..
|
|
float stripVal = saturate(SAMPLE_TEXTURE2D_LOD(_Diffuse, sampler_Diffuse, config.uv0, 11).r + 2);
|
|
stripVal *= saturate(SAMPLE_TEXTURE2D_LOD(_NormalSAO, sampler_NormalSAO, config.uv0, 11).r + 2);
|
|
l.Albedo *= stripVal;
|
|
l.Normal *= stripVal;
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
ProceduralTextureDebugOutput(l, weights, config);
|
|
#endif
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float4 ConstructTerrainTangent(float3 normal, float3 positiveZ)
|
|
{
|
|
// Consider a flat terrain. It should have tangent be (1, 0, 0) and bitangent be (0, 0, 1) as the UV of the terrain grid mesh is a scale of the world XZ position.
|
|
// In CreateTangentToWorld function (in SpaceTransform.hlsl), it is cross(normal, tangent) * sgn for the bitangent vector.
|
|
// It is not true in a left-handed coordinate system for the terrain bitangent, if we provide 1 as the tangent.w. It would produce (0, 0, -1) instead of (0, 0, 1).
|
|
// Also terrain's tangent calculation was wrong in a left handed system because cross((0,0,1), terrainNormalOS) points to the wrong direction as negative X.
|
|
// Therefore all the 4 xyzw components of the tangent needs to be flipped to correct the tangent frame.
|
|
// (See TerrainLitData.hlsl - GetSurfaceAndBuiltinData)
|
|
float3 tangent = normalize(cross(normal, positiveZ));
|
|
return float4(tangent, -1);
|
|
}
|
|
|
|
|
|
|
|
void TerrainInstancing(inout float4 vertex, inout float3 normal, inout float2 uv)
|
|
{
|
|
#if _MICROTERRAIN && defined(UNITY_INSTANCING_ENABLED) && !_TERRAINBLENDABLESHADER
|
|
|
|
float2 patchVertex = vertex.xy;
|
|
float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);
|
|
|
|
float2 sampleCoords = (patchVertex.xy + instanceData.xy) * instanceData.z; // (xy + float2(xBase,yBase)) * skipScale
|
|
uv = sampleCoords * _TerrainHeightmapRecipSize.zw;
|
|
|
|
float2 sampleUV = (uv / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleUV, 0));
|
|
|
|
vertex.xz = sampleCoords * _TerrainHeightmapScale.xz;
|
|
vertex.y = height * _TerrainHeightmapScale.y;
|
|
|
|
|
|
normal = float3(0, 1, 0);
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
void ApplyMeshModification(inout VertexData input)
|
|
{
|
|
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
|
|
float2 uv = input.texcoord0.xy;
|
|
TerrainInstancing(input.vertex, input.normal, uv);
|
|
input.texcoord0.xy = uv;
|
|
#endif
|
|
#if _PERPIXNORMAL && !_TERRAINBLENDABLESHADER
|
|
input.normal = float3(0,1,0);
|
|
#endif
|
|
|
|
#if _MICROVERSEPREVIEW
|
|
float4 recipSize = _TerrainHeightmapTexture_TexelSize;
|
|
recipSize.zw = (1.0f / (_TerrainHeightmapTexture_TexelSize.zw-1));
|
|
float2 sampleCoords = (input.texcoord0.xy / recipSize.zw + 0.5f) * recipSize.xy;
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleCoords, 0));
|
|
input.vertex.xyz += float3(0,1,0) * height * _TerrainHeight * 2;
|
|
#endif
|
|
|
|
}
|
|
|
|
// called by the template, so we can remove tangent from VertexData
|
|
void ApplyTerrainTangent(inout VertexToPixel input)
|
|
{
|
|
#if (_MICROTERRAIN || _PERPIXNORMAL) && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
|
|
// digger meshes ain't got no tangent either..
|
|
#if _MICRODIGGERMESH && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
void ModifyVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
ApplyMeshModification(v);
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
EncodeVertexWorkflow(v, d);
|
|
#elif _MEGASPLAT
|
|
EncodeMegaSplatVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void ModifyTessellatedVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
#if _MICROVERSEPREVIEW
|
|
v.vertex.y = OffsetVertex(v, d).y;
|
|
#elif _TESSDISTANCE || _TESSEDGE
|
|
v.vertex.xyz += OffsetVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
float3 GetTessFactors ()
|
|
{
|
|
#if _TESSEDGE
|
|
return float3(_TessData1.x, _TessData1.w, 0);
|
|
#endif
|
|
#if _TESSDISTANCE
|
|
return float3(_TessData2.x, _TessData2.y, _TessData1.x);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SurfaceFunction(inout Surface o, inout ShaderData d)
|
|
{
|
|
|
|
float3 worldNormalVertex = d.worldSpaceNormal;
|
|
#if _MICROVERSEPREVIEW
|
|
float2 sampleCoords = d.texcoord0.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif (defined(UNITY_INSTANCING_ENABLED) && _MICROTERRAIN && !_TERRAINBLENDABLESHADER)
|
|
float2 sampleCoords = (d.texcoord0.xy / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif _PERPIXNORMAL && (_MICROTERRAIN || _MICROMESHTERRAIN) && !_TERRAINBLENDABLESHADER
|
|
float2 sampleCoords = (d.texcoord0.xy * _PerPixelNormal_TexelSize.zw + 0.5f) * _PerPixelNormal_TexelSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_PerPixelNormal, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
|
|
float3 geomBitangent = normalize(cross(geomTangent, geomNormal)) * -1;
|
|
#if _MICROMESHTERRAIN
|
|
geomBitangent *= -1;
|
|
#endif
|
|
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#endif
|
|
|
|
#if _TOONPOLYEDGE
|
|
FlatShade(d);
|
|
#endif
|
|
|
|
Input i = DescToInput(d);
|
|
|
|
|
|
|
|
#if _SRPTERRAINBLEND
|
|
MicroSplatLayer l = BlendWithTerrain(d);
|
|
|
|
#if _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(l, normalize(TangentToWorldSpace(d, l.Normal)) * saturate(l.Albedo.z+1));
|
|
#endif
|
|
#else
|
|
MicroSplatLayer l = SurfImpl(i, worldNormalVertex);
|
|
#endif
|
|
|
|
DoDebugOutput(l);
|
|
|
|
|
|
|
|
|
|
o.Albedo = l.Albedo;
|
|
o.Normal = l.Normal;
|
|
o.Smoothness = l.Smoothness;
|
|
o.Occlusion = l.Occlusion;
|
|
o.Metallic = l.Metallic;
|
|
o.Emission = l.Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = l.Specular;
|
|
#endif
|
|
o.Height = l.Height;
|
|
o.Alpha = l.Alpha;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SHADERDESC
|
|
|
|
ShaderData CreateShaderData(VertexToPixel i)
|
|
{
|
|
ShaderData d = (ShaderData)0;
|
|
d.worldSpacePosition = i.worldPos;
|
|
|
|
d.worldSpaceNormal = i.worldNormal;
|
|
d.worldSpaceTangent = i.worldTangent.xyz;
|
|
float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * -1;
|
|
|
|
|
|
d.TBNMatrix = float3x3(d.worldSpaceTangent, bitangent, d.worldSpaceNormal);
|
|
d.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
d.texcoord0 = i.texcoord0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
d.texcoord1 = i.texcoord1;
|
|
// d.texcoord2 = i.texcoord2;
|
|
#endif
|
|
// d.texcoord3 = i.texcoord3;
|
|
// d.vertexColor = i.vertexColor;
|
|
|
|
// these rarely get used, so we back transform them. Usually will be stripped.
|
|
#if _HDRP
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(GetCameraRelativePositionWS(i.worldPos), 1));
|
|
#else
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(i.worldPos, 1));
|
|
#endif
|
|
// d.localSpaceNormal = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldNormal));
|
|
// d.localSpaceTangent = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldTangent.xyz));
|
|
|
|
// d.screenPos = i.screenPos;
|
|
// d.screenUV = i.screenPos.xy / i.screenPos.w;
|
|
|
|
// d.extraV2F0 = i.extraV2F0;
|
|
// d.extraV2F1 = i.extraV2F1;
|
|
// d.extraV2F2 = i.extraV2F2;
|
|
// d.extraV2F3 = i.extraV2F3;
|
|
// d.extraV2F4 = i.extraV2F4;
|
|
// d.extraV2F5 = i.extraV2F5;
|
|
// d.extraV2F6 = i.extraV2F6;
|
|
// d.extraV2F7 = i.extraV2F7;
|
|
|
|
return d;
|
|
}
|
|
// CHAINS
|
|
|
|
void ChainModifyVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
ModifyVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
void ChainModifyTessellatedVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
// d.extraV2F0 = v2p.extraV2F0;
|
|
// d.extraV2F1 = v2p.extraV2F1;
|
|
// d.extraV2F2 = v2p.extraV2F2;
|
|
// d.extraV2F3 = v2p.extraV2F3;
|
|
// d.extraV2F4 = v2p.extraV2F4;
|
|
// d.extraV2F5 = v2p.extraV2F5;
|
|
// d.extraV2F6 = v2p.extraV2F6;
|
|
// d.extraV2F7 = v2p.extraV2F7;
|
|
|
|
ModifyTessellatedVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
|
|
void ChainFinalColorForward(inout Surface l, inout ShaderData d, inout half4 color)
|
|
{
|
|
|
|
}
|
|
|
|
void ChainFinalGBufferStandard(inout Surface s, inout ShaderData d, inout half4 GBuffer0, inout half4 GBuffer1, inout half4 GBuffer2, inout half4 outEmission, inout half4 outShadowMask)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _PASSSHADOW
|
|
float3 _LightDirection;
|
|
float3 _LightPosition;
|
|
#endif
|
|
|
|
// vertex shader
|
|
VertexToPixel Vert (VertexData v)
|
|
{
|
|
|
|
VertexToPixel o = (VertexToPixel)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
|
|
|
|
|
#if !_TESSELLATION_ON
|
|
ChainModifyVertex(v, o);
|
|
#endif
|
|
|
|
o.texcoord0 = v.texcoord0;
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
o.texcoord1 = v.texcoord1;
|
|
// o.texcoord2 = v.texcoord2;
|
|
#endif
|
|
|
|
// o.texcoord3 = v.texcoord3;
|
|
// o.vertexColor = v.vertexColor;
|
|
|
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
|
|
o.worldPos = TransformObjectToWorld(v.vertex.xyz);
|
|
o.worldNormal = TransformObjectToWorldNormal(v.normal);
|
|
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float2 uv1 = v.texcoord1.xy;
|
|
float2 uv2 = v.texcoord2.xy;
|
|
o.worldTangent = float4(TransformObjectToWorldDir(v.tangent.xyz), v.tangent.w);
|
|
#else
|
|
float2 uv1 = v.texcoord0.xy;
|
|
float2 uv2 = uv1;
|
|
#endif
|
|
|
|
// MS Only
|
|
ApplyTerrainTangent(o);
|
|
|
|
|
|
#if _PASSSHADOW
|
|
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
float3 lightDirectionWS = normalize(_LightPosition - o.worldPos);
|
|
#else
|
|
float3 lightDirectionWS = _LightDirection;
|
|
#endif
|
|
// Define shadow pass specific clip position for Universal
|
|
o.pos = TransformWorldToHClip(ApplyShadowBias(o.worldPos, o.worldNormal, lightDirectionWS));
|
|
#if UNITY_REVERSED_Z
|
|
o.pos.z = min(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#else
|
|
o.pos.z = max(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#endif
|
|
#elif _PASSMETA
|
|
#if _MICROTERRAIN
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), v.texcoord0.xy, v.texcoord0.xy, unity_LightmapST, unity_DynamicLightmapST);
|
|
#else
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), uv1, uv2, unity_LightmapST, unity_DynamicLightmapST);
|
|
#endif
|
|
#else
|
|
o.pos = TransformWorldToHClip(o.worldPos);
|
|
#endif
|
|
|
|
|
|
|
|
// o.screenPos = ComputeScreenPos(o.pos, _ProjectionParams.x);
|
|
|
|
|
|
#if _PASSFORWARD || _PASSGBUFFER
|
|
#if _MICROTERRAIN
|
|
OUTPUT_LIGHTMAP_UV(v.texcoord0.xy, unity_LightmapST, o.lightmapUV);
|
|
#else
|
|
OUTPUT_LIGHTMAP_UV(uv1, unity_LightmapST, o.lightmapUV);
|
|
#endif
|
|
OUTPUT_SH(o.worldNormal, o.sh);
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
o.dynamicLightmapUV.xy = uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
|
|
half fogFactor = 0;
|
|
#if defined(_FOG_FRAGMENT)
|
|
fogFactor = ComputeFogFactor(o.pos.z);
|
|
#endif
|
|
#if _BAKEDLIT
|
|
half3 vertexLight = VertexLighting(o.worldPos, o.worldNormal);
|
|
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
|
|
#else
|
|
o.fogFactorAndVertexLight = half4(fogFactor, 0,0,0);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
|
|
o.shadowCoord = GetShadowCoord(vertexInput);
|
|
#endif
|
|
|
|
return o;
|
|
}
|
|
|
|
|
|
|
|
|
|
// fragment shader
|
|
half4 Frag (VertexToPixel IN) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
|
|
ShaderData d = CreateShaderData(IN);
|
|
|
|
Surface l = (Surface)0;
|
|
|
|
l.Albedo = half3(0.5, 0.5, 0.5);
|
|
l.Normal = float3(0,0,1);
|
|
l.Occlusion = 1;
|
|
l.Alpha = 1;
|
|
|
|
SurfaceFunction(l, d);
|
|
|
|
MetaInput metaInput = (MetaInput)0;
|
|
metaInput.Albedo = l.Albedo;
|
|
metaInput.Emission = l.Emission;
|
|
|
|
return MetaFragment(metaInput);
|
|
|
|
}
|
|
|
|
ENDHLSL
|
|
|
|
}
|
|
|
|
|
|
|
|
Pass
|
|
{
|
|
Name "DepthNormals"
|
|
Tags
|
|
{
|
|
"LightMode" = "DepthNormals"
|
|
}
|
|
|
|
// Render State
|
|
Cull Back
|
|
Blend One Zero
|
|
ZTest LEqual
|
|
ZWrite On
|
|
|
|
|
|
|
|
HLSLPROGRAM
|
|
|
|
#pragma vertex Vert
|
|
#pragma fragment Frag
|
|
|
|
#pragma target 3.5
|
|
|
|
#pragma prefer_hlslcc gles
|
|
#pragma exclude_renderers d3d11_9x
|
|
#pragma multi_compile_fog
|
|
#pragma multi_compile_instancing
|
|
#pragma multi_compile _ DOTS_INSTANCING_ON
|
|
#pragma multi_compile_local _ _ALPHATEST_ON
|
|
#pragma multi_compile_fragment _ _WRITE_RENDERING_LAYERS
|
|
|
|
#define SHADERPASS SHADERPASS_DEPTHNORMALSONLY
|
|
#define _PASSDEPTH 1
|
|
#define _PASSDEPTHNORMALS 1
|
|
|
|
|
|
|
|
#define _MICROSPLAT 1
|
|
#define _MICROPOLARISMESH 1
|
|
#define _USEGRADMIP 1
|
|
#define _PERTEXUVSCALEOFFSET 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
#define _MSRENDERLOOP_UNITYLD 1
|
|
#define _MSRENDERLOOP_UNITYURP2020 1
|
|
#define _MSRENDERLOOP_UNITYURP2021 1
|
|
#define _MSRENDERLOOP_UNITYURP2022 1
|
|
|
|
|
|
|
|
#define _URP 1
|
|
|
|
|
|
|
|
// this has to be here or specular color will be ignored. Not in SG code
|
|
#if _SIMPLELIT
|
|
#define _SPECULAR_COLOR
|
|
#endif
|
|
|
|
|
|
// Includes
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
|
|
#include "Packages/com.unity.shadergraph/ShaderGraphLibrary/ShaderVariablesFunctions.hlsl"
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, float3x3(d.worldSpaceTangent, cross(d.worldSpaceTangent, d.worldSpaceNormal), d.worldSpaceNormal))
|
|
|
|
|
|
#define UnityObjectToWorldNormal(normal) mul(GetObjectToWorldMatrix(), normal)
|
|
|
|
#define _WorldSpaceLightPos0 _MainLightPosition
|
|
|
|
#define UNITY_DECLARE_TEX2D(name) TEXTURE2D(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2D_NOSAMPLER(name) TEXTURE2D(name);
|
|
#define UNITY_DECLARE_TEX2DARRAY(name) TEXTURE2D_ARRAY(name); SAMPLER(sampler##name);
|
|
#define UNITY_DECLARE_TEX2DARRAY_NOSAMPLER(name) TEXTURE2D_ARRAY(name);
|
|
|
|
#define UNITY_SAMPLE_TEX2DARRAY(tex,coord) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, coord.xy, coord.z)
|
|
#define UNITY_SAMPLE_TEX2DARRAY_LOD(tex,coord,lod) SAMPLE_TEXTURE2D_ARRAY_LOD(tex, sampler##tex, coord.xy, coord.z, lod)
|
|
#define UNITY_SAMPLE_TEX2D(tex, coord) SAMPLE_TEXTURE2D(tex, sampler##tex, coord)
|
|
#define UNITY_SAMPLE_TEX2D_SAMPLER(tex, samp, coord) SAMPLE_TEXTURE2D(tex, sampler##samp, coord)
|
|
|
|
#if defined(UNITY_COMPILER_HLSL)
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name) name = (type)0;
|
|
#else
|
|
#define UNITY_INITIALIZE_OUTPUT(type,name)
|
|
#endif
|
|
|
|
#define sampler2D_float sampler2D
|
|
#define sampler2D_half sampler2D
|
|
|
|
|
|
|
|
// data across stages, stripped like the above.
|
|
struct VertexToPixel
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float3 worldPos : TEXCOORD0;
|
|
float3 worldNormal : TEXCOORD1;
|
|
float4 worldTangent : TEXCOORD2;
|
|
float4 texcoord0 : TEXCCOORD3;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 texcoord1 : TEXCCOORD4;
|
|
// float4 texcoord2 : TEXCCOORD5;
|
|
#endif
|
|
// float4 texcoord3 : TEXCCOORD6;
|
|
// float4 screenPos : TEXCOORD7;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
// float4 extraV2F0 : TEXCOORD13;
|
|
// float4 extraV2F1 : TEXCOORD14;
|
|
// float4 extraV2F2 : TEXCOORD15;
|
|
// float4 extraV2F3 : TEXCOORD16;
|
|
// float4 extraV2F4 : TEXCOORD17;
|
|
// float4 extraV2F5 : TEXCOORD18;
|
|
// float4 extraV2F6 : TEXCOORD19;
|
|
// float4 extraV2F7 : TEXCOORD20;
|
|
|
|
|
|
#if defined(LIGHTMAP_ON)
|
|
float2 lightmapUV : TEXCOORD8;
|
|
#endif
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
float2 dynamicLightmapUV : TEXCOORD9;
|
|
#endif
|
|
#if !defined(LIGHTMAP_ON)
|
|
float3 sh : TEXCOORD10;
|
|
#endif
|
|
|
|
float4 fogFactorAndVertexLight : TEXCOORD11;
|
|
float4 shadowCoord : TEXCOORD12;
|
|
|
|
#if UNITY_ANY_INSTANCING_ENABLED
|
|
uint instanceID : CUSTOM_INSTANCE_ID;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_MULTIVIEW_ENABLED)) || (defined(UNITY_STEREO_INSTANCING_ENABLED) && (defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)))
|
|
uint stereoTargetEyeIndexAsBlendIdx0 : BLENDINDICES0;
|
|
#endif
|
|
#if (defined(UNITY_STEREO_INSTANCING_ENABLED))
|
|
uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex;
|
|
#endif
|
|
#if defined(SHADER_STAGE_FRAGMENT) && defined(VARYINGS_NEED_CULLFACE)
|
|
FRONT_FACE_TYPE cullFace : FRONT_FACE_SEMANTIC;
|
|
#endif
|
|
};
|
|
|
|
|
|
// TEMPLATE_SHARED
|
|
|
|
// data describing the user output of a pixel
|
|
struct Surface
|
|
{
|
|
half3 Albedo;
|
|
half Height;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half3 Emission;
|
|
half Metallic;
|
|
half3 Specular;
|
|
half Occlusion;
|
|
half Alpha;
|
|
// HDRP Only
|
|
half SpecularOcclusion;
|
|
half SubsurfaceMask;
|
|
half Thickness;
|
|
half CoatMask;
|
|
half Anisotropy;
|
|
half IridescenceMask;
|
|
half IridescenceThickness;
|
|
};
|
|
|
|
// data the user might need, this will grow to be big. But easy to strip
|
|
struct ShaderData
|
|
{
|
|
float3 localSpacePosition;
|
|
float3 localSpaceNormal;
|
|
float3 localSpaceTangent;
|
|
|
|
float3 worldSpacePosition;
|
|
float3 worldSpaceNormal;
|
|
float3 worldSpaceTangent;
|
|
|
|
float3 worldSpaceViewDir;
|
|
float3 tangentSpaceViewDir;
|
|
|
|
float4 texcoord0;
|
|
float4 texcoord1;
|
|
float4 texcoord2;
|
|
float4 texcoord3;
|
|
|
|
float2 screenUV;
|
|
float4 screenPos;
|
|
|
|
float4 vertexColor;
|
|
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
|
|
float3x3 TBNMatrix;
|
|
};
|
|
|
|
struct VertexData
|
|
{
|
|
#if SHADER_TARGET > 30 && _PLANETCOMPUTE
|
|
// // uint vertexID : SV_VertexID;
|
|
#endif
|
|
float4 vertex : POSITION;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD4; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD5; // Add Precomputed Velocity (Alembic computes velocities on runtime side).
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct TessVertex
|
|
{
|
|
float4 vertex : INTERNALTESSPOS;
|
|
float3 normal : NORMAL;
|
|
float4 texcoord0 : TEXCOORD0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float4 tangent : TANGENT;
|
|
float4 texcoord1 : TEXCOORD1;
|
|
float4 texcoord2 : TEXCOORD2;
|
|
#endif
|
|
// float4 texcoord3 : TEXCOORD3;
|
|
// float4 vertexColor : COLOR;
|
|
|
|
|
|
// float4 extraV2F0 : TEXCOORD4;
|
|
// float4 extraV2F1 : TEXCOORD5;
|
|
// float4 extraV2F2 : TEXCOORD6;
|
|
// float4 extraV2F3 : TEXCOORD7;
|
|
// float4 extraV2F4 : TEXCOORD8;
|
|
// float4 extraV2F5 : TEXCOORD9;
|
|
// float4 extraV2F6 : TEXCOORD10;
|
|
// float4 extraV2F7 : TEXCOORD11;
|
|
|
|
#if _HDRP && (_PASSMOTIONVECTOR || (_PASSFORWARD && defined(_WRITE_TRANSPARENT_MOTION_VECTOR)))
|
|
float3 previousPositionOS : TEXCOORD12; // Contain previous transform position (in case of skinning for example)
|
|
#if defined (_ADD_PRECOMPUTED_VELOCITY)
|
|
float3 precomputedVelocity : TEXCOORD13;
|
|
#endif
|
|
#endif
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
struct ExtraV2F
|
|
{
|
|
float4 extraV2F0;
|
|
float4 extraV2F1;
|
|
float4 extraV2F2;
|
|
float4 extraV2F3;
|
|
float4 extraV2F4;
|
|
float4 extraV2F5;
|
|
float4 extraV2F6;
|
|
float4 extraV2F7;
|
|
};
|
|
|
|
|
|
float3 WorldToTangentSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(d.TBNMatrix, normal);
|
|
}
|
|
|
|
float3 TangentToWorldSpace(ShaderData d, float3 normal)
|
|
{
|
|
return mul(normal, d.TBNMatrix);
|
|
}
|
|
|
|
// in this case, make standard more like SRPs, because we can't fix
|
|
// GetWorldToObjectMatrix() in HDRP, since it already does macro-fu there
|
|
|
|
#if _STANDARD
|
|
float3 TransformWorldToObject(float3 p) { return mul(GetWorldToObjectMatrix(), float4(p, 1)); };
|
|
float3 TransformObjectToWorld(float3 p) { return mul(GetObjectToWorldMatrix(), float4(p, 1)); };
|
|
float4 TransformWorldToObject(float4 p) { return mul(GetWorldToObjectMatrix(), p); };
|
|
float4 TransformObjectToWorld(float4 p) { return mul(GetObjectToWorldMatrix(), p); };
|
|
float4x4 GetWorldToObjectMatrix() { return GetWorldToObjectMatrix(); }
|
|
float4x4 GetObjectToWorldMatrix() { return GetObjectToWorldMatrix(); }
|
|
#endif
|
|
|
|
float3 GetCameraWorldPosition()
|
|
{
|
|
#if _HDRP
|
|
return GetCameraRelativePositionWS(_WorldSpaceCameraPos);
|
|
#else
|
|
return _WorldSpaceCameraPos;
|
|
#endif
|
|
}
|
|
|
|
|
|
#if _HDRP
|
|
|
|
half3 UnpackNormalmapRGorAG(half4 packednormal)
|
|
{
|
|
// This do the trick
|
|
packednormal.x *= packednormal.w;
|
|
|
|
half3 normal;
|
|
normal.xy = packednormal.xy * 2 - 1;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
half3 UnpackNormal(half4 packednormal)
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
return packednormal.xyz * 2 - 1;
|
|
#else
|
|
return UnpackNormalmapRGorAG(packednormal);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if _HDRP || _URP
|
|
|
|
half3 UnpackScaleNormal(half4 packednormal, half scale)
|
|
{
|
|
#ifndef UNITY_NO_DXT5nm
|
|
// Unpack normal as DXT5nm (1, y, 1, x) or BC5 (x, y, 0, 1)
|
|
// Note neutral texture like "bump" is (0, 0, 1, 1) to work with both plain RGB normal and DXT5nm/BC5
|
|
packednormal.x *= packednormal.w;
|
|
#endif
|
|
half3 normal;
|
|
normal.xy = (packednormal.xy * 2 - 1) * scale;
|
|
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void GetSun(out float3 lightDir, out float3 color)
|
|
{
|
|
lightDir = float3(0.5, 0.5, 0);
|
|
color = 1;
|
|
#if _HDRP
|
|
if (_DirectionalLightCount > 0)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[0];
|
|
lightDir = -light.forward.xyz;
|
|
color = light.color;
|
|
}
|
|
#elif _STANDARD
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
color = _LightColor0.rgb;
|
|
#elif _URP
|
|
Light light = GetMainLight();
|
|
lightDir = light.direction;
|
|
color = light.color;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
|
|
|
|
|
|
#if _MESHSUBARRAY
|
|
half4 _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
float4 _Diffuse_TexelSize;
|
|
float4 _NormalSAO_TexelSize;
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
float _HybridHeightBlendDistance;
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
float4 _SmoothAO_TexelSize;
|
|
#endif
|
|
|
|
#ifdef _ALPHATEST_ON
|
|
float4 _TerrainHolesTexture_TexelSize;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
float4 _Specular_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
float4 _EmissiveMetal_TexelSize;
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
half _EmissiveMult;
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
half _AutoNormalHeightScale;
|
|
#endif
|
|
|
|
float4 _UVScale; // scale and offset
|
|
|
|
half _Contrast;
|
|
|
|
|
|
|
|
#if _VSSHADOWMAP
|
|
float4 gVSSunDirection;
|
|
#endif
|
|
|
|
#if _FORCELOCALSPACE && _PLANETVECTORS
|
|
float4x4 _PQSToLocal;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
float4x4 _GlobalOriginMTX;
|
|
#endif
|
|
|
|
float4 _Control0_TexelSize;
|
|
#if _CUSTOMSPLATTEXTURES
|
|
float4 _CustomControl0_TexelSize;
|
|
#endif
|
|
float4 _PerPixelNormal_TexelSize;
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
float2 _NoiseUVParams;
|
|
#endif
|
|
|
|
float4 _PerTexProps_TexelSize;
|
|
|
|
#if _SURFACENORMALS
|
|
float3 surfTangent;
|
|
float3 surfBitangent;
|
|
float3 surfNormal;
|
|
#endif
|
|
|
|
|
|
|
|
CBUFFER_END
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef WorldNormalVector
|
|
#define WorldNormalVector(data, normal) mul(normal, data.TBN)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// In Unity 2020.3LTS, Unity will spew tons of errors about missing this sampler in
|
|
// URP, even though it shouldn't be required.
|
|
TEXTURE2D(_MainTex);
|
|
|
|
// globals, outside of CBuffer, but used by more than one module
|
|
float3 _gGlitterLightDir;
|
|
float3 _gGlitterLightWorldPos;
|
|
half3 _gGlitterLightColor;
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
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)
|
|
float4 _TerrainNormalmapTexture_TexelSize;
|
|
#endif
|
|
|
|
#if (_MICROTERRAIN || _MICROMESHTERRAIN)
|
|
TEXTURE2D(_TerrainHeightmapTexture);
|
|
float4 _TerrainHeightmapTexture_TexelSize;
|
|
TEXTURE2D(_TerrainNormalmapTexture);
|
|
#endif
|
|
|
|
UNITY_INSTANCING_BUFFER_START(Terrain)
|
|
UNITY_DEFINE_INSTANCED_PROP(float4, _TerrainPatchInstanceData) // float4(xBase, yBase, skipScale, ~)
|
|
UNITY_INSTANCING_BUFFER_END(Terrain)
|
|
|
|
|
|
|
|
|
|
// dynamic branching helpers, for regular and aggressive branching
|
|
// debug mode shows how many samples using branching will save us.
|
|
//
|
|
// These macros are always used instead of the UNITY_BRANCH macro
|
|
// to maintain debug displays and allow branching to be disabled
|
|
// on as granular level as we want.
|
|
|
|
#if _BRANCHSAMPLES
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++; if (w > 0)
|
|
#else
|
|
#define MSBRANCH(w) UNITY_BRANCH if (w > 0)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_WEIGHT || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchWeightCount;
|
|
#define MSBRANCH(w) if (w > 0) _branchWeightCount++;
|
|
#else
|
|
#define MSBRANCH(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _BRANCHSAMPLESAGR
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER ||_DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++; if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++; if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++; if (w > 0.001)
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHCLUSTER(w) UNITY_BRANCH if (w > 0.001)
|
|
#define MSBRANCHOTHER(w) UNITY_BRANCH if (w > 0.001)
|
|
#endif
|
|
#else
|
|
#if _DEBUG_BRANCHCOUNT_TRIPLANAR || _DEBUG_BRANCHCOUNT_CLUSTER || _DEBUG_BRANCHCOUNT_OTHER || _DEBUG_BRANCHCOUNT_TOTAL
|
|
float _branchTriplanarCount;
|
|
float _branchClusterCount;
|
|
float _branchOtherCount;
|
|
#define MSBRANCHTRIPLANAR(w) if (w > 0.001) _branchTriplanarCount++;
|
|
#define MSBRANCHCLUSTER(w) if (w > 0.001) _branchClusterCount++;
|
|
#define MSBRANCHOTHER(w) if (w > 0.001) _branchOtherCount++;
|
|
#else
|
|
#define MSBRANCHTRIPLANAR(w)
|
|
#define MSBRANCHCLUSTER(w)
|
|
#define MSBRANCHOTHER(w)
|
|
#endif
|
|
#endif
|
|
|
|
#if _DEBUG_SAMPLECOUNT
|
|
int _sampleCount;
|
|
#define COUNTSAMPLE { _sampleCount++; }
|
|
#else
|
|
#define COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _DEBUG_PROCLAYERS
|
|
int _procLayerCount;
|
|
#define COUNTPROCLAYER { _procLayerCount++; }
|
|
#else
|
|
#define COUNTPROCLAYER
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
TEXTURE2D(_DebugWorldPos);
|
|
TEXTURE2D(_DebugWorldNormal);
|
|
#endif
|
|
|
|
|
|
// splat
|
|
UNITY_DECLARE_TEX2DARRAY(_Diffuse);
|
|
UNITY_DECLARE_TEX2DARRAY(_NormalSAO);
|
|
|
|
#if _CONTROLNOISEUV || _GLOBALNOISEUV
|
|
TEXTURE2D(_NoiseUV);
|
|
#endif
|
|
|
|
#if _PACKINGHQ
|
|
UNITY_DECLARE_TEX2DARRAY(_SmoothAO);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
UNITY_DECLARE_TEX2DARRAY(_Specular);
|
|
#endif
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
UNITY_DECLARE_TEX2DARRAY(_EmissiveMetal);
|
|
#endif
|
|
|
|
TEXTURE2D(_PerPixelNormal);
|
|
|
|
SamplerState shared_linear_clamp_sampler;
|
|
SamplerState shared_point_clamp_sampler;
|
|
|
|
TEXTURE2D(_Control0);
|
|
#if _CUSTOMSPLATTEXTURES
|
|
TEXTURE2D(_CustomControl0);
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_CustomControl1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_CustomControl2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_CustomControl3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_CustomControl7);
|
|
#endif
|
|
#else
|
|
#if !_MAX4TEXTURES
|
|
TEXTURE2D(_Control1);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
TEXTURE2D(_Control2);
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
TEXTURE2D(_Control3);
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control4);
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control5);
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
TEXTURE2D(_Control6);
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
TEXTURE2D(_Control7);
|
|
#endif
|
|
#endif
|
|
|
|
TEXTURE2D_FLOAT(_PerTexProps);
|
|
|
|
struct DecalLayer
|
|
{
|
|
float3 uv;
|
|
float2 dx;
|
|
float2 dy;
|
|
int decalIndex;
|
|
bool dynamic;
|
|
};
|
|
|
|
struct DecalOutput
|
|
{
|
|
DecalLayer l0;
|
|
DecalLayer l1;
|
|
DecalLayer l2;
|
|
DecalLayer l3;
|
|
|
|
half4 Weights;
|
|
half4 Indexes;
|
|
half4 fxLevels;
|
|
|
|
};
|
|
|
|
|
|
struct TriGradMipFormat
|
|
{
|
|
float4 d0;
|
|
float4 d1;
|
|
float4 d2;
|
|
};
|
|
|
|
float InverseLerp(float x, float y, float v) { return (v-x)/max(y-x, 0.001); }
|
|
float2 InverseLerp(float2 x, float2 y, float2 v) { return (v-x)/max(y-x, float2(0.001, 0.001)); }
|
|
float3 InverseLerp(float3 x, float3 y, float3 v) { return (v-x)/max(y-x, float3(0.001, 0.001, 0.001)); }
|
|
float4 InverseLerp(float4 x, float4 y, float4 v) { return (v-x)/max(y-x, float4(0.001, 0.001, 0.001, 0.001)); }
|
|
|
|
|
|
// 2019.3 holes
|
|
#ifdef _ALPHATEST_ON
|
|
TEXTURE2D(_TerrainHolesTexture);
|
|
|
|
void ClipHoles(float2 uv)
|
|
{
|
|
float hole = SAMPLE_TEXTURE2D(_TerrainHolesTexture, shared_linear_clamp_sampler, uv).r;
|
|
COUNTSAMPLE
|
|
clip(hole < 0.5f ? -1 : 1);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT TriGradMipFormat
|
|
#define INITMIPFORMAT (TriGradMipFormat)0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float3
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float3
|
|
#endif
|
|
#else
|
|
#if _USEGRADMIP
|
|
#define MIPFORMAT float4
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float4
|
|
#else
|
|
#define MIPFORMAT float
|
|
#define INITMIPFORMAT 0;
|
|
#define MIPFROMATRAW float
|
|
#endif
|
|
#endif
|
|
|
|
float2 TotalOne(float2 v) { return v * (1.0 / max(v.x + v.y, 0.001)); }
|
|
float3 TotalOne(float3 v) { return v * (1.0 / max(v.x + v.y + v.z, 0.001)); }
|
|
float4 TotalOne(float4 v) { return v * (1.0 / max(v.x + v.y + v.z + v.w, 0.001)); }
|
|
|
|
float2 RotateUV(float2 uv, float amt)
|
|
{
|
|
uv -=0.5;
|
|
float s = sin ( amt);
|
|
float c = cos ( amt );
|
|
float2x2 mtx = float2x2( c, -s, s, c);
|
|
mtx *= 0.5;
|
|
mtx += 0.5;
|
|
mtx = mtx * 2-1;
|
|
uv = mul ( uv, mtx );
|
|
uv += 0.5;
|
|
return uv;
|
|
}
|
|
|
|
float4 DecodeToFloat4(float v)
|
|
{
|
|
uint vi = (uint)(v * (256.0f * 256.0f * 256.0f * 256.0f));
|
|
int ex = (int)(vi / (256 * 256 * 256) % 256);
|
|
int ey = (int)((vi / (256 * 256)) % 256);
|
|
int ez = (int)((vi / (256)) % 256);
|
|
int ew = (int)(vi % 256);
|
|
float4 e = float4(ex / 255.0, ey / 255.0, ez / 255.0, ew / 255.0);
|
|
return e;
|
|
}
|
|
|
|
|
|
|
|
struct Input
|
|
{
|
|
ShaderData shaderData;
|
|
float2 uv_Control0;
|
|
float2 uv2_Diffuse;
|
|
|
|
float worldHeight;
|
|
float3 worldUpVector;
|
|
|
|
float3 viewDir;
|
|
float3 worldPos;
|
|
float3 worldNormal;
|
|
float4 color;
|
|
float3x3 TBN;
|
|
|
|
// vertex/digger workflow data
|
|
half4 w0;
|
|
half4 w1;
|
|
half4 w2;
|
|
half4 w3;
|
|
half4 w4;
|
|
half4 w5;
|
|
half4 w6;
|
|
|
|
// megasplat data
|
|
half4 layer0;
|
|
half4 layer1;
|
|
half3 baryWeights;
|
|
half4 scatter0;
|
|
half4 scatter1;
|
|
|
|
// wetness, puddles, streams, lava from vertex or megasplat
|
|
half4 fx;
|
|
// snow min, snow max
|
|
half4 fx2;
|
|
|
|
|
|
};
|
|
|
|
struct TriplanarConfig
|
|
{
|
|
float3x3 uv0;
|
|
float3x3 uv1;
|
|
float3x3 uv2;
|
|
float3x3 uv3;
|
|
half3 pN;
|
|
half3 pN0;
|
|
half3 pN1;
|
|
half3 pN2;
|
|
half3 pN3;
|
|
half3 axisSign;
|
|
Input IN;
|
|
};
|
|
|
|
|
|
struct Config
|
|
{
|
|
float2 uv;
|
|
float3 uv0;
|
|
float3 uv1;
|
|
float3 uv2;
|
|
float3 uv3;
|
|
|
|
half4 cluster0;
|
|
half4 cluster1;
|
|
half4 cluster2;
|
|
half4 cluster3;
|
|
|
|
};
|
|
|
|
|
|
struct MicroSplatLayer
|
|
{
|
|
half3 Albedo;
|
|
half3 Normal;
|
|
half Smoothness;
|
|
half Occlusion;
|
|
half Metallic;
|
|
half Height;
|
|
half3 Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
half3 Specular;
|
|
#endif
|
|
half Alpha;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// raw, unblended samples from arrays
|
|
struct RawSamples
|
|
{
|
|
half4 albedo0;
|
|
half4 albedo1;
|
|
half4 albedo2;
|
|
half4 albedo3;
|
|
#if _SURFACENORMALS
|
|
half3 surf0;
|
|
half3 surf1;
|
|
half3 surf2;
|
|
half3 surf3;
|
|
#endif
|
|
|
|
half4 normSAO0;
|
|
half4 normSAO1;
|
|
half4 normSAO2;
|
|
half4 normSAO3;
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALEMIS || _GLOBALSMOOTHAOMETAL || _PERTEXSSS || _PERTEXRIMLIGHT
|
|
half4 emisMetal0;
|
|
half4 emisMetal1;
|
|
half4 emisMetal2;
|
|
half4 emisMetal3;
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
half3 specular0;
|
|
half3 specular1;
|
|
half3 specular2;
|
|
half3 specular3;
|
|
#endif
|
|
};
|
|
|
|
void InitRawSamples(inout RawSamples s)
|
|
{
|
|
s.normSAO0 = half4(0,0,0,1);
|
|
s.normSAO1 = half4(0,0,0,1);
|
|
s.normSAO2 = half4(0,0,0,1);
|
|
s.normSAO3 = half4(0,0,0,1);
|
|
#if _SURFACENORMALS
|
|
s.surf0 = half3(0,0,1);
|
|
s.surf1 = half3(0,0,1);
|
|
s.surf2 = half3(0,0,1);
|
|
s.surf3 = half3(0,0,1);
|
|
#endif
|
|
}
|
|
|
|
float3 GetGlobalLightDir(Input i)
|
|
{
|
|
float3 lightDir = float3(1,0,0);
|
|
|
|
#if _HDRP || PASS_DEFERRED
|
|
lightDir = normalize(_gGlitterLightDir.xyz);
|
|
#elif _URP
|
|
lightDir = GetMainLight().direction;
|
|
#else
|
|
#ifndef USING_DIRECTIONAL_LIGHT
|
|
lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
|
|
#else
|
|
lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
|
#endif
|
|
#endif
|
|
return lightDir;
|
|
}
|
|
|
|
float3x3 GetTBN(Input i)
|
|
{
|
|
return i.TBN;
|
|
}
|
|
|
|
float3 GetGlobalLightDirTS(Input i)
|
|
{
|
|
float3 lightDirWS = GetGlobalLightDir(i);
|
|
return mul(GetTBN(i), lightDirWS);
|
|
}
|
|
|
|
half3 GetGlobalLightColor()
|
|
{
|
|
#if _HDRP || PASS_DEFERRED
|
|
return _gGlitterLightColor;
|
|
#elif _URP
|
|
return (GetMainLight().color);
|
|
#else
|
|
return _LightColor0.rgb;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 FuzzyShade(half3 color, half3 normal, half coreMult, half edgeMult, half power, float3 viewDir)
|
|
{
|
|
half dt = saturate(dot(viewDir, normal));
|
|
half dark = 1.0 - (coreMult * dt);
|
|
half edge = pow(1-dt, power) * edgeMult;
|
|
return color * (dark + edge);
|
|
}
|
|
|
|
half3 ComputeSSS(Input i, float3 V, float3 N, half3 tint, half thickness, half distortion, half scale, half power)
|
|
{
|
|
float3 L = GetGlobalLightDir(i);
|
|
half3 lightColor = GetGlobalLightColor();
|
|
float3 H = normalize(L + N * distortion);
|
|
float VdotH = pow(saturate(dot(V, -H)), power) * scale;
|
|
float3 I = (VdotH) * thickness;
|
|
return lightColor * I * tint;
|
|
}
|
|
|
|
|
|
#if _MAX2LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y; }
|
|
#elif _MAX3LAYER
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z; }
|
|
#else
|
|
inline half BlendWeights(half s1, half s2, half s3, half s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half2 BlendWeights(half2 s1, half2 s2, half2 s3, half2 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half3 BlendWeights(half3 s1, half3 s2, half3 s3, half3 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
inline half4 BlendWeights(half4 s1, half4 s2, half4 s3, half4 s4, half4 w) { return s1 * w.x + s2 * w.y + s3 * w.z + s4 * w.w; }
|
|
#endif
|
|
|
|
|
|
#if _MAX3LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#elif _MAX2LAYER
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = defVal; \
|
|
half4 varName##1 = defVal; \
|
|
half4 varName##2 = defVal; \
|
|
half4 varName##3 = defVal; \
|
|
varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#else
|
|
#define SAMPLE_PER_TEX(varName, pixel, config, defVal) \
|
|
half4 varName##0 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv0.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##1 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv1.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##2 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv2.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
half4 varName##3 = SAMPLE_TEXTURE2D_LOD(_PerTexProps, shared_point_clamp_sampler, float2(config.uv3.z*_PerTexProps_TexelSize.x, pixel*_PerTexProps_TexelSize.y), 0); \
|
|
|
|
#endif
|
|
|
|
half2 BlendNormal2(half2 base, half2 blend) { return normalize(half3(base.xy + blend.xy, 1)).xy; }
|
|
half3 BlendOverlay(half3 base, half3 blend) { return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))); }
|
|
half3 BlendMult2X(half3 base, half3 blend) { return (base * (blend * 2)); }
|
|
half3 BlendLighterColor(half3 s, half3 d) { return (s.x + s.y + s.z > d.x + d.y + d.z) ? s : d; }
|
|
|
|
|
|
#if _SURFACENORMALS
|
|
|
|
#define HALF_EPS 4.8828125e-4 // 2^-11, machine epsilon: 1 + EPS = 1 (half of the ULP for 1.0f)
|
|
|
|
|
|
|
|
void ConstructSurfaceGradientTBN(Input i)
|
|
{
|
|
float3x3 tbn = GetTBN(i);
|
|
float3 t = tbn[0];
|
|
float3 b = tbn[1];
|
|
float3 n = tbn[2];
|
|
|
|
surfNormal = n;//mul(GetWorldToObjectMatrix(), float4(n, 1)).xyz;
|
|
surfTangent = t;//mul(GetWorldToObjectMatrix(), float4(t, 1)).xyz;
|
|
surfBitangent = b;//cross(surfNormal, surfTangent);
|
|
|
|
float renormFactor = 1.0 / length(surfNormal);
|
|
surfNormal *= renormFactor;
|
|
surfTangent *= renormFactor;
|
|
surfBitangent *= renormFactor;
|
|
}
|
|
|
|
half3 SurfaceGradientFromTBN(half2 deriv)
|
|
{
|
|
return deriv.x * surfTangent + deriv.y * surfBitangent;
|
|
}
|
|
|
|
// Input: vM is tangent space normal in [-1;1].
|
|
// Output: convert vM to a derivative.
|
|
half2 TspaceNormalToDerivative(half3 vM)
|
|
{
|
|
const half scale = 1.0/128.0;
|
|
|
|
// Ensure vM delivers a positive third component using abs() and
|
|
// constrain vM.z so the range of the derivative is [-128; 128].
|
|
const half3 vMa = abs(vM);
|
|
const half z_ma = max(vMa.z, scale*max(vMa.x, vMa.y));
|
|
|
|
return -half2(vM.x, vM.y)/z_ma;
|
|
}
|
|
|
|
// Used to produce a surface gradient from the gradient of a volume
|
|
// bump function such as 3D Perlin noise. Equation 2 in [Mik10].
|
|
half3 SurfgradFromVolumeGradient(half3 grad)
|
|
{
|
|
return grad - dot(surfNormal, grad) * surfNormal;
|
|
}
|
|
|
|
half3 SurfgradFromTriplanarProjection(half3 pN, half2 xPlaneTN, half2 yPlaneTN, half2 zPlaneTN)
|
|
{
|
|
const half w0 = pN.x;
|
|
const half w1 = pN.y;
|
|
const half w2 = pN.z;
|
|
|
|
// X-plane tangent normal to gradient derivative
|
|
xPlaneTN = xPlaneTN * 2.0 - 1.0;
|
|
half xPlaneRcpZ = rsqrt(max(1 - dot(xPlaneTN.x, xPlaneTN.x) - dot(xPlaneTN.y, xPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_xplane = xPlaneTN * -xPlaneRcpZ;
|
|
|
|
// Y-plane tangent normal to gradient derivative
|
|
yPlaneTN = yPlaneTN * 2.0 - 1.0;
|
|
half yPlaneRcpZ = rsqrt(max(1 - dot(yPlaneTN.x, yPlaneTN.x) - dot(yPlaneTN.y, yPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_yplane = yPlaneTN * -yPlaneRcpZ;
|
|
|
|
// Z-plane tangent normal to gradient derivative
|
|
zPlaneTN = zPlaneTN * 2.0 - 1.0;
|
|
half zPlaneRcpZ = rsqrt(max(1 - dot(zPlaneTN.x, zPlaneTN.x) - dot(zPlaneTN.y, zPlaneTN.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
|
|
half2 d_zplane = zPlaneTN * -zPlaneRcpZ;
|
|
|
|
// Assume deriv xplane, deriv yplane, and deriv zplane are
|
|
// sampled using (z,y), (x,z), and (x,y), respectively.
|
|
// Positive scales of the lookup coordinate will work
|
|
// as well, but for negative scales the derivative components
|
|
// will need to be negated accordingly.
|
|
float3 grad = float3(w2*d_zplane.x + w1*d_yplane.x,
|
|
w2*d_zplane.y + w0*d_xplane.y,
|
|
w0*d_xplane.x + w1*d_yplane.y);
|
|
|
|
return SurfgradFromVolumeGradient(grad);
|
|
}
|
|
|
|
half3 ConvertNormalToGradient(half3 normal)
|
|
{
|
|
half2 deriv = TspaceNormalToDerivative(normal);
|
|
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
half3 ConvertNormal2ToGradient(half2 packedNormal)
|
|
{
|
|
half2 tNormal = packedNormal;
|
|
half rcpZ = rsqrt(max(1 - dot(tNormal.x, tNormal.x) - dot(tNormal.y, tNormal.y), dot(HALF_EPS, HALF_EPS))); // Clamp to avoid INF
|
|
half2 deriv = tNormal * -rcpZ;
|
|
return SurfaceGradientFromTBN(deriv);
|
|
}
|
|
|
|
|
|
half3 ResolveNormalFromSurfaceGradient(half3 gradient)
|
|
{
|
|
return normalize(surfNormal - gradient);
|
|
}
|
|
|
|
|
|
#endif // _SURFACENORMALS
|
|
|
|
void BlendNormalPerTex(inout RawSamples o, half2 noise, float4 fades)
|
|
{
|
|
#if _SURFACENORMALS
|
|
float3 grad = ConvertNormal2ToGradient(noise.xy);
|
|
o.surf0 += grad * fades.x;
|
|
o.surf1 += grad * fades.y;
|
|
#if !_MAX2LAYER
|
|
o.surf2 += grad * fades.z;
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.surf3 += grad * fades.w;
|
|
#endif
|
|
#else
|
|
o.normSAO0.xy = lerp(o.normSAO0.xy, BlendNormal2(o.normSAO0.xy, noise.xy), fades.x);
|
|
o.normSAO1.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#if !_MAX2LAYER
|
|
o.normSAO2.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO2.xy, noise.xy), fades.y);
|
|
#endif
|
|
#if !_MAX2LAYER && !_MAX3LAYER
|
|
o.normSAO3.xy = lerp(o.normSAO1.xy, BlendNormal2(o.normSAO1.xy, noise.xy), fades.y);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
half3 BlendNormal3(half3 n1, half3 n2)
|
|
{
|
|
n1 += float3( 0, 0, 1);
|
|
n2 *= float3(-1, -1, 1);
|
|
return n1*dot(n1, n2) / n1.z - n2;
|
|
}
|
|
|
|
half2 TransformTriplanarNormal(Input IN, float3x3 t2w, half3 axisSign, half3 absVertNormal,
|
|
half3 pN, half2 a0, half2 a1, half2 a2)
|
|
{
|
|
|
|
a0 = a0 * 2 - 1;
|
|
a1 = a1 * 2 - 1;
|
|
a2 = a2 * 2 - 1;
|
|
|
|
a0.x *= axisSign.x;
|
|
a1.x *= axisSign.y;
|
|
a2.x *= axisSign.z;
|
|
|
|
half3 n0 = half3(a0.xy, 1);
|
|
half3 n1 = half3(a1.xy, 1);
|
|
half3 n2 = half3(a2.xy, 1);
|
|
|
|
float3 wn = IN.worldNormal;
|
|
|
|
n0 = BlendNormal3(half3(wn.zy, absVertNormal.x), n0);
|
|
n1 = BlendNormal3(half3(wn.xz, absVertNormal.y), n1 * float3(-1, 1, 1));
|
|
n2 = BlendNormal3(half3(wn.xy, absVertNormal.z), n2);
|
|
|
|
n0.z *= axisSign.x;
|
|
n1.z *= axisSign.y;
|
|
n2.z *= -axisSign.z;
|
|
|
|
half3 worldNormal = (n0.zyx * pN.x + n1.xzy * pN.y + n2.xyz * pN.z);
|
|
return mul(t2w, worldNormal).xy;
|
|
|
|
}
|
|
|
|
// funcs
|
|
|
|
inline half MSLuminance(half3 rgb)
|
|
{
|
|
#ifdef UNITY_COLORSPACE_GAMMA
|
|
return dot(rgb, half3(0.22, 0.707, 0.071));
|
|
#else
|
|
return dot(rgb, half3(0.0396819152, 0.458021790, 0.00609653955));
|
|
#endif
|
|
}
|
|
|
|
|
|
float2 Hash2D( float2 x )
|
|
{
|
|
float2 k = float2( 0.3183099, 0.3678794 );
|
|
x = x*k + k.yx;
|
|
return -1.0 + 2.0*frac( 16.0 * k*frac( x.x*x.y*(x.x+x.y)) );
|
|
}
|
|
|
|
float Noise2D(float2 p )
|
|
{
|
|
float2 i = floor( p );
|
|
float2 f = frac( p );
|
|
|
|
float2 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( dot( Hash2D( i + float2(0.0,0.0) ), f - float2(0.0,0.0) ),
|
|
dot( Hash2D( i + float2(1.0,0.0) ), f - float2(1.0,0.0) ), u.x),
|
|
lerp( dot( Hash2D( i + float2(0.0,1.0) ), f - float2(0.0,1.0) ),
|
|
dot( Hash2D( i + float2(1.0,1.0) ), f - float2(1.0,1.0) ), u.x), u.y);
|
|
}
|
|
|
|
float FBM2D(float2 uv)
|
|
{
|
|
float f = 0.5000*Noise2D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise2D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise2D( uv );
|
|
return f;
|
|
}
|
|
|
|
float3 Hash3D( float3 p )
|
|
{
|
|
p = float3( dot(p,float3(127.1,311.7, 74.7)),
|
|
dot(p,float3(269.5,183.3,246.1)),
|
|
dot(p,float3(113.5,271.9,124.6)));
|
|
|
|
return -1.0 + 2.0*frac(sin(p)*437.5453123);
|
|
}
|
|
|
|
float Noise3D( float3 p )
|
|
{
|
|
float3 i = floor( p );
|
|
float3 f = frac( p );
|
|
|
|
float3 u = f*f*(3.0-2.0*f);
|
|
|
|
return lerp( lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,0.0) ), f - float3(0.0,0.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,0.0) ), f - float3(1.0,0.0,0.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,0.0) ), f - float3(0.0,1.0,0.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,0.0) ), f - float3(1.0,1.0,0.0) ), u.x), u.y),
|
|
lerp( lerp( dot( Hash3D( i + float3(0.0,0.0,1.0) ), f - float3(0.0,0.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,0.0,1.0) ), f - float3(1.0,0.0,1.0) ), u.x),
|
|
lerp( dot( Hash3D( i + float3(0.0,1.0,1.0) ), f - float3(0.0,1.0,1.0) ),
|
|
dot( Hash3D( i + float3(1.0,1.0,1.0) ), f - float3(1.0,1.0,1.0) ), u.x), u.y), u.z );
|
|
}
|
|
|
|
float FBM3D(float3 uv)
|
|
{
|
|
float f = 0.5000*Noise3D( uv ); uv *= 2.01;
|
|
f += 0.2500*Noise3D( uv ); uv *= 1.96;
|
|
f += 0.1250*Noise3D( uv );
|
|
return f;
|
|
}
|
|
|
|
|
|
|
|
float GetSaturation(float3 c)
|
|
{
|
|
float mi = min(min(c.x, c.y), c.z);
|
|
float ma = max(max(c.x, c.y), c.z);
|
|
return (ma - mi)/(ma + 1e-7);
|
|
}
|
|
|
|
// Better Color Lerp, does not have darkening issue
|
|
float3 BetterColorLerp(float3 a, float3 b, float x)
|
|
{
|
|
float3 ic = lerp(a, b, x) + float3(1e-6,0.0,0.0);
|
|
float sd = abs(GetSaturation(ic) - lerp(GetSaturation(a), GetSaturation(b), x));
|
|
|
|
float3 dir = normalize(float3(2.0 * ic.x - ic.y - ic.z, 2.0 * ic.y - ic.x - ic.z, 2.0 * ic.z - ic.y - ic.x));
|
|
float lgt = dot(float3(1.0, 1.0, 1.0), ic);
|
|
|
|
float ff = dot(dir, normalize(ic));
|
|
|
|
const float dsp_str = 1.5;
|
|
ic += dsp_str * dir * sd * ff * lgt;
|
|
return saturate(ic);
|
|
}
|
|
|
|
|
|
half4 ComputeWeights(half4 iWeights, half h0, half h1, half h2, half h3, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return iWeights;
|
|
#else
|
|
// compute weight with height map
|
|
//half4 weights = half4(iWeights.x * h0, iWeights.y * h1, iWeights.z * h2, iWeights.w * h3);
|
|
half4 weights = half4(iWeights.x * max(h0,0.001), iWeights.y * max(h1,0.001), iWeights.z * max(h2,0.001), iWeights.w * max(h3,0.001));
|
|
|
|
// Contrast weights
|
|
half maxWeight = max(max(weights.x, max(weights.y, weights.z)), weights.w);
|
|
half transition = max(contrast * maxWeight, 0.0001);
|
|
half threshold = maxWeight - transition;
|
|
half scale = 1.0 / transition;
|
|
weights = saturate((weights - threshold) * scale);
|
|
|
|
weights = TotalOne(weights);
|
|
return weights;
|
|
#endif
|
|
}
|
|
|
|
half HeightBlend(half h1, half h2, half slope, half contrast)
|
|
{
|
|
#if _DISABLEHEIGHTBLENDING
|
|
return slope;
|
|
#else
|
|
h2 = 1 - h2;
|
|
half tween = saturate((slope - min(h1, h2)) / max(abs(h1 - h2), 0.001));
|
|
half blend = saturate( ( tween - (1-contrast) ) / max(contrast, 0.001));
|
|
return blend;
|
|
#endif
|
|
}
|
|
|
|
#if _MAX4TEXTURES
|
|
#define TEXCOUNT 4
|
|
#elif _MAX8TEXTURES
|
|
#define TEXCOUNT 8
|
|
#elif _MAX12TEXTURES
|
|
#define TEXCOUNT 12
|
|
#elif _MAX20TEXTURES
|
|
#define TEXCOUNT 20
|
|
#elif _MAX24TEXTURES
|
|
#define TEXCOUNT 24
|
|
#elif _MAX28TEXTURES
|
|
#define TEXCOUNT 28
|
|
#elif _MAX32TEXTURES
|
|
#define TEXCOUNT 32
|
|
#else
|
|
#define TEXCOUNT 16
|
|
#endif
|
|
|
|
#if _DECAL_SPLAT
|
|
|
|
void DoMergeDecalSplats(half4 iWeights, half4 iIndexes, inout half4 indexes, inout half4 weights)
|
|
{
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
half w = iWeights[i];
|
|
half index = iIndexes[i];
|
|
if (w > weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = index;
|
|
}
|
|
else if (w > weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = index;
|
|
}
|
|
else if (w > weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = index;
|
|
}
|
|
else if (w > weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = index;
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
void Setup(out half4 weights, float2 uv, out Config config, half4 w0, half4 w1, half4 w2, half4 w3, half4 w4, half4 w5, half4 w6, half4 w7, float3 worldPos, DecalOutput decalOutput)
|
|
{
|
|
config = (Config)0;
|
|
half4 indexes = 0;
|
|
|
|
config.uv = uv;
|
|
|
|
#if _WORLDUV
|
|
uv = worldPos.xz;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
float2 scaledUV = uv;
|
|
#else
|
|
float2 scaledUV = uv * _UVScale.xy + _UVScale.zw;
|
|
#endif
|
|
|
|
// if only 4 textures, and blending 4 textures, skip this whole thing..
|
|
// this saves about 25% of the ALU of the base shader on low end. However if
|
|
// we rely on sorted texture weights (distance resampling) we have to sort..
|
|
float4 defaultIndexes = float4(0,1,2,3);
|
|
#if _MESHSUBARRAY
|
|
defaultIndexes = _MeshSubArrayIndexes;
|
|
#endif
|
|
|
|
#if _MESHSUBARRAY && !_DECAL_SPLAT || (_MAX4TEXTURES && !_MAX3LAYER && !_MAX2LAYER && !_DISTANCERESAMPLE && !_POM && !_DECAL_SPLAT)
|
|
weights = w0;
|
|
config.uv0 = float3(scaledUV, defaultIndexes.x);
|
|
config.uv1 = float3(scaledUV, defaultIndexes.y);
|
|
config.uv2 = float3(scaledUV, defaultIndexes.z);
|
|
config.uv3 = float3(scaledUV, defaultIndexes.w);
|
|
return;
|
|
#endif
|
|
|
|
#if _DISABLESPLATMAPS
|
|
weights = float4(1,0,0,0);
|
|
return;
|
|
#else
|
|
half splats[TEXCOUNT];
|
|
|
|
splats[0] = w0.x;
|
|
splats[1] = w0.y;
|
|
splats[2] = w0.z;
|
|
splats[3] = w0.w;
|
|
#if !_MAX4TEXTURES
|
|
splats[4] = w1.x;
|
|
splats[5] = w1.y;
|
|
splats[6] = w1.z;
|
|
splats[7] = w1.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
splats[8] = w2.x;
|
|
splats[9] = w2.y;
|
|
splats[10] = w2.z;
|
|
splats[11] = w2.w;
|
|
#endif
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
splats[12] = w3.x;
|
|
splats[13] = w3.y;
|
|
splats[14] = w3.z;
|
|
splats[15] = w3.w;
|
|
#endif
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[16] = w4.x;
|
|
splats[17] = w4.y;
|
|
splats[18] = w4.z;
|
|
splats[19] = w4.w;
|
|
#endif
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[20] = w5.x;
|
|
splats[21] = w5.y;
|
|
splats[22] = w5.z;
|
|
splats[23] = w5.w;
|
|
#endif
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
splats[24] = w6.x;
|
|
splats[25] = w6.y;
|
|
splats[26] = w6.z;
|
|
splats[27] = w6.w;
|
|
#endif
|
|
#if _MAX32TEXTURES
|
|
splats[28] = w7.x;
|
|
splats[29] = w7.y;
|
|
splats[30] = w7.z;
|
|
splats[31] = w7.w;
|
|
#endif
|
|
|
|
|
|
|
|
weights[0] = 0;
|
|
weights[1] = 0;
|
|
weights[2] = 0;
|
|
weights[3] = 0;
|
|
indexes[0] = 0;
|
|
indexes[1] = 0;
|
|
indexes[2] = 0;
|
|
indexes[3] = 0;
|
|
|
|
int i = 0;
|
|
for (i = 0; i < TEXCOUNT; ++i)
|
|
{
|
|
half w = splats[i];
|
|
if (w >= weights[0])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = weights[0];
|
|
indexes[1] = indexes[0];
|
|
weights[0] = w;
|
|
indexes[0] = i;
|
|
}
|
|
else if (w >= weights[1])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = weights[1];
|
|
indexes[2] = indexes[1];
|
|
weights[1] = w;
|
|
indexes[1] = i;
|
|
}
|
|
else if (w >= weights[2])
|
|
{
|
|
weights[3] = weights[2];
|
|
indexes[3] = indexes[2];
|
|
weights[2] = w;
|
|
indexes[2] = i;
|
|
}
|
|
else if (w >= weights[3])
|
|
{
|
|
weights[3] = w;
|
|
indexes[3] = i;
|
|
}
|
|
}
|
|
|
|
// NaN Prevention
|
|
if (weights.x <= 0)
|
|
weights = float4(1, 0, 0, 0);
|
|
|
|
#if _DECAL_SPLAT
|
|
DoMergeDecalSplats(decalOutput.Weights, decalOutput.Indexes, weights, indexes);
|
|
#endif
|
|
|
|
|
|
|
|
// clamp and renormalize
|
|
#if _MAX2LAYER
|
|
weights.zw = 0;
|
|
weights.xy = TotalOne(weights.xy);
|
|
#elif _MAX3LAYER
|
|
weights.w = 0;
|
|
weights.xyz = TotalOne(weights.xyz);
|
|
#elif !_DISABLEHEIGHTBLENDING || _NORMALIZEWEIGHTS // prevents black when painting, which the unity shader does not prevent.
|
|
weights = normalize(weights);
|
|
#endif
|
|
|
|
|
|
config.uv0 = float3(scaledUV, indexes.x);
|
|
config.uv1 = float3(scaledUV, indexes.y);
|
|
config.uv2 = float3(scaledUV, indexes.z);
|
|
config.uv3 = float3(scaledUV, indexes.w);
|
|
|
|
|
|
#endif //_DISABLESPLATMAPS
|
|
|
|
|
|
}
|
|
|
|
float3 HeightToNormal(float height, float3 worldPos)
|
|
{
|
|
float3 dx = ddx(worldPos);
|
|
float3 dy = ddy(worldPos);
|
|
float3 crossX = cross(float3(0,1,0), dx);
|
|
float3 crossY = cross(float3(0,1,0), dy);
|
|
float3 d = abs(dot(crossY, dx));
|
|
float3 n = ((((height + ddx(height)) - height) * crossY) + (((height + ddy(height)) - height) * crossX)) * sign(d);
|
|
n.z *= -1;
|
|
return normalize((d * float3(0,1,0)) - n).xzy;
|
|
}
|
|
|
|
float ComputeMipLevel(float2 uv, float2 textureSize)
|
|
{
|
|
uv *= textureSize;
|
|
float2 dx_vtc = ddx(uv);
|
|
float2 dy_vtc = ddy(uv);
|
|
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
|
|
return 0.5 * log2(delta_max_sqr);
|
|
}
|
|
|
|
inline half2 UnpackNormal2(half4 packednormal)
|
|
{
|
|
return packednormal.wy * 2 - 1;
|
|
|
|
}
|
|
|
|
half3 TriplanarHBlend(half h0, half h1, half h2, half3 pN, half contrast)
|
|
{
|
|
half3 blend = pN / dot(pN, half3(1,1,1));
|
|
float3 heights = float3(h0, h1, h2) + (blend * 3.0);
|
|
half height_start = max(max(heights.x, heights.y), heights.z) - contrast;
|
|
half3 h = max(heights - height_start.xxx, half3(0,0,0));
|
|
blend = h / dot(h, half3(1,1,1));
|
|
return blend;
|
|
}
|
|
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half3 display)
|
|
{
|
|
o.Albedo = display.rgb;
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
void ClearAllButAlbedo(inout MicroSplatLayer o, half display)
|
|
{
|
|
o.Albedo = half3(display, display, display);
|
|
o.Normal = half3(0, 0, 1);
|
|
o.Smoothness = 0;
|
|
o.Occlusion = 1;
|
|
o.Emission = 0;
|
|
o.Metallic = 0;
|
|
o.Height = 0;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
half MicroShadow(float3 lightDir, half3 normal, half ao, half strength)
|
|
{
|
|
half shadow = saturate(abs(dot(normal, lightDir)) + (ao * ao * 2.0) - 1.0);
|
|
return 1 - ((1-shadow) * strength);
|
|
}
|
|
|
|
|
|
void DoDebugOutput(inout MicroSplatLayer l)
|
|
{
|
|
#if _DEBUG_OUTPUT_ALBEDO
|
|
ClearAllButAlbedo(l, l.Albedo);
|
|
#elif _DEBUG_OUTPUT_NORMAL
|
|
// oh unit shader compiler normal stripping, how I hate you so..
|
|
// must multiply by albedo to stop the normal from being white. Why, fuck knows?
|
|
ClearAllButAlbedo(l, float3(l.Normal.xy * 0.5 + 0.5, l.Normal.z * saturate(l.Albedo.z+1)));
|
|
#elif _DEBUG_OUTPUT_SMOOTHNESS
|
|
ClearAllButAlbedo(l, l.Smoothness.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_METAL
|
|
ClearAllButAlbedo(l, l.Metallic.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_AO
|
|
ClearAllButAlbedo(l, l.Occlusion.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_EMISSION
|
|
ClearAllButAlbedo(l, l.Emission * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_HEIGHT
|
|
ClearAllButAlbedo(l, l.Height.xxx * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_OUTPUT_SPECULAR && _USESPECULARWORKFLOW
|
|
ClearAllButAlbedo(l, l.Specular * saturate(l.Albedo.z+1));
|
|
#elif _DEBUG_BRANCHCOUNT_WEIGHT
|
|
ClearAllButAlbedo(l, _branchWeightCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TRIPLANAR
|
|
ClearAllButAlbedo(l, _branchTriplanarCount / 24 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_CLUSTER
|
|
ClearAllButAlbedo(l, _branchClusterCount / 12 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_OTHER
|
|
ClearAllButAlbedo(l, _branchOtherCount / 8 * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_BRANCHCOUNT_TOTAL
|
|
l.Albedo.r = _branchWeightCount / 12;
|
|
l.Albedo.g = _branchTriplanarCount / 24;
|
|
l.Albedo.b = _branchClusterCount / 12;
|
|
ClearAllButAlbedo(l, (l.Albedo.r + l.Albedo.g + l.Albedo.b + (_branchOtherCount / 8)) / 4);
|
|
#elif _DEBUG_OUTPUT_MICROSHADOWS
|
|
ClearAllButAlbedo(l,l.Albedo);
|
|
#elif _DEBUG_SAMPLECOUNT
|
|
float sdisp = (float)_sampleCount / max(_SampleCountDiv, 1);
|
|
half3 sdcolor = float3(sdisp, sdisp > 1 ? 1 : 0, 0);
|
|
ClearAllButAlbedo(l, sdcolor * saturate(l.Albedo.z + 1));
|
|
#elif _DEBUG_PROCLAYERS
|
|
ClearAllButAlbedo(l, (float)_procLayerCount / (float)_PCLayerCount * saturate(l.Albedo.z + 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
// abstraction around sampler mode
|
|
#if _USELODMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_LOD(tex, sampler##tex, u, l.x)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u, l.x)
|
|
#elif _USEGRADMIP
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_GRAD(tex, sampler##tex, u, l.xy, l.zw)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY_GRAD(tex, ss, u.xy, u.z, l.xy, l.zw)
|
|
#else
|
|
#define MICROSPLAT_SAMPLE(tex, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, sampler##tex, u.xy, u.z)
|
|
#define MICROSPLAT_SAMPLE_SAMPLER(tex, ss, u, l) SAMPLE_TEXTURE2D_ARRAY(tex, ss, u.xy, y.z)
|
|
#endif
|
|
|
|
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE(u, cl, l) MICROSPLAT_SAMPLE(_Diffuse, u, l)
|
|
#define MICROSPLAT_SAMPLE_EMIS(u, cl, l) MICROSPLAT_SAMPLE(_EmissiveMetal, u, l)
|
|
#define MICROSPLAT_SAMPLE_DIFFUSE_LOD(u, cl, l) UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, u, l)
|
|
|
|
|
|
#if _PACKINGHQ
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) half4(MICROSPLAT_SAMPLE(_NormalSAO, u, l).ga, MICROSPLAT_SAMPLE(_SmoothAO, u, l).ga).brag
|
|
#else
|
|
#define MICROSPLAT_SAMPLE_NORMAL(u, cl, l) MICROSPLAT_SAMPLE(_NormalSAO, u, l)
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
#define MICROSPLAT_SAMPLE_SPECULAR(u, cl, l) MICROSPLAT_SAMPLE(_Specular, u, l)
|
|
#endif
|
|
|
|
struct SimpleTriplanarConfig
|
|
{
|
|
float3 pn;
|
|
float2 uv0;
|
|
float2 uv1;
|
|
float2 uv2;
|
|
};
|
|
|
|
void PrepSimpleTriplanarConfig(inout SimpleTriplanarConfig tc, float3 worldPos, float3 normal, float contrast)
|
|
{
|
|
tc.pn = pow(abs(normal), contrast);
|
|
tc.pn = tc.pn / (tc.pn.x + tc.pn.y + tc.pn.z);
|
|
|
|
half3 axisSign = sign(normal);
|
|
|
|
tc.uv0 = worldPos.zy * axisSign.x;
|
|
tc.uv1 = worldPos.xz * axisSign.y;
|
|
tc.uv2 = worldPos.xy * axisSign.z;
|
|
}
|
|
|
|
#define SimpleTriplanarSample(tex, tc, scale) (SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv0 * scale) * tc.pn.x + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv1 * scale) * tc.pn.y + SAMPLE_TEXTURE2D(tex, sampler_Diffuse, tc.uv2 * scale) * tc.pn.z)
|
|
#define SimpleTriplanarSampleLOD(tex, tc, scale, lod) (SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv0 * scale, lod) * tc.pn.x + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv1 * scale, lod) * tc.pn.y + SAMPLE_TEXTURE2D_LOD(tex, sampler_Diffuse, tc.uv2 * scale, lod) * tc.pn.z)
|
|
#define SimpleTriplanarSampleGrad(tex, tc, scale) (SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv0 * scale, ddx(tc.uv0) * scale, ddy(tc.uv0) * scale) * tc.pn.x + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv1 * scale, ddx(tc.uv1) * scale, ddy(tc.uv1) * scale) * tc.pn.y + SAMPLE_TEXTURE2D_GRAD(tex, sampler_Diffuse, tc.uv2 * scale, ddx(tc.uv2) * scale, ddy(tc.uv2) * scale) * tc.pn.z)
|
|
|
|
|
|
inline half3 MicroSplatDiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
|
|
{
|
|
specColor = lerp (half3(0,0,0), albedo, metallic);
|
|
oneMinusReflectivity = (1-metallic);
|
|
return albedo * oneMinusReflectivity;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Input DescToInput(ShaderData IN)
|
|
{
|
|
Input s = (Input)0;
|
|
s.shaderData = IN;
|
|
s.TBN = IN.TBNMatrix;
|
|
s.worldNormal = IN.worldSpaceNormal;
|
|
s.worldPos = IN.worldSpacePosition;
|
|
s.viewDir = IN.tangentSpaceViewDir;
|
|
s.uv_Control0 = IN.texcoord0.xy;
|
|
|
|
s.worldUpVector = float3(0,1,0);
|
|
s.worldHeight = IN.worldSpacePosition.y;
|
|
|
|
#if _PLANETVECTORS
|
|
float3 rwp = mul(_PQSToLocal, float4(IN.worldSpacePosition, 1));
|
|
s.worldHeight = distance(rwp, float3(0,0,0));
|
|
s.worldUpVector = normalize(rwp);
|
|
#endif
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
s.uv2_Diffuse = IN.texcoord1.xy;
|
|
#endif
|
|
|
|
#if _MEGASPLAT
|
|
UnpackMegaSplat(s, IN);
|
|
#endif
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
UnpackVertexWorkflow(s, IN);
|
|
#endif
|
|
|
|
#if _PLANETVECTORS
|
|
DoPlanetDataInputCopy(s, IN);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
void SampleAlbedo(inout Config config, inout TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half4 contrasts = _Contrast.xxxx;
|
|
#if _PERTEXTRIPLANARCONTRAST
|
|
SAMPLE_PER_TEX(ptc, 9.5, config, half4(1,0.5,0,0));
|
|
contrasts = half4(ptc0.y, ptc1.y, ptc2.y, ptc3.y);
|
|
#endif
|
|
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
SAMPLE_PER_TEX(pttri, 9.5, config, half4(0,0,0,0));
|
|
#endif
|
|
|
|
{
|
|
// For per-texture triplanar, we modify the view based blending factor of the triplanar
|
|
// such that you get a pure blend of either top down projection, or with the top down projection
|
|
// removed and renormalized. This causes dynamic flow control optimizations to kick in and avoid
|
|
// the extra texture samples while keeping the code simple. Yay..
|
|
|
|
// We also only have to do this in the Albedo, because the pN values will be adjusted after the
|
|
// albedo is sampled, causing future samples to use this data.
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri0.x > 0.66)
|
|
{
|
|
tc.pN0 = half3(0,1,0);
|
|
}
|
|
else if (pttri0.x > 0.33)
|
|
{
|
|
tc.pN0.y = 0;
|
|
tc.pN0.xz = TotalOne(tc.pN0.xz);
|
|
}
|
|
#endif
|
|
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN0;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN0, contrasts.x);
|
|
tc.pN0 = bf;
|
|
#endif
|
|
|
|
s.albedo0 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri1.x > 0.66)
|
|
{
|
|
tc.pN1 = half3(0,1,0);
|
|
}
|
|
else if (pttri1.x > 0.33)
|
|
{
|
|
tc.pN1.y = 0;
|
|
tc.pN1.xz = TotalOne(tc.pN1.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
COUNTSAMPLE
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv1[2], config.cluster1, d2);
|
|
}
|
|
half3 bf = tc.pN1;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN1, contrasts.x);
|
|
tc.pN1 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo1 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri2.x > 0.66)
|
|
{
|
|
tc.pN2 = half3(0,1,0);
|
|
}
|
|
else if (pttri2.x > 0.33)
|
|
{
|
|
tc.pN2.y = 0;
|
|
tc.pN2.xz = TotalOne(tc.pN2.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN2;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN2, contrasts.x);
|
|
tc.pN2 = bf;
|
|
#endif
|
|
|
|
|
|
s.albedo2 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
|
|
#if _PERTEXTRIPLANAR
|
|
if (pttri3.x > 0.66)
|
|
{
|
|
tc.pN3 = half3(0,1,0);
|
|
}
|
|
else if (pttri3.x > 0.33)
|
|
{
|
|
tc.pN3.y = 0;
|
|
tc.pN3.xz = TotalOne(tc.pN3.xz);
|
|
}
|
|
#endif
|
|
|
|
half4 a0 = half4(0,0,0,0);
|
|
half4 a1 = half4(0,0,0,0);
|
|
half4 a2 = half4(0,0,0,0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_DIFFUSE(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
half3 bf = tc.pN3;
|
|
#if _TRIPLANARHEIGHTBLEND
|
|
bf = TriplanarHBlend(a0.a, a1.a, a2.a, tc.pN3, contrasts.x);
|
|
tc.pN3 = bf;
|
|
#endif
|
|
|
|
s.albedo3 = a0 * bf.x + a1 * bf.y + a2 * bf.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.albedo0 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.albedo1 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.albedo2 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.albedo3 = MICROSPLAT_SAMPLE_DIFFUSE(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXHEIGHTOFFSET || _PERTEXHEIGHTCONTRAST
|
|
SAMPLE_PER_TEX(ptHeight, 10.5, config, 1);
|
|
|
|
#if _PERTEXHEIGHTOFFSET
|
|
s.albedo0.a = saturate(s.albedo0.a + ptHeight0.b - 1);
|
|
s.albedo1.a = saturate(s.albedo1.a + ptHeight1.b - 1);
|
|
s.albedo2.a = saturate(s.albedo2.a + ptHeight2.b - 1);
|
|
s.albedo3.a = saturate(s.albedo3.a + ptHeight3.b - 1);
|
|
#endif
|
|
#if _PERTEXHEIGHTCONTRAST
|
|
s.albedo0.a = saturate(pow(s.albedo0.a + 0.5, abs(ptHeight0.a)) - 0.5);
|
|
s.albedo1.a = saturate(pow(s.albedo1.a + 0.5, abs(ptHeight1.a)) - 0.5);
|
|
s.albedo2.a = saturate(pow(s.albedo2.a + 0.5, abs(ptHeight2.a)) - 0.5);
|
|
s.albedo3.a = saturate(pow(s.albedo3.a + 0.5, abs(ptHeight3.a)) - 0.5);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void SampleNormal(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
|
|
#if _NONORMALMAP || _AUTONORMAL
|
|
s.normSAO0 = half4(0,0, 0, 1);
|
|
s.normSAO1 = half4(0,0, 0, 1);
|
|
s.normSAO2 = half4(0,0, 0, 1);
|
|
s.normSAO3 = half4(0,0, 0, 1);
|
|
return;
|
|
#endif
|
|
|
|
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
|
|
half3 absVertNormal = abs(tc.IN.worldNormal);
|
|
float3x3 t2w = tc.IN.TBN;
|
|
|
|
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[0], config.cluster0, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[1], config.cluster0, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv0[2], config.cluster0, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = SurfgradFromTriplanarProjection(tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO0.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN0, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO0.zw = a0.zw * tc.pN0.x + a1.zw * tc.pN0.y + a2.zw * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[0], config.cluster1, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[1], config.cluster1, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv1[2], config.cluster1, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = SurfgradFromTriplanarProjection(tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO1.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN1, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO1.zw = a0.zw * tc.pN1.x + a1.zw * tc.pN1.y + a2.zw * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[0], config.cluster2, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[1], config.cluster2, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv2[2], config.cluster2, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf2 = SurfgradFromTriplanarProjection(tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO2.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN2, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO2.zw = a0.zw * tc.pN2.x + a1.zw * tc.pN2.y + a2.zw * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0.5, 0.5, 0, 1);
|
|
half4 a1 = half4(0.5, 0.5, 0, 1);
|
|
half4 a2 = half4(0.5, 0.5, 0, 1);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[0], config.cluster3, d0).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[1], config.cluster3, d1).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_NORMAL(tc.uv3[2], config.cluster3, d2).agrb;
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf3 = SurfgradFromTriplanarProjection(tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#else
|
|
s.normSAO3.xy = TransformTriplanarNormal(tc.IN, t2w, tc.axisSign, absVertNormal, tc.pN3, a0.xy, a1.xy, a2.xy);
|
|
#endif
|
|
|
|
s.normSAO3.zw = a0.zw * tc.pN3.x + a1.zw * tc.pN3.y + a2.zw * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.normSAO0 = MICROSPLAT_SAMPLE_NORMAL(config.uv0, config.cluster0, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO0.xy = s.normSAO0.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf0 = ConvertNormal2ToGradient(s.normSAO0.xy);
|
|
#endif
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.normSAO1 = MICROSPLAT_SAMPLE_NORMAL(config.uv1, config.cluster1, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO1.xy = s.normSAO1.xy * 2 - 1;
|
|
|
|
#if _SURFACENORMALS
|
|
s.surf1 = ConvertNormal2ToGradient(s.normSAO1.xy);
|
|
#endif
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.normSAO2 = MICROSPLAT_SAMPLE_NORMAL(config.uv2, config.cluster2, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO2.xy = s.normSAO2.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf2 = ConvertNormal2ToGradient(s.normSAO2.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.normSAO3 = MICROSPLAT_SAMPLE_NORMAL(config.uv3, config.cluster3, mipLevel).agrb;
|
|
COUNTSAMPLE
|
|
s.normSAO3.xy = s.normSAO3.xy * 2 - 1;
|
|
#if _SURFACENORMALS
|
|
s.surf3 = ConvertNormal2ToGradient(s.normSAO3.xy);
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleEmis(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
s.emisMetal0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_EMIS(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.emisMetal3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.emisMetal0 = MICROSPLAT_SAMPLE_EMIS(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.emisMetal1 = MICROSPLAT_SAMPLE_EMIS(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.emisMetal2 = MICROSPLAT_SAMPLE_EMIS(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.emisMetal3 = MICROSPLAT_SAMPLE_EMIS(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void SampleSpecular(Config config, TriplanarConfig tc, inout RawSamples s, MIPFORMAT mipLevel, half4 weights)
|
|
{
|
|
#if _DISABLESPLATMAPS
|
|
return;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
#if _TRIPLANAR
|
|
|
|
#if _USEGRADMIP
|
|
float4 d0 = mipLevel.d0;
|
|
float4 d1 = mipLevel.d1;
|
|
float4 d2 = mipLevel.d2;
|
|
#elif _USELODMIP
|
|
float d0 = mipLevel.x;
|
|
float d1 = mipLevel.y;
|
|
float d2 = mipLevel.z;
|
|
#else
|
|
MIPFORMAT d0 = mipLevel;
|
|
MIPFORMAT d1 = mipLevel;
|
|
MIPFORMAT d2 = mipLevel;
|
|
#endif
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN0.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[0], config.cluster0, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[1], config.cluster0, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN0.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv0[2], config.cluster0, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular0 = a0 * tc.pN0.x + a1 * tc.pN0.y + a2 * tc.pN0.z;
|
|
}
|
|
MSBRANCH(weights.y)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN1.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[0], config.cluster1, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[1], config.cluster1, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN1.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv1[2], config.cluster1, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular1 = a0 * tc.pN1.x + a1 * tc.pN1.y + a2 * tc.pN1.z;
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN2.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[0], config.cluster2, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[1], config.cluster2, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN2.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv2[2], config.cluster2, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular2 = a0 * tc.pN2.x + a1 * tc.pN2.y + a2 * tc.pN2.z;
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
half4 a0 = half4(0, 0, 0, 0);
|
|
half4 a1 = half4(0, 0, 0, 0);
|
|
half4 a2 = half4(0, 0, 0, 0);
|
|
MSBRANCHTRIPLANAR(tc.pN3.x)
|
|
{
|
|
a0 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[0], config.cluster3, d0);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.y)
|
|
{
|
|
a1 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[1], config.cluster3, d1);
|
|
COUNTSAMPLE
|
|
}
|
|
MSBRANCHTRIPLANAR(tc.pN3.z)
|
|
{
|
|
a2 = MICROSPLAT_SAMPLE_SPECULAR(tc.uv3[2], config.cluster3, d2);
|
|
COUNTSAMPLE
|
|
}
|
|
|
|
s.specular3 = a0 * tc.pN3.x + a1 * tc.pN3.y + a2 * tc.pN3.z;
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
s.specular0 = MICROSPLAT_SAMPLE_SPECULAR(config.uv0, config.cluster0, mipLevel);
|
|
COUNTSAMPLE
|
|
|
|
MSBRANCH(weights.y)
|
|
{
|
|
s.specular1 = MICROSPLAT_SAMPLE_SPECULAR(config.uv1, config.cluster1, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#if !_MAX2LAYER
|
|
MSBRANCH(weights.z)
|
|
{
|
|
s.specular2 = MICROSPLAT_SAMPLE_SPECULAR(config.uv2, config.cluster2, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
MSBRANCH(weights.w)
|
|
{
|
|
s.specular3 = MICROSPLAT_SAMPLE_SPECULAR(config.uv3, config.cluster3, mipLevel);
|
|
COUNTSAMPLE
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
MicroSplatLayer Sample(Input i, half4 weights, inout Config config, float camDist, float3 worldNormalVertex, DecalOutput decalOutput)
|
|
{
|
|
MicroSplatLayer o = (MicroSplatLayer)0;
|
|
UNITY_INITIALIZE_OUTPUT(MicroSplatLayer,o);
|
|
|
|
RawSamples samples = (RawSamples)0;
|
|
InitRawSamples(samples);
|
|
|
|
half4 albedo = 0;
|
|
half4 normSAO = half4(0,0,0,1);
|
|
half3 surfGrad = half3(0,0,0);
|
|
half4 emisMetal = 0;
|
|
half3 specular = 0;
|
|
|
|
float worldHeight = i.worldPos.y;
|
|
float3 upVector = float3(0,1,0);
|
|
|
|
#if _GLOBALTINT || _GLOBALNORMALS || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _GLOBALSPECULAR
|
|
float globalSlopeFilter = 1;
|
|
#if _GLOBALSLOPEFILTER
|
|
float2 gfilterUV = float2(1 - saturate(dot(worldNormalVertex, upVector) * 0.5 + 0.49), 0.5);
|
|
globalSlopeFilter = SAMPLE_TEXTURE2D(_GlobalSlopeTex, sampler_Diffuse, gfilterUV).a;
|
|
#endif
|
|
#endif
|
|
|
|
// declare outside of branchy areas..
|
|
half4 fxLevels = half4(0,0,0,0);
|
|
half burnLevel = 0;
|
|
half wetLevel = 0;
|
|
half3 waterNormalFoam = half3(0, 0, 0);
|
|
half porosity = 0.4;
|
|
float streamFoam = 1.0f;
|
|
half pud = 0;
|
|
half snowCover = 0;
|
|
half SSSThickness = 0;
|
|
half3 SSSTint = half3(1,1,1);
|
|
float traxBuffer = 0;
|
|
float3 traxNormal = 0;
|
|
float2 noiseUV = 0;
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(1 - saturate(camDist - _SplatFade.y))
|
|
{
|
|
#endif
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE || _SNOWFOOTSTEPS
|
|
traxBuffer = SampleTraxBuffer(i.worldPos, worldNormalVertex, traxNormal);
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
#if _MICROMESH
|
|
fxLevels = SampleFXLevels(InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, config.uv), wetLevel, burnLevel, traxBuffer);
|
|
#elif _MICROVERTEXMESH || _MICRODIGGERMESH || _MEGASPLAT
|
|
fxLevels = ProcessFXLevels(i.fx, traxBuffer);
|
|
#else
|
|
fxLevels = SampleFXLevels(config.uv, wetLevel, burnLevel, traxBuffer);
|
|
#endif
|
|
#endif
|
|
|
|
#if _DECAL
|
|
fxLevels = max(fxLevels, decalOutput.fxLevels);
|
|
#endif
|
|
|
|
TriplanarConfig tc = (TriplanarConfig)0;
|
|
UNITY_INITIALIZE_OUTPUT(TriplanarConfig,tc);
|
|
|
|
|
|
MIPFORMAT albedoLOD = INITMIPFORMAT
|
|
MIPFORMAT normalLOD = INITMIPFORMAT
|
|
MIPFORMAT emisLOD = INITMIPFORMAT
|
|
MIPFORMAT specLOD = INITMIPFORMAT
|
|
MIPFORMAT origAlbedoLOD = INITMIPFORMAT;
|
|
|
|
#if _TRIPLANAR && !_DISABLESPLATMAPS
|
|
PrepTriplanar(i.shaderData.texcoord0, worldNormalVertex, i.worldPos, config, tc, weights, albedoLOD, normalLOD, emisLOD, origAlbedoLOD);
|
|
tc.IN = i;
|
|
#endif
|
|
|
|
|
|
#if !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
#if _USELODMIP
|
|
albedoLOD = ComputeMipLevel(config.uv0.xy, _Diffuse_TexelSize.zw);
|
|
normalLOD = ComputeMipLevel(config.uv0.xy, _NormalSAO_TexelSize.zw);
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = ComputeMipLevel(config.uv0.xy, _EmissiveMetal_TexelSize.zw);
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = ComputeMipLevel(config.uv0.xy, _Specular_TexelSize.zw);;
|
|
#endif
|
|
#elif _USEGRADMIP
|
|
albedoLOD = float4(ddx(config.uv0.xy), ddy(config.uv0.xy));
|
|
normalLOD = albedoLOD;
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
|
|
origAlbedoLOD = albedoLOD;
|
|
#endif
|
|
|
|
#if _PERTEXCURVEWEIGHT
|
|
SAMPLE_PER_TEX(ptCurveWeight, 19.5, config, half4(0.5,1,1,1));
|
|
weights.x = lerp(smoothstep(0.5 - ptCurveWeight0.r, 0.5 + ptCurveWeight0.r, weights.x), weights.x, ptCurveWeight0.r*2);
|
|
weights.y = lerp(smoothstep(0.5 - ptCurveWeight1.r, 0.5 + ptCurveWeight1.r, weights.y), weights.y, ptCurveWeight1.r*2);
|
|
weights.z = lerp(smoothstep(0.5 - ptCurveWeight2.r, 0.5 + ptCurveWeight2.r, weights.z), weights.z, ptCurveWeight2.r*2);
|
|
weights.w = lerp(smoothstep(0.5 - ptCurveWeight3.r, 0.5 + ptCurveWeight3.r, weights.w), weights.w, ptCurveWeight3.r*2);
|
|
weights = TotalOne(weights);
|
|
#endif
|
|
|
|
|
|
|
|
// uvScale before anything
|
|
#if _PERTEXUVSCALEOFFSET && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
config.uv0.xy = config.uv0.xy * ptUVScale0.rg + ptUVScale0.ba;
|
|
config.uv1.xy = config.uv1.xy * ptUVScale1.rg + ptUVScale1.ba;
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = config.uv2.xy * ptUVScale2.rg + ptUVScale2.ba;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = config.uv3.xy * ptUVScale3.rg + ptUVScale3.ba;
|
|
#endif
|
|
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = albedoLOD * ptUVScale0.rgrg * weights.x +
|
|
albedoLOD * ptUVScale1.rgrg * weights.y +
|
|
albedoLOD * ptUVScale2.rgrg * weights.z +
|
|
albedoLOD * ptUVScale3.rgrg * weights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXUVROTATION && !_TRIPLANAR && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptUVRot, 16.5, config, half4(0,0,0,0));
|
|
config.uv0.xy = RotateUV(config.uv0.xy, ptUVRot0.x);
|
|
config.uv1.xy = RotateUV(config.uv1.xy, ptUVRot1.x);
|
|
#if !_MAX2LAYER
|
|
config.uv2.xy = RotateUV(config.uv2.xy, ptUVRot2.x);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
config.uv3.xy = RotateUV(config.uv3.xy, ptUVRot0.x);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
o.Alpha = 1;
|
|
|
|
|
|
#if _POM && !_DISABLESPLATMAPS
|
|
DoPOM(i, config, tc, albedoLOD, weights, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
SampleAlbedo(config, tc, samples, albedoLOD, weights);
|
|
|
|
#if _NOISEHEIGHT
|
|
ApplyNoiseHeight(samples, config.uv, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STREAMS || (_PARALLAX && !_DISABLESPLATMAPS)
|
|
half earlyHeight = BlendWeights(samples.albedo0.w, samples.albedo1.w, samples.albedo2.w, samples.albedo3.w, weights);
|
|
#endif
|
|
|
|
|
|
#if _STREAMS
|
|
waterNormalFoam = GetWaterNormal(i, config.uv, worldNormalVertex);
|
|
DoStreamRefract(config, tc, waterNormalFoam, fxLevels.b, earlyHeight);
|
|
#endif
|
|
|
|
#if _PARALLAX && !_DISABLESPLATMAPS
|
|
DoParallax(i, earlyHeight, config, tc, samples, weights, camDist);
|
|
#endif
|
|
|
|
|
|
// Blend results
|
|
#if _PERTEXINTERPCONTRAST && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptContrasts, 1.5, config, 0.5);
|
|
half4 contrast = 0.5;
|
|
contrast.x = ptContrasts0.a;
|
|
contrast.y = ptContrasts1.a;
|
|
#if !_MAX2LAYER
|
|
contrast.z = ptContrasts2.a;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
contrast.w = ptContrasts3.a;
|
|
#endif
|
|
contrast = clamp(contrast + _Contrast, 0.0001, 1.0);
|
|
half cnt = contrast.x * weights.x + contrast.y * weights.y + contrast.z * weights.z + contrast.w * weights.w;
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, cnt);
|
|
#else
|
|
half4 heightWeights = ComputeWeights(weights, samples.albedo0.a, samples.albedo1.a, samples.albedo2.a, samples.albedo3.a, _Contrast);
|
|
#endif
|
|
|
|
#if _HYBRIDHEIGHTBLEND
|
|
heightWeights = lerp(heightWeights, TotalOne(weights), saturate(camDist/max(1.0, _HybridHeightBlendDistance)));
|
|
#endif
|
|
|
|
|
|
// rescale derivatives after height weighting. Basically, in gradmip mode we blend the mip levels,
|
|
// but this is before height mapping is sampled, so reblending them after alpha will make sure the other
|
|
// channels (normal, etc) are sharper, which likely matters most..
|
|
#if _PERTEXUVSCALEOFFSET && !_DISABLESPLATMAPS
|
|
#if _TRIPLANAR
|
|
#if _USEGRADMIP
|
|
SAMPLE_PER_TEX(ptUVScale, 0.5, config, half4(1,1,0,0));
|
|
|
|
albedoLOD.d0 = origAlbedoLOD.d0 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d0 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d0 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d0 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d1 = origAlbedoLOD.d1 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d1 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d1 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d1 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
albedoLOD.d2 = origAlbedoLOD.d2 * ptUVScale0.xyxy * heightWeights.x +
|
|
origAlbedoLOD.d2 * ptUVScale1.xyxy * heightWeights.y +
|
|
origAlbedoLOD.d2 * ptUVScale2.xyxy * heightWeights.z +
|
|
origAlbedoLOD.d2 * ptUVScale3.xyxy * heightWeights.w;
|
|
|
|
normalLOD.d0 = albedoLOD.d0;
|
|
normalLOD.d1 = albedoLOD.d1;
|
|
normalLOD.d2 = albedoLOD.d2;
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD.d0 = albedoLOD.d0;
|
|
emisLOD.d1 = albedoLOD.d1;
|
|
emisLOD.d2 = albedoLOD.d2;
|
|
#endif
|
|
#endif // gradmip
|
|
#else // not triplanar
|
|
// fix for pertex uv scale using gradient sampler and weight blended derivatives
|
|
#if _USEGRADMIP
|
|
albedoLOD = origAlbedoLOD * ptUVScale0.rgrg * heightWeights.x +
|
|
origAlbedoLOD * ptUVScale1.rgrg * heightWeights.y +
|
|
origAlbedoLOD * ptUVScale2.rgrg * heightWeights.z +
|
|
origAlbedoLOD * ptUVScale3.rgrg * heightWeights.w;
|
|
normalLOD = albedoLOD;
|
|
#if _USEEMISSIVEMETAL
|
|
emisLOD = albedoLOD;
|
|
#endif
|
|
#if _USESPECULARWORKFLOW
|
|
specLOD = albedoLOD;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _PARALLAX || _STREAMS
|
|
SampleAlbedo(config, tc, samples, albedoLOD, heightWeights);
|
|
#endif
|
|
|
|
|
|
SampleNormal(config, tc, samples, normalLOD, heightWeights);
|
|
|
|
#if _USEEMISSIVEMETAL
|
|
SampleEmis(config, tc, samples, emisLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
SampleSpecular(config, tc, samples, specLOD, heightWeights);
|
|
#endif
|
|
|
|
#if _DISTANCERESAMPLE && !_DISABLESPLATMAPS
|
|
DistanceResample(samples, config, tc, camDist, i.viewDir, fxLevels, albedoLOD, i.worldPos, heightWeights, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _STARREACHFORMAT
|
|
samples.normSAO0.w = length(samples.normSAO0.xy);
|
|
samples.normSAO1.w = length(samples.normSAO1.xy);
|
|
samples.normSAO2.w = length(samples.normSAO2.xy);
|
|
samples.normSAO3.w = length(samples.normSAO3.xy);
|
|
#endif
|
|
|
|
// PerTexture sampling goes here, passing the samples structure
|
|
|
|
#if _PERTEXMICROSHADOWS || _PERTEXFUZZYSHADE
|
|
SAMPLE_PER_TEX(ptFuzz, 17.5, config, half4(0, 0, 1, 1));
|
|
#endif
|
|
|
|
#if _PERTEXMICROSHADOWS
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
{
|
|
half3 lightDir = GetGlobalLightDirTS(i);
|
|
half4 microShadows = half4(1,1,1,1);
|
|
microShadows.x = MicroShadow(lightDir, half3(samples.normSAO0.xy, 1), samples.normSAO0.a, ptFuzz0.a);
|
|
microShadows.y = MicroShadow(lightDir, half3(samples.normSAO1.xy, 1), samples.normSAO1.a, ptFuzz1.a);
|
|
microShadows.z = MicroShadow(lightDir, half3(samples.normSAO2.xy, 1), samples.normSAO2.a, ptFuzz2.a);
|
|
microShadows.w = MicroShadow(lightDir, half3(samples.normSAO3.xy, 1), samples.normSAO3.a, ptFuzz3.a);
|
|
samples.normSAO0.a *= microShadows.x;
|
|
samples.normSAO1.a *= microShadows.y;
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a *= microShadows.z;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a *= microShadows.w;
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_OUTPUT_MICROSHADOWS
|
|
o.Albedo = BlendWeights(microShadows.x, microShadows.y, microShadows.z, microShadows.a, heightWeights);
|
|
return o;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
#endif // _PERTEXMICROSHADOWS
|
|
|
|
|
|
#if _PERTEXFUZZYSHADE
|
|
samples.albedo0.rgb = FuzzyShade(samples.albedo0.rgb, half3(samples.normSAO0.rg, 1), ptFuzz0.r, ptFuzz0.g, ptFuzz0.b, i.viewDir);
|
|
samples.albedo1.rgb = FuzzyShade(samples.albedo1.rgb, half3(samples.normSAO1.rg, 1), ptFuzz1.r, ptFuzz1.g, ptFuzz1.b, i.viewDir);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = FuzzyShade(samples.albedo2.rgb, half3(samples.normSAO2.rg, 1), ptFuzz2.r, ptFuzz2.g, ptFuzz2.b, i.viewDir);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = FuzzyShade(samples.albedo3.rgb, half3(samples.normSAO3.rg, 1), ptFuzz3.r, ptFuzz3.g, ptFuzz3.b, i.viewDir);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSATURATION && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptSaturattion, 9.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = lerp(MSLuminance(samples.albedo0.rgb), samples.albedo0.rgb, ptSaturattion0.a);
|
|
samples.albedo1.rgb = lerp(MSLuminance(samples.albedo1.rgb), samples.albedo1.rgb, ptSaturattion1.a);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = lerp(MSLuminance(samples.albedo2.rgb), samples.albedo2.rgb, ptSaturattion2.a);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = lerp(MSLuminance(samples.albedo3.rgb), samples.albedo3.rgb, ptSaturattion3.a);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if _PERTEXTINT && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptTints, 1.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb *= ptTints0.rgb;
|
|
samples.albedo1.rgb *= ptTints1.rgb;
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb *= ptTints2.rgb;
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb *= ptTints3.rgb;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PCHEIGHTGRADIENT || _PCHEIGHTHSV || _PCSLOPEGRADIENT || _PCSLOPEHSV
|
|
ProceduralGradients(i, samples, config, worldHeight, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS
|
|
porosity = _GlobalPorosity;
|
|
#endif
|
|
|
|
|
|
#if _PERTEXCOLORINTENSITY
|
|
SAMPLE_PER_TEX(ptCI, 23.5, config, half4(1, 1, 1, 1));
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb * (1 + ptCI0.rrr));
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb * (1 + ptCI1.rrr));
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb * (1 + ptCI2.rrr));
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb * (1 + ptCI3.rrr));
|
|
#endif
|
|
#endif
|
|
|
|
#if (_PERTEXBRIGHTNESS || _PERTEXCONTRAST || _PERTEXPOROSITY || _PERTEXFOAM) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(ptBC, 3.5, config, half4(1, 1, 1, 1));
|
|
#if _PERTEXCONTRAST
|
|
samples.albedo0.rgb = saturate(((samples.albedo0.rgb - 0.5) * ptBC0.g) + 0.5);
|
|
samples.albedo1.rgb = saturate(((samples.albedo1.rgb - 0.5) * ptBC1.g) + 0.5);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(((samples.albedo2.rgb - 0.5) * ptBC2.g) + 0.5);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(((samples.albedo3.rgb - 0.5) * ptBC3.g) + 0.5);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXBRIGHTNESS
|
|
samples.albedo0.rgb = saturate(samples.albedo0.rgb + ptBC0.rrr);
|
|
samples.albedo1.rgb = saturate(samples.albedo1.rgb + ptBC1.rrr);
|
|
#if !_MAX2LAYER
|
|
samples.albedo2.rgb = saturate(samples.albedo2.rgb + ptBC2.rrr);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.albedo3.rgb = saturate(samples.albedo3.rgb + ptBC3.rrr);
|
|
#endif
|
|
#endif
|
|
#if _PERTEXPOROSITY
|
|
porosity = BlendWeights(ptBC0.b, ptBC1.b, ptBC2.b, ptBC3.b, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXFOAM
|
|
streamFoam = BlendWeights(ptBC0.a, ptBC1.a, ptBC2.a, ptBC3.a, heightWeights);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if (_PERTEXNORMSTR || _PERTEXAOSTR || _PERTEXSMOOTHSTR || _PERTEXMETALLIC) && !_DISABLESPLATMAPS
|
|
SAMPLE_PER_TEX(perTexMatSettings, 2.5, config, half4(1.0, 1.0, 1.0, 0.0));
|
|
#endif
|
|
|
|
#if _PERTEXNORMSTR && !_DISABLESPLATMAPS
|
|
#if _SURFACENORMALS
|
|
samples.surf0 *= perTexMatSettings0.r;
|
|
samples.surf1 *= perTexMatSettings1.r;
|
|
samples.surf2 *= perTexMatSettings2.r;
|
|
samples.surf3 *= perTexMatSettings3.r;
|
|
#else
|
|
samples.normSAO0.xy *= perTexMatSettings0.r;
|
|
samples.normSAO1.xy *= perTexMatSettings1.r;
|
|
samples.normSAO2.xy *= perTexMatSettings2.r;
|
|
samples.normSAO3.xy *= perTexMatSettings3.r;
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXAOSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.a = pow(abs(samples.normSAO0.a), perTexMatSettings0.b);
|
|
samples.normSAO1.a = pow(abs(samples.normSAO1.a), perTexMatSettings1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.a = pow(abs(samples.normSAO2.a), perTexMatSettings2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.a = pow(abs(samples.normSAO3.a), perTexMatSettings3.b);
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXSMOOTHSTR && !_DISABLESPLATMAPS
|
|
samples.normSAO0.b += perTexMatSettings0.g;
|
|
samples.normSAO1.b += perTexMatSettings1.g;
|
|
samples.normSAO0.b = saturate(samples.normSAO0.b);
|
|
samples.normSAO1.b = saturate(samples.normSAO1.b);
|
|
#if !_MAX2LAYER
|
|
samples.normSAO2.b += perTexMatSettings2.g;
|
|
samples.normSAO2.b = saturate(samples.normSAO2.b);
|
|
#endif
|
|
#if !_MAX3LAYER || !_MAX2LAYER
|
|
samples.normSAO3.b += perTexMatSettings3.g;
|
|
samples.normSAO3.b = saturate(samples.normSAO3.b);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(UNITY_PASS_FORWARDBASE) || defined(UNITY_PASS_DEFERRED) || (defined(_URP) && defined(_PASSFORWARD) || _HDRP)
|
|
#if _PERTEXSSS
|
|
{
|
|
SAMPLE_PER_TEX(ptSSS, 18.5, config, half4(1, 1, 1, 1)); // tint, thickness
|
|
half4 vals = ptSSS0 * heightWeights.x + ptSSS1 * heightWeights.y + ptSSS2 * heightWeights.z + ptSSS3 * heightWeights.w;
|
|
SSSThickness = vals.a;
|
|
SSSTint = vals.rgb;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if _PERTEXRIMLIGHT
|
|
{
|
|
SAMPLE_PER_TEX(ptRimA, 26.5, config, half4(1, 1, 1, 1));
|
|
SAMPLE_PER_TEX(ptRimB, 27.5, config, half4(1, 1, 1, 0));
|
|
samples.emisMetal0.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO0.xy, 1))), max(0.0001, ptRimA0.g)) * ptRimB0.rgb * ptRimB0.a;
|
|
samples.emisMetal1.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO1.xy, 1))), max(0.0001, ptRimA1.g)) * ptRimB1.rgb * ptRimB1.a;
|
|
samples.emisMetal2.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO2.xy, 1))), max(0.0001, ptRimA2.g)) * ptRimB2.rgb * ptRimB2.a;
|
|
samples.emisMetal3.rgb += pow(1.0 - saturate(dot(i.viewDir, float3(samples.normSAO3.xy, 1))), max(0.0001, ptRimA3.g)) * ptRimB3.rgb * ptRimB3.a;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#if (((_DETAILNOISE && _PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && _PERTEXDISTANCENOISESTRENGTH)) || (_NORMALNOISE && _PERTEXNORMALNOISESTRENGTH)) && !_DISABLESPLATMAPS
|
|
ApplyDetailDistanceNoisePerTex(samples, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALNOISEUV
|
|
// noise defaults so that a value of 1, 1 is 4 pixels in size and moves the uvs by 1 pixel max.
|
|
#if _CUSTOMSPLATTEXTURES
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#else
|
|
noiseUV = (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, config.uv * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if _TRAXSINGLE || _TRAXARRAY || _TRAXNOTEXTURE
|
|
ApplyTrax(samples, config, i.worldPos, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if (_ANTITILEARRAYDETAIL || _ANTITILEARRAYDISTANCE || _ANTITILEARRAYNORMAL) && !_DISABLESPLATMAPS
|
|
ApplyAntiTilePerTex(samples, config, camDist, i.worldPos, worldNormalVertex, heightWeights);
|
|
#endif
|
|
|
|
#if _GEOMAP && !_DISABLESPLATMAPS
|
|
GeoTexturePerTex(samples, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
#if _GLOBALTINT && _PERTEXGLOBALTINTSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalTintTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && _PERTEXGLOBALNORMALSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalNormalTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && _PERTEXGLOBALSAOMSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalSAOMTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && _PERTEXGLOBALEMISSTRENGTH && !_DISABLESPLATMAPS
|
|
GlobalEmisTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && _PERTEXGLOBALSPECULARSTRENGTH && !_DISABLESPLATMAPS && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexturePerTex(samples, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _PERTEXMETALLIC && !_DISABLESPLATMAPS
|
|
half metallic = BlendWeights(perTexMatSettings0.a, perTexMatSettings1.a, perTexMatSettings2.a, perTexMatSettings3.a, heightWeights);
|
|
o.Metallic = metallic;
|
|
#endif
|
|
|
|
#if _GLITTER && !_DISABLESPLATMAPS
|
|
DoGlitter(i, samples, config, camDist, worldNormalVertex, i.worldPos);
|
|
#endif
|
|
|
|
// Blend em..
|
|
#if _DISABLESPLATMAPS
|
|
// If we don't sample from the _Diffuse, then the shader compiler will strip the sampler on
|
|
// some platforms, which will cause everything to break. So we sample from the lowest mip
|
|
// and saturate to 1 to keep the cost minimal. Annoying, but the compiler removes the texture
|
|
// and sampler, even though the sampler is still used.
|
|
albedo = saturate(UNITY_SAMPLE_TEX2DARRAY_LOD(_Diffuse, float3(0,0,0), 12) + 1);
|
|
albedo.a = 0.5; // make height something we can blend with for the combined mesh mode, since it still height blends.
|
|
normSAO = half4(0,0,0,1);
|
|
#else
|
|
albedo = BlendWeights(samples.albedo0, samples.albedo1, samples.albedo2, samples.albedo3, heightWeights);
|
|
normSAO = BlendWeights(samples.normSAO0, samples.normSAO1, samples.normSAO2, samples.normSAO3, heightWeights);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = BlendWeights(samples.surf0, samples.surf1, samples.surf2, samples.surf3, heightWeights);
|
|
#endif
|
|
|
|
#if (_USEEMISSIVEMETAL || _PERTEXRIMLIGHT) && !_DISABLESPLATMAPS
|
|
emisMetal = BlendWeights(samples.emisMetal0, samples.emisMetal1, samples.emisMetal2, samples.emisMetal3, heightWeights);
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW && !_DISABLESPLATMAPS
|
|
specular = BlendWeights(samples.specular0, samples.specular1, samples.specular2, samples.specular3, heightWeights);
|
|
#endif
|
|
|
|
#if _PERTEXOUTLINECOLOR
|
|
SAMPLE_PER_TEX(ptOutlineColor, 28.5, config, half4(0.5, 0.5, 0.5, 1));
|
|
half4 outlineColor = BlendWeights(ptOutlineColor0, ptOutlineColor1, ptOutlineColor2, ptOutlineColor3, heightWeights);
|
|
half4 tstr = saturate(abs(heightWeights - 0.5) * 2);
|
|
half transitionBlend = min(min(min(tstr.x, tstr.y), tstr.z), tstr.w);
|
|
albedo.rgb = lerp(albedo.rgb * outlineColor.rgb * 2, albedo.rgb, outlineColor.a * transitionBlend);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHOVERLAYSPLATS || _MESHCOMBINED
|
|
o.Alpha = 1.0;
|
|
if (config.uv0.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.x;
|
|
else if (config.uv1.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.y;
|
|
else if (config.uv2.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.z;
|
|
else if (config.uv3.z == _MeshAlphaIndex)
|
|
o.Alpha = 1 - heightWeights.w;
|
|
#endif
|
|
|
|
|
|
|
|
// effects which don't require per texture adjustments and are part of the splats sample go here.
|
|
// Often, as an optimization, you can compute the non-per tex version of above effects here..
|
|
|
|
|
|
#if ((_DETAILNOISE && !_PERTEXDETAILNOISESTRENGTH) || (_DISTANCENOISE && !_PERTEXDISTANCENOISESTRENGTH) || (_NORMALNOISE && !_PERTEXNORMALNOISESTRENGTH))
|
|
ApplyDetailDistanceNoise(albedo.rgb, normSAO, surfGrad, config, camDist, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
}
|
|
#endif
|
|
|
|
#if _SPLATFADE
|
|
|
|
float2 sfDX = ddx(config.uv * _UVScale);
|
|
float2 sfDY = ddy(config.uv * _UVScale);
|
|
|
|
MSBRANCHOTHER(camDist - _SplatFade.x)
|
|
{
|
|
float falloff = saturate(InverseLerp(_SplatFade.x, _SplatFade.y, camDist));
|
|
half4 sfalb = SAMPLE_TEXTURE2D_ARRAY_GRAD(_Diffuse, sampler_Diffuse, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY);
|
|
COUNTSAMPLE
|
|
albedo.rgb = lerp(albedo.rgb, sfalb.rgb, falloff);
|
|
|
|
#if !_NONORMALMAP && !_AUTONORMAL
|
|
half4 sfnormSAO = SAMPLE_TEXTURE2D_ARRAY_GRAD(_NormalSAO, sampler_NormalSAO, config.uv * _UVScale, _SplatFade.z, sfDX, sfDY).agrb;
|
|
COUNTSAMPLE
|
|
sfnormSAO.xy = sfnormSAO.xy * 2 - 1;
|
|
|
|
normSAO = lerp(normSAO, sfnormSAO, falloff);
|
|
|
|
#if _SURFACENORMALS
|
|
surfGrad = lerp(surfGrad, ConvertNormal2ToGradient(sfnormSAO.xy), falloff);
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
#endif
|
|
|
|
#if _AUTONORMAL
|
|
float3 autoNormal = HeightToNormal(albedo.a * _AutoNormalHeightScale, i.worldPos);
|
|
normSAO.xy = autoNormal;
|
|
normSAO.z = 0;
|
|
normSAO.w = (autoNormal.z * autoNormal.z);
|
|
#endif
|
|
|
|
|
|
|
|
#if _MESHCOMBINED
|
|
SampleMeshCombined(albedo, normSAO, surfGrad, emisMetal, specular, o.Alpha, SSSThickness, SSSTint, config, heightWeights);
|
|
#endif
|
|
|
|
#if _ISOBJECTSHADER
|
|
SampleObjectShader(i, albedo, normSAO, surfGrad, emisMetal, specular, config);
|
|
#endif
|
|
|
|
#if _GEOMAP
|
|
GeoTexture(albedo.rgb, normSAO, surfGrad, i.worldPos, worldHeight, config, worldNormalVertex, upVector);
|
|
#endif
|
|
|
|
|
|
#if _SCATTER
|
|
ApplyScatter(
|
|
#if _MEGASPLAT
|
|
config,
|
|
#endif
|
|
i, albedo, normSAO, surfGrad, config.uv, camDist);
|
|
#endif
|
|
|
|
#if _DECAL
|
|
DoDecalBlend(decalOutput, albedo, normSAO, surfGrad, emisMetal, i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
#if _GLOBALTINT && !_PERTEXGLOBALTINTSTRENGTH
|
|
GlobalTintTexture(albedo.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _VSGRASSMAP
|
|
VSGrassTexture(albedo.rgb, config, camDist);
|
|
#endif
|
|
|
|
#if _GLOBALNORMALS && !_PERTEXGLOBALNORMALSTRENGTH
|
|
GlobalNormalTexture(normSAO, surfGrad, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSMOOTHAOMETAL && !_PERTEXGLOBALSAOMSTRENGTH
|
|
GlobalSAOMTexture(normSAO, emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALEMIS && !_PERTEXGLOBALEMISSTRENGTH
|
|
GlobalEmisTexture(emisMetal, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
#if _GLOBALSPECULAR && !_PERTEXGLOBALSPECULARSTRENGTH && _USESPECULARWORKFLOW
|
|
GlobalSpecularTexture(specular.rgb, config, camDist, globalSlopeFilter, noiseUV);
|
|
#endif
|
|
|
|
|
|
|
|
o.Albedo = albedo.rgb;
|
|
o.Height = albedo.a;
|
|
|
|
#if _NONORMALMAP
|
|
o.Normal = half3(0,0,1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#elif _SURFACENORMALS
|
|
o.Normal = ResolveNormalFromSurfaceGradient(surfGrad);
|
|
o.Normal = mul(GetTBN(i), o.Normal);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#else
|
|
o.Normal = half3(normSAO.xy, 1);
|
|
o.Smoothness = normSAO.b;
|
|
o.Occlusion = normSAO.a;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if _USEEMISSIVEMETAL || _GLOBALSMOOTHAOMETAL || _GLOBALEMIS || _PERTEXRIMLIGHT
|
|
#if _USEEMISSIVEMETAL
|
|
emisMetal.rgb *= _EmissiveMult;
|
|
#endif
|
|
|
|
o.Emission += emisMetal.rgb;
|
|
o.Metallic = emisMetal.a;
|
|
|
|
#endif
|
|
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = specular;
|
|
#endif
|
|
|
|
#if _WETNESS || _PUDDLES || _STREAMS || _LAVA
|
|
pud = DoStreams(i, o, fxLevels, config.uv, porosity, waterNormalFoam, worldNormalVertex, streamFoam, wetLevel, burnLevel, i.worldPos);
|
|
#endif
|
|
|
|
|
|
#if _SNOW
|
|
snowCover = DoSnow(i, o, config.uv, WorldNormalVector(i, o.Normal), worldNormalVertex, i.worldPos, pud, porosity, camDist,
|
|
config, weights, SSSTint, SSSThickness, traxBuffer, traxNormal);
|
|
#endif
|
|
|
|
#if _PERTEXSSS || _MESHCOMBINEDUSESSS || (_SNOW && _SNOWSSS)
|
|
{
|
|
half3 worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
|
|
|
|
o.Emission += ComputeSSS(i, worldView, WorldNormalVector(i, o.Normal),
|
|
SSSTint, SSSThickness, _SSSDistance, _SSSScale, _SSSPower);
|
|
}
|
|
#endif
|
|
|
|
#if _SNOWGLITTER
|
|
DoSnowGlitter(i, config, o, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
#if _WINDPARTICULATE || _SNOWPARTICULATE
|
|
DoWindParticulate(i, o, config, weights, camDist, worldNormalVertex, snowCover);
|
|
#endif
|
|
|
|
o.Normal.z = sqrt(1 - saturate(dot(o.Normal.xy, o.Normal.xy)));
|
|
|
|
#if _SPECULARFADE
|
|
{
|
|
float specFade = saturate((i.worldPos.y - _SpecularFades.x) / max(_SpecularFades.y - _SpecularFades.x, 0.0001));
|
|
o.Metallic *= specFade;
|
|
o.Smoothness *= specFade;
|
|
}
|
|
#endif
|
|
|
|
#if _VSSHADOWMAP
|
|
VSShadowTexture(o, i, config, camDist);
|
|
#endif
|
|
|
|
#if _TOONWIREFRAME
|
|
ToonWireframe(config.uv, o.Albedo, camDist);
|
|
#endif
|
|
|
|
#if _SEETHROUGHSHADER
|
|
SeethroughShader(o.Albedo, o.Emission, o.Alpha, i.worldPos, o.Normal, i.worldNormal);
|
|
#endif
|
|
|
|
|
|
#if _DEBUG_TRAXBUFFER
|
|
ClearAllButAlbedo(o, half3(traxBuffer, 0, 0) * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMALVERTEX
|
|
ClearAllButAlbedo(o, worldNormalVertex * saturate(o.Albedo.z+1));
|
|
#elif _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(o, WorldNormalVector(i, o.Normal) * saturate(o.Albedo.z+1));
|
|
#endif
|
|
|
|
#if _DEBUG_MEGABARY && _MEGASPLAT
|
|
o.Albedo = i.baryWeights.xyz;
|
|
#endif
|
|
|
|
|
|
return o;
|
|
}
|
|
|
|
void SampleSplats(float2 controlUV, inout half4 w0, inout half4 w1, inout half4 w2, inout half4 w3, inout half4 w4, inout half4 w5, inout half4 w6, inout half4 w7)
|
|
{
|
|
#if _CUSTOMSPLATTEXTURES
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_CustomControl0_TexelSize.zw - 1.0f) + 0.5f) * _CustomControl0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _CustomControl0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _CustomControl0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_CustomControl0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_CustomControl1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_CustomControl2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_CustomControl3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_CustomControl4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_CustomControl5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_CustomControl6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_CustomControl7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#else
|
|
#if !_MICROMESH
|
|
controlUV = (controlUV * (_Control0_TexelSize.zw - 1.0f) + 0.5f) * _Control0_TexelSize.xy;
|
|
#endif
|
|
|
|
#if _CONTROLNOISEUV
|
|
controlUV += (SAMPLE_TEXTURE2D(_NoiseUV, sampler_Diffuse, controlUV * _Control0_TexelSize.zw * 0.2 * _NoiseUVParams.x).ga - 0.5) * _Control0_TexelSize.xy * _NoiseUVParams.y;
|
|
#endif
|
|
|
|
w0 = SAMPLE_TEXTURE2D(_Control0, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
|
|
#if !_MAX4TEXTURES
|
|
w1 = SAMPLE_TEXTURE2D(_Control1, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES
|
|
w2 = SAMPLE_TEXTURE2D(_Control2, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if !_MAX4TEXTURES && !_MAX8TEXTURES && !_MAX12TEXTURES
|
|
w3 = SAMPLE_TEXTURE2D(_Control3, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX20TEXTURES || _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w4 = SAMPLE_TEXTURE2D(_Control4, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX24TEXTURES || _MAX28TEXTURES || _MAX32TEXTURES
|
|
w5 = SAMPLE_TEXTURE2D(_Control5, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX28TEXTURES || _MAX32TEXTURES
|
|
w6 = SAMPLE_TEXTURE2D(_Control6, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
|
|
#if _MAX32TEXTURES
|
|
w7 = SAMPLE_TEXTURE2D(_Control7, shared_linear_clamp_sampler, controlUV);
|
|
COUNTSAMPLE
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
MicroSplatLayer SurfImpl(Input i, float3 worldNormalVertex)
|
|
{
|
|
#if _MEGANOUV
|
|
i.uv_Control0 = i.worldPos.xz;
|
|
#endif
|
|
|
|
float camDist = distance(_WorldSpaceCameraPos, i.worldPos);
|
|
|
|
#if _FORCELOCALSPACE
|
|
worldNormalVertex = mul((float3x3)GetWorldToObjectMatrix(), worldNormalVertex).xyz;
|
|
i.worldPos = i.worldPos - mul(GetObjectToWorldMatrix(), float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ORIGINSHIFT
|
|
i.worldPos = i.worldPos + mul(_GlobalOriginMTX, float4(0,0,0,1)).xyz;
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _DEBUG_USE_TOPOLOGY
|
|
i.worldPos = SAMPLE_TEXTURE2D(_DebugWorldPos, sampler_Diffuse, i.uv_Control0);
|
|
worldNormalVertex = SAMPLE_TEXTURE2D(_DebugWorldNormal, sampler_Diffuse, i.uv_Control0);
|
|
i.worldHeight = i.worldPos.y;
|
|
#endif
|
|
|
|
#if _ALPHABELOWHEIGHT && !_TBDISABLEALPHAHOLES
|
|
ClipWaterLevel(i.worldPos);
|
|
#endif
|
|
|
|
#if !_TBDISABLEALPHAHOLES && defined(_ALPHATEST_ON)
|
|
// UNITY 2019.3 holes
|
|
ClipHoles(i.uv_Control0);
|
|
#endif
|
|
|
|
|
|
float2 origUV = i.uv_Control0;
|
|
|
|
#if _MICROMESH && _MESHUV2
|
|
float2 controlUV = i.uv2_Diffuse;
|
|
#else
|
|
float2 controlUV = i.uv_Control0;
|
|
#endif
|
|
|
|
|
|
#if _MICROMESH
|
|
controlUV = InverseLerp(_UVMeshRange.xy, _UVMeshRange.zw, controlUV);
|
|
#endif
|
|
|
|
half4 weights = half4(1,0,0,0);
|
|
|
|
Config config = (Config)0;
|
|
UNITY_INITIALIZE_OUTPUT(Config,config);
|
|
config.uv = origUV;
|
|
|
|
DecalOutput decalOutput = (DecalOutput)0;
|
|
#if _DECAL
|
|
decalOutput = DoDecals(i.uv_Control0, i.worldPos, camDist, worldNormalVertex);
|
|
#endif
|
|
|
|
#if _SURFACENORMALS
|
|
// Initialize the surface gradient basis vectors
|
|
ConstructSurfaceGradientTBN(i);
|
|
#endif
|
|
|
|
|
|
|
|
#if _SPLATFADE
|
|
MSBRANCHOTHER(_SplatFade.y - camDist)
|
|
#endif // _SPLATFADE
|
|
{
|
|
#if !_DISABLESPLATMAPS
|
|
|
|
// Sample the splat data, from textures or vertices, and setup the config..
|
|
#if _MICRODIGGERMESH
|
|
DiggerSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLAT
|
|
MegaSplatVertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MEGASPLATTEXTURE
|
|
MegaSplatTextureSetup(controlUV, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif _MICROVERTEXMESH
|
|
VertexSetup(i, weights, origUV, config, i.worldPos, decalOutput);
|
|
#elif !_PROCEDURALTEXTURE || _PROCEDURALBLENDSPLATS
|
|
half4 w0 = 0; half4 w1 = 0; half4 w2 = 0; half4 w3 = 0; half4 w4 = 0; half4 w5 = 0; half4 w6 = 0; half4 w7 = 0;
|
|
SampleSplats(controlUV, w0, w1, w2, w3, w4, w5, w6, w7);
|
|
Setup(weights, origUV, config, w0, w1, w2, w3, w4, w5, w6, w7, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
float3 procNormal = worldNormalVertex;
|
|
float3 worldPos = i.worldPos;
|
|
ProceduralSetup(i, worldPos, i.worldHeight, procNormal, i.worldUpVector, weights, origUV, config, ddx(origUV), ddy(origUV), ddx(worldPos), ddy(worldPos), decalOutput);
|
|
#endif
|
|
#else // _DISABLESPLATMAPS
|
|
Setup(weights, origUV, config, half4(1,0,0,0), 0, 0, 0, 0, 0, 0, 0, i.worldPos, decalOutput);
|
|
#endif
|
|
|
|
#if _SLOPETEXTURE
|
|
SlopeTexture(config, weights, worldNormalVertex);
|
|
#endif
|
|
} // _SPLATFADE else case
|
|
|
|
|
|
#if _TOONFLATTEXTURE
|
|
float2 quv = floor(origUV * _ToonTerrainSize);
|
|
float2 fuv = frac(origUV * _ToonTerrainSize);
|
|
#if !_TOONFLATTEXTUREQUAD
|
|
quv = Hash2D((fuv.x > fuv.y) ? quv : quv * 0.333);
|
|
#endif
|
|
float2 uvq = quv / _ToonTerrainSize;
|
|
config.uv0.xy = uvq;
|
|
config.uv1.xy = uvq;
|
|
config.uv2.xy = uvq;
|
|
config.uv3.xy = uvq;
|
|
#endif
|
|
|
|
#if (_TEXTURECLUSTER2 || _TEXTURECLUSTER3) && !_DISABLESPLATMAPS
|
|
PrepClusters(origUV, config, i.worldPos, worldNormalVertex);
|
|
#endif
|
|
|
|
#if (_ALPHAHOLE || _ALPHAHOLETEXTURE) && !_DISABLESPLATMAPS && !_TBDISABLEALPHAHOLES
|
|
ClipAlphaHole(config, weights);
|
|
#endif
|
|
|
|
|
|
|
|
MicroSplatLayer l = Sample(i, weights, config, camDist, worldNormalVertex, decalOutput);
|
|
|
|
// On windows, sometimes the shared samplers gets stripped, so we have to do this crap.
|
|
// We sample from the lowest mip, so it shouldn't cost much, but still, I hate this, wtf..
|
|
float stripVal = saturate(SAMPLE_TEXTURE2D_LOD(_Diffuse, sampler_Diffuse, config.uv0, 11).r + 2);
|
|
stripVal *= saturate(SAMPLE_TEXTURE2D_LOD(_NormalSAO, sampler_NormalSAO, config.uv0, 11).r + 2);
|
|
l.Albedo *= stripVal;
|
|
l.Normal *= stripVal;
|
|
|
|
#if _PROCEDURALTEXTURE
|
|
ProceduralTextureDebugOutput(l, weights, config);
|
|
#endif
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float4 ConstructTerrainTangent(float3 normal, float3 positiveZ)
|
|
{
|
|
// Consider a flat terrain. It should have tangent be (1, 0, 0) and bitangent be (0, 0, 1) as the UV of the terrain grid mesh is a scale of the world XZ position.
|
|
// In CreateTangentToWorld function (in SpaceTransform.hlsl), it is cross(normal, tangent) * sgn for the bitangent vector.
|
|
// It is not true in a left-handed coordinate system for the terrain bitangent, if we provide 1 as the tangent.w. It would produce (0, 0, -1) instead of (0, 0, 1).
|
|
// Also terrain's tangent calculation was wrong in a left handed system because cross((0,0,1), terrainNormalOS) points to the wrong direction as negative X.
|
|
// Therefore all the 4 xyzw components of the tangent needs to be flipped to correct the tangent frame.
|
|
// (See TerrainLitData.hlsl - GetSurfaceAndBuiltinData)
|
|
float3 tangent = normalize(cross(normal, positiveZ));
|
|
return float4(tangent, -1);
|
|
}
|
|
|
|
|
|
|
|
void TerrainInstancing(inout float4 vertex, inout float3 normal, inout float2 uv)
|
|
{
|
|
#if _MICROTERRAIN && defined(UNITY_INSTANCING_ENABLED) && !_TERRAINBLENDABLESHADER
|
|
|
|
float2 patchVertex = vertex.xy;
|
|
float4 instanceData = UNITY_ACCESS_INSTANCED_PROP(Terrain, _TerrainPatchInstanceData);
|
|
|
|
float2 sampleCoords = (patchVertex.xy + instanceData.xy) * instanceData.z; // (xy + float2(xBase,yBase)) * skipScale
|
|
uv = sampleCoords * _TerrainHeightmapRecipSize.zw;
|
|
|
|
float2 sampleUV = (uv / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleUV, 0));
|
|
|
|
vertex.xz = sampleCoords * _TerrainHeightmapScale.xz;
|
|
vertex.y = height * _TerrainHeightmapScale.y;
|
|
|
|
|
|
normal = float3(0, 1, 0);
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
void ApplyMeshModification(inout VertexData input)
|
|
{
|
|
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
|
|
float2 uv = input.texcoord0.xy;
|
|
TerrainInstancing(input.vertex, input.normal, uv);
|
|
input.texcoord0.xy = uv;
|
|
#endif
|
|
#if _PERPIXNORMAL && !_TERRAINBLENDABLESHADER
|
|
input.normal = float3(0,1,0);
|
|
#endif
|
|
|
|
#if _MICROVERSEPREVIEW
|
|
float4 recipSize = _TerrainHeightmapTexture_TexelSize;
|
|
recipSize.zw = (1.0f / (_TerrainHeightmapTexture_TexelSize.zw-1));
|
|
float2 sampleCoords = (input.texcoord0.xy / recipSize.zw + 0.5f) * recipSize.xy;
|
|
float height = UnpackHeightmap(SAMPLE_TEXTURE2D_LOD(_TerrainHeightmapTexture, shared_linear_clamp_sampler, sampleCoords, 0));
|
|
input.vertex.xyz += float3(0,1,0) * height * _TerrainHeight * 2;
|
|
#endif
|
|
|
|
}
|
|
|
|
// called by the template, so we can remove tangent from VertexData
|
|
void ApplyTerrainTangent(inout VertexToPixel input)
|
|
{
|
|
#if (_MICROTERRAIN || _PERPIXNORMAL) && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
|
|
// digger meshes ain't got no tangent either..
|
|
#if _MICRODIGGERMESH && !_TERRAINBLENDABLESHADER
|
|
input.worldTangent = ConstructTerrainTangent(input.worldNormal, float3(0, 0, 1));
|
|
#endif
|
|
}
|
|
|
|
|
|
void ModifyVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
ApplyMeshModification(v);
|
|
|
|
#if _MICROVERTEXMESH || _MICRODIGGERMESH
|
|
EncodeVertexWorkflow(v, d);
|
|
#elif _MEGASPLAT
|
|
EncodeMegaSplatVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
void ModifyTessellatedVertex(inout VertexData v, inout ExtraV2F d)
|
|
{
|
|
#if _MICROVERSEPREVIEW
|
|
v.vertex.y = OffsetVertex(v, d).y;
|
|
#elif _TESSDISTANCE || _TESSEDGE
|
|
v.vertex.xyz += OffsetVertex(v, d);
|
|
#endif
|
|
|
|
}
|
|
|
|
float3 GetTessFactors ()
|
|
{
|
|
#if _TESSEDGE
|
|
return float3(_TessData1.x, _TessData1.w, 0);
|
|
#endif
|
|
#if _TESSDISTANCE
|
|
return float3(_TessData2.x, _TessData2.y, _TessData1.x);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SurfaceFunction(inout Surface o, inout ShaderData d)
|
|
{
|
|
|
|
float3 worldNormalVertex = d.worldSpaceNormal;
|
|
#if _MICROVERSEPREVIEW
|
|
float2 sampleCoords = d.texcoord0.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif (defined(UNITY_INSTANCING_ENABLED) && _MICROTERRAIN && !_TERRAINBLENDABLESHADER)
|
|
float2 sampleCoords = (d.texcoord0.xy / _TerrainHeightmapRecipSize.zw + 0.5f) * _TerrainHeightmapRecipSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_TerrainNormalmapTexture, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
float3 geomBitangent = normalize(cross(geomNormal, geomTangent)) * -1;
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#elif _PERPIXNORMAL && (_MICROTERRAIN || _MICROMESHTERRAIN) && !_TERRAINBLENDABLESHADER
|
|
float2 sampleCoords = (d.texcoord0.xy * _PerPixelNormal_TexelSize.zw + 0.5f) * _PerPixelNormal_TexelSize.xy;
|
|
#if _TOONHARDEDGENORMAL
|
|
sampleCoords = ToonEdgeUV(d.texcoord0.xy);
|
|
#endif
|
|
|
|
float3 geomNormal = normalize(SAMPLE_TEXTURE2D(_PerPixelNormal, shared_linear_clamp_sampler, sampleCoords).xyz * 2 - 1);
|
|
|
|
float3 geomTangent = normalize(cross(geomNormal, float3(0, 0, 1)));
|
|
|
|
float3 geomBitangent = normalize(cross(geomTangent, geomNormal)) * -1;
|
|
#if _MICROMESHTERRAIN
|
|
geomBitangent *= -1;
|
|
#endif
|
|
|
|
worldNormalVertex = geomNormal;
|
|
d.worldSpaceNormal = geomNormal;
|
|
d.worldSpaceTangent = geomTangent;
|
|
d.TBNMatrix = float3x3(geomTangent, geomBitangent, geomNormal);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
|
|
#endif
|
|
|
|
#if _TOONPOLYEDGE
|
|
FlatShade(d);
|
|
#endif
|
|
|
|
Input i = DescToInput(d);
|
|
|
|
|
|
|
|
#if _SRPTERRAINBLEND
|
|
MicroSplatLayer l = BlendWithTerrain(d);
|
|
|
|
#if _DEBUG_WORLDNORMAL
|
|
ClearAllButAlbedo(l, normalize(TangentToWorldSpace(d, l.Normal)) * saturate(l.Albedo.z+1));
|
|
#endif
|
|
#else
|
|
MicroSplatLayer l = SurfImpl(i, worldNormalVertex);
|
|
#endif
|
|
|
|
DoDebugOutput(l);
|
|
|
|
|
|
|
|
|
|
o.Albedo = l.Albedo;
|
|
o.Normal = l.Normal;
|
|
o.Smoothness = l.Smoothness;
|
|
o.Occlusion = l.Occlusion;
|
|
o.Metallic = l.Metallic;
|
|
o.Emission = l.Emission;
|
|
#if _USESPECULARWORKFLOW
|
|
o.Specular = l.Specular;
|
|
#endif
|
|
o.Height = l.Height;
|
|
o.Alpha = l.Alpha;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SHADERDESC
|
|
|
|
ShaderData CreateShaderData(VertexToPixel i)
|
|
{
|
|
ShaderData d = (ShaderData)0;
|
|
d.worldSpacePosition = i.worldPos;
|
|
|
|
d.worldSpaceNormal = i.worldNormal;
|
|
d.worldSpaceTangent = i.worldTangent.xyz;
|
|
float3 bitangent = cross(i.worldTangent.xyz, i.worldNormal) * i.worldTangent.w * -1;
|
|
|
|
|
|
d.TBNMatrix = float3x3(d.worldSpaceTangent, bitangent, d.worldSpaceNormal);
|
|
d.worldSpaceViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
|
|
d.tangentSpaceViewDir = mul(d.worldSpaceViewDir, d.TBNMatrix);
|
|
d.texcoord0 = i.texcoord0;
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
d.texcoord1 = i.texcoord1;
|
|
// d.texcoord2 = i.texcoord2;
|
|
#endif
|
|
// d.texcoord3 = i.texcoord3;
|
|
// d.vertexColor = i.vertexColor;
|
|
|
|
// these rarely get used, so we back transform them. Usually will be stripped.
|
|
#if _HDRP
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(GetCameraRelativePositionWS(i.worldPos), 1));
|
|
#else
|
|
// d.localSpacePosition = mul(GetWorldToObjectMatrix(), float4(i.worldPos, 1));
|
|
#endif
|
|
// d.localSpaceNormal = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldNormal));
|
|
// d.localSpaceTangent = normalize(mul((float3x3)GetWorldToObjectMatrix(), i.worldTangent.xyz));
|
|
|
|
// d.screenPos = i.screenPos;
|
|
// d.screenUV = i.screenPos.xy / i.screenPos.w;
|
|
|
|
// d.extraV2F0 = i.extraV2F0;
|
|
// d.extraV2F1 = i.extraV2F1;
|
|
// d.extraV2F2 = i.extraV2F2;
|
|
// d.extraV2F3 = i.extraV2F3;
|
|
// d.extraV2F4 = i.extraV2F4;
|
|
// d.extraV2F5 = i.extraV2F5;
|
|
// d.extraV2F6 = i.extraV2F6;
|
|
// d.extraV2F7 = i.extraV2F7;
|
|
|
|
return d;
|
|
}
|
|
// CHAINS
|
|
|
|
void ChainModifyVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
ModifyVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
void ChainModifyTessellatedVertex(inout VertexData v, inout VertexToPixel v2p)
|
|
{
|
|
ExtraV2F d = (ExtraV2F)0;
|
|
// d.extraV2F0 = v2p.extraV2F0;
|
|
// d.extraV2F1 = v2p.extraV2F1;
|
|
// d.extraV2F2 = v2p.extraV2F2;
|
|
// d.extraV2F3 = v2p.extraV2F3;
|
|
// d.extraV2F4 = v2p.extraV2F4;
|
|
// d.extraV2F5 = v2p.extraV2F5;
|
|
// d.extraV2F6 = v2p.extraV2F6;
|
|
// d.extraV2F7 = v2p.extraV2F7;
|
|
|
|
ModifyTessellatedVertex(v, d);
|
|
|
|
// v2p.extraV2F0 = d.extraV2F0;
|
|
// v2p.extraV2F1 = d.extraV2F1;
|
|
// v2p.extraV2F2 = d.extraV2F2;
|
|
// v2p.extraV2F3 = d.extraV2F3;
|
|
// v2p.extraV2F4 = d.extraV2F4;
|
|
// v2p.extraV2F5 = d.extraV2F5;
|
|
// v2p.extraV2F6 = d.extraV2F6;
|
|
// v2p.extraV2F7 = d.extraV2F7;
|
|
}
|
|
|
|
|
|
void ChainFinalColorForward(inout Surface l, inout ShaderData d, inout half4 color)
|
|
{
|
|
|
|
}
|
|
|
|
void ChainFinalGBufferStandard(inout Surface s, inout ShaderData d, inout half4 GBuffer0, inout half4 GBuffer1, inout half4 GBuffer2, inout half4 outEmission, inout half4 outShadowMask)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _PASSSHADOW
|
|
float3 _LightDirection;
|
|
float3 _LightPosition;
|
|
#endif
|
|
|
|
// vertex shader
|
|
VertexToPixel Vert (VertexData v)
|
|
{
|
|
|
|
VertexToPixel o = (VertexToPixel)0;
|
|
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
|
|
|
|
|
#if !_TESSELLATION_ON
|
|
ChainModifyVertex(v, o);
|
|
#endif
|
|
|
|
o.texcoord0 = v.texcoord0;
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
o.texcoord1 = v.texcoord1;
|
|
// o.texcoord2 = v.texcoord2;
|
|
#endif
|
|
|
|
// o.texcoord3 = v.texcoord3;
|
|
// o.vertexColor = v.vertexColor;
|
|
|
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
|
|
o.worldPos = TransformObjectToWorld(v.vertex.xyz);
|
|
o.worldNormal = TransformObjectToWorldNormal(v.normal);
|
|
|
|
|
|
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
|
|
float2 uv1 = v.texcoord1.xy;
|
|
float2 uv2 = v.texcoord2.xy;
|
|
o.worldTangent = float4(TransformObjectToWorldDir(v.tangent.xyz), v.tangent.w);
|
|
#else
|
|
float2 uv1 = v.texcoord0.xy;
|
|
float2 uv2 = uv1;
|
|
#endif
|
|
|
|
// MS Only
|
|
ApplyTerrainTangent(o);
|
|
|
|
|
|
#if _PASSSHADOW
|
|
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
float3 lightDirectionWS = normalize(_LightPosition - o.worldPos);
|
|
#else
|
|
float3 lightDirectionWS = _LightDirection;
|
|
#endif
|
|
// Define shadow pass specific clip position for Universal
|
|
o.pos = TransformWorldToHClip(ApplyShadowBias(o.worldPos, o.worldNormal, lightDirectionWS));
|
|
#if UNITY_REVERSED_Z
|
|
o.pos.z = min(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#else
|
|
o.pos.z = max(o.pos.z, o.pos.w * UNITY_NEAR_CLIP_VALUE);
|
|
#endif
|
|
#elif _PASSMETA
|
|
#if _MICROTERRAIN
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), v.texcoord0.xy, v.texcoord0.xy, unity_LightmapST, unity_DynamicLightmapST);
|
|
#else
|
|
o.pos = MetaVertexPosition(float4(v.vertex.xyz, 0), uv1, uv2, unity_LightmapST, unity_DynamicLightmapST);
|
|
#endif
|
|
#else
|
|
o.pos = TransformWorldToHClip(o.worldPos);
|
|
#endif
|
|
|
|
|
|
|
|
// o.screenPos = ComputeScreenPos(o.pos, _ProjectionParams.x);
|
|
|
|
|
|
#if _PASSFORWARD || _PASSGBUFFER
|
|
#if _MICROTERRAIN
|
|
OUTPUT_LIGHTMAP_UV(v.texcoord0.xy, unity_LightmapST, o.lightmapUV);
|
|
#else
|
|
OUTPUT_LIGHTMAP_UV(uv1, unity_LightmapST, o.lightmapUV);
|
|
#endif
|
|
OUTPUT_SH(o.worldNormal, o.sh);
|
|
#if defined(DYNAMICLIGHTMAP_ON)
|
|
o.dynamicLightmapUV.xy = uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef VARYINGS_NEED_FOG_AND_VERTEX_LIGHT
|
|
half fogFactor = 0;
|
|
#if defined(_FOG_FRAGMENT)
|
|
fogFactor = ComputeFogFactor(o.pos.z);
|
|
#endif
|
|
#if _BAKEDLIT
|
|
half3 vertexLight = VertexLighting(o.worldPos, o.worldNormal);
|
|
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
|
|
#else
|
|
o.fogFactorAndVertexLight = half4(fogFactor, 0,0,0);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
|
|
o.shadowCoord = GetShadowCoord(vertexInput);
|
|
#endif
|
|
|
|
return o;
|
|
}
|
|
|
|
|
|
|
|
|
|
// fragment shader
|
|
void Frag (VertexToPixel IN
|
|
, out half4 outNormalWS : SV_Target0
|
|
#ifdef _WRITE_RENDERING_LAYERS
|
|
, out float4 outRenderingLayers : SV_Target1
|
|
#endif
|
|
#ifdef _DEPTHOFFSET_ON
|
|
, out float outputDepth : SV_Depth
|
|
#endif
|
|
#if NEED_FACING
|
|
, bool facing : SV_IsFrontFace
|
|
#endif
|
|
)
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
|
|
|
|
ShaderData d = CreateShaderData(IN);
|
|
Surface l = (Surface)0;
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
l.outputDepth = outputDepth;
|
|
#endif
|
|
|
|
l.Albedo = half3(0.5, 0.5, 0.5);
|
|
l.Normal = float3(0,0,1);
|
|
l.Occlusion = 1;
|
|
l.Alpha = 1;
|
|
|
|
SurfaceFunction(l, d);
|
|
|
|
#ifdef _DEPTHOFFSET_ON
|
|
outputDepth = l.outputDepth;
|
|
#endif
|
|
|
|
#if defined(_GBUFFER_NORMALS_OCT)
|
|
float3 normalWS = d.worldSpaceNormal;
|
|
float2 octNormalWS = PackNormalOctQuadEncode(normalWS); // values between [-1, +1], must use fp32 on some platforms
|
|
float2 remappedOctNormalWS = saturate(octNormalWS * 0.5 + 0.5); // values between [ 0, 1]
|
|
half3 packedNormalWS = PackFloat2To888(remappedOctNormalWS); // values between [ 0, 1]
|
|
outNormalWS = half4(packedNormalWS, 0.0);
|
|
#else
|
|
float3 wsn = l.Normal;
|
|
#if !_WORLDSPACENORMAL
|
|
wsn = TangentToWorldSpace(d, l.Normal);
|
|
#endif
|
|
outNormalWS = half4(NormalizeNormalPerPixel(wsn), 0.0);
|
|
#endif
|
|
|
|
#ifdef _WRITE_RENDERING_LAYERS
|
|
uint renderingLayers = GetMeshRenderingLayer();
|
|
outRenderingLayers = float4(EncodeMeshRenderingLayer(renderingLayers), 0, 0, 0);
|
|
#endif
|
|
|
|
}
|
|
|
|
ENDHLSL
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
Dependency "BaseMapShader" = "Hidden/ABCPolaris__Base687910241"
|
|
Fallback "Hidden/ABCPolaris__Base687910241"
|
|
CustomEditor "MicroSplatShaderGUI"
|
|
}
|