2025-04-25 21:14:54 +09:00

181 lines
7.5 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
// #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
// Required by all Universal Render Pipeline shaders.
// It will include Unity built-in shader variables (except the lighting variables)
// (https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
// It will also include many utilitary functions.
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// Include this if you are doing a lit shader. This includes lighting shader variables,
// lighting and shadow functions
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
// include a few small utility .hlsl files to help us
#include "/../ShaderLibrary/NiloUtilityHLSL/NiloAllUtilIncludes.hlsl"
sampler2D _BaseMap;
sampler2D _OverrideAlphaMap;
#if _NILOTOON_DISSOLVE
sampler2D _DissolveThresholdMap;
#endif
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
// to support GPU instancing and Single Pass Stereo rendering(VR), add the following section
//------------------------------------------------------------------------------------------------------------------------------
UNITY_VERTEX_INPUT_INSTANCE_ID // in non OpenGL / non PSSL, will turn into -> uint instanceID : SV_InstanceID;
//------------------------------------------------------------------------------------------------------------------------------
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
half fogFactor : TEXCOORD1;
// to support GPU instancing and Single Pass Stereo rendering(VR), add the following section
//------------------------------------------------------------------------------------------------------------------------------
UNITY_VERTEX_INPUT_INSTANCE_ID // will turn into this in non OpenGL / non PSSL -> uint instanceID : SV_InstanceID;
UNITY_VERTEX_OUTPUT_STEREO // will turn into this in non OpenGL / non PSSL -> uint stereoTargetEyeIndexAsRTArrayIdx : SV_RenderTargetArrayIndex;
//------------------------------------------------------------------------------------------------------------------------------
};
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
half4 _BaseColor;
// perspective removal
float _PerspectiveRemovalAmount; // total amount
// perspective removal(sphere)
float _PerspectiveRemovalRadius;
//float3 _HeadBonePositionWS; // Converted to global array
// perspective removal(world height)
float _PerspectiveRemovalStartHeight; // usually is world space pos.y 0
float _PerspectiveRemovalEndHeight;
float _DitherFadeoutAmount;
float _PerCharZOffset;
float _ZOffset;
// _NILOTOON_DISSOLVE
float _DissolveAmount;
half _FadeoutByBaseMapAlpha;
// Character ID for read global 1D array or load 1D texture
uint _CharacterID;
CBUFFER_END
half3 _GlobalVolumeMulColor;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Global Arrays
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define MAX_CHARACTER_COUNT 128
float3 _NiloToonGlobalPerCharHeadBonePosWSArray[MAX_CHARACTER_COUNT];
Varyings vert(Attributes IN)
{
Varyings OUT;
// disable rendering sticker if minimum shader debug is on
#if _NILOTOON_FORCE_MINIMUM_SHADER
return (Varyings)0;
#endif
// to support GPU instancing and Single Pass Stereo rendering(VR), add the following section
//------------------------------------------------------------------------------------------------------------------------------
UNITY_SETUP_INSTANCE_ID(IN); // will turn into this in non OpenGL / non PSSL -> UnitySetupInstanceID(input.instanceID);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT); // will turn into this in non OpenGL / non PSSL -> output.instanceID = input.instanceID;
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); // will turn into this in non OpenGL / non PSSL -> output.stereoTargetEyeIndexAsRTArrayIdx = unity_StereoEyeIndex;
//------------------------------------------------------------------------------------------------------------------------------
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
// fog, do it before any positionHCS.z's edit
OUT.fogFactor = ComputeFogFactor(OUT.positionHCS.z);
// zoffset
OUT.positionHCS = NiloGetNewClipPosWithZOffsetVS(OUT.positionHCS, -(_ZOffset+_PerCharZOffset));
// perspective removal
float3 positionWS = mul(UNITY_MATRIX_M, float4(IN.positionOS.xyz,1)).xyz;
OUT.positionHCS = NiloDoPerspectiveRemoval(OUT.positionHCS,positionWS,_NiloToonGlobalPerCharHeadBonePosWSArray[_CharacterID],_PerspectiveRemovalRadius,_PerspectiveRemovalAmount, _PerspectiveRemovalStartHeight, _PerspectiveRemovalEndHeight);
OUT.uv = TRANSFORM_TEX(IN.uv,_BaseMap);
return OUT;
}
half FogAsAlpha(real fogFactor)
{
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
return ComputeFogIntensity(fogFactor);
#else
return 1; // if fog is off, return constant 1 so it will not affect any multiplication (compiler will remove * 1)
#endif
}
half4 frag(Varyings IN) : SV_Target
{
// to support GPU instancing and Single Pass Stereo rendering(VR), add the following section
//------------------------------------------------------------------------------------------------------------------------------
UNITY_SETUP_INSTANCE_ID(IN); // in non OpenGL / non PSSL, MACRO will turn into -> UnitySetupInstanceID(input.instanceID);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN); // in non OpenGL / non PSSL, MACRO will turn into -> unity_StereoEyeIndex = input.stereoTargetEyeIndexAsRTArrayIdx;
//------------------------------------------------------------------------------------------------------------------------------
// dither
#if _NILOTOON_DITHER_FADEOUT
NiloDoDitherFadeoutClip(IN.positionHCS.xy, 1-_DitherFadeoutAmount);
#endif
// dissolve (copied from nilotoon character shader's ApplyDissolve())
#if _NILOTOON_DISSOLVE
// read black and white map
half dissolveMapThresholdMapValue = tex2D(_DissolveThresholdMap, IN.uv).g;
half dissolve = dissolveMapThresholdMapValue - _DissolveAmount;
// clip threshold
clip(dissolve);
// no need to edit color, we only need clip()
//...
#endif
half4 customColor = tex2D(_BaseMap, IN.uv);
#if OVERRIDE_ALPHA
customColor.a = tex2D(_OverrideAlphaMap, IN.uv).r; // TODO: accept r,g,b,a option
#endif
customColor *= _BaseColor;
half fogAsAlpha = FogAsAlpha(IN.fogFactor);
half opacity = customColor.a * fogAsAlpha;
#if NiloToonStickerMultiply
customColor.rgb = lerp(1,customColor.rgb, opacity);
#endif
#if NiloToonStickerAdditive
customColor.rgb *= opacity;
customColor.rgb *= _GlobalVolumeMulColor;
#endif
// return const 1 alpha, since ColorMask is RGB, the return value of alpha doesn't matter
return half4(customColor.rgb, 1);
}