summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2024-07-15 00:36:05 -0700
committeryum <yum.food.vr@gmail.com>2024-07-15 00:36:05 -0700
commitd4a703fffb2de50d43c25c4b607b7c7b252fd70e (patch)
treef8c25ed1505a06855ae8941a0749a983eeab049a
parent2af60b243f15a4aa609176a6b0259bb4d2f1984f (diff)
Add Toon shading mode
Same as "realistic" except spherical harmonics all get the same normal. Approach derived from Poiyomi Toon shader.
-rw-r--r--Editor/tooner.cs3
-rw-r--r--pbr.cginc46
-rw-r--r--poi.cginc40
3 files changed, 66 insertions, 23 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs
index e7fdf6b..adc0fca 100644
--- a/Editor/tooner.cs
+++ b/Editor/tooner.cs
@@ -476,7 +476,8 @@ public class ToonerGUI : ShaderGUI {
enum NormalsMode {
Flat,
Spherical,
- Realistic
+ Realistic,
+ Toon
};
void DoShadingMode() {
diff --git a/pbr.cginc b/pbr.cginc
index 44e0b88..581df3f 100644
--- a/pbr.cginc
+++ b/pbr.cginc
@@ -97,12 +97,11 @@ float3 BoxProjection (
float4 cubemapPosition, float3 boxMin, float3 boxMax
) {
#if UNITY_SPECCUBE_BOX_PROJECTION
- UNITY_BRANCH
if (cubemapPosition.w > 0) {
float3 factors =
((direction > 0 ? boxMax : boxMin) - position) / direction;
float scalar = min(min(factors.x, factors.y), factors.z);
- direction = direction * scalar + (position - cubemapPosition);
+ direction = direction * scalar + (position - cubemapPosition.xyz);
}
#endif
return direction;
@@ -120,7 +119,11 @@ UnityIndirect CreateIndirectLight(float4 vertexLightColor, float3 view_dir, floa
// Avatars are not static, don't use lightmap.
indirect.diffuse = 0;
#else
- indirect.diffuse += max(0, ShadeSH9(float4(normal, 1)));
+ if (_Mesh_Normals_Mode == 3) { // Toon
+ indirect.diffuse += max(0, BetterSH9(float4(0, 0, 0, 1)));
+ } else {
+ indirect.diffuse += max(0, BetterSH9(float4(normal, 1)));
+ }
#endif
float3 reflect_dir = reflect(-view_dir, normal);
Unity_GlossyEnvironmentData env_data;
@@ -133,38 +136,37 @@ UnityIndirect CreateIndirectLight(float4 vertexLightColor, float3 view_dir, floa
float3 probe0 = Unity_GlossyEnvironment(
UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, env_data
);
- env_data.reflUVW = BoxProjection(
- reflect_dir, worldPos,
- unity_SpecCube1_ProbePosition,
- unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax
- );
+ indirect.specular = probe0;
#if UNITY_SPECCUBE_BLENDING
- float interpolator = unity_SpecCube0_BoxMin.w;
- UNITY_BRANCH
- if (interpolator < 0.99999) {
- float3 probe1 = Unity_GlossyEnvironment(
- UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0),
- unity_SpecCube0_HDR, env_data
- );
- indirect.specular = lerp(probe1, probe0, interpolator);
- }
- else {
- indirect.specular = probe0;
- }
+ if (unity_SpecCube0_BoxMin.w < 0.99999) {
+ env_data.reflUVW = BoxProjection(
+ reflect_dir, worldPos,
+ unity_SpecCube1_ProbePosition,
+ unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax
+ );
+ float3 probe1 = Unity_GlossyEnvironment(
+ UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0),
+ unity_SpecCube0_HDR, env_data
+ );
+ indirect.specular = lerp(probe1, probe0, unity_SpecCube0_BoxMin.w);
+ }
#else
indirect.specular = probe0;
#endif // UNITY_SPECCUBE_BLENDING
+ // Lifted from poi toon shader (MIT).
+ float horizon = min(1 + dot(reflect_dir, normal), 1);
+ indirect.specular *= horizon * horizon;
+
#if defined(_CUBEMAP)
float roughness = GetRoughness(smoothness);
- probe0 =
+ indirect.specular =
UNITY_SAMPLE_TEXCUBE_LOD(
_Cubemap,
reflect_dir,
roughness * UNITY_SPECCUBE_LOD_STEPS);
#endif // _CUBEMAP
- indirect.specular = probe0;
#endif // FORWARD_BASE_PASS
indirect.diffuse *= ao;
diff --git a/poi.cginc b/poi.cginc
index 5e31a42..1d2b846 100644
--- a/poi.cginc
+++ b/poi.cginc
@@ -57,4 +57,44 @@ float3 HSVtoRGB(in float3 HSV)
return ((RGB - 1) * HSV.y + 1) * HSV.z;
}
+float shEvaluateDiffuseL1Geomerics_local(float L0, float3 L1, float3 n)
+{
+ // average energy
+ float R0 = max(0, L0);
+
+ // avg direction of incoming light
+ float3 R1 = 0.5f * L1;
+
+ // directional brightness
+ float lenR1 = length(R1);
+
+ // linear angle between normal and direction 0-1
+ //float q = 0.5f * (1.0f + dot(R1 / lenR1, n));
+ //float q = dot(R1 / lenR1, n) * 0.5 + 0.5;
+ float q = dot(normalize(R1), n) * 0.5 + 0.5;
+ q = saturate(q); // Thanks to ScruffyRuffles for the bug identity.
+
+ // power for q
+ // lerps from 1 (linear) to 3 (cubic) based on directionality
+ float p = 1.0f + 2.0f * lenR1 / R0;
+
+ // dynamic range constant
+ // should vary between 4 (highly directional) and 0 (ambient)
+ float a = (1.0f - lenR1 / R0) / (1.0f + lenR1 / R0);
+
+ return R0 * (a + (1.0f - a) * (p + 1.0f) * pow(q, p));
+}
+
+half3 BetterSH9(half4 normal)
+{
+ float3 indirect;
+ float3 L0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w) + float3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z) / 3.0;
+ indirect.r = shEvaluateDiffuseL1Geomerics_local(L0.r, unity_SHAr.xyz, normal.xyz);
+ indirect.g = shEvaluateDiffuseL1Geomerics_local(L0.g, unity_SHAg.xyz, normal.xyz);
+ indirect.b = shEvaluateDiffuseL1Geomerics_local(L0.b, unity_SHAb.xyz, normal.xyz);
+ indirect = max(0, indirect);
+ indirect += SHEvalLinearL2(normal);
+ return indirect;
+}
+
#endif // __POI_INC