327 lines
12 KiB
HLSL
327 lines
12 KiB
HLSL
|
#ifndef DUSTYROOM_STYLIZED_LIGHTING_INCLUDED
|
||
|
#define DUSTYROOM_STYLIZED_LIGHTING_INCLUDED
|
||
|
|
||
|
#include "UnityPBSLighting.cginc"
|
||
|
|
||
|
UNITY_INSTANCING_BUFFER_START(Props)
|
||
|
|
||
|
UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color)
|
||
|
|
||
|
#ifdef _CELPRIMARYMODE_SINGLE
|
||
|
UNITY_DEFINE_INSTANCED_PROP(fixed4, _ColorDim)
|
||
|
#endif // _CELPRIMARYMODE_SINGLE
|
||
|
|
||
|
#ifdef DR_SPECULAR_ON
|
||
|
UNITY_DEFINE_INSTANCED_PROP(half4, _FlatSpecularColor)
|
||
|
UNITY_DEFINE_INSTANCED_PROP(float, _FlatSpecularSize)
|
||
|
UNITY_DEFINE_INSTANCED_PROP(float, _FlatSpecularEdgeSmoothness)
|
||
|
#endif // DR_SPECULAR_ON
|
||
|
|
||
|
#ifdef DR_RIM_ON
|
||
|
UNITY_DEFINE_INSTANCED_PROP(half4, _FlatRimColor)
|
||
|
UNITY_DEFINE_INSTANCED_PROP(float, _FlatRimSize)
|
||
|
UNITY_DEFINE_INSTANCED_PROP(float, _FlatRimEdgeSmoothness)
|
||
|
UNITY_DEFINE_INSTANCED_PROP(float, _FlatRimLightAlign)
|
||
|
#endif // DR_RIM_ON
|
||
|
|
||
|
UNITY_INSTANCING_BUFFER_END(Props)
|
||
|
|
||
|
half _SelfShadingSize;
|
||
|
half _ShadowEdgeSize;
|
||
|
half _LightContribution;
|
||
|
half _Flatness;
|
||
|
|
||
|
half _UnityShadowPower;
|
||
|
half _UnityShadowSharpness;
|
||
|
half3 _UnityShadowColor;
|
||
|
|
||
|
#ifdef _CELPRIMARYMODE_STEPS
|
||
|
fixed4 _ColorDimSteps;
|
||
|
sampler2D _CelStepTexture;
|
||
|
#endif // _CELPRIMARYMODE_STEPS
|
||
|
|
||
|
#ifdef _CELPRIMARYMODE_CURVE
|
||
|
fixed4 _ColorDimCurve;
|
||
|
sampler2D _CelCurveTexture;
|
||
|
#endif // _CELPRIMARYMODE_CURVE
|
||
|
|
||
|
#ifdef DR_CEL_EXTRA_ON
|
||
|
fixed4 _ColorDimExtra;
|
||
|
half _SelfShadingSizeExtra;
|
||
|
half _ShadowEdgeSizeExtra;
|
||
|
half _FlatnessExtra;
|
||
|
#endif // DR_CEL_EXTRA_ON
|
||
|
|
||
|
#ifdef DR_GRADIENT_ON
|
||
|
half4 _ColorGradient;
|
||
|
half _GradientCenterX;
|
||
|
half _GradientCenterY;
|
||
|
half _GradientSize;
|
||
|
half _GradientAngle;
|
||
|
#endif // DR_GRADIENT_ON
|
||
|
|
||
|
half _TextureImpact;
|
||
|
|
||
|
sampler2D _MainTex;
|
||
|
sampler2D _BumpMap;
|
||
|
|
||
|
float3 _LightmapDirection = float3(1, 0, 0);
|
||
|
float _OverrideLightmapDir = 0;
|
||
|
|
||
|
struct InputObject
|
||
|
{
|
||
|
float2 uv_MainTex;
|
||
|
float2 uv_BumpMap;
|
||
|
|
||
|
float3 viewDir;
|
||
|
float3 lightDir;
|
||
|
float3 worldPos;
|
||
|
float3 worldNormalCustom; // "worldNormal" is a reserved Unity variable.
|
||
|
|
||
|
#ifdef DR_VERTEX_COLORS_ON
|
||
|
float4 color: Color; // Vertex color
|
||
|
#endif // DR_VERTEX_COLORS_ON
|
||
|
};
|
||
|
|
||
|
struct SurfaceOutputDustyroom
|
||
|
{
|
||
|
fixed3 Albedo;
|
||
|
fixed3 Normal;
|
||
|
half3 Emission;
|
||
|
float Smoothness;
|
||
|
float Metallic;
|
||
|
half Occlusion;
|
||
|
fixed Alpha;
|
||
|
float Attenuation;
|
||
|
float SpecularLightmapOcclusion;
|
||
|
};
|
||
|
|
||
|
inline half NdotLTransition(half3 normal, half3 lightDir, half selfShadingSize, half shadowEdgeSize, half flatness) {
|
||
|
// normal and lightDir are assumed to be normalized.
|
||
|
half NdotL = dot(normal, lightDir);
|
||
|
half angleDiff = saturate((NdotL * 0.5 + 0.5) - selfShadingSize);
|
||
|
half angleDiffTransition = smoothstep(0, shadowEdgeSize, angleDiff);
|
||
|
return lerp(angleDiff, angleDiffTransition, flatness);
|
||
|
}
|
||
|
|
||
|
inline half NdotLTransitionPrimary(half3 normal, half3 lightDir) {
|
||
|
return NdotLTransition(normal, lightDir, _SelfShadingSize, _ShadowEdgeSize, _Flatness);
|
||
|
}
|
||
|
|
||
|
#if defined(DR_CEL_EXTRA_ON)
|
||
|
inline half NdotLTransitionExtra(half3 normal, half3 lightDir) {
|
||
|
return NdotLTransition(normal, lightDir, _SelfShadingSizeExtra, _ShadowEdgeSizeExtra, _FlatnessExtra);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
inline half NdotLTransitionTexture(half3 normal, half3 lightDir, sampler2D stepTex) {
|
||
|
half NdotL = dot(normal, lightDir);
|
||
|
half angleDiff = saturate((NdotL * 0.5 + 0.5) - _SelfShadingSize);
|
||
|
half4 rampColor = tex2D(stepTex, half2(angleDiff, 0.5));
|
||
|
// NOTE: The color channel here corresponds to the texture format in the shader editor script.
|
||
|
half angleDiffTransition = rampColor.r;
|
||
|
return angleDiffTransition;
|
||
|
}
|
||
|
|
||
|
inline half4 LightingDustyroomStylized(inout SurfaceOutputDustyroom s, half3 viewDir, UnityGI gi) {
|
||
|
half attenSharpened = saturate(s.Attenuation * _UnityShadowSharpness);
|
||
|
|
||
|
#if defined(_UNITYSHADOWMODE_COLOR) && defined(USING_DIRECTIONAL_LIGHT)
|
||
|
s.Albedo = lerp(_UnityShadowColor, s.Albedo, attenSharpened);
|
||
|
#endif
|
||
|
|
||
|
#if defined(USING_DIRECTIONAL_LIGHT)
|
||
|
half3 light = lerp(half3(1, 1, 1), _LightColor0.rgb, _LightContribution);
|
||
|
#else
|
||
|
half3 light = gi.light.color.rgb;
|
||
|
#endif
|
||
|
|
||
|
half unityShadowPower = 1; // Corresponds to no shadow mode keyword.
|
||
|
#if defined(_UNITYSHADOWMODE_MULTIPLY)
|
||
|
unityShadowPower = lerp(1, attenSharpened, _UnityShadowPower);
|
||
|
#endif
|
||
|
|
||
|
half4 c;
|
||
|
c.rgb = s.Albedo * light * unityShadowPower;
|
||
|
|
||
|
#if defined(UNITY_LIGHT_FUNCTION_APPLY_INDIRECT)
|
||
|
c.rgb += s.Albedo * gi.indirect.diffuse;
|
||
|
#endif
|
||
|
|
||
|
c.a = s.Alpha;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
inline void LightingDustyroomStylized_GI(inout SurfaceOutputDustyroom s, UnityGIInput data, inout UnityGI gi)
|
||
|
{
|
||
|
gi = UnityGlobalIllumination(data, s.Occlusion, s.Normal);
|
||
|
s.Attenuation = data.atten;
|
||
|
// TODO: Customize lightmap handling. See https://docs.unity3d.com/Manual/SL-SurfaceShaderLighting.html.
|
||
|
}
|
||
|
|
||
|
inline half4 LightingDustyroomStylized_Deferred(
|
||
|
SurfaceOutputDustyroom s, float3 viewDir, UnityGI gi, out half4 outGBuffer0, out half4 outGBuffer1, out half4 outGBuffer2)
|
||
|
{
|
||
|
half oneMinusReflectivity;
|
||
|
half3 specColor;
|
||
|
s.Albedo = DiffuseAndSpecularFromMetallic (s.Albedo, s.Metallic, /*out*/ specColor, /*out*/ oneMinusReflectivity);
|
||
|
|
||
|
half4 c = UNITY_BRDF_PBS (s.Albedo, specColor, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);
|
||
|
|
||
|
UnityStandardData data;
|
||
|
data.diffuseColor = s.Albedo;
|
||
|
data.occlusion = s.Occlusion;
|
||
|
data.specularColor = specColor;
|
||
|
data.smoothness = s.Smoothness;
|
||
|
data.normalWorld = s.Normal;
|
||
|
|
||
|
UnityStandardDataToGbuffer(data, outGBuffer0, outGBuffer1, outGBuffer2);
|
||
|
|
||
|
half4 emission = half4(s.Emission + c.rgb, 1);
|
||
|
return emission;
|
||
|
}
|
||
|
|
||
|
inline half4 LightingDustyroomStylizedSpecular_Deferred(
|
||
|
SurfaceOutputDustyroom s, float3 viewDir, UnityGI gi, out half4 outGBuffer0, out half4 outGBuffer1, out half4 outGBuffer2)
|
||
|
{
|
||
|
// energy conservation
|
||
|
half oneMinusReflectivity;
|
||
|
s.Albedo = EnergyConservationBetweenDiffuseAndSpecular (s.Albedo, /*s.Specular*/s.Albedo, /*out*/ oneMinusReflectivity);
|
||
|
|
||
|
half4 c = UNITY_BRDF_PBS (s.Albedo, /*s.Specular*/s.Albedo, oneMinusReflectivity, s.Smoothness, s.Normal, viewDir, gi.light, gi.indirect);
|
||
|
|
||
|
UnityStandardData data;
|
||
|
data.diffuseColor = s.Albedo;
|
||
|
data.occlusion = s.Occlusion;
|
||
|
data.specularColor = /*s.Specular*/c;
|
||
|
data.smoothness = s.Smoothness;
|
||
|
data.normalWorld = s.Normal;
|
||
|
|
||
|
UnityStandardDataToGbuffer(data, outGBuffer0, outGBuffer1, outGBuffer2);
|
||
|
|
||
|
half4 emission = half4(s.Emission + c.rgb, 1);
|
||
|
return emission;
|
||
|
}
|
||
|
|
||
|
inline void LightingDustyroomStylizedSpecular_GI (
|
||
|
SurfaceOutputDustyroom s,
|
||
|
UnityGIInput data,
|
||
|
inout UnityGI gi)
|
||
|
{
|
||
|
#if defined(UNITY_PASS_DEFERRED) && UNITY_ENABLE_REFLECTION_BUFFERS
|
||
|
gi = UnityGlobalIllumination(data, s.Occlusion, s.Normal);
|
||
|
#else
|
||
|
Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(s.Smoothness, data.worldViewDir, s.Normal, /*s.Specular*/s.Albedo);
|
||
|
gi = UnityGlobalIllumination(data, s.Occlusion, s.Normal, g);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void vertObject(inout appdata_full v, out InputObject o) {
|
||
|
UNITY_INITIALIZE_OUTPUT(InputObject, o);
|
||
|
o.lightDir = WorldSpaceLightDir(v.vertex);
|
||
|
o.worldNormalCustom = mul(unity_ObjectToWorld, float4(v.normal, 0.0)).xyz;
|
||
|
}
|
||
|
|
||
|
inline half4 SurfaceCore(half3 worldNormal, half3 worldPos, half3 lightDir, half3 viewDir) {
|
||
|
fixed4 c = UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
|
||
|
|
||
|
#if defined(_CELPRIMARYMODE_SINGLE)
|
||
|
half NdotLTPrimary = NdotLTransitionPrimary(worldNormal, lightDir);
|
||
|
c = lerp(UNITY_ACCESS_INSTANCED_PROP(Props, _ColorDim), c, NdotLTPrimary);
|
||
|
#endif // _CELPRIMARYMODE_SINGLE
|
||
|
|
||
|
#if defined(_CELPRIMARYMODE_STEPS)
|
||
|
half NdotLTSteps = NdotLTransitionTexture(worldNormal, lightDir, _CelStepTexture);
|
||
|
c = lerp(_ColorDimSteps, c, NdotLTSteps);
|
||
|
#endif // _CELPRIMARYMODE_STEPS
|
||
|
|
||
|
#if defined(_CELPRIMARYMODE_CURVE)
|
||
|
half NdotLTCurve = NdotLTransitionTexture(worldNormal, lightDir, _CelCurveTexture);
|
||
|
c = lerp(_ColorDimCurve, c, NdotLTCurve);
|
||
|
#endif // _CELPRIMARYMODE_CURVE
|
||
|
|
||
|
#if defined(DR_CEL_EXTRA_ON)
|
||
|
half NdotLTExtra = NdotLTransitionExtra(worldNormal, lightDir);
|
||
|
c = lerp(_ColorDimExtra, c, NdotLTExtra);
|
||
|
#endif // DR_CEL_EXTRA_ON
|
||
|
|
||
|
#if defined(DR_GRADIENT_ON)
|
||
|
float angleRadians = _GradientAngle / 180.0 * 3.14159265359;
|
||
|
float posGradRotated = (worldPos.x - _GradientCenterX) * sin(angleRadians) +
|
||
|
(worldPos.y - _GradientCenterY) * cos(angleRadians);
|
||
|
float gradientTop = _GradientCenterY + _GradientSize * 0.5;
|
||
|
half gradientFactor = saturate((gradientTop - posGradRotated) / _GradientSize);
|
||
|
c = lerp(c, _ColorGradient, gradientFactor);
|
||
|
#endif // DR_GRADIENT_ON
|
||
|
|
||
|
#if defined(DR_RIM_ON)
|
||
|
float rim = 1.0 - dot(viewDir, worldNormal);
|
||
|
half NdotL = dot(worldNormal, lightDir);
|
||
|
float rimLightAlign = UNITY_ACCESS_INSTANCED_PROP(Props, _FlatRimLightAlign);
|
||
|
float rimSize = UNITY_ACCESS_INSTANCED_PROP(Props, _FlatRimSize);
|
||
|
float rimSpread = 1.0 - rimSize - NdotL * rimLightAlign;
|
||
|
float rimEdgeSmooth = UNITY_ACCESS_INSTANCED_PROP(Props, _FlatRimEdgeSmoothness);
|
||
|
float rimTransition = smoothstep(rimSpread - rimEdgeSmooth * 0.5, rimSpread + rimEdgeSmooth * 0.5, rim);
|
||
|
c = lerp(c, UNITY_ACCESS_INSTANCED_PROP(Props, _FlatRimColor), rimTransition);
|
||
|
#endif // DR_RIM_ON
|
||
|
|
||
|
#if defined(DR_SPECULAR_ON)
|
||
|
float3 halfVector = normalize(lightDir + viewDir);
|
||
|
float NdotH = dot(worldNormal, halfVector) * 0.5 + 0.5;
|
||
|
float specularSize = UNITY_ACCESS_INSTANCED_PROP(Props, _FlatSpecularSize);
|
||
|
float specEdgeSmooth = UNITY_ACCESS_INSTANCED_PROP(Props, _FlatSpecularEdgeSmoothness);
|
||
|
float specular = saturate(pow(NdotH, 100.0 * (1.0 - specularSize) * (1.0 - specularSize)));
|
||
|
float specularTransition = smoothstep(0.5 - specEdgeSmooth * 0.1, 0.5 + specEdgeSmooth * 0.1, specular);
|
||
|
c = lerp(c, UNITY_ACCESS_INSTANCED_PROP(Props, _FlatSpecularColor), specularTransition);
|
||
|
#endif // DR_SPECULAR_ON
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
// https://www.gamedev.net/forums/topic/678043-how-to-blend-world-space-normals/5287707/?view=findpost&p=5287707
|
||
|
float3 ReorientNormal(in float3 u, in float3 t, in float3 s)
|
||
|
{
|
||
|
// Build the shortest-arc quaternion
|
||
|
float4 q = float4(cross(s, t), dot(s, t) + 1) / sqrt(2 * (dot(s, t) + 1));
|
||
|
|
||
|
// Rotate the normal
|
||
|
return u * (q.w * q.w - dot(q.xyz, q.xyz)) + 2 * q.xyz * dot(q.xyz, u) + 2 * q.w * cross(q.xyz, u);
|
||
|
}
|
||
|
|
||
|
void surfObject(InputObject IN, inout SurfaceOutputDustyroom o) {
|
||
|
#if !defined(TERRAIN_STANDARD_SHADER)
|
||
|
half3 mapNormal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
|
||
|
mapNormal = UnityObjectToWorldNormal(mapNormal);
|
||
|
half3 zNormal = UnityObjectToWorldNormal(half3(0, 0, 1));
|
||
|
half3 blendedNormal = normalize(ReorientNormal(IN.worldNormalCustom, mapNormal, zNormal));
|
||
|
#else
|
||
|
half3 blendedNormal = IN.worldNormalCustom;
|
||
|
#endif
|
||
|
|
||
|
// If all light in the scene is baked, we use custom light direction for the cel shading.
|
||
|
// IN.lightDir = lerp(IN.lightDir, _LightmapDirection, _EnableLightmapDir);
|
||
|
|
||
|
half4 c = SurfaceCore(blendedNormal, IN.worldPos, IN.lightDir, IN.viewDir);
|
||
|
|
||
|
{
|
||
|
#if defined(_TEXTUREBLENDINGMODE_ADD)
|
||
|
c += lerp(half4(0.0, 0.0, 0.0, 0.0), tex2D(_MainTex, IN.uv_MainTex), _TextureImpact);
|
||
|
#else // _TEXTUREBLENDINGMODE_MULTIPLY
|
||
|
// This is the default blending mode for compatibility with the v.1 of the asset.
|
||
|
c *= lerp(half4(1.0, 1.0, 1.0, 1.0), tex2D(_MainTex, IN.uv_MainTex), _TextureImpact);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
{
|
||
|
#ifdef DR_VERTEX_COLORS_ON
|
||
|
c *= IN.color;
|
||
|
#endif // DR_VERTEX_COLORS_ON
|
||
|
}
|
||
|
|
||
|
o.Albedo = c.rgb;
|
||
|
o.Alpha = c.a;
|
||
|
// o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
|
||
|
}
|
||
|
|
||
|
#endif // DUSTYROOM_STYLIZED_LIGHTING_INCLUDED
|