diff options
| author | yum <yum.food.vr@gmail.com> | 2025-02-01 19:26:29 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2025-02-01 19:26:29 -0800 |
| commit | ff997cfb850ec42a977381a2becf0ccedb2035d9 (patch) | |
| tree | 183c4a1d25bea43b985ba8308c65fa3c529f14db | |
| parent | fb26b02a20ef751cdd1832abc925b5e57bb2234b (diff) | |
Begin work on ssfd in lens shader
| -rw-r--r-- | Editor/tooner.cs | 14 | ||||
| -rw-r--r-- | feature_macros.cginc | 2 | ||||
| -rw-r--r-- | globals.cginc | 6 | ||||
| -rw-r--r-- | tooner.shader | 3 | ||||
| -rw-r--r-- | tooner_lighting.cginc | 116 |
5 files changed, 83 insertions, 58 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs index c7d89d4..01e30ed 100644 --- a/Editor/tooner.cs +++ b/Editor/tooner.cs @@ -3182,6 +3182,7 @@ public class ToonerGUI : ShaderGUI { enum Lens00Mode { Bayer, InterleavedGradientNoise, + SurfaceStableFractalDithering, } void DoLens00() { @@ -3232,6 +3233,19 @@ public class ToonerGUI : ShaderGUI { bc.floatValue = (float) mode; SetKeyword("_GIMMICK_LENS_00_BAYER", mode == Lens00Mode.Bayer); SetKeyword("_GIMMICK_LENS_00_INTERLEAVED_GRADIENT_NOISE", mode == Lens00Mode.InterleavedGradientNoise); + SetKeyword("_GIMMICK_LENS_00_SSFD", mode == Lens00Mode.SurfaceStableFractalDithering); + + if (mode == Lens00Mode.SurfaceStableFractalDithering) { + EditorGUI.indentLevel += 1; + bc = FindProperty("_Gimmick_Lens_00_SSFD_Scale"); + FloatProperty(bc, "Scale"); + bc = FindProperty("_Gimmick_Lens_00_SSFD_Max_Fwidth"); + FloatProperty(bc, "Max fwidth"); + bc = FindProperty("_Gimmick_Lens_00_SSFD_Noise"); + TexturePropertySingleLine(MakeLabel(bc, "Noise"), bc); + EditorGUI.indentLevel -= 1; + } + EditorGUI.indentLevel -= 1; } diff --git a/feature_macros.cginc b/feature_macros.cginc index 3f5d177..d870fb9 100644 --- a/feature_macros.cginc +++ b/feature_macros.cginc @@ -291,7 +291,9 @@ #pragma shader_feature_local _ _GIMMICK_LENS_00_GRABPASS #pragma shader_feature_local _ _GIMMICK_LENS_00_BAYER #pragma shader_feature_local _ _GIMMICK_LENS_00_INTERLEAVED_GRADIENT_NOISE +#pragma shader_feature_local _ _GIMMICK_LENS_00_SSFD #pragma shader_feature_local _ _SURFACE_STABLE_FRACTAL_DITHERING + #endif // __FEATURE_MACROS_INC diff --git a/globals.cginc b/globals.cginc index 88abb0f..578fb8e 100644 --- a/globals.cginc +++ b/globals.cginc @@ -1137,6 +1137,11 @@ float _Gimmick_Lens_00_Subdivisions; #if defined(_GIMMICK_LENS_00_FRAME_COUNTER) float _Gimmick_Lens_00_Frame_Counter_Speed; #endif +#if defined(_GIMMICK_LENS_00_SSFD) +float _Gimmick_Lens_00_SSFD_Scale; +float _Gimmick_Lens_00_SSFD_Max_Fwidth; +texture3D _Gimmick_Lens_00_SSFD_Noise; +#endif #endif #if defined(_SURFACE_STABLE_FRACTAL_DITHERING) @@ -1145,5 +1150,6 @@ float _Surface_Stable_Fractal_Dithering_Scale; float _Surface_Stable_Fractal_Dithering_Max_Fwidth; #endif + #endif diff --git a/tooner.shader b/tooner.shader index 5632ce2..15386c7 100644 --- a/tooner.shader +++ b/tooner.shader @@ -1174,6 +1174,9 @@ Shader "yum_food/tooner" _Gimmick_Lens_00_Subdivisions("Quantization subdivisions", Float) = 1 _Gimmick_Lens_00_Mode("Mode", Float) = 0 // 0 = Bayer, 1 = InterleavedGradientNoise _Gimmick_Lens_00_Scale("Scale", Float) = 1 + _Gimmick_Lens_00_SSFD_Scale("Scale", Float) = 1 + _Gimmick_Lens_00_SSFD_Max_Fwidth("Max fwidth", Float) = 0.001 + _Gimmick_Lens_00_SSFD_Noise("Noise", 3D) = "white" {} _Surface_Stable_Fractal_Dithering_Enable_Static("Enable stable fractal dithering", Float) = 0 _Surface_Stable_Fractal_Dithering_Noise("Noise", 3D) = "white" {} diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc index ab885e6..09043f5 100644 --- a/tooner_lighting.cginc +++ b/tooner_lighting.cginc @@ -985,6 +985,59 @@ float4 map_color_epilepsy(float4 color) { #define FILTER_COLOR(color) color #endif +float ssfd(float2 uv, float scale, float max_fwidth, texture3D noise) +{ + float2 duv = uv; + + //float duv_fw = fwidth(duv.x) + fwidth(duv.y); + // Original paper uses SVD instead of fwidth. + float2x2 M = float2x2(ddx(duv), ddy(duv)); + float2x2 MtM = mul(transpose(M), M); + float trace = MtM[0][0] + MtM[1][1]; + float det = determinant(MtM); + // Calculate eigenvalues using quadratic formula. + float tmp = sqrt(trace * trace - 4 * det); + float e1 = (trace + tmp) * 0.5; + float e2 = (trace - tmp) * 0.5; + float2 singular_values = sqrt(float2(e1, e2)); + // Logic from original paper: the smaller eigenvalue corresponds to the + // largest amount of stretching, so we use it to determine when to + // subdivide. + float duv_fw = singular_values.y; + + // Suppose Max_Fwidth is 1. + // duv_fw is 16. That means UV is changing a lot per pixel. That means we want to shrink the scale of the UV. + // Factor is 16. + // log_2(factor) is 4. + // Divide original by 16. + float fw_factor = duv_fw / max_fwidth; + float fractal_level = log2(fw_factor); + float fractal_level_floor = floor(fractal_level); + float fractal_remainder = fractal_level - fractal_level_floor; + + duv /= pow(2, fractal_level_floor); + duv *= scale; + +#if 1 + // Four layers -> coarsest at 0.125, finest at 0.875. + uint width, height, depth; + noise.GetDimensions(width, height, depth); + float n_layers = depth; + float not_used_lo = 1/(n_layers*2); + float not_used_hi = 1 - not_used_lo; + + float uvw = (not_used_hi - not_used_lo) * (1 - fractal_remainder) + not_used_lo; + + float3 duv_3d = float3(duv, uvw); +#else + float3 duv_3d = float3(duv, 0); +#endif + float dither = noise.SampleLevel(bilinear_repeat_s, duv_3d, 0); + dither = (dither > 0.5) ? 1 : 0; + + return dither; +} + float4 effect(inout v2f i, out float depth) { ToonerData tdata; @@ -1070,63 +1123,7 @@ float4 effect(inout v2f i, out float depth) #endif // _FRAME_COUNTER #if defined(_SURFACE_STABLE_FRACTAL_DITHERING) - { - float2 duv = i.uv0; - - //float duv_fw = fwidth(duv.x) + fwidth(duv.y); - // Original paper uses SVD instead of fwidth. - float2x2 M = float2x2(ddx(duv), ddy(duv)); - float2x2 MtM = mul(transpose(M), M); - float trace = MtM[0][0] + MtM[1][1]; - float det = determinant(MtM); - // Calculate eigenvalues using quadratic formula. - float tmp = sqrt(trace * trace - 4 * det); - float e1 = (trace + tmp) * 0.5; - float e2 = (trace - tmp) * 0.5; - float2 singular_values = sqrt(float2(e1, e2)); - // Logic from original paper: the smaller eigenvalue corresponds to the - // largest amount of stretching, so we use it to determine when to - // subdivide. - float duv_fw = singular_values.y; - - // Suppose Max_Fwidth is 1. - // duv_fw is 16. That means UV is changing a lot per pixel. That means we want to shrink the scale of the UV. - // Factor is 16. - // log_2(factor) is 4. - // Divide original by 16. - float fw_factor = duv_fw / _Surface_Stable_Fractal_Dithering_Max_Fwidth; - float fractal_level = log2(fw_factor); - float fractal_level_floor = floor(fractal_level); - float fractal_remainder = fractal_level - fractal_level_floor; - duv /= pow(2, fractal_level_floor); - duv *= _Surface_Stable_Fractal_Dithering_Scale; - - //float subdivisions = 4; - //float fractal_remainder_subd = fractal_remainder * subdivisions; - -#if 1 - // Four layers -> coarsest at 0.125, finest at 0.875. - uint width, height, depth; - _Surface_Stable_Fractal_Dithering_Noise.GetDimensions(width, height, depth); - float n_layers = depth; - float not_used_lo = 1/(n_layers*2); - float not_used_hi = 1 - not_used_lo; - float uvw = (not_used_hi - not_used_lo) * (1 - fractal_remainder) + not_used_lo; - - float3 duv_3d = float3(duv, uvw); -#else - float3 duv_3d = float3(duv, 0); -#endif - float noise = _Surface_Stable_Fractal_Dithering_Noise.SampleLevel(bilinear_repeat_s, duv_3d, 0); - noise = (noise > 0.5) ? 1 : 0; - - albedo.rgb = noise; -#if 0 - float hue = 0; - hue += glsl_mod(fractal_level_floor*.1, 1); - albedo.rgb *= HSVtoRGB(float3(hue, 1, 1)); -#endif - } + albedo.rgb = ssfd(i.uv0, _Surface_Stable_Fractal_Dithering_Scale, _Surface_Stable_Fractal_Dithering_Max_Fwidth, _Surface_Stable_Fractal_Dithering_Noise); #endif #if defined(_GIMMICK_GERSTNER_WATER) @@ -2353,14 +2350,17 @@ float4 effect(inout v2f i, out float depth) float mask = BayerM8x8[bayer_idx.y * 8 + bayer_idx.x]; #elif defined(_GIMMICK_LENS_00_INTERLEAVED_GRADIENT_NOISE) float mask = ign(glasses_uv_round); +#elif defined(_GIMMICK_LENS_00_SSFD) + float mask = ssfd(glasses_uv_round, _Gimmick_Lens_00_SSFD_Scale, _Gimmick_Lens_00_SSFD_Max_Fwidth, _Gimmick_Lens_00_SSFD_Noise); #endif - mask = frac(mask + frame * PHI * _Gimmick_Lens_00_Frame_Counter_Speed); + //mask = frac(mask + frame * PHI * _Gimmick_Lens_00_Frame_Counter_Speed); float2 grab_uv = i.grabPos.xy / i.grabPos.w; //grab_uv = floor(grab_uv * _ScreenParams.xy * _Gimmick_Lens_00_Scale) / (_ScreenParams.xy * _Gimmick_Lens_00_Scale); float3 grab_color = _Tooner_Grabpass.SampleLevel(linear_clamp_s, grab_uv, 0).rgb; grab_color = round(grab_color * _Gimmick_Lens_00_Subdivisions) / _Gimmick_Lens_00_Subdivisions; lit.rgb = (grab_color > mask); + lit.rgb = mask * .1; } #endif |
