summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Editor/tooner.cs83
-rw-r--r--MochieStandardBRDF.cginc176
-rw-r--r--MochieStandardSSR.cginc176
-rw-r--r--MochieStandardSSS.cginc83
-rw-r--r--README.md34
-rw-r--r--feature_macros.cginc1
-rw-r--r--globals.cginc28
-rw-r--r--interpolators.cginc6
-rw-r--r--pbr.cginc77
-rw-r--r--tooner.shader24
-rw-r--r--tooner_lighting.cginc4
11 files changed, 645 insertions, 47 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs
index ba45a5d..e7fdf6b 100644
--- a/Editor/tooner.cs
+++ b/Editor/tooner.cs
@@ -1025,6 +1025,84 @@ public class ToonerGUI : ShaderGUI {
DoGimmickTrochoid();
}
+ void DoMochieParams() {
+ MaterialProperty bc;
+ GUILayout.Label("SSS", EditorStyles.boldLabel);
+ {
+ EditorGUI.indentLevel += 1;
+ bc = FindProperty("_ScatterDist");
+ editor.FloatProperty(bc, "Distance");
+ bc = FindProperty("_ScatterPow");
+ editor.FloatProperty(bc, "Power");
+ bc = FindProperty("_ScatterIntensity");
+ editor.FloatProperty(bc, "Intensity");
+ bc = FindProperty("_ScatterAmbient");
+ editor.FloatProperty(bc, "Ambient");
+ EditorGUI.indentLevel -= 1;
+ }
+ GUILayout.Label("SSR", EditorStyles.boldLabel);
+ {
+ EditorGUI.indentLevel += 1;
+
+ bc = FindProperty("_Enable_SSR");
+ bool enabled = (bc.floatValue != 0.0);
+ EditorGUI.BeginChangeCheck();
+ enabled = EditorGUILayout.Toggle("Enable SSR", enabled);
+ EditorGUI.EndChangeCheck();
+ bc.floatValue = enabled ? 1.0f : 0.0f;
+ SetKeyword("SSR_ENABLED", enabled);
+
+ if (enabled) {
+ bc = FindProperty("_SSRStrength");
+ editor.FloatProperty(bc, "Strength");
+ bc = FindProperty("_SSRHeight");
+ editor.FloatProperty(bc, "Height");
+ bc = FindProperty("_EdgeFade");
+ editor.FloatProperty(bc, "Edge fade");
+ }
+
+ EditorGUI.indentLevel -= 1;
+ }
+ GUILayout.Label("GSAA", EditorStyles.boldLabel);
+ {
+ EditorGUI.indentLevel += 1;
+ bc = FindProperty("_GSAA");
+ editor.FloatProperty(bc, "Enable");
+ bc = FindProperty("_GSAAStrength");
+ editor.FloatProperty(bc, "Strength");
+ EditorGUI.indentLevel -= 1;
+ }
+ bc = FindProperty("_WrappingFactor");
+ editor.FloatProperty(bc, "Wrapping factor");
+ bc = FindProperty("_Subsurface");
+ editor.FloatProperty(bc, "Subsurface");
+ bc = FindProperty("_SpecularStrength");
+ editor.FloatProperty(bc, "Specular strength");
+ bc = FindProperty("_FresnelStrength");
+ editor.FloatProperty(bc, "Fresnel strength");
+ bc = FindProperty("_UseFresnel");
+ editor.FloatProperty(bc, "Use fresnel");
+ bc = FindProperty("_ReflectionStrength");
+ editor.FloatProperty(bc, "Reflection strength");
+ /*
+float _ScatterDist;
+float _ScatterPow;
+float _ScatterIntensity;
+float _ScatterAmbient;
+float _GSAA;
+float _GSAAStrength;
+float _WrappingFactor;
+float _Subsurface;
+float _SpecularStrength;
+float _FresnelStrength;
+float _UseFresnel;
+float _ReflectionStrength;
+float3 shadowedReflections;
+float3 _ReflShadows;
+float3 _ReflShadowStrength;
+*/
+ }
+
enum RenderingMode {
Opaque,
Cutout,
@@ -1286,6 +1364,11 @@ public class ToonerGUI : ShaderGUI {
DoGimmicks();
EditorGUI.indentLevel -= 1;
+ GUILayout.Label("Mochie", EditorStyles.boldLabel);
+ EditorGUI.indentLevel += 1;
+ DoMochieParams();
+ EditorGUI.indentLevel -= 1;
+
GUILayout.Label("Rendering", EditorStyles.boldLabel);
EditorGUI.indentLevel += 1;
DoRendering();
diff --git a/MochieStandardBRDF.cginc b/MochieStandardBRDF.cginc
new file mode 100644
index 0000000..795bbee
--- /dev/null
+++ b/MochieStandardBRDF.cginc
@@ -0,0 +1,176 @@
+#ifndef MOCHIE_STANDARD_BRDF_INCLUDED
+#define MOCHIE_STANDARD_BRDF_INCLUDED
+
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020 MochiesCode
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE
+ * SOFTWARE.
+ */
+
+#include "UnityCG.cginc"
+#include "UnityStandardConfig.cginc"
+#include "UnityLightingCommon.cginc"
+#include "MochieStandardSSR.cginc"
+#include "MochieStandardSSS.cginc"
+
+float3 get_camera_pos() {
+ float3 worldCam;
+ worldCam.x = unity_CameraToWorld[0][3];
+ worldCam.y = unity_CameraToWorld[1][3];
+ worldCam.z = unity_CameraToWorld[2][3];
+ return worldCam;
+}
+
+float GSAARoughness(float3 normal, float roughness){
+ float3 normalDDX = ddx(normal);
+ float3 normalDDY = ddy(normal);
+ float dotX = dot(normalDDX, normalDDX);
+ float dotY = dot(normalDDY, normalDDY);
+ float base = saturate(max(dotX, dotY));
+ return max(roughness, pow(base, 0.333)*_GSAAStrength);
+}
+
+half4 BRDF1_Mochie_PBS (
+ half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,
+ half3 normal, half3 viewDir, half3 worldPos, half2 screenUVs, half4 screenPos,
+ half metallic, half thickness, half3 ssColor, half atten, float2 lightmapUV, float3 vertexColor,
+ UnityLight light, UnityIndirect gi)
+{
+
+ half perceptualRoughness = SmoothnessToPerceptualRoughness(smoothness);
+ if (_GSAA == 1){
+ perceptualRoughness = GSAARoughness(normal, perceptualRoughness);
+ }
+ half3 halfDir = Unity_SafeNormalize (half3(light.dir) + viewDir);
+ half nv = abs(dot(normal, viewDir));
+ half nl = saturate(dot(normal, light.dir));
+ half nh = saturate(dot(normal, halfDir));
+ half lv = saturate(dot(light.dir, viewDir));
+ half lh = saturate(dot(light.dir, halfDir));
+
+ // Diffuse term
+ half diffuseTerm = DisneyDiffuse(nv, nl, lh, perceptualRoughness) * nl;
+ float wrappedDiffuse = saturate((diffuseTerm + _WrappingFactor) /
+ (1.0f + _WrappingFactor)) * 2 / (2 * (1 + _WrappingFactor));
+
+ // Specular term
+ half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
+#if UNITY_BRDF_GGX
+ roughness = max(roughness, 0.002);
+ half V = SmithJointGGXVisibilityTerm (nl, nv, roughness);
+ half D = GGXTerm(nh, roughness);
+#else
+ half V = SmithBeckmannVisibilityTerm (nl, nv, roughness);
+ half D = NDFBlinnPhongNormalizedTerm (nh, PerceptualRoughnessToSpecPower(perceptualRoughness));
+#endif
+
+#if defined(_SPECULARHIGHLIGHTS_OFF)
+ half specularTerm = 0.0;
+#else
+ half specularTerm = V*D * UNITY_PI;
+#ifdef UNITY_COLORSPACE_GAMMA
+ specularTerm = sqrt(max(1e-4h, specularTerm));
+#endif
+ specularTerm = max(0, specularTerm * nl);
+#endif
+ half surfaceReduction;
+#ifdef UNITY_COLORSPACE_GAMMA
+ surfaceReduction = 1.0-0.28*roughness*perceptualRoughness;
+#else
+ surfaceReduction = 1.0 / (roughness*roughness + 1.0);
+#endif
+
+ half grazingTerm = saturate(smoothness + (1-oneMinusReflectivity));
+
+ half3 diffCol = 0;
+ diffCol = diffColor * (gi.diffuse + light.color * lerp(diffuseTerm, wrappedDiffuse, thickness));
+
+ half3 specCol = specularTerm * light.color * FresnelTerm (specColor, lh) * _SpecularStrength;
+ half3 reflCol = surfaceReduction * gi.specular * FresnelLerp (specColor, grazingTerm, lerp(1, nv, _FresnelStrength*_UseFresnel)) * _ReflectionStrength;
+#if SSR_ENABLED
+ half4 ssrCol = GetSSR(worldPos, viewDir, reflect(-viewDir, normal), normal, smoothness, diffColor, metallic, screenUVs, screenPos);
+ ssrCol.rgb *= _SSRStrength;
+ if (_EdgeFade == 0)
+ ssrCol.a = ssrCol.a > 0 ? 1 : 0;
+ reflCol = lerp(reflCol, ssrCol.rgb, ssrCol.a * saturate(_SSRStrength));
+ specCol *= 1-ssrCol.a;
+#endif
+
+ half3 subsurfaceCol = 0;
+ if (_Subsurface == 1){
+ subsurfaceCol = GetSubsurfaceLight(
+ light.color,
+ light.dir,
+ normal,
+ viewDir,
+ atten,
+ thickness,
+ gi.diffuse,
+ ssColor
+ );
+ }
+
+#ifdef LTCGI
+ if (_LTCGIStrength > 0){
+ half3 diffLight = 0;
+ LTCGI_Contribution(
+ worldPos,
+ normal,
+ viewDir,
+ perceptualRoughness,
+ (lightmapUV - unity_LightmapST.zw) / unity_LightmapST.xy,
+ diffLight
+#ifndef _GLOSSYREFLECTIONS_OFF
+ , reflCol
+#endif
+ );
+ diffCol += (diffColor * diffLight) * _LTCGIStrength;
+ }
+#endif
+
+#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
+ if (_ReflShadows == 1){
+ float3 lightmap = Desaturate(DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, lightmapUV)));
+ lightmap = GetContrast(lightmap, _ContrastReflShad);
+ lightmap = lerp(lightmap, GetHDR(lightmap), _HDRReflShad);
+ lightmap *= _BrightnessReflShad;
+ lightmap *= _TintReflShad;
+ shadowedReflections = saturate(lerp(1, lightmap, _ReflShadowStrength));
+ reflCol *= shadowedReflections;
+ specCol *= shadowedReflections;
+ }
+#else
+ shadowedReflections = lerp(1, lerp(1, atten, 0.9), _ReflShadows*_ReflShadowStrength);
+ reflCol *= shadowedReflections;
+#endif
+
+ // #ifdef FULL_VERSION
+ // reflCol *= lerp(1, vertexColor, _ReflVertexColor*_ReflVertexColorStrength);
+ // #endif
+
+ return half4(diffCol + specCol + reflCol + subsurfaceCol, 1);
+}
+
+#endif // MOCHIE_STANDARD_BRDF_INCLUDED
diff --git a/MochieStandardSSR.cginc b/MochieStandardSSR.cginc
new file mode 100644
index 0000000..d7683d7
--- /dev/null
+++ b/MochieStandardSSR.cginc
@@ -0,0 +1,176 @@
+#ifndef MOCHIE_STANDARD_SSR_INCLUDED
+#define MOCHIE_STANDARD_SSR_INCLUDED
+
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020 MochiesCode
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE
+ * SOFTWARE.
+ */
+
+//-----------------------------------------------------------------------------------
+// SCREEN SPACE REFLECTIONS
+//
+// Original made by error.mdl, Toocanzs, and Xiexe.
+// Reworked and updated by Mochie
+//-----------------------------------------------------------------------------------
+
+#if SSR_ENABLED
+
+bool IsInMirror(){
+ return unity_CameraProjection[2][0] != 0.f || unity_CameraProjection[2][1] != 0.f;
+}
+
+float3 GetBlurredGP(const sampler2D ssrg, const float2 texelSize, const float2 uvs, const float dim){
+ float2 pixSize = 2/texelSize;
+ float dimFloored = floor(dim);
+ float center = floor(dim*0.5);
+ float3 refTotal = float3(0,0,0);
+ for (int i = 0; i < dimFloored; i++){
+ for (int j = 0; j < dimFloored; j++){
+ float4 refl = tex2Dlod(ssrg, float4(uvs.x + pixSize.x*(i-center), uvs.y + pixSize.y*(j-center),0,0));
+ refTotal += refl.rgb;
+ }
+ }
+ return refTotal/(dimFloored*dimFloored);
+}
+
+float4 ReflectRay(float3 reflectedRay, float3 rayDir, float _LRad, float _SRad, float _Step, float noise, const int maxIterations){
+
+ #if UNITY_SINGLE_PASS_STEREO || defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
+ half x_min = 0.5*unity_StereoEyeIndex;
+ half x_max = 0.5 + 0.5*unity_StereoEyeIndex;
+ #else
+ half x_min = 0.0;
+ half x_max = 1.0;
+ #endif
+
+ reflectedRay = mul(UNITY_MATRIX_V, float4(reflectedRay, 1));
+ rayDir = mul(UNITY_MATRIX_V, float4(rayDir, 0));
+ int totalIterations = 0;
+ int direction = 1;
+ float3 finalPos = 0;
+ float step = _Step;
+ float lRad = _LRad;
+ float sRad = _SRad;
+
+ for (int i = 0; i < maxIterations; i++){
+ totalIterations = i;
+ float4 spos = ComputeGrabScreenPos(mul(UNITY_MATRIX_P, float4(reflectedRay, 1)));
+ float2 uvDepth = spos.xy / spos.w;
+ UNITY_BRANCH
+ if (uvDepth.x > x_max || uvDepth.x < x_min || uvDepth.y > 1 || uvDepth.y < 0){
+ break;
+ }
+
+ float rawDepth = DecodeFloatRG(SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture,float4(uvDepth,0,0)));
+ float linearDepth = Linear01Depth(rawDepth);
+ float sampleDepth = -reflectedRay.z;
+ float realDepth = linearDepth * _ProjectionParams.z;
+ float depthDifference = abs(sampleDepth - realDepth);
+
+ if (depthDifference < lRad){
+ if (direction == 1){
+ if(sampleDepth > (realDepth - sRad)){
+ if(sampleDepth < (realDepth + sRad)){
+ finalPos = reflectedRay;
+ break;
+ }
+ direction = -1;
+ step = step*0.1;
+ }
+ }
+ else {
+ if(sampleDepth < (realDepth + sRad)){
+ direction = 1;
+ step = step*0.1;
+ }
+ }
+ }
+ reflectedRay = reflectedRay + direction*step*rayDir;
+ step += step*(0.025 + 0.005*noise);
+ lRad += lRad*(0.025 + 0.005*noise);
+ sRad += sRad*(0.025 + 0.005*noise);
+ }
+ return float4(finalPos, totalIterations);
+}
+
+float4 GetSSR(const float3 wPos, const float3 viewDir, float3 rayDir, const half3 faceNormal, float smoothness, float3 albedo, float metallic, float2 screenUVs, float4 screenPos){
+
+ float FdotR = dot(faceNormal, rayDir.xyz);
+ float roughness = 1-smoothness;
+
+ UNITY_BRANCH
+ if (IsInMirror() || FdotR < 0 || roughness > 0.65){
+ return 0;
+ }
+ else {
+ float4 noiseUvs = screenPos;
+ noiseUvs.xy = (noiseUvs.xy * _GrabTexture_TexelSize.zw) / (_NoiseTexSSR_TexelSize.zw * noiseUvs.w);
+ float4 noiseRGBA = tex2Dlod(_NoiseTexSSR, float4(noiseUvs.xy,0,0));
+ float noise = noiseRGBA.r;
+
+ float3 reflectedRay = wPos + (_SSRHeight*_SSRHeight/FdotR + noise*_SSRHeight)*rayDir;
+ float4 finalPos = ReflectRay(reflectedRay, rayDir, _SSRHeight, 0.02, _SSRHeight, noise, 50);
+ float totalSteps = finalPos.w;
+ finalPos.w = 1;
+
+ if (!any(finalPos.xyz)){
+ return 0;
+ }
+
+ float4 uvs = UNITY_PROJ_COORD(ComputeGrabScreenPos(mul(UNITY_MATRIX_P, finalPos)));
+ uvs.xy = uvs.xy / uvs.w;
+
+ #if UNITY_SINGLE_PASS_STEREO || defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
+ float xfade = 1;
+ #else
+ float xfade = smoothstep(0, _EdgeFade, uvs.x) * smoothstep(1, 1-_EdgeFade, uvs.x); //Fade x uvs out towards the edges
+ #endif
+ float yfade = smoothstep(0, _EdgeFade, uvs.y)*smoothstep(1, 1-_EdgeFade, uvs.y); //Same for y
+ // float lengthFade = smoothstep(1, 0, 2*(totalSteps / 50)-1);
+ float smoothFade = smoothstep(0.65, 0.5, 1-smoothness);
+ float reflectionAlpha = xfade * yfade * smoothFade; // * lengthFade;
+
+
+ float4 reflection = 0;
+ if (reflectionAlpha > 0){
+ float blurFac = max(1,min(12, 12 * (-2)*(smoothness-1)));
+ // if (blurFac > 1){
+ reflection.rgb = GetBlurredGP(_GrabTexture, _GrabTexture_TexelSize.zw, uvs.xy, blurFac);
+ // }
+ // else {
+ // reflection.rgb = tex2Dlod(_GrabTexture, float4(uvs.xy,0,0)).rgb;
+ // }
+ reflection.rgb = lerp(reflection.rgb, reflection.rgb*albedo.rgb,smoothstep(0, 1.75, metallic));
+ reflection.a = reflectionAlpha;
+ }
+
+ return max(0,reflection);
+ }
+}
+
+#endif
+
+#endif // MOCHIE_STANDARD_SSR_INCLUDED
diff --git a/MochieStandardSSS.cginc b/MochieStandardSSS.cginc
new file mode 100644
index 0000000..1d5ffbf
--- /dev/null
+++ b/MochieStandardSSS.cginc
@@ -0,0 +1,83 @@
+#ifndef MOCHIE_STANDARD_SSS_INCLUDED
+#define MOCHIE_STANDARD_SSS_INCLUDED
+
+/*
+ * MIT License
+ *
+ * Copyright (c) 2020 MochiesCode
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE
+ * SOFTWARE.
+ */
+
+float3 GetSubsurfaceLight(
+ float3 lightColor, float3 lightDirection, float3 normalDirection, float3 viewDirection,
+ float attenuation, float3 thickness, float3 indirectLight, float3 subsurfaceColor
+){
+ float3 vLTLight = lightDirection + normalDirection * _ScatterDist; // Distortion
+ float3 fLTDot = pow(saturate(dot(viewDirection, -vLTLight)), _ScatterPow) * _ScatterIntensity * 1.0/UNITY_PI;
+
+ return lerp(1, attenuation, float(any(_WorldSpaceLightPos0.xyz)))
+ * (fLTDot + _ScatterAmbient) * thickness
+ * (lightColor + indirectLight) * subsurfaceColor;
+
+}
+
+float3 GeneralWrapSH(float fA){
+ // Normalization factor for our model.
+ float norm = 0.5 * (2 + fA) / (1 + fA);
+ float4 t = float4(2 * (fA + 1), fA + 2, fA + 3, fA + 4);
+ return norm * float3(t.x / t.y, 2 * t.x / (t.y * t.z),
+ t.x * (fA * fA - t.x + 5) / (t.y * t.z * t.w));
+}
+
+float3 ShadeSH9_wrappedCorrect(float3 normal, float3 conv){
+ const float3 cosconv_inv = float3(1, 1.5, 4); // Inverse of the pre-applied cosine convolution
+ float3 x0, x1, x2;
+ conv *= cosconv_inv; // Undo pre-applied cosine convolution
+ //conv *= _Bands.xyz; // debugging
+
+ // Constant (L0)
+ x0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
+ // Remove the constant part from L2 and add it back with correct convolution
+ float3 otherband = float3(unity_SHBr.z, unity_SHBg.z, unity_SHBb.z) / 3.0;
+ x0 = (x0 + otherband) * conv.x - otherband * conv.z;
+
+ // Linear (L1) polynomial terms
+ x1.r = (dot(unity_SHAr.xyz, normal));
+ x1.g = (dot(unity_SHAg.xyz, normal));
+ x1.b = (dot(unity_SHAb.xyz, normal));
+
+ // 4 of the quadratic (L2) polynomials
+ float4 vB = normal.xyzz * normal.yzzx;
+ x2.r = dot(unity_SHBr, vB);
+ x2.g = dot(unity_SHBg, vB);
+ x2.b = dot(unity_SHBb, vB);
+
+ // Final (5th) quadratic (L2) polynomial
+ float vC = normal.x * normal.x - normal.y * normal.y;
+ x2 += unity_SHC.rgb * vC;
+
+ return x0 + x1 * conv.y + x2 * conv.z;
+}
+
+#endif // UNITY_STANDARD_SSS_INCLUDED
diff --git a/README.md b/README.md
index a71dd66..d37c1bc 100644
--- a/README.md
+++ b/README.md
@@ -1,28 +1,40 @@
## Tooner
-A toon shader for VRChat.
+My toon shader for VRChat. I use this on my personal and commercial models.
+It's semi optimized and a little scuffed.
Features:
* PBR
* Emissions
* Outlines
+ * With/without stenciling
* Glitter
* Explosion
* PBR detail maps x4
+ * Albedo, emission, normal, metallic, roughness, mask
+* Decals x4
+ * Albedo, emission, angle
* Matcaps x2
+ * Add, mul, replace, sub, min, max
+ * Quantization
* Rim lighting x2
+ * Add, mul, replace, sub, min, max
+ * Glitter
+ * Quantization
* Rendering modes: opaque, cutout, fade, transparent, transclipping
* Culling modes: front, back, none
* OKLCH color adjustment
-* Reflection probe override
-* Min/max brightness limits
+* Reflection probe (cubemap) override
+* Lighting min/max
* Flat/realistic normals
* Geometry scroll (similar to Poiyomi's shatterwave)
* UV scroll
* Clones
* LTCGI
* Shadows (both casting and receiving)
-* Extensive use of variants to minimize performance cost
+* Gimmicks
+ * Vertex location quantization (object space)
+ * Vertex location scaling (object space)
Disclaimers:
1. This is a WIP.
@@ -30,7 +42,7 @@ Disclaimers:
3. Stability is a non-goal. Keywords are likely to change in the interest of
performance and simplicity.
-Strawman FAQ
+### Strawman FAQ
1. Why create another toon shader?
@@ -40,16 +52,16 @@ too fucking huge and complicated to fit my needs.
2. Does it work?
-Sort of. I haven't implemented shadow receiving yet, so some water effects are
-fucked up.
+I think so?
3. Is it optimized?
-Sort of. I haven't benchmarked it. I know it's slower than Poiyomi.
+Sort of.
-I use keywords on every feature so it shouldn't be obscenely bad. But I haven't
-gotten to the point of like, deduplicating all computation and shoving as much
-as possible into the vertex shader. So it's like. Sort of optimized.
+I use static keywords on every feature, so you don't pay for anything you don't
+use. I use branchless programming wherever appropriate. Dynamic branches are
+only used where I either know they won't cause thread divergence, or where they
+can't be avoided.
I'd like to strike a balance between performance and readability. Since it's
mostly for *my* use, I don't feel a need to make it totally optimal.
diff --git a/feature_macros.cginc b/feature_macros.cginc
index ea9edf8..d9de678 100644
--- a/feature_macros.cginc
+++ b/feature_macros.cginc
@@ -91,6 +91,7 @@
#pragma shader_feature_local _ _GIMMICK_EYES_00
#pragma shader_feature_local _ _PIXELLATE
#pragma shader_feature_local _ _TROCHOID
+#pragma shader_feature_local _ SSR_ENABLED
#endif // __FEATURE_MACROS_INC
diff --git a/globals.cginc b/globals.cginc
index bec4b01..4aab736 100644
--- a/globals.cginc
+++ b/globals.cginc
@@ -22,6 +22,34 @@ float _Confabulate_Normals;
float _Shadow_Strength;
float _Mip_Multiplier;
+float _ScatterDist;
+float _ScatterPow;
+float _ScatterIntensity;
+float _ScatterAmbient;
+float _GSAA;
+float _GSAAStrength;
+float _WrappingFactor;
+float _Subsurface;
+float _SpecularStrength;
+float _FresnelStrength;
+float _UseFresnel;
+float _ReflectionStrength;
+float3 shadowedReflections;
+float3 _ReflShadows;
+float3 _ReflShadowStrength;
+
+#if defined(SSR_ENABLED)
+UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
+sampler2D _GrabTexture;
+sampler2D _NoiseTexSSR;
+float4 _GrabTexture_TexelSize;
+float4 _NoiseTexSSR_TexelSize;
+float _EdgeFade;
+float _SSRStrength;
+float _SSRHeight;
+#endif
+
+
#if defined(_BASECOLOR_MAP)
texture2D _MainTex;
float4 _MainTex_ST;
diff --git a/interpolators.cginc b/interpolators.cginc
index 9677422..0a9784e 100644
--- a/interpolators.cginc
+++ b/interpolators.cginc
@@ -23,6 +23,9 @@ struct v2f
float3 worldPos : TEXCOORD2;
float3 normal : TEXCOORD3;
float3 objPos : TEXCOORD4;
+ #if defined(SSR_ENABLED)
+ float4 screenPos : TEXCOORD5;
+ #endif
};
#else
@@ -52,6 +55,9 @@ struct v2f
#if defined(VERTEXLIGHT_ON)
float3 vertexLightColor : TEXCOORD7;
#endif
+ #if defined(SSR_ENABLED)
+ float4 screenPos : TEXCOORD8;
+ #endif
};
#endif
diff --git a/pbr.cginc b/pbr.cginc
index ca3fdb5..44e0b88 100644
--- a/pbr.cginc
+++ b/pbr.cginc
@@ -4,6 +4,8 @@
#include "UnityPBSLighting.cginc"
#include "AutoLight.cginc"
+#include "MochieStandardBRDF.cginc"
+
#include "globals.cginc"
#include "interpolators.cginc"
#include "poi.cginc"
@@ -34,7 +36,7 @@ void ltcgi_cb_specular(inout ltcgi_acc acc, in ltcgi_output output) {
UNITY_DECLARE_TEXCUBE(_Cubemap);
-UnityLight CreateDirectLight(float3 normal, float ao, v2f i)
+UnityLight CreateDirectLight(float3 normal, float ao, v2f i, out float attenuation)
{
#if 1
// This whole block is yoinked from AutoLight.cginc. I needed a way to
@@ -42,26 +44,26 @@ UnityLight CreateDirectLight(float3 normal, float ao, v2f i)
#if defined(DIRECTIONAL_COOKIE)
DECLARE_LIGHT_COORD(i, i.worldPos);
float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
- float attenuation = tex2D(_LightTexture0, lightCoord).w;
+ attenuation = tex2D(_LightTexture0, lightCoord).w;
#elif defined(POINT_COOKIE)
DECLARE_LIGHT_COORD(i, i.worldPos);
float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
- float attenuation = tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).r *
+ attenuation = tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).r *
texCUBE(_LightTexture0, lightCoord).w;
#elif defined(DIRECTIONAL)
float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
- float attenuation = 1;
+ attenuation = 1;
#elif defined(SPOT)
DECLARE_LIGHT_COORD(i, i.worldPos);
float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
- float attenuation = (lightCoord.z > 0) * UnitySpotCookie(lightCoord) * UnitySpotAttenuate(lightCoord.xyz);
+ attenuation = (lightCoord.z > 0) * UnitySpotCookie(lightCoord) * UnitySpotAttenuate(lightCoord.xyz);
#elif defined(POINT)
unityShadowCoord3 lightCoord = mul(unity_WorldToLight, unityShadowCoord4(i.worldPos, 1)).xyz;
float shadow = UNITY_SHADOW_ATTENUATION(i, i.worldPos);
- float attenuation = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).r;
+ attenuation = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).r;
#else
float shadow = 1;
- float attenuation = 1;
+ attenuation = 1;
#endif
attenuation *= lerp(1, shadow, _Shadow_Strength);
#else
@@ -196,8 +198,9 @@ float4 getLitColor(
UnityIndirect indirect_light = CreateIndirectLight(vertexLightColor,
view_dir, normal, smoothness, worldPos, ao, uv);
- UnityLight direct_light = CreateDirectLight(normal, ao, i);
- if (normals_mode == 0 || normals_mode == 2) {
+ float attenuation;
+ UnityLight direct_light = CreateDirectLight(normal, ao, i, attenuation);
+ if (normals_mode == 0) {
float e = 0.8;
indirect_light.diffuse += direct_light.color * e;
direct_light.color *= (1 - e);
@@ -220,38 +223,40 @@ float4 getLitColor(
}
#endif
- direct_light.color = clamp(direct_light.color, _Min_Brightness, _Max_Brightness*.5);
+ direct_light.color = clamp(direct_light.color, _Min_Brightness, _Max_Brightness);
indirect_light.diffuse = clamp(indirect_light.diffuse, _Min_Brightness, _Max_Brightness);
indirect_light.specular = clamp(indirect_light.specular, _Min_Brightness, _Max_Brightness);
- float3 pbr;
- if (round(_Confabulate_Normals)) {
- pbr = UNITY_BRDF_PBS(
- albedo,
- specular_tint,
- one_minus_reflectivity,
- smoothness,
- view_dir,
- normal,
- direct_light,
- indirect_light).xyz;
- } else {
- pbr = UNITY_BRDF_PBS(
- albedo,
- specular_tint,
- one_minus_reflectivity,
- smoothness,
- normal,
- view_dir,
- direct_light,
- indirect_light).xyz;
- }
-
-#if defined(_LTCGI)
- pbr.rgb += (acc.specular + acc.diffuse) * metallic;
+ float2 screenUVs = 0;
+ float4 screenPos = 0;
+#if defined(SSR_ENABLED)
+ screenUVs = i.screenPos.xy / (i.screenPos.w+0.0000000001);
+#if UNITY_SINGLE_PASS_STEREO || defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
+ screenUVs.x *= 2;
+#endif
+ screenPos = i.screenPos;
#endif
- return float4(pbr, albedo.a);
+ float4 pbr = BRDF1_Mochie_PBS(
+ albedo,
+ specular_tint,
+ one_minus_reflectivity,
+ smoothness,
+ normal,
+ view_dir,
+ i.worldPos,
+ screenUVs,
+ screenPos,
+ metallic,
+ /*thickness=*/1,
+ /*ssColor=*/0,
+ attenuation,
+ /*lightmapUV=*/0,
+ vertexLightColor,
+ direct_light,
+ indirect_light);
+
+ return float4(pbr.rgb, albedo.a);
}
#endif // __PBR_INC
diff --git a/tooner.shader b/tooner.shader
index 3185682..cd2371f 100644
--- a/tooner.shader
+++ b/tooner.shader
@@ -271,12 +271,36 @@ Shader "yum_food/tooner"
_Trochoid_R("R", Float) = 5.0
_Trochoid_r("r", Float) = 3.0
_Trochoid_d("d", Float) = 5.0
+
+ _Enable_SSR("Enable SSR", Float) = 0
+ _SSRStrength("SSR Strength", Float) = 1
+ _SSRHeight("SSR Height", Float) = 0.1
+ [HideInInspector]_NoiseTexSSR("SSR Noise Texture", 2D) = "black" {}
+ _EdgeFade("Edge Fade", Range(0,1)) = 0.1
+ [ToggleUI]_EdgeFadeToggle("Edge Fade Toggle", Int) = 1
+
+ _ScatterDist("_ScatterDist", Float) = 0
+ _ScatterPow("_ScatterPow", Float) = 0
+ _ScatterIntensity("_ScatterIntensity", Float) = 0
+ _ScatterAmbient("_ScatterAmbient", Float) = 0
+ _GSAA("_GSAA", Float) = 0
+ _GSAAStrength("_GSAAStrength", Float) = 0
+ _WrappingFactor("_WrappingFactor", Float) = 0
+ _Subsurface("_Subsurface", Float) = 0
+ _SpecularStrength("_SpecularStrength", Float) = 0
+ _FresnelStrength("_FresnelStrength", Float) = 0
+ _UseFresnel("_UseFresnel", Float) = 0
+ _ReflectionStrength("_ReflectionStrength", Float) = 0
+ shadowedReflections("shadowedReflections", Vector) = (0, 0, 0, 0)
+ _ReflShadows("_ReflShadows", Vector) = (0, 0, 0, 0)
+ _ReflShadowStrength("_ReflShadowStrength", Vector) = (0, 0, 0, 0)
}
SubShader
{
Tags {
"VRCFallback"="ToonCutout"
}
+
Pass {
Tags {
"RenderType"="Opaque"
diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc
index 4288293..16f3fe3 100644
--- a/tooner_lighting.cginc
+++ b/tooner_lighting.cginc
@@ -132,6 +132,10 @@ v2f vert(appdata v)
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.objPos = v.vertex;
+#if defined(SSR_ENABLED)
+ o.screenPos = ComputeGrabScreenPos(o.vertex);
+#endif
+
o.normal = UnityObjectToWorldNormal(v.normal);
o.tangent = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
o.uv = v.uv0;