diff options
| -rw-r--r-- | Editor/tooner.cs | 83 | ||||
| -rw-r--r-- | MochieStandardBRDF.cginc | 176 | ||||
| -rw-r--r-- | MochieStandardSSR.cginc | 176 | ||||
| -rw-r--r-- | MochieStandardSSS.cginc | 83 | ||||
| -rw-r--r-- | README.md | 34 | ||||
| -rw-r--r-- | feature_macros.cginc | 1 | ||||
| -rw-r--r-- | globals.cginc | 28 | ||||
| -rw-r--r-- | interpolators.cginc | 6 | ||||
| -rw-r--r-- | pbr.cginc | 77 | ||||
| -rw-r--r-- | tooner.shader | 24 | ||||
| -rw-r--r-- | tooner_lighting.cginc | 4 |
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 @@ -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 @@ -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; |
