BITFALL/Assets/_Demo/MicroSplatConfigs/MicroSplatData/MicroSplat_Base.shader

22551 lines
893 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: Standard
// Platform: WindowsEditor
////////////////////////////////////////
Shader "Hidden/MicroSplat/ABCPolaris__Base"
{
Properties
{
[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 {"RenderType" = "Opaque" "Queue" = "Geometry+100" "IgnoreProjector" = "False" "SplatCount" = "16"}
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardBase" }
CGPROGRAM
// compile directives
#pragma vertex Vert
#pragma fragment Frag
#pragma target 3.0
#pragma multi_compile_instancing
#pragma multi_compile_local __ _ALPHATEST_ON
#pragma multi_compile_fog
#pragma multi_compile_fwdbase
#include "HLSLSupport.cginc"
#define _PASSFORWARD 1
#include "UnityShaderVariables.cginc"
#include "UnityShaderUtilities.cginc"
// -------- variant for: <when no other keywords are defined>
#define _MICROPOLARISMESH 1
#define _BRANCHSAMPLES 1
#define _BRANCHSAMPLESARG 1
#define _MSRENDERLOOP_UNITYLD 1
#define _MSRENDERLOOP_UNITYURP2020 1
#define _MSRENDERLOOP_UNITYURP2021 1
#define _MSRENDERLOOP_UNITYURP2022 1
#define _STANDARD 1
// If your looking in here and thinking WTF, yeah, I know. These are taken from the SRPs, to allow us to use the same
// texturing library they use. However, since they are not included in the standard pipeline by default, there is no
// way to include them in and they have to be inlined, since someone could copy this shader onto another machine without
// MicroSplat installed. Unfortunate, but I'd rather do this and have a nice library for texture sampling instead
// of the patchy one Unity provides being inlined/emulated in HDRP/URP. Strangely, PSSL and XBoxOne libraries are not
// included in the standard SRP code, but they are in tons of Unity own projects on the web, so I grabbed them from there.
#if defined(SHADER_API_GAMECORE)
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index)
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)
#elif defined(SHADER_API_XBOXONE)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_PSSL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.GetLOD(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_D3D11)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_METAL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_VULKAN)
// This file assume SHADER_API_VULKAN is defined
// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed.
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_SWITCH)
// This file assume SHADER_API_SWITCH is defined
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLCORE)
// OpenGL 4.1 SM 5.0 https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 46)
#define OPENGL4_1_SM5 1
#else
#define OPENGL4_1_SM5 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES3)
// GLES 3.1 + AEP shader feature https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 40)
#define GLES3_1_AEP 1
#else
#define GLES3_1_AEP 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES)
#define uint int
#define rcp(x) 1.0 / (x)
#define ddx_fine ddx
#define ddy_fine ddy
#define asfloat
#define asuint(x) asint(x)
#define f32tof16
#define f16tof32
#define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLES 2.0
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) #error calculate Level of Detail not supported in GLES2
// Texture abstraction
#define TEXTURE2D(textureName) sampler2D textureName
#define TEXTURE2D_ARRAY(textureName) samplerCUBE textureName // No support to texture2DArray
#define TEXTURECUBE(textureName) samplerCUBE textureName
#define TEXTURECUBE_ARRAY(textureName) samplerCUBE textureName // No supoport to textureCubeArray and can't emulate with texture2DArray
#define TEXTURE3D(textureName) sampler3D textureName
#define TEXTURE2D_FLOAT(textureName) sampler2D_float textureName
#define TEXTURECUBE_FLOAT(textureName) samplerCUBE_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to texture2DArray
#define TEXTURE2D_HALF(textureName) sampler2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to texture2DArray
#define SAMPLER(samplerName)
#define SAMPLER_CMP(samplerName)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2)
#if (SHADER_TARGET >= 30)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) tex2Dlod(textureName, float4(coord2, 0, lod))
#else
// No lod support. Very poor approximation with bias.
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, lod)
#endif
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) tex2Dbias(textureName, float4(coord2, 0, bias))
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_LOD)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_BIAS)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_GRAD)
#else
#error unsupported shader api
#endif
// default flow control attributes
#ifndef UNITY_BRANCH
# define UNITY_BRANCH
#endif
#ifndef UNITY_FLATTEN
# define UNITY_FLATTEN
#endif
#ifndef UNITY_UNROLL
# define UNITY_UNROLL
#endif
#ifndef UNITY_UNROLLX
# define UNITY_UNROLLX(_x)
#endif
#ifndef UNITY_LOOP
# define UNITY_LOOP
#endif
#include "UnityCG.cginc"
#if _NOMINDIELETRIC
// for Standard
#ifdef unity_ColorSpaceDielectricSpec
#undef unity_ColorSpaceDielectricSpec
#endif
#define unity_ColorSpaceDielectricSpec half4(0,0,0,1)
#endif
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"
#include "AutoLight.cginc"
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
#define UNITY_ASSUME_UNIFORM_SCALING
#define UNITY_DONT_INSTANCE_OBJECT_MATRICES
#define UNITY_INSTANCED_LOD_FADE
#else
#define UNITY_INSTANCED_LOD_FADE
#define UNITY_INSTANCED_SH
#define UNITY_INSTANCED_LIGHTMAPSTS
#endif
// data across stages, stripped like the above.
struct VertexToPixel
{
UNITY_POSITION(pos);
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 lmap : TEXCOORD8;
#if UNITY_SHOULD_SAMPLE_SH
half3 sh : TEXCOORD9; // SH
#endif
#ifdef LIGHTMAP_ON
UNITY_LIGHTING_COORDS(10,11)
UNITY_FOG_COORDS(12)
#else
UNITY_FOG_COORDS(10)
UNITY_SHADOW_COORDS(11)
#endif
// float4 extraV2F0 : TEXCOORD13;
// float4 extraV2F1 : TEXCOORD14;
// float4 extraV2F2 : TEXCOORD15;
// float4 extraV2F3 : TEXCOORD16;
// float4 extraV2F4 : TEXCOORD17;
// float4 extraV2F5 : TEXCOORD18;
// float4 extraV2F6 : TEXCOORD19;
// float4 extraV2F7 : TEXCOORD20;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// 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
// unity_WorldToObject in HDRP, since it already does macro-fu there
#if _STANDARD
float3 TransformWorldToObject(float3 p) { return mul(unity_WorldToObject, float4(p, 1)); };
float3 TransformObjectToWorld(float3 p) { return mul(unity_ObjectToWorld, float4(p, 1)); };
float4 TransformWorldToObject(float4 p) { return mul(unity_WorldToObject, p); };
float4 TransformObjectToWorld(float4 p) { return mul(unity_ObjectToWorld, p); };
float4x4 GetWorldToObjectMatrix() { return unity_WorldToObject; }
float4x4 GetObjectToWorldMatrix() { return unity_ObjectToWorld; }
#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
}
#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
#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
fixed4 w0;
fixed4 w1;
fixed4 w2;
fixed4 w3;
fixed4 w4;
fixed4 w5;
fixed4 w6;
// megasplat data
half4 layer0;
half4 layer1;
half3 baryWeights;
half4 scatter0;
half4 scatter1;
// wetness, puddles, streams, lava from vertex or megasplat
fixed4 fx;
// snow min, snow max
fixed4 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(unity_WorldToObject, float4(n, 1)).xyz;
surfTangent = t;//mul(unity_WorldToObject, 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, fixed4 w0, fixed4 w1, fixed4 w2, fixed4 w3, fixed4 w4, fixed4 w5, fixed4 w6, fixed4 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
fixed 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)
{
fixed 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 fixed2 UnpackNormal2(fixed4 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 fixed4 w0, inout fixed4 w1, inout fixed4 w2, inout fixed4 w3, inout fixed4 w4, inout fixed4 w5, inout fixed4 w6, inout fixed4 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)unity_WorldToObject, worldNormalVertex).xyz;
i.worldPos = i.worldPos - mul(unity_ObjectToWorld, 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
fixed4 w0 = 0; fixed4 w1 = 0; fixed4 w2 = 0; fixed4 w3 = 0; fixed4 w4 = 0; fixed4 w5 = 0; fixed4 w6 = 0; fixed4 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(unity_WorldToObject, float4(GetCameraRelativePositionWS(i.worldPos), 1));
#else
// d.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1));
#endif
// d.localSpaceNormal = normalize(mul((float3x3)unity_WorldToObject, i.worldNormal));
// d.localSpaceTangent = normalize(mul((float3x3)unity_WorldToObject, 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)
{
}
// vertex shader
VertexToPixel Vert (VertexData v)
{
UNITY_SETUP_INSTANCE_ID(v);
VertexToPixel o;
UNITY_INITIALIZE_OUTPUT(VertexToPixel,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#if !_TESSELLATION_ON
ChainModifyVertex(v, o);
#endif
o.pos = UnityObjectToClipPos(v.vertex);
o.texcoord0 = v.texcoord0;
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
o.texcoord1 = v.texcoord1;
// o.texcoord2 = v.texcoord2;
#endif
// o.texcoord3 = v.texcoord3;
// o.vertexColor = v.vertexColor;
// o.screenPos = ComputeScreenPos(o.pos);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
o.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
o.worldTangent.w = tangentSign;
#endif
// MS Only
ApplyTerrainTangent(o);
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
float2 uv1 = v.texcoord1.xy;
float2 uv2 = v.texcoord2.xy;
#else
float2 uv1 = v.texcoord0.xy;
float2 uv2 = uv1;
#endif
#ifdef DYNAMICLIGHTMAP_ON
o.lmap.zw = uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
#ifdef LIGHTMAP_ON
o.lmap.xy = uv1 * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
// SH/ambient and vertex lights
#ifndef LIGHTMAP_ON
#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
o.sh = 0;
// Approximated illumination from non-important point lights
#ifdef VERTEXLIGHT_ON
o.sh += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, o.worldPos, o.worldNormal);
#endif
o.sh = ShadeSHPerVertex (o.worldNormal, o.sh);
#endif
#endif // !LIGHTMAP_ON
UNITY_TRANSFER_LIGHTING(o, uv1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader
#ifdef FOG_COMBINED_WITH_TSPACE
UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader
#elif defined (FOG_COMBINED_WITH_WORLD_POS)
UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader
#else
UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
#endif
return o;
}
// fragment shader
fixed4 Frag (VertexToPixel IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
// prepare and unpack data
#ifdef FOG_COMBINED_WITH_TSPACE
UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
#elif defined (FOG_COMBINED_WITH_WORLD_POS)
UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
#else
UNITY_EXTRACT_FOG(IN);
#endif
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);
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
// compute lighting & shadowing factor
UNITY_LIGHT_ATTENUATION(atten, IN, d.worldSpacePosition)
#if _USESPECULAR || _USESPECULARWORKFLOW || _SPECULARFROMMETALLIC
#ifdef UNITY_COMPILER_HLSL
SurfaceOutputStandardSpecular o = (SurfaceOutputStandardSpecular)0;
#else
SurfaceOutputStandardSpecular o;
#endif
o.Specular = l.Specular;
#elif _BDRFLAMBERT || _BDRF3
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
#else
#ifdef UNITY_COMPILER_HLSL
SurfaceOutputStandard o = (SurfaceOutputStandard)0;
#else
SurfaceOutputStandard o;
#endif
o.Metallic = l.Metallic;
#endif
o.Albedo = l.Albedo;
o.Emission = l.Emission;
o.Alpha = l.Alpha;
o.Normal = normalize(TangentToWorldSpace(d, l.Normal));
#if _BDRFLAMBERT || _BDRF3
o.Specular = l.Specular;
o.Gloss = l.Smoothness;
#elif _SPECULARFROMMETALLIC
o.Occlusion = l.Occlusion;
o.Smoothness = l.Smoothness;
o.Albedo = MicroSplatDiffuseAndSpecularFromMetallic(l.Albedo, l.Metallic, o.Specular, o.Smoothness);
o.Smoothness = 1-o.Smoothness;
#elif _USESPECULARWORKFLOW
o.Occlusion = l.Occlusion;
o.Smoothness = l.Smoothness;
o.Specular = l.Specular;
#else
o.Smoothness = l.Smoothness;
o.Metallic = l.Metallic;
o.Occlusion = l.Occlusion;
#endif
#if !_UNLIT
fixed4 c = 0;
// Setup lighting environment
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
gi.light.color = _LightColor0.rgb;
gi.light.dir = lightDir;
// Call GI (lightmaps/SH/reflections) lighting function
UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
giInput.light = gi.light;
giInput.worldPos = d.worldSpacePosition;
giInput.worldViewDir = d.worldSpaceViewDir;
giInput.atten = atten;
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
giInput.lightmapUV = IN.lmap;
#else
giInput.lightmapUV = 0;
#endif
#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
giInput.ambient = IN.sh;
#else
giInput.ambient.rgb = 0.0;
#endif
giInput.probeHDR[0] = unity_SpecCube0_HDR;
giInput.probeHDR[1] = unity_SpecCube1_HDR;
#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
#endif
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
giInput.boxMax[0] = unity_SpecCube0_BoxMax;
giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
giInput.boxMax[1] = unity_SpecCube1_BoxMax;
giInput.boxMin[1] = unity_SpecCube1_BoxMin;
giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
#endif
#if _USESPECULAR || _USESPECULARWORKFLOW || _SPECULARFROMMETALLIC
LightingStandardSpecular_GI(o, giInput, gi);
c += LightingStandardSpecular (o, d.worldSpaceViewDir, gi);
#elif _BDRFLAMBERT
LightingLambert_GI(o, giInput, gi);
c += LightingLambert (o, gi);
#elif _BDRF3
LightingBlinnPhong_GI(o, giInput, gi);
c += LightingBlinnPhong (o, d.worldSpaceViewDir, gi);
#else
LightingStandard_GI(o, giInput, gi);
c += LightingStandard (o, d.worldSpaceViewDir, gi);
#endif
c.rgb += o.Emission;
UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
#else
fixed4 c = fixed4(o.Albedo.rgb, o.Alpha);
UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
#endif
#if !_ALPHABLEND_ON
UNITY_OPAQUE_ALPHA(c.a);
#endif
ChainFinalColorForward(l, d, c);
return c;
}
ENDCG
}
// ---- forward rendering additive lights pass:
Pass
{
Name "FORWARD"
Tags { "LightMode" = "ForwardAdd" }
ZWrite Off Blend One One
CGPROGRAM
#pragma vertex Vert
#pragma fragment Frag
// compile directives
#pragma target 3.0
#pragma multi_compile_instancing
#pragma multi_compile_fog
#pragma multi_compile_local __ _ALPHATEST_ON
#pragma multi_compile_fwdadd_fullshadows
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
#include "UnityShaderUtilities.cginc"
#define _PASSFORWARD 1
#define _MICROPOLARISMESH 1
#define _BRANCHSAMPLES 1
#define _BRANCHSAMPLESARG 1
#define _MSRENDERLOOP_UNITYLD 1
#define _MSRENDERLOOP_UNITYURP2020 1
#define _MSRENDERLOOP_UNITYURP2021 1
#define _MSRENDERLOOP_UNITYURP2022 1
#define _STANDARD 1
// If your looking in here and thinking WTF, yeah, I know. These are taken from the SRPs, to allow us to use the same
// texturing library they use. However, since they are not included in the standard pipeline by default, there is no
// way to include them in and they have to be inlined, since someone could copy this shader onto another machine without
// MicroSplat installed. Unfortunate, but I'd rather do this and have a nice library for texture sampling instead
// of the patchy one Unity provides being inlined/emulated in HDRP/URP. Strangely, PSSL and XBoxOne libraries are not
// included in the standard SRP code, but they are in tons of Unity own projects on the web, so I grabbed them from there.
#if defined(SHADER_API_GAMECORE)
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index)
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)
#elif defined(SHADER_API_XBOXONE)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_PSSL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.GetLOD(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_D3D11)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_METAL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_VULKAN)
// This file assume SHADER_API_VULKAN is defined
// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed.
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_SWITCH)
// This file assume SHADER_API_SWITCH is defined
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLCORE)
// OpenGL 4.1 SM 5.0 https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 46)
#define OPENGL4_1_SM5 1
#else
#define OPENGL4_1_SM5 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES3)
// GLES 3.1 + AEP shader feature https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 40)
#define GLES3_1_AEP 1
#else
#define GLES3_1_AEP 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES)
#define uint int
#define rcp(x) 1.0 / (x)
#define ddx_fine ddx
#define ddy_fine ddy
#define asfloat
#define asuint(x) asint(x)
#define f32tof16
#define f16tof32
#define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLES 2.0
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) #error calculate Level of Detail not supported in GLES2
// Texture abstraction
#define TEXTURE2D(textureName) sampler2D textureName
#define TEXTURE2D_ARRAY(textureName) samplerCUBE textureName // No support to texture2DArray
#define TEXTURECUBE(textureName) samplerCUBE textureName
#define TEXTURECUBE_ARRAY(textureName) samplerCUBE textureName // No supoport to textureCubeArray and can't emulate with texture2DArray
#define TEXTURE3D(textureName) sampler3D textureName
#define TEXTURE2D_FLOAT(textureName) sampler2D_float textureName
#define TEXTURECUBE_FLOAT(textureName) samplerCUBE_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to texture2DArray
#define TEXTURE2D_HALF(textureName) sampler2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to texture2DArray
#define SAMPLER(samplerName)
#define SAMPLER_CMP(samplerName)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2)
#if (SHADER_TARGET >= 30)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) tex2Dlod(textureName, float4(coord2, 0, lod))
#else
// No lod support. Very poor approximation with bias.
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, lod)
#endif
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) tex2Dbias(textureName, float4(coord2, 0, bias))
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_LOD)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_BIAS)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_GRAD)
#else
#error unsupported shader api
#endif
// default flow control attributes
#ifndef UNITY_BRANCH
# define UNITY_BRANCH
#endif
#ifndef UNITY_FLATTEN
# define UNITY_FLATTEN
#endif
#ifndef UNITY_UNROLL
# define UNITY_UNROLL
#endif
#ifndef UNITY_UNROLLX
# define UNITY_UNROLLX(_x)
#endif
#ifndef UNITY_LOOP
# define UNITY_LOOP
#endif
#include "UnityCG.cginc"
#if _NOMINDIELETRIC
// for Standard
#ifdef unity_ColorSpaceDielectricSpec
#undef unity_ColorSpaceDielectricSpec
#endif
#define unity_ColorSpaceDielectricSpec half4(0,0,0,1)
#endif
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"
#include "AutoLight.cginc"
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
#define UNITY_ASSUME_UNIFORM_SCALING
#define UNITY_DONT_INSTANCE_OBJECT_MATRICES
#define UNITY_INSTANCED_LOD_FADE
#else
#define UNITY_INSTANCED_LOD_FADE
#define UNITY_INSTANCED_SH
#define UNITY_INSTANCED_LIGHTMAPSTS
#endif
// data across stages, stripped like the above.
struct VertexToPixel
{
UNITY_POSITION(pos); // must be named pos because Unity does stupid macro stuff
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;
UNITY_LIGHTING_COORDS(8,9)
UNITY_FOG_COORDS(10)
// float4 extraV2F0 : TEXCOORD11;
// float4 extraV2F1 : TEXCOORD12;
// float4 extraV2F2 : TEXCOORD13;
// float4 extraV2F3 : TEXCOORD14;
// float4 extraV2F4 : TEXCOORD15;
// float4 extraV2F5 : TEXCOORD16;
// float4 extraV2F6 : TEXCOORD17;
// float4 extraV2F7 : TEXCOORD18;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// 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
// unity_WorldToObject in HDRP, since it already does macro-fu there
#if _STANDARD
float3 TransformWorldToObject(float3 p) { return mul(unity_WorldToObject, float4(p, 1)); };
float3 TransformObjectToWorld(float3 p) { return mul(unity_ObjectToWorld, float4(p, 1)); };
float4 TransformWorldToObject(float4 p) { return mul(unity_WorldToObject, p); };
float4 TransformObjectToWorld(float4 p) { return mul(unity_ObjectToWorld, p); };
float4x4 GetWorldToObjectMatrix() { return unity_WorldToObject; }
float4x4 GetObjectToWorldMatrix() { return unity_ObjectToWorld; }
#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
}
#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
#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
fixed4 w0;
fixed4 w1;
fixed4 w2;
fixed4 w3;
fixed4 w4;
fixed4 w5;
fixed4 w6;
// megasplat data
half4 layer0;
half4 layer1;
half3 baryWeights;
half4 scatter0;
half4 scatter1;
// wetness, puddles, streams, lava from vertex or megasplat
fixed4 fx;
// snow min, snow max
fixed4 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(unity_WorldToObject, float4(n, 1)).xyz;
surfTangent = t;//mul(unity_WorldToObject, 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, fixed4 w0, fixed4 w1, fixed4 w2, fixed4 w3, fixed4 w4, fixed4 w5, fixed4 w6, fixed4 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
fixed 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)
{
fixed 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 fixed2 UnpackNormal2(fixed4 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 fixed4 w0, inout fixed4 w1, inout fixed4 w2, inout fixed4 w3, inout fixed4 w4, inout fixed4 w5, inout fixed4 w6, inout fixed4 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)unity_WorldToObject, worldNormalVertex).xyz;
i.worldPos = i.worldPos - mul(unity_ObjectToWorld, 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
fixed4 w0 = 0; fixed4 w1 = 0; fixed4 w2 = 0; fixed4 w3 = 0; fixed4 w4 = 0; fixed4 w5 = 0; fixed4 w6 = 0; fixed4 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(unity_WorldToObject, float4(GetCameraRelativePositionWS(i.worldPos), 1));
#else
// d.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1));
#endif
// d.localSpaceNormal = normalize(mul((float3x3)unity_WorldToObject, i.worldNormal));
// d.localSpaceTangent = normalize(mul((float3x3)unity_WorldToObject, 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)
{
}
// vertex shader
VertexToPixel Vert (VertexData v)
{
UNITY_SETUP_INSTANCE_ID(v);
VertexToPixel o;
UNITY_INITIALIZE_OUTPUT(VertexToPixel,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#if !_TESSELLATION_ON
ChainModifyVertex(v, o);
#endif
o.pos = UnityObjectToClipPos(v.vertex);
o.texcoord0 = v.texcoord0;
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
o.texcoord1 = v.texcoord1;
// o.texcoord2 = v.texcoord2;
#endif
// o.texcoord3 = v.texcoord3;
// o.vertexColor = v.vertexColor;
// o.screenPos = ComputeScreenPos(o.pos);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
o.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
o.worldTangent.w = tangentSign;
#endif
// MS Only
ApplyTerrainTangent(o);
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
float2 uv1 = v.texcoord1.xy;
float2 uv2 = v.texcoord2.xy;
#else
float2 uv1 = v.texcoord0.xy;
float2 uv2 = uv1;
#endif
UNITY_TRANSFER_LIGHTING(o,uv1); // pass shadow and, possibly, light cookie coordinates to pixel shader
UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
return o;
}
// fragment shader
fixed4 Frag (VertexToPixel IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
// prepare and unpack data
#ifdef FOG_COMBINED_WITH_TSPACE
UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
#elif defined (FOG_COMBINED_WITH_WORLD_POS)
UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
#else
UNITY_EXTRACT_FOG(IN);
#endif
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);
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(d.worldSpacePosition));
#if _USESPECULAR || _USESPECULARWORKFLOW || _SPECULARFROMMETALLIC
#ifdef UNITY_COMPILER_HLSL
SurfaceOutputStandardSpecular o = (SurfaceOutputStandardSpecular)0;
#else
SurfaceOutputStandardSpecular o;
#endif
o.Specular = l.Specular;
#elif _BDRFLAMBERT || _BDRF3
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
#else
#ifdef UNITY_COMPILER_HLSL
SurfaceOutputStandard o = (SurfaceOutputStandard)0;
#else
SurfaceOutputStandard o;
#endif
o.Metallic = l.Metallic;
#endif
o.Albedo = l.Albedo;
o.Emission = l.Emission;
o.Alpha = l.Alpha;
o.Normal = normalize(TangentToWorldSpace(d, l.Normal));
#if _BDRFLAMBERT || _BDRF3
o.Specular = l.Specular;
o.Gloss = l.Smoothness;
#elif _SPECULARFROMMETALLIC
o.Occlusion = l.Occlusion;
o.Smoothness = l.Smoothness;
o.Albedo = MicroSplatDiffuseAndSpecularFromMetallic(l.Albedo, l.Metallic, o.Specular, o.Smoothness);
o.Smoothness = 1-o.Smoothness;
#elif _USESPECULARWORKFLOW
o.Occlusion = l.Occlusion;
o.Smoothness = l.Smoothness;
o.Specular = l.Specular;
#else
o.Smoothness = l.Smoothness;
o.Metallic = l.Metallic;
o.Occlusion = l.Occlusion;
#endif
UNITY_LIGHT_ATTENUATION(atten, IN, d.worldSpacePosition)
half4 c = 0;
// Setup lighting environment
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
gi.light.color = _LightColor0.rgb;
gi.light.dir = lightDir;
gi.light.color *= atten;
#if _USESPECULAR || _USESPECULARWORKFLOW || _SPECULARFROMMETALLIC
c += LightingStandardSpecular (o, worldViewDir, gi);
#elif _BDRFLAMBERT
c += LightingLambert(o, gi);
c.a = 0;
#elif _BDRF3
c += LightingBlinnPhong (o, worldViewDir, gi);
#else
c += LightingStandard (o, worldViewDir, gi);
#endif
ChainFinalColorForward(l, d, c);
UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
#if !_ALPHABLEND_ON
UNITY_OPAQUE_ALPHA(c.a);
#endif
return c;
}
ENDCG
}
// ---- deferred shading pass:
Pass
{
Name "DEFERRED"
Tags { "LightMode" = "Deferred" }
CGPROGRAM
#pragma vertex Vert
#pragma fragment Frag
// compile directives
#pragma target 3.0
#pragma multi_compile_instancing
#pragma exclude_renderers nomrt
#pragma multi_compile_local __ _ALPHATEST_ON
#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
#pragma multi_compile_prepassfinal
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
#include "UnityShaderUtilities.cginc"
#include "UnityCG.cginc"
#define _PASSGBUFFER 1
#define _MICROPOLARISMESH 1
#define _BRANCHSAMPLES 1
#define _BRANCHSAMPLESARG 1
#define _MSRENDERLOOP_UNITYLD 1
#define _MSRENDERLOOP_UNITYURP2020 1
#define _MSRENDERLOOP_UNITYURP2021 1
#define _MSRENDERLOOP_UNITYURP2022 1
#define _STANDARD 1
// If your looking in here and thinking WTF, yeah, I know. These are taken from the SRPs, to allow us to use the same
// texturing library they use. However, since they are not included in the standard pipeline by default, there is no
// way to include them in and they have to be inlined, since someone could copy this shader onto another machine without
// MicroSplat installed. Unfortunate, but I'd rather do this and have a nice library for texture sampling instead
// of the patchy one Unity provides being inlined/emulated in HDRP/URP. Strangely, PSSL and XBoxOne libraries are not
// included in the standard SRP code, but they are in tons of Unity own projects on the web, so I grabbed them from there.
#if defined(SHADER_API_GAMECORE)
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index)
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)
#elif defined(SHADER_API_XBOXONE)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_PSSL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.GetLOD(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_D3D11)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_METAL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_VULKAN)
// This file assume SHADER_API_VULKAN is defined
// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed.
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_SWITCH)
// This file assume SHADER_API_SWITCH is defined
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLCORE)
// OpenGL 4.1 SM 5.0 https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 46)
#define OPENGL4_1_SM5 1
#else
#define OPENGL4_1_SM5 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES3)
// GLES 3.1 + AEP shader feature https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 40)
#define GLES3_1_AEP 1
#else
#define GLES3_1_AEP 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES)
#define uint int
#define rcp(x) 1.0 / (x)
#define ddx_fine ddx
#define ddy_fine ddy
#define asfloat
#define asuint(x) asint(x)
#define f32tof16
#define f16tof32
#define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLES 2.0
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) #error calculate Level of Detail not supported in GLES2
// Texture abstraction
#define TEXTURE2D(textureName) sampler2D textureName
#define TEXTURE2D_ARRAY(textureName) samplerCUBE textureName // No support to texture2DArray
#define TEXTURECUBE(textureName) samplerCUBE textureName
#define TEXTURECUBE_ARRAY(textureName) samplerCUBE textureName // No supoport to textureCubeArray and can't emulate with texture2DArray
#define TEXTURE3D(textureName) sampler3D textureName
#define TEXTURE2D_FLOAT(textureName) sampler2D_float textureName
#define TEXTURECUBE_FLOAT(textureName) samplerCUBE_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to texture2DArray
#define TEXTURE2D_HALF(textureName) sampler2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to texture2DArray
#define SAMPLER(samplerName)
#define SAMPLER_CMP(samplerName)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2)
#if (SHADER_TARGET >= 30)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) tex2Dlod(textureName, float4(coord2, 0, lod))
#else
// No lod support. Very poor approximation with bias.
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, lod)
#endif
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) tex2Dbias(textureName, float4(coord2, 0, bias))
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_LOD)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_BIAS)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_GRAD)
#else
#error unsupported shader api
#endif
// default flow control attributes
#ifndef UNITY_BRANCH
# define UNITY_BRANCH
#endif
#ifndef UNITY_FLATTEN
# define UNITY_FLATTEN
#endif
#ifndef UNITY_UNROLL
# define UNITY_UNROLL
#endif
#ifndef UNITY_UNROLLX
# define UNITY_UNROLLX(_x)
#endif
#ifndef UNITY_LOOP
# define UNITY_LOOP
#endif
#if _NOMINDIELETRIC
// for Standard
#ifdef unity_ColorSpaceDielectricSpec
#undef unity_ColorSpaceDielectricSpec
#endif
#define unity_ColorSpaceDielectricSpec half4(0,0,0,1)
#endif
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
#define UNITY_ASSUME_UNIFORM_SCALING
#define UNITY_DONT_INSTANCE_OBJECT_MATRICES
#define UNITY_INSTANCED_LOD_FADE
#else
#define UNITY_INSTANCED_LOD_FADE
#define UNITY_INSTANCED_SH
#define UNITY_INSTANCED_LIGHTMAPSTS
#endif
// data across stages, stripped like the above.
struct VertexToPixel
{
UNITY_POSITION(pos); // must be named pos because Unity does stupid macro stuff
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;
#ifndef DIRLIGHTMAP_OFF
float3 viewDir : TEXCOORD8;
#endif
float4 lmap : TEXCOORD9;
#ifndef LIGHTMAP_ON
#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
half3 sh : TEXCOORD10; // SH
#endif
#else
#ifdef DIRLIGHTMAP_OFF
float4 lmapFadePos : TEXCOORD11;
#endif
#endif
// float4 extraV2F0 : TEXCOORD12;
// float4 extraV2F1 : TEXCOORD13;
// float4 extraV2F2 : TEXCOORD14;
// float4 extraV2F3 : TEXCOORD15;
// float4 extraV2F4 : TEXCOORD16;
// float4 extraV2F5 : TEXCOORD17;
// float4 extraV2F6 : TEXCOORD18;
// float4 extraV2F7 : TEXCOORD19;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// 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
// unity_WorldToObject in HDRP, since it already does macro-fu there
#if _STANDARD
float3 TransformWorldToObject(float3 p) { return mul(unity_WorldToObject, float4(p, 1)); };
float3 TransformObjectToWorld(float3 p) { return mul(unity_ObjectToWorld, float4(p, 1)); };
float4 TransformWorldToObject(float4 p) { return mul(unity_WorldToObject, p); };
float4 TransformObjectToWorld(float4 p) { return mul(unity_ObjectToWorld, p); };
float4x4 GetWorldToObjectMatrix() { return unity_WorldToObject; }
float4x4 GetObjectToWorldMatrix() { return unity_ObjectToWorld; }
#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
}
#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
#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
fixed4 w0;
fixed4 w1;
fixed4 w2;
fixed4 w3;
fixed4 w4;
fixed4 w5;
fixed4 w6;
// megasplat data
half4 layer0;
half4 layer1;
half3 baryWeights;
half4 scatter0;
half4 scatter1;
// wetness, puddles, streams, lava from vertex or megasplat
fixed4 fx;
// snow min, snow max
fixed4 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(unity_WorldToObject, float4(n, 1)).xyz;
surfTangent = t;//mul(unity_WorldToObject, 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, fixed4 w0, fixed4 w1, fixed4 w2, fixed4 w3, fixed4 w4, fixed4 w5, fixed4 w6, fixed4 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
fixed 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)
{
fixed 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 fixed2 UnpackNormal2(fixed4 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 fixed4 w0, inout fixed4 w1, inout fixed4 w2, inout fixed4 w3, inout fixed4 w4, inout fixed4 w5, inout fixed4 w6, inout fixed4 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)unity_WorldToObject, worldNormalVertex).xyz;
i.worldPos = i.worldPos - mul(unity_ObjectToWorld, 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
fixed4 w0 = 0; fixed4 w1 = 0; fixed4 w2 = 0; fixed4 w3 = 0; fixed4 w4 = 0; fixed4 w5 = 0; fixed4 w6 = 0; fixed4 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(unity_WorldToObject, float4(GetCameraRelativePositionWS(i.worldPos), 1));
#else
// d.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1));
#endif
// d.localSpaceNormal = normalize(mul((float3x3)unity_WorldToObject, i.worldNormal));
// d.localSpaceTangent = normalize(mul((float3x3)unity_WorldToObject, 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)
{
}
// vertex shader
VertexToPixel Vert (VertexData v)
{
UNITY_SETUP_INSTANCE_ID(v);
VertexToPixel o;
UNITY_INITIALIZE_OUTPUT(VertexToPixel,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#if !_TESSELLATION_ON
ChainModifyVertex(v, o);
#endif
o.pos = UnityObjectToClipPos(v.vertex);
o.texcoord0 = v.texcoord0;
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
o.texcoord1 = v.texcoord1;
// o.texcoord2 = v.texcoord2;
#endif
// o.texcoord3 = v.texcoord3;
// o.vertexColor = v.vertexColor;
// o.screenPos = ComputeScreenPos(o.pos);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
o.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
float3 worldBinormal = cross(o.worldNormal, o.worldTangent.xyz) * tangentSign;
o.worldTangent.w = tangentSign;
#else
// MS Only
ApplyTerrainTangent(o);
float3 worldBinormal = cross(o.worldNormal, o.worldTangent.xyz) * unity_WorldTransformParams.w;
#endif
float3 viewDirForLight = UnityWorldSpaceViewDir(o.worldPos);
#ifndef DIRLIGHTMAP_OFF
o.viewDir.x = dot(viewDirForLight, o.worldTangent.xyz);
o.viewDir.y = dot(viewDirForLight, worldBinormal);
o.viewDir.z = dot(viewDirForLight, o.worldNormal);
#endif
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
float2 uv1 = v.texcoord1.xy;
float2 uv2 = v.texcoord2.xy;
#else
float2 uv1 = v.texcoord0.xy;
float2 uv2 = uv1;
#endif
#ifdef DYNAMICLIGHTMAP_ON
o.lmap.zw = uv2 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#else
o.lmap.zw = 0;
#endif
#ifdef LIGHTMAP_ON
o.lmap.xy = uv1 * unity_LightmapST.xy + unity_LightmapST.zw;
#ifdef DIRLIGHTMAP_OFF
o.lmapFadePos.xyz = (mul(unity_ObjectToWorld, v.vertex).xyz - unity_ShadowFadeCenterAndType.xyz) * unity_ShadowFadeCenterAndType.w;
o.lmapFadePos.w = (-UnityObjectToViewPos(v.vertex).z) * (1.0 - unity_ShadowFadeCenterAndType.w);
#endif
#else
o.lmap.xy = 0;
#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
o.sh = 0;
o.sh = ShadeSHPerVertex (o.worldNormal, o.sh);
#endif
#endif
return o;
}
#ifdef LIGHTMAP_ON
float4 unity_LightmapFade;
#endif
fixed4 unity_Ambient;
// fragment shader
void Frag (VertexToPixel IN,
out half4 outGBuffer0 : SV_Target0,
out half4 outGBuffer1 : SV_Target1,
out half4 outGBuffer2 : SV_Target2,
out half4 outEmission : SV_Target3
#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4)
, out half4 outShadowMask : SV_Target4
#endif
)
{
UNITY_SETUP_INSTANCE_ID(IN);
// prepare and unpack data
#ifdef FOG_COMBINED_WITH_TSPACE
UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
#elif defined (FOG_COMBINED_WITH_WORLD_POS)
UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
#else
UNITY_EXTRACT_FOG(IN);
#endif
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);
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(d.worldSpacePosition));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(d.worldSpacePosition));
#if _USESPECULAR || _USESPECULARWORKFLOW || _SPECULARFROMMETALLIC
#ifdef UNITY_COMPILER_HLSL
SurfaceOutputStandardSpecular o = (SurfaceOutputStandardSpecular)0;
#else
SurfaceOutputStandardSpecular o;
#endif
o.Specular = l.Specular;
#elif _BDRFLAMBERT || _BDRF3
#ifdef UNITY_COMPILER_HLSL
SurfaceOutput o = (SurfaceOutput)0;
#else
SurfaceOutput o;
#endif
#else
#ifdef UNITY_COMPILER_HLSL
SurfaceOutputStandard o = (SurfaceOutputStandard)0;
#else
SurfaceOutputStandard o;
#endif
o.Metallic = l.Metallic;
#endif
o.Albedo = l.Albedo;
o.Emission = l.Emission;
o.Alpha = l.Alpha;
o.Normal = normalize(TangentToWorldSpace(d, l.Normal));
#if _BDRFLAMBERT || _BDRF3
o.Specular = l.Occlusion;
o.Gloss = l.Smoothness;
#elif _SPECULARFROMMETALLIC
o.Occlusion = l.Occlusion;
o.Smoothness = l.Smoothness;
o.Albedo = MicroSplatDiffuseAndSpecularFromMetallic(l.Albedo, l.Metallic, o.Specular, o.Smoothness);
o.Smoothness = 1-o.Smoothness;
#elif _USESPECULARWORKFLOW
o.Occlusion = l.Occlusion;
o.Smoothness = l.Smoothness;
o.Specular = l.Specular;
#else
o.Smoothness = l.Smoothness;
o.Metallic = l.Metallic;
o.Occlusion = l.Occlusion;
#endif
half atten = 1;
// Setup lighting environment
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
gi.light.color = 0;
gi.light.dir = half3(0,1,0);
// Call GI (lightmaps/SH/reflections) lighting function
UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
giInput.light = gi.light;
giInput.worldPos = d.worldSpacePosition;
giInput.worldViewDir = worldViewDir;
giInput.atten = atten;
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
giInput.lightmapUV = IN.lmap;
#else
giInput.lightmapUV = 0.0;
#endif
#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
giInput.ambient = IN.sh;
#else
giInput.ambient.rgb = 0.0;
#endif
giInput.probeHDR[0] = unity_SpecCube0_HDR;
giInput.probeHDR[1] = unity_SpecCube1_HDR;
#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
#endif
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
giInput.boxMax[0] = unity_SpecCube0_BoxMax;
giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
giInput.boxMax[1] = unity_SpecCube1_BoxMax;
giInput.boxMin[1] = unity_SpecCube1_BoxMin;
giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
#endif
#if _USESPECULAR || _USESPECULARWORKFLOW || _SPECULARFROMMETALLIC
LightingStandardSpecular_GI(o, giInput, gi);
// call lighting function to output g-buffer
outEmission = LightingStandardSpecular_Deferred (o, worldViewDir, gi, outGBuffer0, outGBuffer1, outGBuffer2);
#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4)
outShadowMask = UnityGetRawBakedOcclusions (IN.lmap.xy, d.worldSpacePosition);
#endif
#ifndef UNITY_HDR_ON
outEmission.rgb = exp2(-outEmission.rgb);
#endif
#else
LightingStandard_GI(o, giInput, gi);
// call lighting function to output g-buffer
outEmission = LightingStandard_Deferred (o, worldViewDir, gi, outGBuffer0, outGBuffer1, outGBuffer2);
#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4)
outShadowMask = UnityGetRawBakedOcclusions (IN.lmap.xy, d.worldSpacePosition);
#endif
#ifndef UNITY_HDR_ON
outEmission.rgb = exp2(-outEmission.rgb);
#endif
#endif
#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4)
ChainFinalGBufferStandard(l, d, outGBuffer0, outGBuffer1, outGBuffer2, outEmission, outShadowMask);
#else
half4 outShadowMask = 0;
ChainFinalGBufferStandard(l, d, outGBuffer0, outGBuffer1, outGBuffer2, outEmission, outShadowMask);
#endif
}
ENDCG
}
Pass {
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On ZTest LEqual
CGPROGRAM
#pragma vertex Vert
#pragma fragment Frag
// compile directives
#pragma target 3.0
#pragma multi_compile_instancing
#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
#pragma multi_compile_shadowcaster
#pragma multi_compile_local __ _ALPHATEST_ON
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
#include "UnityShaderUtilities.cginc"
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"
#define _PASSSHADOW 1
#define _MICROPOLARISMESH 1
#define _BRANCHSAMPLES 1
#define _BRANCHSAMPLESARG 1
#define _MSRENDERLOOP_UNITYLD 1
#define _MSRENDERLOOP_UNITYURP2020 1
#define _MSRENDERLOOP_UNITYURP2021 1
#define _MSRENDERLOOP_UNITYURP2022 1
#define _STANDARD 1
// If your looking in here and thinking WTF, yeah, I know. These are taken from the SRPs, to allow us to use the same
// texturing library they use. However, since they are not included in the standard pipeline by default, there is no
// way to include them in and they have to be inlined, since someone could copy this shader onto another machine without
// MicroSplat installed. Unfortunate, but I'd rather do this and have a nice library for texture sampling instead
// of the patchy one Unity provides being inlined/emulated in HDRP/URP. Strangely, PSSL and XBoxOne libraries are not
// included in the standard SRP code, but they are in tons of Unity own projects on the web, so I grabbed them from there.
#if defined(SHADER_API_GAMECORE)
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index)
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)
#elif defined(SHADER_API_XBOXONE)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_PSSL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.GetLOD(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_D3D11)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_METAL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_VULKAN)
// This file assume SHADER_API_VULKAN is defined
// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed.
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_SWITCH)
// This file assume SHADER_API_SWITCH is defined
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLCORE)
// OpenGL 4.1 SM 5.0 https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 46)
#define OPENGL4_1_SM5 1
#else
#define OPENGL4_1_SM5 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES3)
// GLES 3.1 + AEP shader feature https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 40)
#define GLES3_1_AEP 1
#else
#define GLES3_1_AEP 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES)
#define uint int
#define rcp(x) 1.0 / (x)
#define ddx_fine ddx
#define ddy_fine ddy
#define asfloat
#define asuint(x) asint(x)
#define f32tof16
#define f16tof32
#define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLES 2.0
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) #error calculate Level of Detail not supported in GLES2
// Texture abstraction
#define TEXTURE2D(textureName) sampler2D textureName
#define TEXTURE2D_ARRAY(textureName) samplerCUBE textureName // No support to texture2DArray
#define TEXTURECUBE(textureName) samplerCUBE textureName
#define TEXTURECUBE_ARRAY(textureName) samplerCUBE textureName // No supoport to textureCubeArray and can't emulate with texture2DArray
#define TEXTURE3D(textureName) sampler3D textureName
#define TEXTURE2D_FLOAT(textureName) sampler2D_float textureName
#define TEXTURECUBE_FLOAT(textureName) samplerCUBE_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to texture2DArray
#define TEXTURE2D_HALF(textureName) sampler2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to texture2DArray
#define SAMPLER(samplerName)
#define SAMPLER_CMP(samplerName)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2)
#if (SHADER_TARGET >= 30)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) tex2Dlod(textureName, float4(coord2, 0, lod))
#else
// No lod support. Very poor approximation with bias.
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, lod)
#endif
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) tex2Dbias(textureName, float4(coord2, 0, bias))
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_LOD)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_BIAS)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_GRAD)
#else
#error unsupported shader api
#endif
// default flow control attributes
#ifndef UNITY_BRANCH
# define UNITY_BRANCH
#endif
#ifndef UNITY_FLATTEN
# define UNITY_FLATTEN
#endif
#ifndef UNITY_UNROLL
# define UNITY_UNROLL
#endif
#ifndef UNITY_UNROLLX
# define UNITY_UNROLLX(_x)
#endif
#ifndef UNITY_LOOP
# define UNITY_LOOP
#endif
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
#define UNITY_ASSUME_UNIFORM_SCALING
#define UNITY_DONT_INSTANCE_OBJECT_MATRICES
#define UNITY_INSTANCED_LOD_FADE
#else
#define UNITY_INSTANCED_LOD_FADE
#define UNITY_INSTANCED_SH
#define UNITY_INSTANCED_LIGHTMAPSTS
#endif
// data across stages, stripped like the above.
struct VertexToPixel
{
V2F_SHADOW_CASTER;
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 : TEXCOORD8;
// float4 extraV2F1 : TEXCOORD9;
// float4 extraV2F2 : TEXCOORD10;
// float4 extraV2F3 : TEXCOORD11;
// float4 extraV2F4 : TEXCOORD12;
// float4 extraV2F5 : TEXCOORD13;
// float4 extraV2F6 : TEXCOORD14;
// float4 extraV2F7 : TEXCOORD15;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// 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
// unity_WorldToObject in HDRP, since it already does macro-fu there
#if _STANDARD
float3 TransformWorldToObject(float3 p) { return mul(unity_WorldToObject, float4(p, 1)); };
float3 TransformObjectToWorld(float3 p) { return mul(unity_ObjectToWorld, float4(p, 1)); };
float4 TransformWorldToObject(float4 p) { return mul(unity_WorldToObject, p); };
float4 TransformObjectToWorld(float4 p) { return mul(unity_ObjectToWorld, p); };
float4x4 GetWorldToObjectMatrix() { return unity_WorldToObject; }
float4x4 GetObjectToWorldMatrix() { return unity_ObjectToWorld; }
#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
}
#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
#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
fixed4 w0;
fixed4 w1;
fixed4 w2;
fixed4 w3;
fixed4 w4;
fixed4 w5;
fixed4 w6;
// megasplat data
half4 layer0;
half4 layer1;
half3 baryWeights;
half4 scatter0;
half4 scatter1;
// wetness, puddles, streams, lava from vertex or megasplat
fixed4 fx;
// snow min, snow max
fixed4 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(unity_WorldToObject, float4(n, 1)).xyz;
surfTangent = t;//mul(unity_WorldToObject, 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, fixed4 w0, fixed4 w1, fixed4 w2, fixed4 w3, fixed4 w4, fixed4 w5, fixed4 w6, fixed4 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
fixed 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)
{
fixed 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 fixed2 UnpackNormal2(fixed4 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 fixed4 w0, inout fixed4 w1, inout fixed4 w2, inout fixed4 w3, inout fixed4 w4, inout fixed4 w5, inout fixed4 w6, inout fixed4 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)unity_WorldToObject, worldNormalVertex).xyz;
i.worldPos = i.worldPos - mul(unity_ObjectToWorld, 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
fixed4 w0 = 0; fixed4 w1 = 0; fixed4 w2 = 0; fixed4 w3 = 0; fixed4 w4 = 0; fixed4 w5 = 0; fixed4 w6 = 0; fixed4 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(unity_WorldToObject, float4(GetCameraRelativePositionWS(i.worldPos), 1));
#else
// d.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1));
#endif
// d.localSpaceNormal = normalize(mul((float3x3)unity_WorldToObject, i.worldNormal));
// d.localSpaceTangent = normalize(mul((float3x3)unity_WorldToObject, 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)
{
}
// vertex shader
VertexToPixel Vert (VertexData v)
{
UNITY_SETUP_INSTANCE_ID(v);
VertexToPixel o;
UNITY_INITIALIZE_OUTPUT(VertexToPixel,o);
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;
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
o.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
o.worldTangent.w = tangentSign;
#endif
// MS Only
ApplyTerrainTangent(o);
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
// o.screenPos = ComputeScreenPos(o.pos);
return o;
}
// fragment shader
fixed4 Frag (VertexToPixel IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
// prepare and unpack data
#ifdef FOG_COMBINED_WITH_TSPACE
UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
#elif defined (FOG_COMBINED_WITH_WORLD_POS)
UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
#else
UNITY_EXTRACT_FOG(IN);
#endif
#ifndef USING_DIRECTIONAL_LIGHT
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(IN.worldPos));
#else
fixed3 lightDir = _WorldSpaceLightPos0.xyz;
#endif
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);
SHADOW_CASTER_FRAGMENT(IN)
}
ENDCG
}
// ---- meta information extraction pass:
Pass
{
Name "Meta"
Tags { "LightMode" = "Meta" }
Cull Off
CGPROGRAM
#pragma vertex Vert
#pragma fragment Frag
// compile directives
#pragma target 3.0
#pragma multi_compile_instancing
#pragma multi_compile_local __ _ALPHATEST_ON
#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
#pragma shader_feature EDITOR_VISUALIZATION
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
#include "UnityShaderUtilities.cginc"
#include "UnityCG.cginc"
#define _PASSMETA 1
#define _MICROPOLARISMESH 1
#define _BRANCHSAMPLES 1
#define _BRANCHSAMPLESARG 1
#define _MSRENDERLOOP_UNITYLD 1
#define _MSRENDERLOOP_UNITYURP2020 1
#define _MSRENDERLOOP_UNITYURP2021 1
#define _MSRENDERLOOP_UNITYURP2022 1
#define _STANDARD 1
// If your looking in here and thinking WTF, yeah, I know. These are taken from the SRPs, to allow us to use the same
// texturing library they use. However, since they are not included in the standard pipeline by default, there is no
// way to include them in and they have to be inlined, since someone could copy this shader onto another machine without
// MicroSplat installed. Unfortunate, but I'd rather do this and have a nice library for texture sampling instead
// of the patchy one Unity provides being inlined/emulated in HDRP/URP. Strangely, PSSL and XBoxOne libraries are not
// included in the standard SRP code, but they are in tons of Unity own projects on the web, so I grabbed them from there.
#if defined(SHADER_API_GAMECORE)
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURECUBE(textureName) TextureCube textureName
#define TEXTURECUBE_ARRAY(textureName) TextureCubeArray textureName
#define TEXTURE3D(textureName) Texture3D textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_FLOAT(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_FLOAT(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_FLOAT(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_HALF(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_HALF(textureName) TEXTURECUBE_ARRAY(textureName)
#define TEXTURE3D_HALF(textureName) TEXTURE3D(textureName)
#define TEXTURE2D_SHADOW(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_SHADOW(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURECUBE_SHADOW(textureName) TEXTURECUBE(textureName)
#define TEXTURECUBE_ARRAY_SHADOW(textureName) TEXTURECUBE_ARRAY(textureName)
#define RW_TEXTURE2D(type, textureName) RWTexture2D<type> textureName
#define RW_TEXTURE2D_ARRAY(type, textureName) RWTexture2DArray<type> textureName
#define RW_TEXTURE3D(type, textureName) RWTexture3D<type> textureName
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define ASSIGN_SAMPLER(samplerName, samplerValue) samplerName = samplerValue
#define TEXTURE2D_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_ARRAY_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER(samplerName)
#define TEXTURECUBE_ARRAY_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER(samplerName)
#define TEXTURE3D_PARAM(textureName, samplerName) TEXTURE3D(textureName), SAMPLER(samplerName)
#define TEXTURE2D_SHADOW_PARAM(textureName, samplerName) TEXTURE2D(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURE2D_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE(textureName), SAMPLER_CMP(samplerName)
#define TEXTURECUBE_ARRAY_SHADOW_PARAM(textureName, samplerName) TEXTURECUBE_ARRAY(textureName), SAMPLER_CMP(samplerName)
#define TEXTURE2D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE3D_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURE2D_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define TEXTURECUBE_ARRAY_SHADOW_ARGS(textureName, samplerName) textureName, samplerName
#define PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#define PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) textureName.SampleBias(samplerName, coord3, bias)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Sample(samplerName, float4(coord3, index))
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) textureName.SampleLevel(samplerName, float4(coord3, index), lod)
#define PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) textureName.SampleBias(samplerName, float4(coord3, index), bias)
#define PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3) textureName.Sample(samplerName, coord3)
#define PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) textureName.SampleLevel(samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) PLATFORM_SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) PLATFORM_SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) PLATFORM_SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) PLATFORM_SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) PLATFORM_SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy)
#define SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3)
#define SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURECUBE_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias) PLATFORM_SAMPLE_TEXTURECUBE_BIAS(textureName, samplerName, coord3, bias)
#define SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index)
#define SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#define SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias) PLATFORM_SAMPLE_TEXTURECUBE_ARRAY_BIAS(textureName, samplerName, coord3, index, bias)
#define SAMPLE_TEXTURE3D(textureName, samplerName, coord3) PLATFORM_SAMPLE_TEXTURE3D(textureName, samplerName, coord3)
#define SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod) PLATFORM_SAMPLE_TEXTURE3D_LOD(textureName, samplerName, coord3, lod)
#define SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) textureName.SampleCmpLevelZero(samplerName, (coord3).xy, (coord3).z)
#define SAMPLE_TEXTURE2D_ARRAY_SHADOW(textureName, samplerName, coord3, index) textureName.SampleCmpLevelZero(samplerName, float3((coord3).xy, index), (coord3).z)
#define SAMPLE_TEXTURECUBE_SHADOW(textureName, samplerName, coord4) textureName.SampleCmpLevelZero(samplerName, (coord4).xyz, (coord4).w)
#define SAMPLE_TEXTURECUBE_ARRAY_SHADOW(textureName, samplerName, coord4, index) textureName.SampleCmpLevelZero(samplerName, float4((coord4).xyz, index), (coord4).w)
#define SAMPLE_DEPTH_TEXTURE(textureName, samplerName, coord2) SAMPLE_TEXTURE2D(textureName, samplerName, coord2).r
#define SAMPLE_DEPTH_TEXTURE_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod).r
#define LOAD_TEXTURE2D(textureName, unCoord2) textureName.Load(int3(unCoord2, 0))
#define LOAD_TEXTURE2D_LOD(textureName, unCoord2, lod) textureName.Load(int3(unCoord2, lod))
#define LOAD_TEXTURE2D_MSAA(textureName, unCoord2, sampleIndex) textureName.Load(unCoord2, sampleIndex)
#define LOAD_TEXTURE2D_ARRAY(textureName, unCoord2, index) textureName.Load(int4(unCoord2, index, 0))
#define LOAD_TEXTURE2D_ARRAY_MSAA(textureName, unCoord2, index, sampleIndex) textureName.Load(int3(unCoord2, index), sampleIndex)
#define LOAD_TEXTURE2D_ARRAY_LOD(textureName, unCoord2, index, lod) textureName.Load(int4(unCoord2, index, lod))
#define LOAD_TEXTURE3D(textureName, unCoord3) textureName.Load(int4(unCoord3, 0))
#define LOAD_TEXTURE3D_LOD(textureName, unCoord3, lod) textureName.Load(int4(unCoord3, lod))
#define PLATFORM_SUPPORT_GATHER
#define GATHER_TEXTURE2D(textureName, samplerName, coord2) textureName.Gather(samplerName, coord2)
#define GATHER_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Gather(samplerName, float3(coord2, index))
#define GATHER_TEXTURECUBE(textureName, samplerName, coord3) textureName.Gather(samplerName, coord3)
#define GATHER_TEXTURECUBE_ARRAY(textureName, samplerName, coord3, index) textureName.Gather(samplerName, float4(coord3, index))
#define GATHER_RED_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherRed(samplerName, coord2)
#define GATHER_GREEN_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherGreen(samplerName, coord2)
#define GATHER_BLUE_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherBlue(samplerName, coord2)
#define GATHER_ALPHA_TEXTURE2D(textureName, samplerName, coord2) textureName.GatherAlpha(samplerName, coord2)
#elif defined(SHADER_API_XBOXONE)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_PSSL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.GetLOD(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_D3D11)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_METAL)
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_VULKAN)
// This file assume SHADER_API_VULKAN is defined
// TODO: This is a straight copy from D3D11.hlsl. Go through all this stuff and adjust where needed.
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_SWITCH)
// This file assume SHADER_API_SWITCH is defined
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, dpdx, dpdy) textureName.SampleGrad(samplerName, coord2, dpdx, dpdy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLCORE)
// OpenGL 4.1 SM 5.0 https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 46)
#define OPENGL4_1_SM5 1
#else
#define OPENGL4_1_SM5 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURE2D_ARRAY(textureName)
#define TEXTURE2D_HALF(textureName) TEXTURE2D(textureName)
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURE2D_ARRAY(textureName)
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES3)
// GLES 3.1 + AEP shader feature https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
#if (SHADER_TARGET >= 40)
#define GLES3_1_AEP 1
#else
#define GLES3_1_AEP 0
#endif
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) textureName.CalculateLevelOfDetail(samplerName, coord2)
// Texture abstraction
#define TEXTURE2D(textureName) Texture2D textureName
#define TEXTURE2D_ARRAY(textureName) Texture2DArray textureName
#define TEXTURE2D_FLOAT(textureName) Texture2D_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define TEXTURE2D_HALF(textureName) Texture2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) Texture2DArray textureName // no support to _float on Array, it's being added
#define SAMPLER(samplerName) SamplerState samplerName
#define SAMPLER_CMP(samplerName) SamplerComparisonState samplerName
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) textureName.SampleLevel(samplerName, coord2, lod)
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) textureName.SampleBias(samplerName, coord2, bias)
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) textureName.SampleGrad(samplerName, coord2, ddx, ddy)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)
#elif defined(SHADER_API_GLES)
#define uint int
#define rcp(x) 1.0 / (x)
#define ddx_fine ddx
#define ddy_fine ddy
#define asfloat
#define asuint(x) asint(x)
#define f32tof16
#define f16tof32
#define ERROR_ON_UNSUPPORTED_FUNCTION(funcName) #error #funcName is not supported on GLES 2.0
// Initialize arbitrary structure with zero values.
// Do not exist on some platform, in this case we need to have a standard name that call a function that will initialize all parameters to 0
#define ZERO_INITIALIZE(type, name) name = (type)0;
#define ZERO_INITIALIZE_ARRAY(type, name, arraySize) { for (int arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) { name[arrayIndex] = (type)0; } }
// Texture util abstraction
#define CALCULATE_TEXTURE2D_LOD(textureName, samplerName, coord2) #error calculate Level of Detail not supported in GLES2
// Texture abstraction
#define TEXTURE2D(textureName) sampler2D textureName
#define TEXTURE2D_ARRAY(textureName) samplerCUBE textureName // No support to texture2DArray
#define TEXTURECUBE(textureName) samplerCUBE textureName
#define TEXTURECUBE_ARRAY(textureName) samplerCUBE textureName // No supoport to textureCubeArray and can't emulate with texture2DArray
#define TEXTURE3D(textureName) sampler3D textureName
#define TEXTURE2D_FLOAT(textureName) sampler2D_float textureName
#define TEXTURECUBE_FLOAT(textureName) samplerCUBE_float textureName
#define TEXTURE2D_ARRAY_FLOAT(textureName) TEXTURECUBE_FLOAT(textureName) // No support to texture2DArray
#define TEXTURE2D_HALF(textureName) sampler2D_half textureName
#define TEXTURE2D_ARRAY_HALF(textureName) TEXTURECUBE_HALF(textureName) // No support to texture2DArray
#define SAMPLER(samplerName)
#define SAMPLER_CMP(samplerName)
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2)
#if (SHADER_TARGET >= 30)
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) tex2Dlod(textureName, float4(coord2, 0, lod))
#else
// No lod support. Very poor approximation with bias.
#define SAMPLE_TEXTURE2D_LOD(textureName, samplerName, coord2, lod) SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, lod)
#endif
#define SAMPLE_TEXTURE2D_BIAS(textureName, samplerName, coord2, bias) tex2Dbias(textureName, float4(coord2, 0, bias))
#define SAMPLE_TEXTURE2D_GRAD(textureName, samplerName, coord2, ddx, ddy) SAMPLE_TEXTURE2D(textureName, samplerName, coord2)
#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY)
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_LOD)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_BIAS)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) ERROR_ON_UNSUPPORTED_FUNCTION(SAMPLE_TEXTURE2D_ARRAY_GRAD)
#else
#error unsupported shader api
#endif
// default flow control attributes
#ifndef UNITY_BRANCH
# define UNITY_BRANCH
#endif
#ifndef UNITY_FLATTEN
# define UNITY_FLATTEN
#endif
#ifndef UNITY_UNROLL
# define UNITY_UNROLL
#endif
#ifndef UNITY_UNROLLX
# define UNITY_UNROLLX(_x)
#endif
#ifndef UNITY_LOOP
# define UNITY_LOOP
#endif
#if _NOMINDIELETRIC
// for Standard
#ifdef unity_ColorSpaceDielectricSpec
#undef unity_ColorSpaceDielectricSpec
#endif
#define unity_ColorSpaceDielectricSpec half4(0,0,0,1)
#endif
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"
#include "UnityMetaPass.cginc"
#if _MICROTERRAIN && !_TERRAINBLENDABLESHADER
#define UNITY_ASSUME_UNIFORM_SCALING
#define UNITY_DONT_INSTANCE_OBJECT_MATRICES
#define UNITY_INSTANCED_LOD_FADE
#else
#define UNITY_INSTANCED_LOD_FADE
#define UNITY_INSTANCED_SH
#define UNITY_INSTANCED_LIGHTMAPSTS
#endif
// data across stages, stripped like the above.
struct VertexToPixel
{
UNITY_POSITION(pos);
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;
#ifdef EDITOR_VISUALIZATION
float2 vizUV : TEXCOORD8;
float4 lightCoord : TEXCOORD9;
#endif
// float4 extraV2F0 : TEXCOORD10;
// float4 extraV2F1 : TEXCOORD11;
// float4 extraV2F2 : TEXCOORD12;
// float4 extraV2F3 : TEXCOORD13;
// float4 extraV2F4 : TEXCOORD14;
// float4 extraV2F5 : TEXCOORD15;
// float4 extraV2F6 : TEXCOORD16;
// float4 extraV2F7 : TEXCOORD17;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// 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
// unity_WorldToObject in HDRP, since it already does macro-fu there
#if _STANDARD
float3 TransformWorldToObject(float3 p) { return mul(unity_WorldToObject, float4(p, 1)); };
float3 TransformObjectToWorld(float3 p) { return mul(unity_ObjectToWorld, float4(p, 1)); };
float4 TransformWorldToObject(float4 p) { return mul(unity_WorldToObject, p); };
float4 TransformObjectToWorld(float4 p) { return mul(unity_ObjectToWorld, p); };
float4x4 GetWorldToObjectMatrix() { return unity_WorldToObject; }
float4x4 GetObjectToWorldMatrix() { return unity_ObjectToWorld; }
#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
}
#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
#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
fixed4 w0;
fixed4 w1;
fixed4 w2;
fixed4 w3;
fixed4 w4;
fixed4 w5;
fixed4 w6;
// megasplat data
half4 layer0;
half4 layer1;
half3 baryWeights;
half4 scatter0;
half4 scatter1;
// wetness, puddles, streams, lava from vertex or megasplat
fixed4 fx;
// snow min, snow max
fixed4 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(unity_WorldToObject, float4(n, 1)).xyz;
surfTangent = t;//mul(unity_WorldToObject, 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, fixed4 w0, fixed4 w1, fixed4 w2, fixed4 w3, fixed4 w4, fixed4 w5, fixed4 w6, fixed4 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
fixed 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)
{
fixed 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 fixed2 UnpackNormal2(fixed4 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 fixed4 w0, inout fixed4 w1, inout fixed4 w2, inout fixed4 w3, inout fixed4 w4, inout fixed4 w5, inout fixed4 w6, inout fixed4 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)unity_WorldToObject, worldNormalVertex).xyz;
i.worldPos = i.worldPos - mul(unity_ObjectToWorld, 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
fixed4 w0 = 0; fixed4 w1 = 0; fixed4 w2 = 0; fixed4 w3 = 0; fixed4 w4 = 0; fixed4 w5 = 0; fixed4 w6 = 0; fixed4 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(unity_WorldToObject, float4(GetCameraRelativePositionWS(i.worldPos), 1));
#else
// d.localSpacePosition = mul(unity_WorldToObject, float4(i.worldPos, 1));
#endif
// d.localSpaceNormal = normalize(mul((float3x3)unity_WorldToObject, i.worldNormal));
// d.localSpaceTangent = normalize(mul((float3x3)unity_WorldToObject, 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)
{
}
// vertex shader
VertexToPixel Vert (VertexData v)
{
UNITY_SETUP_INSTANCE_ID(v);
VertexToPixel o;
UNITY_INITIALIZE_OUTPUT(VertexToPixel,o);
UNITY_TRANSFER_INSTANCE_ID(v,o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#if !_TESSELLATION_ON
ChainModifyVertex(v, o);
#endif
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
float2 uv1 = v.texcoord1.xy;
float2 uv2 = v.texcoord2.xy;
#else
float2 uv1 = v.texcoord0.xy;
float2 uv2 = uv1;
#endif
o.pos = UnityMetaVertexPosition(v.vertex, uv1, uv2, unity_LightmapST, unity_DynamicLightmapST);
#ifdef EDITOR_VISUALIZATION
o.vizUV = 0;
o.lightCoord = 0;
if (unity_VisualizationMode == EDITORVIZ_TEXTURE)
o.vizUV = UnityMetaVizUV(unity_EditorViz_UVIndex, v.texcoord0.xy, uv1, uv2, unity_EditorViz_Texture_ST);
else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK)
{
o.vizUV = uv1 * unity_LightmapST.xy + unity_LightmapST.zw;
o.lightCoord = mul(unity_EditorViz_WorldToLight, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1)));
}
#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;
// o.screenPos = ComputeScreenPos(o.pos);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
#if !_MICROTERRAIN || _TERRAINBLENDABLESHADER
o.worldTangent.xyz = UnityObjectToWorldDir(v.tangent.xyz);
fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
o.worldTangent.w = tangentSign;
#endif
// MS Only
ApplyTerrainTangent(o);
return o;
}
// fragment shader
fixed4 Frag (VertexToPixel IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
#ifdef FOG_COMBINED_WITH_TSPACE
UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
#elif defined (FOG_COMBINED_WITH_WORLD_POS)
UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
#else
UNITY_EXTRACT_FOG(IN);
#endif
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);
UnityMetaInput metaIN;
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN);
metaIN.Albedo = l.Albedo;
metaIN.Emission = l.Emission;
#if _USESPECULAR
metaIN.SpecularColor = l.Specular;
#endif
#ifdef EDITOR_VISUALIZATION
metaIN.VizUV = IN.vizUV;
metaIN.LightCoord = IN.lightCoord;
#endif
return UnityMetaFragment(metaIN);
}
ENDCG
}
UsePass "Hidden/Nature/Terrain/Utilities/PICKING"
UsePass "Hidden/Nature/Terrain/Utilities/SELECTION"
}
CustomEditor "MicroSplatShaderGUI"
}