// 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 #pragma once half3 BlendGenericMatCapColor(half3 dstCol, half3 srcCol, half3 srcA, uint blendMode) { half3 add = dstCol + srcCol; half3 mul = dstCol * srcCol; half3 outCol = dstCol; if (blendMode == 0) outCol = srcCol; else if (blendMode == 1) outCol = add; else if (blendMode == 2) outCol = max(add - mul, dstCol); else if (blendMode == 3) outCol = mul; return lerp(dstCol, outCol, srcA); } float3 GetGenericMatCapCameraUpWS() { return float3(UNITY_MATRIX_I_V[0][1], UNITY_MATRIX_I_V[1][1], UNITY_MATRIX_I_V[2][1]); } float3 GetGenericMatCapCameraForwardWS() { return normalize(-float3(UNITY_MATRIX_I_V[0][2], UNITY_MATRIX_I_V[1][2], UNITY_MATRIX_I_V[2][2])); } float2 CalcGenericMatCapUV(float2 uv1, float3 normalWS, ToonLightingData lightingData, float4 mapST, float4 blendUV1, half zRotCancel, half perspective, half vrParallaxStrength) { // VR stereo fix: head direction = HMD-center based (stable across eyes), // viewDirection = per-eye (parallax-correct). The vrParallaxStrength slider // lerps between "stable (0)" and "per-eye parallax (1)". Without this fix, // both vectors were equal and the slider had no effect. float3 headDirectionWS = GetMatCapHeadDirectionWS(lightingData.positionWS, lightingData.viewDirectionWS); float3 viewDirectionWS = lightingData.viewDirectionWS; float3 normalVD = normalize(lerp(headDirectionWS, viewDirectionWS, vrParallaxStrength)); if (unity_OrthoParams.w > 0.5 || perspective < 0.5) { normalVD = GetGenericMatCapCameraForwardWS(); } float3 bitangentVD = zRotCancel > 0.5 ? float3(0, 1, 0) : GetGenericMatCapCameraUpWS(); bitangentVD = normalize(bitangentVD - normalVD * dot(bitangentVD, normalVD)); float3 tangentVD = cross(normalVD, bitangentVD); float2 uvMat = float2(dot(tangentVD, normalWS), dot(bitangentVD, normalWS)); uvMat = lerp(uvMat, saturate(uv1) * 2 - 1, blendUV1.xy); uvMat = uvMat * mapST.xy + mapST.zw; return uvMat * 0.5 + 0.5; } // lilToon-faithful matcap is applied as a post-light decoration on the lit color, // not as a pre-light albedo modifier. Inner guard makes the body empty unless the // shader keyword is on AND we are in the ForwardLit pass (matcap should not affect // outline / shadow / depth / stencil passes). void ApplyGenericMatCap1(inout half3 color, ToonSurfaceData surfaceData, Varyings varyings, ToonLightingData lightingData) { #if _GENERIC_MATCAP1 && NiloToonForwardLitPass && !_NILOTOON_FUR half3 normalWS = normalize(lerp(lightingData.normalWS_NoNormalMap, lightingData.normalWS, _GenericMatCap1NormalStrength)); #if _GENERIC_MATCAP1_CUSTOM_NORMAL float2 bumpUv = CalcUV(GetUV(varyings), _GenericMatCap1BumpMap_ST); half3 customNormalTS = UnpackNormalScale(tex2D(_GenericMatCap1BumpMap, bumpUv), _GenericMatCap1BumpScale); normalWS = NormalizeNormalPerPixel(TransformTangentToWorld(customNormalTS, lightingData.TBN_WS)); #endif float2 matCapUv = CalcGenericMatCapUV(GetUV(varyings, 1), normalWS, lightingData, _GenericMatCap1Map_ST, _GenericMatCap1BlendUV1, _GenericMatCap1ZRotCancel, _GenericMatCap1Perspective, _GenericMatCap1VRParallaxStrength); half4 matCapColor = _GenericMatCap1Color * tex2Dlod(_GenericMatCap1Map, float4(matCapUv, 0, _GenericMatCap1Lod)); matCapColor.rgb = lerp(matCapColor.rgb, matCapColor.rgb * saturate(lightingData.mainLight.color), _GenericMatCap1EnableLighting); matCapColor.a = lerp(matCapColor.a, matCapColor.a * lightingData.averageShadowAttenuation, _GenericMatCap1ShadowMask); if (_GenericMatCap1ApplyTransparency > 0.5) { matCapColor.a *= surfaceData.alpha; } matCapColor.a = lightingData.facing < (_GenericMatCap1BackfaceMask - 1.0) ? 0.0 : matCapColor.a; float2 maskUv = CalcUV(GetUV(varyings), _GenericMatCap1Mask_ST); half3 matCapMask = tex2D(_GenericMatCap1Mask, maskUv).rgb; matCapColor.rgb = lerp(matCapColor.rgb, matCapColor.rgb * surfaceData.albedo, _GenericMatCap1MainStrength); color = BlendGenericMatCapColor(color, matCapColor.rgb, _GenericMatCap1Blend * matCapColor.a * matCapMask, _GenericMatCap1BlendMode); #endif } void ApplyGenericMatCap2(inout half3 color, ToonSurfaceData surfaceData, Varyings varyings, ToonLightingData lightingData) { #if _GENERIC_MATCAP2 && NiloToonForwardLitPass && !_NILOTOON_FUR half3 normalWS = normalize(lerp(lightingData.normalWS_NoNormalMap, lightingData.normalWS, _GenericMatCap2NormalStrength)); #if _GENERIC_MATCAP2_CUSTOM_NORMAL float2 bumpUv = CalcUV(GetUV(varyings), _GenericMatCap2BumpMap_ST); half3 customNormalTS = UnpackNormalScale(tex2D(_GenericMatCap2BumpMap, bumpUv), _GenericMatCap2BumpScale); normalWS = NormalizeNormalPerPixel(TransformTangentToWorld(customNormalTS, lightingData.TBN_WS)); #endif float2 matCapUv = CalcGenericMatCapUV(GetUV(varyings, 1), normalWS, lightingData, _GenericMatCap2Map_ST, _GenericMatCap2BlendUV1, _GenericMatCap2ZRotCancel, _GenericMatCap2Perspective, _GenericMatCap2VRParallaxStrength); half4 matCapColor = _GenericMatCap2Color * tex2Dlod(_GenericMatCap2Map, float4(matCapUv, 0, _GenericMatCap2Lod)); matCapColor.rgb = lerp(matCapColor.rgb, matCapColor.rgb * saturate(lightingData.mainLight.color), _GenericMatCap2EnableLighting); matCapColor.a = lerp(matCapColor.a, matCapColor.a * lightingData.averageShadowAttenuation, _GenericMatCap2ShadowMask); if (_GenericMatCap2ApplyTransparency > 0.5) { matCapColor.a *= surfaceData.alpha; } matCapColor.a = lightingData.facing < (_GenericMatCap2BackfaceMask - 1.0) ? 0.0 : matCapColor.a; float2 maskUv = CalcUV(GetUV(varyings), _GenericMatCap2Mask_ST); half3 matCapMask = tex2D(_GenericMatCap2Mask, maskUv).rgb; matCapColor.rgb = lerp(matCapColor.rgb, matCapColor.rgb * surfaceData.albedo, _GenericMatCap2MainStrength); color = BlendGenericMatCapColor(color, matCapColor.rgb, _GenericMatCap2Blend * matCapColor.a * matCapMask, _GenericMatCap2BlendMode); #endif }