2022-01-17 11:26:35 +03:00

552 lines
17 KiB
HLSL

//////////////////////////////////////////////////////
// MK Toon Pipeline //
// //
// Created by Michael Kremmel //
// www.michaelkremmel.de //
// Copyright © 2021 All rights reserved. //
//////////////////////////////////////////////////////
#ifndef MK_TOON_PIPELINE
#define MK_TOON_PIPELINE
#include "Config.hlsl"
#if defined(MK_URP)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#elif defined(MK_LWRP)
#include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Lighting.hlsl"
#else
#include "AutoLight.cginc"
#include "UnityGlobalIllumination.cginc"
#endif
/////////////////////////////////////////////////////////////////////////////////////////////
// Helpers
/////////////////////////////////////////////////////////////////////////////////////////////
//Somehow on Metal overloaded methods (with different types) cause a redefinition compiler issue
//therefore force float only on Metal here
#ifndef SHADER_API_METAL
half SafeDivide(half v, half d)
{
return v / (d + HALF_MIN);
}
half2 SafeDivide(half2 v, half d)
{
return v / (d + HALF_MIN);
}
half2 SafeDivide(half2 v, half2 d)
{
return v / (d + HALF_MIN);
}
half3 SafeDivide(half3 v, half d)
{
return v / (d + HALF_MIN);
}
half3 SafeDivide(half3 v, half3 d)
{
return v / (d + HALF_MIN);
}
half4 SafeDivide(half4 v, half d)
{
return v / (d + HALF_MIN);
}
half4 SafeDivide(half4 v, half4 d)
{
return v / (d + HALF_MIN);
}
#endif
float SafeDivide(float v, float d)
{
return v / (d + HALF_MIN);
}
float2 SafeDivide(float2 v, float d)
{
return v / (d + HALF_MIN);
}
float2 SafeDivide(float2 v, float2 d)
{
return v / (d + HALF_MIN);
}
float3 SafeDivide(float3 v, float d)
{
return v / (d + HALF_MIN);
}
float3 SafeDivide(float3 v, float3 d)
{
return v / (d + HALF_MIN);
}
float4 SafeDivide(float4 v, float d)
{
return v / (d + HALF_MIN);
}
float4 SafeDivide(float4 v, float4 d)
{
return v / (d + HALF_MIN);
}
half SafeNormalize(half v)
{
return normalize(v + HALF_MIN);
}
half2 SafeNormalize(half2 v)
{
return normalize(v + HALF_MIN);
}
half3 SafeNormalize(half3 v)
{
return normalize(v + HALF_MIN);
}
half4 SafeNormalize(half4 v)
{
return normalize(v + HALF_MIN);
}
inline half FastPow2(half v)
{
return v * v;
}
inline half FastPow3(half v)
{
return v * v * v;
}
inline half FastPow4(half v)
{
return v * v * v * v;
}
inline half FastPow5(half v)
{
return v * v * v * v * v;
}
//Single Component Reciprocal
inline half Rcp(half v)
{
#if SHADER_TARGET >= 50
return rcp(v);
#else
//avoid division by 0
return SafeDivide(1.0, v);
#endif
}
//modified clip function for a complete discard when input equal zero oder smaller
inline void Clip0(half c)
{
//if(any(c < 0.0)) discard;
clip(c + HALF_MIN);
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Sampling
/////////////////////////////////////////////////////////////////////////////////////////////
#if SHADER_TARGET >= 35
#if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
#define UNIFORM_TEXTURE_2D_AUTO(textureName) uniform Texture2DArray<half4> textureName;
#define UNIFORM_SAMPLER_AND_TEXTURE_2D_AUTO(textureName) uniform Texture2DArray<half4> textureName; uniform SamplerState sampler##textureName;
#define DECLARE_TEXTURE_2D_ARGS_AUTO(textureName, samplerName) Texture2DArray<half4> textureName, SamplerState samplerName
#define UNIFORM_SAMPLER_AND_TEXTURE_2D_AUTO_HP(textureName) uniform Texture2DArray<float4> textureName; uniform SamplerState sampler##textureName;
#define DECLARE_TEXTURE_2D_ARGS_AUTO_HP(textureName, samplerName) Texture2DArray<float4> textureName, SamplerState samplerName
#else
#define UNIFORM_TEXTURE_2D_AUTO(textureName) uniform Texture2D<half4> textureName;
#define UNIFORM_SAMPLER_AND_TEXTURE_2D_AUTO(textureName) uniform Texture2D<half4> textureName; uniform SamplerState sampler##textureName;
#define DECLARE_TEXTURE_2D_ARGS_AUTO(textureName, samplerName) Texture2D<half4> textureName, SamplerState samplerName
#define UNIFORM_SAMPLER_AND_TEXTURE_2D_AUTO_HP(textureName) uniform Texture2D<float4> textureName; uniform SamplerState sampler##textureName;
#define DECLARE_TEXTURE_2D_ARGS_AUTO_HP(textureName, samplerName) Texture2D<float4> textureName, SamplerState samplerName
#endif
#define DECLARE_TEXTURE_2D_ARGS(textureName, samplerName) Texture2D<half4> textureName, SamplerState samplerName
#define UNIFORM_SAMPLER(samplerName) uniform SamplerState sampler##samplerName;
#define UNIFORM_TEXTURE_2D(textureName) uniform Texture2D<half4> textureName;
#define PASS_TEXTURE_2D(textureName, samplerName) textureName, samplerName
#else
#define UNIFORM_TEXTURE_2D_AUTO(textureName) uniform sampler2D textureName;
#define UNIFORM_SAMPLER_AND_TEXTURE_2D_AUTO(textureName) uniform sampler2D textureName;
#define DECLARE_TEXTURE_2D_ARGS_AUTO(textureName, samplerName) sampler2D textureName
#define UNIFORM_SAMPLER_AND_TEXTURE_2D_AUTO_HP(textureName) uniform sampler2D textureName;
#define DECLARE_TEXTURE_2D_ARGS_AUTO_HP(textureName, samplerName) sampler2D textureName
#define DECLARE_TEXTURE_2D_ARGS(textureName, samplerName) sampler2D textureName
#define UNIFORM_SAMPLER(samplerName)
#define UNIFORM_TEXTURE_2D(textureName) uniform sampler2D textureName;
#define PASS_TEXTURE_2D(textureName, samplerName) textureName
#endif
#ifdef MK_POINT_FILTERING
UNIFORM_SAMPLER(_point_repeat_Main)
#else
UNIFORM_SAMPLER(_linear_repeat_Main)
#endif
UNIFORM_SAMPLER(_point_clamp_Main)
#if SHADER_TARGET >= 35
#ifdef MK_POINT_FILTERING
#ifndef SAMPLER_REPEAT_MAIN
#define SAMPLER_REPEAT_MAIN sampler_point_repeat_Main
#endif
#else
#ifndef SAMPLER_REPEAT_MAIN
#define SAMPLER_REPEAT_MAIN sampler_linear_repeat_Main
#endif
#endif
#ifndef SAMPLER_CLAMPED_MAIN
#define SAMPLER_CLAMPED_MAIN sampler_point_clamp_Main
#endif
#else
#ifndef SAMPLER_REPEAT_MAIN
#define SAMPLER_REPEAT_MAIN 0
#endif
#ifndef SAMPLER_CLAMPED_MAIN
#define SAMPLER_CLAMPED_MAIN 0
#endif
#endif
inline half4 SampleTex2DAuto(DECLARE_TEXTURE_2D_ARGS_AUTO(tex, samplerTex), float2 uv)
{
#if SHADER_TARGET >= 35
#if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
return tex.SampleLevel(samplerTex, float3((uv).xy, (float)unity_StereoEyeIndex), 0);
#else
return tex.SampleLevel(samplerTex, UnityStereoTransformScreenSpaceTex(uv), 0);
#endif
#else
return tex2D(tex, UnityStereoTransformScreenSpaceTex(uv));
#endif
}
inline float4 SampleTex2DAutoHP(DECLARE_TEXTURE_2D_ARGS_AUTO_HP(tex, samplerTex), float2 uv)
{
#if SHADER_TARGET >= 35
#if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
return tex.SampleLevel(samplerTex, float3((uv).xy, (float)unity_StereoEyeIndex), 0);
#else
return tex.SampleLevel(samplerTex, UnityStereoTransformScreenSpaceTex(uv), 0);
#endif
#else
return tex2D(tex, UnityStereoTransformScreenSpaceTex(uv));
#endif
}
inline half4 SampleTex2D(DECLARE_TEXTURE_2D_ARGS(tex, samplerTex), float2 uv)
{
#if SHADER_TARGET >= 35
return tex.Sample(samplerTex, uv);
#else
return tex2D(tex, uv);
#endif
}
//Clamped ramp samplings
/*
inline half4 SampleRamp1D(DECLARE_TEXTURE_2D_ARGS(ramp, samplerTex), half value)
{
#if SHADER_TARGET >= 35
return ramp.Sample(samplerTex, float2(clamp(value, HALF_MIN, ONE_MINUS_HALF_MIN), 0.5));
#else
return SampleTex2D(PASS_TEXTURE_2D(ramp, samplerTex), float2(clamp(value, HALF_MIN, ONE_MINUS_HALF_MIN), 0.5));
#endif
}
inline half4 SampleRamp2D(DECLARE_TEXTURE_2D_ARGS(ramp, samplerTex), half2 value)
{
#if SHADER_TARGET >= 35
return ramp.Sample(samplerTex, clamp(value, HALF_MIN, ONE_MINUS_HALF_MIN));
#else
return SampleTex2D(PASS_TEXTURE_2D(ramp, samplerTex), clamp(value, HALF_MIN, ONE_MINUS_HALF_MIN));
#endif
}
*/
//saturated ramp samplings
inline half4 SampleRamp1D(DECLARE_TEXTURE_2D_ARGS(ramp, samplerTex), half value)
{
#if SHADER_TARGET >= 35
return ramp.Sample(samplerTex, float2(saturate(value), 0.5));
#else
return SampleTex2D(PASS_TEXTURE_2D(ramp, samplerTex), float2(saturate(value), 0.5));
#endif
}
inline half4 SampleRamp2D(DECLARE_TEXTURE_2D_ARGS(ramp, samplerTex), half2 value)
{
#if SHADER_TARGET >= 35
return ramp.Sample(samplerTex, saturate(value));
#else
return SampleTex2D(PASS_TEXTURE_2D(ramp, samplerTex), saturate(value));
#endif
}
/*
//unclamped ramp samplings
inline half4 SampleRamp1D(DECLARE_TEXTURE_2D_ARGS(ramp, samplerTex), half value)
{
#if SHADER_TARGET >= 35
return ramp.Sample(samplerTex, float2(value, 0.5));
#else
return SampleTex2D(PASS_TEXTURE_2D(ramp, samplerTex), float2(value, 0.5));
#endif
}
inline half4 SampleRamp2D(DECLARE_TEXTURE_2D_ARGS(ramp, samplerTex), half2 value)
{
#if SHADER_TARGET >= 35
return ramp.Sample(samplerTex, value);
#else
return SampleTex2D(PASS_TEXTURE_2D(ramp, samplerTex), value);
#endif
}
*/
#ifdef MK_FLIPBOOK
#define SAMPLE_TEX2D_FLIPBOOK(tex, samplerTex, uv, blendUV) SampleTex2DFlipbook(PASS_TEXTURE_2D(tex, samplerTex), uv, blendUV)
#else
#define SAMPLE_TEX2D_FLIPBOOK(tex, samplerTex, uv, blendUV) SampleTex2D(PASS_TEXTURE_2D(tex, SAMPLER_REPEAT_MAIN), uv)
#endif
/*
#ifdef MK_FLIPBOOK
#if SHADER_TARGET >= 35
#define SAMPLE_TEX2D_FLIPBOOK(tex, samplerTex, uv, blendUV) SampleTex2DFlipbook(PASS_TEXTURE_2D(tex, samplerTex), uv, blendUV)
#else
#define SAMPLE_TEX2D_FLIPBOOK(tex, uv, blendUV) SampleTex2DFlipbook(PASS_TEXTURE_2D(tex, SAMPLER_REPEAT_MAIN), uv, blendUV)
#endif
#else
#if SHADER_TARGET >= 35
#define SAMPLE_TEX2D_FLIPBOOK(tex, samplerTex, uv, blendUV) SampleTex2D(PASS_TEXTURE_2D(tex, samplerTex), uv)
#else
#define SAMPLE_TEX2D_FLIPBOOK(tex, uv, blendUV) SampleTex2D(PASS_TEXTURE_2D(tex, SAMPLER_REPEAT_MAIN), uv)
#endif
#endif
*/
inline half4 SampleTex2DFlipbook(DECLARE_TEXTURE_2D_ARGS(tex, samplerTex), float2 uv, float3 blendUV)
{
#ifdef MK_FLIPBOOK
half4 color0 = SampleTex2D(PASS_TEXTURE_2D(tex, samplerTex), uv);
half4 color1 = SampleTex2D(PASS_TEXTURE_2D(tex, samplerTex), blendUV.xy);
return lerp(color0, color1, blendUV.z);
#else
return SampleTex2D(PASS_TEXTURE_2D(tex, samplerTex), uv);
#endif
}
struct TriplanarUV
{
float2 x, y, z;
half3 weights;
};
inline TriplanarUV UVTriplanar(float3 position, float scale, half blend, half3 normal)
{
TriplanarUV uv;
float3 uvp = position * scale;
uv.x = uvp.zy;
uv.y = uvp.xz;
uv.z = uvp.xy;
uv.x.y += 0.5;
uv.z.x += 0.5;
uv.weights = pow(abs(normal), blend);
uv.weights = SafeDivide(uv.weights, uv.weights.x + uv.weights.y + uv.weights.z);
return uv;
}
inline half4 SampleTriplanar(DECLARE_TEXTURE_2D_ARGS(texX, samplerX), DECLARE_TEXTURE_2D_ARGS(texY, samplerY), DECLARE_TEXTURE_2D_ARGS(texZ, samplerZ), TriplanarUV uv)
{
half4 colorX = SampleTex2D(PASS_TEXTURE_2D(texX, samplerX), uv.x);
half4 colorY = SampleTex2D(PASS_TEXTURE_2D(texY, samplerY), uv.y);
half4 colorZ = SampleTex2D(PASS_TEXTURE_2D(texZ, samplerZ), uv.z);
return colorX * uv.weights.x + colorY * uv.weights.y + colorZ * uv.weights.z;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Transformations
/////////////////////////////////////////////////////////////////////////////////////////////
#define CAMERA_POSITION_WORLD _WorldSpaceCameraPos
#define MATRIX_VP UNITY_MATRIX_VP
#define MATRIX_MVP UNITY_MATRIX_MVP
#if defined(MK_URP) || defined(MK_LWRP)
#define MATRIX_M UNITY_MATRIX_M
#define MATRIX_I_M UNITY_MATRIX_I_M
#define VERTEX_INPUT vertexInput
#define SV_CLIP_POS svPositionClip
#else
#define MATRIX_M unity_ObjectToWorld
#define MATRIX_I_M unity_WorldToObject
#define VERTEX_INPUT v
#define SV_CLIP_POS pos
#endif
#define Z_BUFFER_PARAMS _ZBufferParams
inline float4 ComputeObjectToClipSpace(float3 positionObject)
{
return mul(MATRIX_VP, mul(MATRIX_M, float4(positionObject, 1.0)));
//return mul(MATRIX_MVP, float4(positionObject, 1.0));
}
inline float3 ComputeObjectToWorldSpace(float3 positionObject)
{
return mul(MATRIX_M, float4(positionObject, 1.0)).xyz;
}
inline float4 ComputeWorldToClipSpace(float3 positionWorld)
{
return mul(MATRIX_VP, float4(positionWorld, 1.0));
}
inline half3 ComputeNormalWorld(half3 normalDirectionObject)
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return SafeNormalize(mul((float3x3) MATRIX_M, normalDirectionObject));
#else
// Normal need to be multiply by inverse transpose
return SafeNormalize(mul(normalDirectionObject, (float3x3) MATRIX_I_M));
#endif
}
inline half3 ComputeNormalObjectToClipSpace(half3 normalDirectionObject)
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return SafeNormalize(mul((float3x3) UNITY_MATRIX_VP, mul((float3x3) MATRIX_M, normalDirectionObject)));
#else
// Normal need to be multiply by inverse transpose
return SafeNormalize(mul((float3x3) UNITY_MATRIX_VP, mul(normalDirectionObject, (float3x3) MATRIX_I_M)));
#endif
}
inline half3 ComputeTangentWorld(half3 tangentObject)
{
return SafeNormalize(mul((float3x3) MATRIX_M, tangentObject));
}
inline half3 ComputeBitangentWorld(half3 normalWorld, half3 tangentWorld, half scale)
{
return SafeNormalize(cross(normalWorld, tangentWorld)) * scale;
}
inline half3 ComputeViewWorld(float3 positionWorld)
{
return SafeNormalize(CAMERA_POSITION_WORLD - positionWorld);
}
inline half3 ComputeViewObject(float3 positionObject)
{
return SafeNormalize(mul(MATRIX_I_M, float4(CAMERA_POSITION_WORLD, 1)).xyz - positionObject);
}
inline half3 ComputeViewTangent(half3 view, half3 normal, half3 tangent, half3 bitangent)
{
return SafeNormalize(mul(half3x3(tangent, bitangent, normal), view));
}
inline float ComputeLinearDepth(float depth)
{
return Rcp(Z_BUFFER_PARAMS.z * depth + Z_BUFFER_PARAMS.w);
}
inline float4 ComputeNDC(float4 positionClip)
{
float4 ndc;
ndc = positionClip * 0.5;
ndc.xy = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w;
ndc.zw = positionClip.zw;
/*
#if defined(UNITY_SINGLE_PASS_STEREO)
ndc.xy = TransformStereoScreenSpaceTex(ndc.xy, ndc.w);
#endif
*/
ndc.xyz = SafeDivide(ndc.xyz, ndc.w);
return ndc;
}
inline float2 ComputeNormalizedScreenUV(float4 ndc, float4 nullNdc, float scale)
{
//Orthographic camera is hard to handle => no ability to get "size"
//therefore ortho view differs from perspective view
//NDC offset
ndc.xy -= nullNdc.xy;
//Scale based on rendertarget size
#if defined(UNITY_SINGLE_PASS_STEREO)
half aspect = SafeDivide(_ScreenParams.x, _ScreenParams.y);
#else
half aspect = SafeDivide(_ScreenParams.x, _ScreenParams.y);
#endif
ndc.x *= aspect;
ndc.xy *= scale;
ndc.xy *= nullNdc.w;
return ndc.xy;
};
/////////////////////////////////////////////////////////////////////////////////////////////
// Fog
/////////////////////////////////////////////////////////////////////////////////////////////
inline float FogFactorVertex(float zClipSpace)
{
#if defined(MK_URP) || defined(MK_LWRP)
return ComputeFogFactor(zClipSpace);
#else
#if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)
UNITY_CALC_FOG_FACTOR(zClipSpace);
return unityFogFactor;
#else
return zClipSpace;
#endif
#endif
}
inline void ApplyFog(inout half3 color, float fogFactor)
{
#if defined(MK_URP) || defined(MK_LWRP)
color = MixFog(color, fogFactor);
#else
#if defined(MK_FORWARD_BASE_PASS) || defined(MK_OUTLINE_PASS)
UNITY_APPLY_FOG_COLOR(fogFactor, color, unity_FogColor);
#elif defined(MK_FORWARD_ADD_PASS)
UNITY_APPLY_FOG_COLOR(fogFactor, color, half4(0,0,0,0));
#endif
#endif
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Refraction
/////////////////////////////////////////////////////////////////////////////////////////////
#if defined(MK_URP) || defined(MK_LWRP)
UNIFORM_TEXTURE_2D_AUTO(_CameraOpaqueTexture)
#else
UNIFORM_TEXTURE_2D_AUTO(_MKToonRefraction)
#endif
inline half3 SampleRefraction(float2 uv)
{
#if defined(MK_URP) || defined(MK_LWRP)
return SampleTex2DAuto(PASS_TEXTURE_2D(_CameraOpaqueTexture, SAMPLER_CLAMPED_MAIN), uv).rgb;
#else
return SampleTex2DAuto(PASS_TEXTURE_2D(_MKToonRefraction, SAMPLER_CLAMPED_MAIN), uv).rgb;
#endif
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Depth
/////////////////////////////////////////////////////////////////////////////////////////////
UNIFORM_SAMPLER_AND_TEXTURE_2D_AUTO_HP(_CameraDepthTexture)
inline float SampleDepth(float2 uv)
{
return SampleTex2DAutoHP(PASS_TEXTURE_2D(_CameraDepthTexture, SAMPLER_CLAMPED_MAIN), uv).r;
}
#endif