Streamingle_URP/Assets/NiloToonURP/Shaders/NiloToonEnvironment_HLSL/NiloToonEnvironment_LitForwardPass.hlsl

717 lines
31 KiB
HLSL

// SPDX-License-Identifier: (Not available for this version, you are only allowed to use this software if you have express permission from the copyright holder and agreed to the latest NiloToonURP EULA)
// Copyright (c) 2021 Kuroneko ShaderLab Limited
// For more information, visit -> https://github.com/ColinLeung-NiloCat/UnityURPToonLitShaderExample
// This shader is a direct copy of Unity6.1 URP17.0.3's LitForwardPass.hlsl, but with some edit.
// If you want to see what is the difference, all edited lines will have a [NiloToon] tag, you can search [NiloToon] in this file,
// or compare Unity6.1 URP17.0.3's LitForwardPass.hlsl with this file using tools like SourceGear DiffMerge.
// #pragma once is a safeguard best practice in almost every .hlsl,
// doing this can make sure your .hlsl's user can include this .hlsl anywhere anytime without producing any multi include conflict
#pragma once
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#if UNITY_VERSION >= 202220
#if defined(LOD_FADE_CROSSFADE)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
#endif
#endif
// [NiloToon] add:
//==========================================================================================================
// + Rider code highlight support for all shader_feature and multi_compile
// (__RESHARPER__ is only defined while in IDE. Used to help editing this file with proper highlighting.)
#ifdef __RESHARPER__
#define _NILOTOON_GLOBAL_ENABLE_SCREENSPACE_OUTLINE 1
#define _NILOTOON_GLOBAL_ENABLE_SCREENSPACE_OUTLINE_V2 1
#define _SPLATMAP 1
#define _RECEIVE_NILOTOON_CHAR_SHADOW 1
#define _NILOTOON_RECEIVE_SELF_SHADOW 1
#endif
#include "../../ShaderLibrary/NiloUtilityHLSL/NiloAllUtilIncludes.hlsl"
#if defined(_SPLATMAP)
#if !defined(_NORMALMAP)
#define _NORMALMAP
#endif
#endif
//==========================================================================================================
#if defined(_PARALLAXMAP)
#define REQUIRES_TANGENT_SPACE_VIEW_DIR_INTERPOLATOR
#endif
#if (defined(_NORMALMAP) || (defined(_PARALLAXMAP) && !defined(REQUIRES_TANGENT_SPACE_VIEW_DIR_INTERPOLATOR))) || defined(_DETAIL)
#define REQUIRES_WORLD_SPACE_TANGENT_INTERPOLATOR
#endif
// keep this file in sync with LitGBufferPass.hlsl
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float2 texcoord : TEXCOORD0;
float2 staticLightmapUV : TEXCOORD1;
float2 dynamicLightmapUV : TEXCOORD2;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float2 uv : TEXCOORD0;
#if defined(REQUIRES_WORLD_SPACE_POS_INTERPOLATOR)
float3 positionWS : TEXCOORD1;
#endif
float3 normalWS : TEXCOORD2;
#if defined(REQUIRES_WORLD_SPACE_TANGENT_INTERPOLATOR)
half4 tangentWS : TEXCOORD3; // xyz: tangent, w: sign
#endif
#if UNITY_VERSION < 202220
float3 viewDirWS : TEXCOORD4;
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
half4 fogFactorAndVertexLight : TEXCOORD5; // x: fogFactor, yzw: vertex light
#else
half fogFactor : TEXCOORD5;
#endif
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
float4 shadowCoord : TEXCOORD6;
#endif
#if defined(REQUIRES_TANGENT_SPACE_VIEW_DIR_INTERPOLATOR)
half3 viewDirTS : TEXCOORD7;
#endif
DECLARE_LIGHTMAP_OR_SH(staticLightmapUV, vertexSH, 8);
#ifdef DYNAMICLIGHTMAP_ON
float2 dynamicLightmapUV : TEXCOORD9; // Dynamic lightmap UVs
#endif
#ifdef USE_APV_PROBE_OCCLUSION
float4 probeOcclusion : TEXCOORD10;
#endif
// [NiloToon] add:
//=======================================================
float4 screenPos : TEXCOORD11;
//=======================================================
float4 positionCS : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
void InitializeInputData(Varyings input, half3 normalTS, out InputData inputData)
{
inputData = (InputData)0;
#if defined(REQUIRES_WORLD_SPACE_POS_INTERPOLATOR)
inputData.positionWS = input.positionWS;
#endif
#if UNITY_VERSION >= 60000000
#if defined(DEBUG_DISPLAY)
inputData.positionCS = input.positionCS;
#endif
#endif
half3 viewDirWS = GetWorldSpaceNormalizeViewDir(input.positionWS);
#if defined(_NORMALMAP) || defined(_DETAIL)
float sgn = input.tangentWS.w; // should be either +1 or -1
float3 bitangent = sgn * cross(input.normalWS.xyz, input.tangentWS.xyz);
half3x3 tangentToWorld = half3x3(input.tangentWS.xyz, bitangent.xyz, input.normalWS.xyz);
#if defined(_NORMALMAP)
inputData.tangentToWorld = tangentToWorld;
#endif
inputData.normalWS = TransformTangentToWorld(normalTS, tangentToWorld);
#else
inputData.normalWS = input.normalWS;
#endif
inputData.normalWS = NormalizeNormalPerPixel(inputData.normalWS);
inputData.viewDirectionWS = viewDirWS;
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
inputData.shadowCoord = input.shadowCoord;
#elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
inputData.shadowCoord = TransformWorldToShadowCoord(inputData.positionWS);
#else
inputData.shadowCoord = float4(0, 0, 0, 0);
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
inputData.fogCoord = InitializeInputDataFog(float4(input.positionWS, 1.0), input.fogFactorAndVertexLight.x);
inputData.vertexLighting = input.fogFactorAndVertexLight.yzw;
#else
inputData.fogCoord = InitializeInputDataFog(float4(input.positionWS, 1.0), input.fogFactor);
#endif
#if UNITY_VERSION < 60000000
#if defined(DYNAMICLIGHTMAP_ON)
inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.dynamicLightmapUV, input.vertexSH, inputData.normalWS);
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
inputData.bakedGI = SAMPLE_GI(input.vertexSH,
GetAbsolutePositionWS(inputData.positionWS),
inputData.normalWS,
inputData.viewDirectionWS,
input.positionCS.xy);
#else
inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.vertexSH, inputData.normalWS);
#endif
#endif
inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS);
#if UNITY_VERSION < 60000000
inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV);
#endif
#if defined(DEBUG_DISPLAY)
#if defined(DYNAMICLIGHTMAP_ON)
inputData.dynamicLightmapUV = input.dynamicLightmapUV;
#endif
#if defined(LIGHTMAP_ON)
inputData.staticLightmapUV = input.staticLightmapUV;
#else
inputData.vertexSH = input.vertexSH;
#endif
#if UNITY_VERSION >= 60000000
#if defined(USE_APV_PROBE_OCCLUSION)
inputData.probeOcclusion = input.probeOcclusion;
#endif
#endif
#endif
}
#if UNITY_VERSION >= 60000000
void InitializeBakedGIData(Varyings input, inout InputData inputData)
{
#if defined(DYNAMICLIGHTMAP_ON)
inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.dynamicLightmapUV, input.vertexSH, inputData.normalWS);
inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV);
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2))
inputData.bakedGI = SAMPLE_GI(input.vertexSH,
GetAbsolutePositionWS(inputData.positionWS),
inputData.normalWS,
inputData.viewDirectionWS,
input.positionCS.xy,
input.probeOcclusion,
inputData.shadowMask);
#else
inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.vertexSH, inputData.normalWS);
inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV);
#endif
}
#endif
// [NiloToon] add:
//==========================================================================================================================================================
// debug on off
float _NiloToonGlobalEnviMinimumShader;
// shadow boader color
float4 _NiloToonGlobalEnviShadowBorderTintColor;
// global GI edit
float3 _NiloToonGlobalEnviGITintColor;
float3 _NiloToonGlobalEnviGIAddColor;
// global GI override
float4 _NiloToonGlobalEnviGIOverride;
// global albedo override
float4 _NiloToonGlobalEnviAlbedoOverrideColor;
// global surface color result override
float4 _NiloToonGlobalEnviSurfaceColorResultOverrideColor;
// global screen space outline settings
float _GlobalScreenSpaceOutlineIntensityForEnvi;
float _GlobalScreenSpaceOutlineWidthMultiplierForEnvi;
float _GlobalScreenSpaceOutlineNormalsSensitivityOffsetForEnvi;
float _GlobalScreenSpaceOutlineDepthSensitivityOffsetForEnvi;
float _GlobalScreenSpaceOutlineDepthSensitivityDistanceFadeoutStrengthForEnvi;
half3 _GlobalScreenSpaceOutlineTintColorForEnvi;
// global screen space outline V2 settings
float _GlobalScreenSpaceOutlineV2IntensityForEnvi;
float _GlobalScreenSpaceOutlineV2WidthMultiplierForEnvi;
float _GlobalScreenSpaceOutlineV2EnableGeometryEdgeForEnvi;
float _GlobalScreenSpaceOutlineV2GeometryEdgeThresholdForEnvi;
float _GlobalScreenSpaceOutlineV2EnableNormalAngleEdgeForEnvi;
float _GlobalScreenSpaceOutlineV2NormalAngleCosThetaThresholdForEnvi;
// global camera uniforms
float _CurrentCameraFOV;
// NiloToon Character Self Shadow uniforms and texture
#if defined(_RECEIVE_NILOTOON_CHAR_SHADOW) && defined(_NILOTOON_RECEIVE_SELF_SHADOW)
TEXTURE2D(_NiloToonCharSelfShadowMapRT);
SAMPLER_CMP(sampler_NiloToonCharSelfShadowMapRT_LinearClampCompare);
SAMPLER(sampler_NiloToonCharSelfShadowMapRT_Linear_Clamp); // for raw depth sampling
float4x4 _NiloToonSelfShadowWorldToClip;
float4 _NiloToonSelfShadowParam; // (1/w, 1/h, w, h)
float3 _NiloToonSelfShadowLightDirection;
float _GlobalReceiveNiloToonSelfShadowMap;
float _NiloToonSelfShadowRange;
float _NiloToonSelfShadowUseNdotLFix;
float _NiloToonCharShadowStrength; // per-material shadow strength
#endif
// include files, include as late as possible to get all defines
#include "NiloToonEnvironment_ExtendFunctionsForUserCustomLogic.hlsl"
// NiloToon Character Self Shadow sampling function
#if defined(_RECEIVE_NILOTOON_CHAR_SHADOW) && defined(_NILOTOON_RECEIVE_SELF_SHADOW)
half SampleNiloToonCharSelfShadow(float3 positionWS, float3 normalWS, float linearEyeDepth)
{
// Transform world position to shadow map clip space
float4 positionSelfShadowCS = mul(_NiloToonSelfShadowWorldToClip, float4(positionWS, 1));
float3 positionSelfShadowNDC = positionSelfShadowCS.xyz;
// Convert NDC.xy[-1,1] to UV[0,1]
float2 shadowMapUV = positionSelfShadowNDC.xy * 0.5 + 0.5;
// Calculate compare value for shadow test
float ndcZCompareValue = positionSelfShadowNDC.z;
// If OpenGL, convert NDC.z[-1,1] to [0,1], because shadowmap uses [0,1] range
// If DirectX, it's already [0,1]
ndcZCompareValue = UNITY_NEAR_CLIP_VALUE < 0 ? ndcZCompareValue * 0.5 + 0.5 : ndcZCompareValue;
// If DirectX, flip shadowMapUV.y (y = 1-y)
// If OpenGL, do nothing
#if UNITY_UV_STARTS_AT_TOP
shadowMapUV.y = 1 - shadowMapUV.y;
#endif
// Check if outside shadow map UV bounds - no shadow outside
if(shadowMapUV.x < 0 || shadowMapUV.x > 1 || shadowMapUV.y < 0 || shadowMapUV.y > 1)
{
return 1; // no shadow
}
// Sample raw depth from shadow map to check if this is an empty area (no character)
// Empty areas have depth = 0 (cleared value), which would incorrectly cause shadow
float shadowMapRawDepth = SAMPLE_TEXTURE2D_LOD(_NiloToonCharSelfShadowMapRT,
sampler_NiloToonCharSelfShadowMapRT_Linear_Clamp,
shadowMapUV, 0).r;
// If shadowmap depth is near 0 (empty area - no character rendered there), no shadow
// In reverse-Z, 0 = far plane (empty/cleared), values closer to 1 = actual geometry
if(shadowMapRawDepth < 0.0001)
{
return 1; // no shadow - empty area in shadow map
}
// Pack UV and compare value for SAMPLE_TEXTURE2D_SHADOW
float4 selfShadowmapUV = float4(shadowMapUV, ndcZCompareValue, 0);
// Sample shadow map with depth comparison (hardware 1-tap bilinear filter)
half shadow = SAMPLE_TEXTURE2D_SHADOW(_NiloToonCharSelfShadowMapRT,
sampler_NiloToonCharSelfShadowMapRT_LinearClampCompare,
selfShadowmapUV.xyz);
// Fadeout shadow if reaching the end of shadow distance
float fadeTotalDistance = 1.0;
shadow = lerp(shadow, 1, saturate((1.0 / fadeTotalDistance) * (linearEyeDepth - (_NiloToonSelfShadowRange - fadeTotalDistance))));
// Use N dot L fix to hide shadow acne on surfaces facing away from light
if(_NiloToonSelfShadowUseNdotLFix > 0.5)
{
shadow *= smoothstep(0.1, 0.2, saturate(dot(normalWS, _NiloToonSelfShadowLightDirection)));
}
return shadow;
}
#endif
//==========================================================================================================================================================
///////////////////////////////////////////////////////////////////////////////
// Vertex and Fragment functions //
///////////////////////////////////////////////////////////////////////////////
// Used in Standard (Physically Based) shader
Varyings LitPassVertex(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
// [NiloToon] add:
//==========================================================================================================================================================
ApplyCustomUserLogicToVertexAttributeAtVertexShaderStart(input);
//==========================================================================================================================================================
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
// normalWS and tangentWS already normalize.
// this is required to avoid skewing the direction during interpolation
// also required for per-vertex lighting and SH evaluation
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
half3 vertexLight = VertexLighting(vertexInput.positionWS, normalInput.normalWS);
half fogFactor = 0;
#if !defined(_FOG_FRAGMENT)
fogFactor = ComputeFogFactor(vertexInput.positionCS.z);
#endif
output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
// already normalized from normal transform to WS.
output.normalWS = normalInput.normalWS;
#if defined(REQUIRES_WORLD_SPACE_TANGENT_INTERPOLATOR) || defined(REQUIRES_TANGENT_SPACE_VIEW_DIR_INTERPOLATOR)
real sign = input.tangentOS.w * GetOddNegativeScale();
half4 tangentWS = half4(normalInput.tangentWS.xyz, sign);
#endif
#if defined(REQUIRES_WORLD_SPACE_TANGENT_INTERPOLATOR)
output.tangentWS = tangentWS;
#endif
#if defined(REQUIRES_TANGENT_SPACE_VIEW_DIR_INTERPOLATOR)
half3 viewDirWS = GetWorldSpaceNormalizeViewDir(vertexInput.positionWS);
half3 viewDirTS = GetViewDirectionTangentSpace(tangentWS, output.normalWS, viewDirWS);
output.viewDirTS = viewDirTS;
#endif
OUTPUT_LIGHTMAP_UV(input.staticLightmapUV, unity_LightmapST, output.staticLightmapUV);
#ifdef DYNAMICLIGHTMAP_ON
output.dynamicLightmapUV = input.dynamicLightmapUV.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
#if UNITY_VERSION >= 60000011
OUTPUT_SH4(vertexInput.positionWS, output.normalWS.xyz, GetWorldSpaceNormalizeViewDir(vertexInput.positionWS), output.vertexSH, output.probeOcclusion);
#elif UNITY_VERSION >= 202310
OUTPUT_SH4(vertexInput.positionWS, output.normalWS.xyz, GetWorldSpaceNormalizeViewDir(vertexInput.positionWS), output.vertexSH);
#else
OUTPUT_SH(output.normalWS.xyz, output.vertexSH);
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
output.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
#else
output.fogFactor = fogFactor;
#endif
#if defined(REQUIRES_WORLD_SPACE_POS_INTERPOLATOR)
output.positionWS = vertexInput.positionWS;
#endif
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
output.shadowCoord = GetShadowCoord(vertexInput);
#endif
output.positionCS = vertexInput.positionCS;
// [NiloToon] add:
//==========================================================================================================================================================
output.screenPos = ComputeScreenPos(output.positionCS);
ApplyCustomUserLogicToVertexShaderOutputAtVertexShaderEnd(output, input);
//==========================================================================================================================================================
return output;
}
// [NiloToon] add:
//==========================================================================================================================================================
half4 CalculateFinalSplatBlendFactor(half blendSoftness, half depth1, half depth2, half depth3, half depth4, half4 splatControlMapRGBA)
{
half4 blend;
blend.r = depth1 * splatControlMapRGBA.r;
blend.g = depth2 * splatControlMapRGBA.g;
blend.b = depth3 * splatControlMapRGBA.b;
blend.a = depth4 * splatControlMapRGBA.a;
half ma = max(blend.r, max(blend.g, max(blend.b, blend.a)));
blend = max(blend - ma + max(0.001,blendSoftness), 0) * splatControlMapRGBA; // 0.001 is safer than 0.00001 when testing with different textures
return blend/(blend.r + blend.g + blend.b + blend.a);
}
void ApplySplatMapToSurfaceData(inout SurfaceData surfaceData, Varyings input)
{
// for reference see URP's TerrainLitPasses.hlsl -> SplatmapMix()
#if defined(_SPLATMAP)
// uv
float2 uvR = input.uv * _SplatAlbedoMapRTiling;
float2 uvG = input.uv * _SplatAlbedoMapGTiling;
float2 uvB = input.uv * _SplatAlbedoMapBTiling;
float2 uvA = input.uv * _SplatAlbedoMapATiling;
// sample packed data map (not yet apply mask)
half4 packedDataR = SAMPLE_TEXTURE2D(_SplatPackedDataMapR, sampler_SplatPackedDataMap_linear_repeat, uvR);
half4 packedDataG = SAMPLE_TEXTURE2D(_SplatPackedDataMapG, sampler_SplatPackedDataMap_linear_repeat, uvG);
half4 packedDataB = SAMPLE_TEXTURE2D(_SplatPackedDataMapB, sampler_SplatPackedDataMap_linear_repeat, uvB);
half4 packedDataA = SAMPLE_TEXTURE2D(_SplatPackedDataMapA, sampler_SplatPackedDataMap_linear_repeat, uvA);
// get height from each type of material
half heightR = packedDataR.b * _SplatHeightMultiplierR;
half heightG = packedDataG.b * _SplatHeightMultiplierG;
half heightB = packedDataB.b * _SplatHeightMultiplierB;
half heightA = packedDataA.b * _SplatHeightMultiplierA;
// sample and remap mask (using height from PackedDataMap)
half4 mask = SAMPLE_TEXTURE2D(_SplatMaskMap, sampler_SplatMaskMap, input.uv);
mask = CalculateFinalSplatBlendFactor(_SplatMaskBlendingSoftness,heightR,heightG,heightB,heightA,mask);
// sample albedo + smoothness
half4 albedoSmoothnessR = SAMPLE_TEXTURE2D(_SplatAlbedoMapR, sampler_SplatAlbedoMap_linear_repeat, uvR) * mask.r;
half4 albedoSmoothnessG = SAMPLE_TEXTURE2D(_SplatAlbedoMapG, sampler_SplatAlbedoMap_linear_repeat, uvG) * mask.g;
half4 albedoSmoothnessB = SAMPLE_TEXTURE2D(_SplatAlbedoMapB, sampler_SplatAlbedoMap_linear_repeat, uvB) * mask.b;
half4 albedoSmoothnessA = SAMPLE_TEXTURE2D(_SplatAlbedoMapA, sampler_SplatAlbedoMap_linear_repeat, uvA) * mask.a;
// apply albedo
half3 albedoR = albedoSmoothnessR.rgb * _SplatAlbedoMapRTintColor;
half3 albedoG = albedoSmoothnessG.rgb * _SplatAlbedoMapGTintColor;
half3 albedoB = albedoSmoothnessB.rgb * _SplatAlbedoMapBTintColor;
half3 albedoA = albedoSmoothnessA.rgb * _SplatAlbedoMapATintColor;
surfaceData.albedo = lerp(surfaceData.albedo, albedoR + albedoG + albedoB + albedoA, _SplatMapFeatureOnOff);
/*
// apply metallic
half metallicR = lerp(1,packedDataR.r,_SplatOverrideMetallicR) * mask.r;
half metallicG = lerp(1,packedDataG.r,_SplatOverrideMetallicG) * mask.g;
half metallicB = lerp(1,packedDataB.r,_SplatOverrideMetallicB) * mask.b;
half metallicA = lerp(1,packedDataA.r,_SplatOverrideMetallicA) * mask.a;
surfaceData.metallic = lerp(surfaceData.metallic, metallicR + metallicG + metallicB + metallicA, _SplatMapFeatureOnOff);
// apply occlusion
half occlusionR = packedDataR.g * mask.r;
half occlusionG = packedDataG.g * mask.g;
half occlusionB = packedDataB.g * mask.b;
half occlusionA = packedDataA.g * mask.a;
surfaceData.occlusion = lerp(surfaceData.occlusion, occlusionR + occlusionG + occlusionB + occlusionA, _SplatMapFeatureOnOff);
*/
// apply smoothness
half smoothnessR = saturate(albedoSmoothnessR.a * _SplatSmoothnessMultiplierR);
half smoothnessG = saturate(albedoSmoothnessG.a * _SplatSmoothnessMultiplierG);
half smoothnessB = saturate(albedoSmoothnessB.a * _SplatSmoothnessMultiplierB);
half smoothnessA = saturate(albedoSmoothnessA.a * _SplatSmoothnessMultiplierA);
surfaceData.smoothness = lerp(surfaceData.smoothness, smoothnessR + smoothnessG + smoothnessB + smoothnessA, _SplatMapFeatureOnOff);
// sample and apply normal
half3 normalTSR = UnpackNormalScale(SAMPLE_TEXTURE2D(_SplatNormalMapR, sampler_SplatNormalMap_linear_repeat, uvR),_SplatNormalMapIntensityR) * mask.r;
half3 normalTSG = UnpackNormalScale(SAMPLE_TEXTURE2D(_SplatNormalMapG, sampler_SplatNormalMap_linear_repeat, uvG),_SplatNormalMapIntensityG) * mask.g;
half3 normalTSB = UnpackNormalScale(SAMPLE_TEXTURE2D(_SplatNormalMapB, sampler_SplatNormalMap_linear_repeat, uvB),_SplatNormalMapIntensityB) * mask.b;
half3 normalTSA = UnpackNormalScale(SAMPLE_TEXTURE2D(_SplatNormalMapA, sampler_SplatNormalMap_linear_repeat, uvA),_SplatNormalMapIntensityA) * mask.a;
surfaceData.normalTS = lerp(surfaceData.normalTS, (normalTSR + normalTSG + normalTSB + normalTSA), _SplatMapFeatureOnOff);
#endif
}
//==========================================================================================================================================================
// Used in Standard (Physically Based) shader
void LitPassFragment(
Varyings input
, out half4 outColor : SV_Target0
#ifdef _WRITE_RENDERING_LAYERS
, out float4 outRenderingLayers : SV_Target1
#endif
)
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#if defined(_PARALLAXMAP)
#if defined(REQUIRES_TANGENT_SPACE_VIEW_DIR_INTERPOLATOR)
half3 viewDirTS = input.viewDirTS;
#else
half3 viewDirWS = GetWorldSpaceNormalizeViewDir(input.positionWS);
half3 viewDirTS = GetViewDirectionTangentSpace(input.tangentWS, input.normalWS, viewDirWS);
#endif
ApplyPerPixelDisplacement(viewDirTS, input.uv);
#endif
SurfaceData surfaceData;
InitializeStandardLitSurfaceData(input.uv, surfaceData);
#if UNITY_VERSION >= 202220
#ifdef LOD_FADE_CROSSFADE
LODFadeCrossFade(input.positionCS);
#endif
#endif
//[NiloToon] add:
//==========================================================================================================================================================
// albedo,normal,smoothness override by splat map
ApplySplatMapToSurfaceData(surfaceData, input);
ApplyCustomUserLogicToSurfaceData(surfaceData, input);
// global albedo override
surfaceData.albedo.rgb = lerp(surfaceData.albedo.rgb, _NiloToonGlobalEnviAlbedoOverrideColor.rgb, _NiloToonGlobalEnviAlbedoOverrideColor.a);
//==========================================================================================================================================================
InputData inputData;
InitializeInputData(input, surfaceData.normalTS, inputData);
#if UNITY_VERSION >= 60000000
SETUP_DEBUG_TEXTURE_DATA(inputData, UNDO_TRANSFORM_TEX(input.uv, _BaseMap));
#else
SETUP_DEBUG_TEXTURE_DATA(inputData, input.uv, _BaseMap);
#endif
#if defined(_DBUFFER)
ApplyDecalToSurfaceData(input.positionCS, surfaceData, inputData);
#endif
#if UNITY_VERSION >= 60000000
InitializeBakedGIData(input, inputData);
#endif
//[NiloToon] add:
//==========================================================================================================================================================
// debug on off
if(_NiloToonGlobalEnviMinimumShader)
{
Light mainLight = GetMainLight();
outColor = half4(saturate(dot(mainLight.direction, input.normalWS)) * mainLight.color * surfaceData.albedo,1);
return;
}
// GI edit and override
inputData.bakedGI = inputData.bakedGI * _NiloToonGlobalEnviGITintColor + _NiloToonGlobalEnviGIAddColor;
inputData.bakedGI = lerp(inputData.bakedGI, _NiloToonGlobalEnviGIOverride.rgb, _NiloToonGlobalEnviGIOverride.a);
//==========================================================================================================================================================
half4 color = UniversalFragmentPBR(inputData, surfaceData);
//[NiloToon] add:
//==========================================================================================================================================================
// copy from URP10.4's Lighting.hlsl->UniversalFragmentPBR()
// To ensure backward compatibility we have to avoid using shadowMask input, as it is not present in older shaders
#if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
half4 shadowMask = inputData.shadowMask;
#elif !defined (LIGHTMAP_ON)
half4 shadowMask = unity_ProbesOcclusion;
#else
half4 shadowMask = half4(1, 1, 1, 1);
#endif
Light mainLight = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask);
// NiloToon Character Self Shadow
#if defined(_RECEIVE_NILOTOON_CHAR_SHADOW) && defined(_NILOTOON_RECEIVE_SELF_SHADOW)
{
float linearEyeDepth = abs(mul(UNITY_MATRIX_V, float4(input.positionWS, 1)).z);
half charSelfShadow = SampleNiloToonCharSelfShadow(input.positionWS, inputData.normalWS, linearEyeDepth);
charSelfShadow = lerp(1, charSelfShadow, _NiloToonCharShadowStrength * _GlobalReceiveNiloToonSelfShadowMap);
color.rgb *= charSelfShadow;
}
#endif
// shadow border tint color
float isShadowEdge = 1-abs(mainLight.shadowAttenuation-0.5)*2;
color.rgb = lerp(color.rgb,color.rgb * _NiloToonGlobalEnviShadowBorderTintColor.rgb, isShadowEdge * _NiloToonGlobalEnviShadowBorderTintColor.a);
// global surface color result override
color.rgb = lerp(color.rgb,_NiloToonGlobalEnviSurfaceColorResultOverrideColor.rgb, _NiloToonGlobalEnviSurfaceColorResultOverrideColor.a);
float2 SV_POSITIONxy = input.positionCS.xy;
// screen space outline
#if _NILOTOON_GLOBAL_ENABLE_SCREENSPACE_OUTLINE || _NILOTOON_GLOBAL_ENABLE_SCREENSPACE_OUTLINE_V2
// we receive screen space outline only when material's SurfaceType is Opaque.
// (_Surface == 0 when SurfaceType is Opaque)
// (_Surface == 1 when SurfaceType is Transparent)
// *see BaseShaderGUI.cs in URP package
if(_Surface == 0)
{
#if _NILOTOON_GLOBAL_ENABLE_SCREENSPACE_OUTLINE
{
float finalOutlineWidth = _ScreenSpaceOutlineWidth * _GlobalScreenSpaceOutlineWidthMultiplierForEnvi;
float finalNormalsSensitivity = max(0,1 + _GlobalScreenSpaceOutlineNormalsSensitivityOffsetForEnvi); // max(0,x) to prevent negative sensitivity
float finalDepthSensitivity = max(0,1 + _GlobalScreenSpaceOutlineDepthSensitivityOffsetForEnvi); // max(0,x) to prevent negative
float selfLinearDepth = abs(mul(UNITY_MATRIX_V,float4(input.positionWS,1)).z);
// reduce finalDepthSensitivity according to depth
finalDepthSensitivity *= 0.35; // make GUI's default value is 1
float isScreenSpaceOutlineArea = IsScreenSpaceOutline(
SV_POSITIONxy,
finalOutlineWidth,
finalDepthSensitivity,
finalNormalsSensitivity,
selfLinearDepth,
_GlobalScreenSpaceOutlineDepthSensitivityDistanceFadeoutStrengthForEnvi,
_CurrentCameraFOV,
inputData.viewDirectionWS);
isScreenSpaceOutlineArea *= _GlobalScreenSpaceOutlineIntensityForEnvi * _ScreenSpaceOutlineIntensity;
color.rgb = lerp(color.rgb, color.rgb * _GlobalScreenSpaceOutlineTintColorForEnvi * _ScreenSpaceOutlineColor.rgb, isScreenSpaceOutlineArea);
}
#endif
//---------------------------------------------------------------
#if _NILOTOON_GLOBAL_ENABLE_SCREENSPACE_OUTLINE_V2
{
// TODO: receive from renderer feature V2
float width = _GlobalScreenSpaceOutlineV2WidthMultiplierForEnvi;
float GeometryEdgeThreshold = _GlobalScreenSpaceOutlineV2GeometryEdgeThresholdForEnvi;
float NormalAngleCosThetaThresholdMin = _GlobalScreenSpaceOutlineV2NormalAngleCosThetaThresholdForEnvi;
float NormalAngleCosThetaThresholdMax = cos(DegToRad(180));
bool DrawGeometryEdge = _GlobalScreenSpaceOutlineV2EnableGeometryEdgeForEnvi;
bool DrawNormalAngleEdge = _GlobalScreenSpaceOutlineV2EnableNormalAngleEdgeForEnvi;
bool DrawMaterialIDBoundary = false; // not supported for envi
bool DrawCustomIDBoundary = false; // not supported for envi
bool DrawWireframe = false;
float isScreenSpaceOutlineArea = IsScreenSpaceOutlineV2(
SV_POSITIONxy,
width,
GeometryEdgeThreshold,
NormalAngleCosThetaThresholdMin,
NormalAngleCosThetaThresholdMax,
DrawGeometryEdge,
DrawNormalAngleEdge,
DrawMaterialIDBoundary,
DrawCustomIDBoundary,
DrawWireframe,
input.positionWS);
color.rgb *= 1-isScreenSpaceOutlineArea * _GlobalScreenSpaceOutlineV2IntensityForEnvi;
}
#endif
}
#endif
ApplyCustomUserLogicBeforeFog(color, surfaceData, inputData);
//==========================================================================================================================================================
color.rgb = MixFog(color.rgb, inputData.fogCoord);
//[NiloToon] add:
//==========================================================================================================================================================
ApplyCustomUserLogicAfterFog(color, surfaceData, inputData);
//==========================================================================================================================================================
#if UNITY_VERSION >= 202220
color.a = OutputAlpha(color.a, IsSurfaceTypeTransparent(_Surface));
#else
color.a = OutputAlpha(color.a, _Surface);
#endif
outColor = color;
#ifdef _WRITE_RENDERING_LAYERS
uint renderingLayers = GetMeshRenderingLayer();
outRenderingLayers = float4(EncodeMeshRenderingLayer(renderingLayers), 0, 0, 0);
#endif
}