Created
May 18, 2017 14:43
-
-
Save xDavidLeon/690fffea93dde2d3f47c19ea87a19b02 to your computer and use it in GitHub Desktop.
Unity 5.6 Deferred Cel Shading Modification
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for the code and article at http://www.gamasutra.com/blogs/DavidLeon/20170519/298374/NextGen_Cel_Shading_in_Unity_56.php