Skip to content

Instantly share code, notes, and snippets.

@xDavidLeon
Created May 18, 2017 14:43
Show Gist options
  • Save xDavidLeon/690fffea93dde2d3f47c19ea87a19b02 to your computer and use it in GitHub Desktop.
Save xDavidLeon/690fffea93dde2d3f47c19ea87a19b02 to your computer and use it in GitHub Desktop.
Unity 5.6 Deferred Cel Shading Modification
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
// Modifications by David Leon. Copyright (c) 2017 Lince Works SL. MIT license (see license.txt)
Shader "ToonDeferredShading2017" {
Properties {
_LightTexture0 ("", any) = "" {}
_LightTextureB0 ("", 2D) = "" {}
_ShadowMapTexture ("", any) = "" {}
_SrcBlend ("", Float) = 1
_DstBlend ("", Float) = 1
}
SubShader {
// Pass 1: Lighting pass
// LDR case - Lighting encoded into a subtractive ARGB8 buffer
// HDR case - Lighting additively blended into floating point buffer
Pass {
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
CGPROGRAM
#define UNITY_BRDF_PBS BRDF_Unity_Toon
#pragma target 3.0
#pragma vertex vert_deferred
#pragma fragment frag
#pragma multi_compile_lightpass
#pragma multi_compile ___ UNITY_HDR_ON
#pragma exclude_renderers nomrt
#include "UnityCG.cginc"
#include "UnityDeferredLibrary.cginc"
//#include "UnityPBSLighting.cginc"
#include "UnityStandardUtils.cginc"
#include "UnityGBuffer.cginc"
#include "UnityStandardBRDF.cginc"
#include "UnityStandardBRDFCustom.cginc"
sampler2D _CameraGBufferTexture0;
sampler2D _CameraGBufferTexture1;
sampler2D _CameraGBufferTexture2;
half4 CalculateLight (unity_v2f_deferred i)
{
float3 wpos;
float2 uv;
float atten, fadeDist;
UnityLight light;
UNITY_INITIALIZE_OUTPUT(UnityLight, light);
UnityDeferredCalculateLightParams(i, wpos, uv, light.dir, atten, fadeDist);
light.color = _LightColor.rgb * atten;
// unpack Gbuffer
half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv);
half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv);
half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv);
UnityStandardData data = UnityStandardDataFromGbuffer(gbuffer0, gbuffer1, gbuffer2);
float3 eyeVec = normalize(wpos-_WorldSpaceCameraPos);
half oneMinusReflectivity = 1 - SpecularStrength(data.specularColor.rgb);
UnityIndirect ind;
UNITY_INITIALIZE_OUTPUT(UnityIndirect, ind);
ind.diffuse = 0;
ind.specular = 0;
half4 res = UNITY_BRDF_PBS (data.diffuseColor, data.specularColor, oneMinusReflectivity, data.smoothness, data.normalWorld, -eyeVec, light, ind);
return res;
}
#ifdef UNITY_HDR_ON
half4
#else
fixed4
#endif
frag (unity_v2f_deferred i) : SV_Target
{
half4 c = CalculateLight(i);
#ifdef UNITY_HDR_ON
return c;
#else
return exp2(-c);
#endif
}
ENDCG
}
// Pass 2: Final decode pass.
// Used only with HDR off, to decode the logarithmic buffer into the main RT
Pass {
ZTest Always Cull Off ZWrite Off
Stencil {
ref [_StencilNonBackground]
readmask [_StencilNonBackground]
// Normally just comp would be sufficient, but there's a bug and only front face stencil state is set (case 583207)
compback equal
compfront equal
}
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma exclude_renderers nomrt
#include "UnityCG.cginc"
sampler2D _LightBuffer;
struct v2f {
float4 vertex : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
v2f vert (float4 vertex : POSITION, float2 texcoord : TEXCOORD0)
{
v2f o;
o.vertex = UnityObjectToClipPos(vertex);
o.texcoord = texcoord.xy;
#ifdef UNITY_SINGLE_PASS_STEREO
o.texcoord = TransformStereoScreenSpaceTex(o.texcoord, 1.0f);
#endif
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return -log2(tex2D(_LightBuffer, i.texcoord));
}
ENDCG
}
}
Fallback Off
}
#include "UnityCG.cginc"
#include "UnityStandardConfig.cginc"
#include "UnityLightingCommon.cginc"
half4 BRDF_Unity_Toon(half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
half3 normal, half3 viewDir,
UnityLight light, UnityIndirect gi)
{
half3 halfDir = Unity_SafeNormalize(light.dir + viewDir);
half nl = smoothstep(0.0, 0.05, saturate(dot(normal, light.dir)));
half nh = saturate(dot(normal, halfDir));
half nv = saturate(dot(normal, viewDir));
half lh = saturate(dot(light.dir, halfDir));
// Specular term
half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness);
half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
#if UNITY_BRDF_GGX
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel
// See "Optimizing PBR for Mobile" from Siggraph 2015 moving mobile graphics course
// https://community.arm.com/events/1155
half a = roughness;
half a2 = a*a;
half d = nh * nh * (a2 - 1.h) + 1.00001h;
#ifdef UNITY_COLORSPACE_GAMMA
// Tighter approximation for Gamma only rendering mode!
// DVF = sqrt(DVF);
// DVF = (a * sqrt(.25)) / (max(sqrt(0.1), lh)*sqrt(roughness + .5) * d);
half specularTerm = a / (max(0.32h, lh) * (1.5h + roughness) * d);
#else
half specularTerm = a2 / (max(0.1h, lh*lh) * (roughness + 0.5h) * (d * d) * 4);
#endif
// on mobiles (where half actually means something) denominator have risk of overflow
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)
// sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))
#if defined (SHADER_API_MOBILE)
specularTerm = specularTerm - 1e-4h;
#endif
#else
// Legacy
half specularPower = PerceptualRoughnessToSpecPower(perceptualRoughness);
// Modified with approximate Visibility function that takes roughness into account
// Original ((n+1)*N.H^n) / (8*Pi * L.H^3) didn't take into account roughness
// and produced extremely bright specular at grazing angles
half invV = lh * lh * smoothness + perceptualRoughness * perceptualRoughness; // approx ModifiedKelemenVisibilityTerm(lh, perceptualRoughness);
half invF = lh;
half specularTerm = ((specularPower + 1) * pow(nh, specularPower)) / (8 * invV * invF + 1e-4h);
#ifdef UNITY_COLORSPACE_GAMMA
specularTerm = sqrt(max(1e-4h, specularTerm));
#endif
#endif
#if defined (SHADER_API_MOBILE)
specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles
#endif
#if defined(_SPECULARHIGHLIGHTS_OFF)
specularTerm = 0.0;
#endif
// surfaceReduction = Int D(NdotH) * NdotH * Id(NdotL>0) dH = 1/(realRoughness^2+1)
// 1-0.28*x^3 as approximation for (1/(x^4+1))^(1/2.2) on the domain [0;1]
// 1-x^3*(0.6-0.08*x) approximation for 1/(x^4+1)
#ifdef UNITY_COLORSPACE_GAMMA
half surfaceReduction = 0.28;
#else
half surfaceReduction = (0.6 - 0.08*perceptualRoughness);
#endif
surfaceReduction = 1.0 - roughness*perceptualRoughness*surfaceReduction;
half grazingTerm = saturate(smoothness + (1 - oneMinusReflectivity));
half3 color = (diffColor + specularTerm * specColor) * light.color * nl
+ gi.diffuse * diffColor
+ surfaceReduction * gi.specular * FresnelLerpFast(specColor, grazingTerm, nv);
return half4(color, 1);
}
@beep2bleep
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment