diff options
| author | yum <yum.food.vr@gmail.com> | 2025-01-21 19:58:34 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2025-01-21 19:58:34 -0800 |
| commit | 4ec13bd7513f29e16ab22b7ffe7d06724c92a912 (patch) | |
| tree | e82920d170455fbfade69f7487ae5f6f4d0c1dd0 | |
| parent | e2911359e5acf79beb5c8359145669b96a931ab0 (diff) | |
Clearcoat can disable texture normals
Also:
* terrain gimmick
* makes some hardcoded shit into params
* add alternative normal evaluation methods
* stochastic method gives best results without getting into analytic
normals
* add FBM noise texture slot to improve perf
* add initial raytrace to sphere
* stabilizes appearance as camera moves
* add backtracking
* eliminates sharp lines without sacrificing perf
* fog 00 can render on a plane now, in addition to cylinder
* add epilepsy protection filter
| -rw-r--r-- | Editor/tooner.cs | 90 | ||||
| -rw-r--r-- | downstairs_02.cginc | 164 | ||||
| -rw-r--r-- | feature_macros.cginc | 1 | ||||
| -rw-r--r-- | fog.cginc | 89 | ||||
| -rw-r--r-- | globals.cginc | 17 | ||||
| -rw-r--r-- | oklab.cginc | 2 | ||||
| -rw-r--r-- | pbr.cginc | 9 | ||||
| -rw-r--r-- | tooner.shader | 19 | ||||
| -rw-r--r-- | tooner_lighting.cginc | 94 |
9 files changed, 408 insertions, 77 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs index d0411e4..4364a3c 100644 --- a/Editor/tooner.cs +++ b/Editor/tooner.cs @@ -313,6 +313,13 @@ public class ToonerGUI : ShaderGUI { bc.floatValue = enabled ? 1.0f : 0.0f; EditorGUI.indentLevel -= 1; } + + bc = FindProperty("_Clearcoat_Use_Texture_Normals"); + enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = Toggle("Use texture normals", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; } EditorGUI.indentLevel -= 1; show_ui.RemoveAt(show_ui.Count - 1); @@ -2012,6 +2019,9 @@ public class ToonerGUI : ShaderGUI { } } + bc = FindProperty("_Gimmick_DS2_11_FBM"); + TexturePropertySingleLine(MakeLabel(bc, "FBM"), bc); + bc = FindProperty("_Gimmick_DS2_11_Snow_Color"); ColorProperty(bc, "Snow color"); bc = FindProperty("_Gimmick_DS2_11_Snowline"); @@ -2045,10 +2055,16 @@ public class ToonerGUI : ShaderGUI { FloatProperty(bc, "Octaves"); bc = FindProperty("_Gimmick_DS2_11_March_Initial_Offset"); FloatProperty(bc, "March initial offset"); + bc = FindProperty("_Gimmick_DS2_11_March_Initial_Step_Size"); + FloatProperty(bc, "March initial step size"); bc = FindProperty("_Gimmick_DS2_11_March_Steps"); FloatProperty(bc, "March steps"); + bc = FindProperty("_Gimmick_DS2_11_March_Backtrack_Steps"); + FloatProperty(bc, "March backtrack steps"); bc = FindProperty("_Gimmick_DS2_11_Simulation_Scale"); FloatProperty(bc, "Simulation scale"); + bc = FindProperty("_Gimmick_DS2_11_Coord_Scale"); + FloatProperty(bc, "Coord scale"); bc = FindProperty("_Gimmick_DS2_11_Height_Scale"); FloatProperty(bc, "Height scale"); bc = FindProperty("_Gimmick_DS2_11_Early_Exit_Cutoff_Cos_Theta"); @@ -2535,6 +2551,11 @@ public class ToonerGUI : ShaderGUI { EditorGUI.indentLevel -= 1; } + enum GimmickFog00BoundaryType { + Cylinder = 0, + Plane = 1, + } + void DoGimmickFog0() { MaterialProperty bc; @@ -2554,8 +2575,25 @@ public class ToonerGUI : ShaderGUI { bc = FindProperty("_Gimmick_Fog_00_Density"); RangeProperty(bc, "Density"); - bc = FindProperty("_Gimmick_Fog_00_Radius"); - FloatProperty(bc, "Radius"); + + bc = FindProperty("_Gimmick_Fog_00_Boundary_Type"); + EditorGUI.BeginChangeCheck(); + GimmickFog00BoundaryType boundary_type = (GimmickFog00BoundaryType) Math.Round(bc.floatValue); + boundary_type = (GimmickFog00BoundaryType) EnumPopup( + MakeLabel("Boundary type"), boundary_type); + EditorGUI.EndChangeCheck(); + bc.floatValue = (int) boundary_type; + + if (boundary_type == GimmickFog00BoundaryType.Cylinder) { + bc = FindProperty("_Gimmick_Fog_00_Radius"); + FloatProperty(bc, "Radius"); + } else if (boundary_type == GimmickFog00BoundaryType.Plane) { + bc = FindProperty("_Gimmick_Fog_00_Plane_Normal"); + VectorProperty(bc, "Plane normal"); + bc = FindProperty("_Gimmick_Fog_00_Plane_Center"); + VectorProperty(bc, "Plane center"); + } + bc = FindProperty("_Gimmick_Fog_00_Step_Size_Factor"); FloatProperty(bc, "Step size multiplier"); bc = FindProperty("_Gimmick_Fog_00_Max_Ray"); @@ -2670,6 +2708,15 @@ public class ToonerGUI : ShaderGUI { EditorGUI.indentLevel -= 1; } + // Composite fog on top of some raymarched effect. Does not rely on depth + // buffer; uses whatever the raymarch generated. + bc = FindProperty("_Gimmick_Fog_00_Overlay_Mode"); + enabled = (bc.floatValue != 0.0); + EditorGUI.BeginChangeCheck(); + enabled = Toggle("Overlay mode", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + EditorGUI.indentLevel -= 1; } @@ -2882,6 +2929,44 @@ public class ToonerGUI : ShaderGUI { EditorGUI.indentLevel -= 1; } + // Dim and desaturate colors. This is in no way comprehensive. Proceed with + // utmost caution whenever creating effects for users with photosensitive + // epilepsy. + void DoGimmickEpilepsyMode() { + MaterialProperty bc; + + bc = FindProperty("_Gimmick_Epilepsy_Mode_Enable_Static"); + bool enabled = (bc.floatValue != 0.0); + EditorGUI.BeginChangeCheck(); + enabled = Toggle("Epilepsy protection mode", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + SetKeyword("_GIMMICK_EPILEPSY_MODE", enabled); + + if (!enabled) { + return; + } + + EditorGUI.indentLevel += 1; + + bc = FindProperty("_Gimmick_Epilepsy_Mode_Enable_Dynamic"); + enabled = (bc.floatValue != 0.0); + EditorGUI.BeginChangeCheck(); + enabled = Toggle("Enable (runtime switch)", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + + bc = FindProperty("_Gimmick_Epilepsy_Mode_Luminance_Cutoff"); + RangeProperty(bc, "Luminance cutoff"); + bc = FindProperty("_Gimmick_Epilepsy_Mode_Saturation_Cutoff"); + RangeProperty(bc, "Saturation cutoff"); + + bc = FindProperty("_Gimmick_Epilepsy_Mode_Rolloff_Power"); + FloatProperty(bc, "Rolloff power"); + + EditorGUI.indentLevel -= 1; + } + void DoGimmicks() { show_ui.Add(AddCollapsibleMenu("Gimmicks", "_Gimmicks")); EditorGUI.indentLevel += 1; @@ -2912,6 +2997,7 @@ public class ToonerGUI : ShaderGUI { DoClones(); DoExplosion(); DoGeoScroll(); + DoGimmickEpilepsyMode(); EditorGUI.indentLevel -= 1; show_ui.RemoveAt(show_ui.Count - 1); diff --git a/downstairs_02.cginc b/downstairs_02.cginc index 7896c7b..e940e34 100644 --- a/downstairs_02.cginc +++ b/downstairs_02.cginc @@ -679,8 +679,7 @@ float ds2_11_height(float2 p) float alpha_rcp_i = 1; for (uint i = 0; i < octaves; i++) { #if defined(_GIMMICK_DS2_11_TEXTURE_NOISE) - // Combine components to increase precision. - float noise = _Gimmick_DS2_Noise.SampleLevel(linear_repeat_s, pp * alpha_rcp_i, 0); + float noise = _Gimmick_DS2_11_FBM.SampleLevel(linear_repeat_s, pp * alpha_rcp_i, 0); #else float noise = perlin_noise(pp * alpha_rcp_i); #endif @@ -703,24 +702,147 @@ float ds2_11_height(float2 p) float3 ds2_11_calc_normal(float3 p) { - float epsilon = 6E-4; +#if 0 + // 4-point anti aliasing in an X shape with full central differences. 16 taps. + float epsilon = 1E-3; + float3 result = 0; + for (uint i = 0; i < 4; i++) { + float2 pp = p.xz + epsilon * (float2(i % 2, (i/2) % 2) - .5) * 2; + result += float3( + ds2_11_height(pp - float2(epsilon, 0)) - ds2_11_height(pp + float2(epsilon, 0)), + 2 * epsilon, + ds2_11_height(pp - float2(0, epsilon)) - ds2_11_height(pp + float2(0, epsilon)) + ); + } + return normalize(result); +#elif 0 + // Full central differences. 4 taps. + float epsilon = 1E-3; return normalize(float3( ds2_11_height(p.xz - float2(epsilon, 0)) - ds2_11_height(p.xz + float2(epsilon, 0)), 2 * epsilon, ds2_11_height(p.xz - float2(0, epsilon)) - ds2_11_height(p.xz + float2(0, epsilon)) )); +#elif 0 + // Abridged central differences along stochastic diagonal. 6 taps. + float epsilon = 1E-3; + float noise = _Gimmick_DS2_Noise.SampleLevel(linear_repeat_s, p.xz * 1000, 0) * TAU; + float2 axis = float2(cos(noise), sin(noise)); + float2 p0 = p.xz + (epsilon * axis); + float2 p1 = p.xz - (epsilon * axis); + float c0 = ds2_11_height(p0); + float c1 = ds2_11_height(p1); + float3 n0 = float3( + ds2_11_height(p0 - float2(epsilon, 0)) - c0, + epsilon, + ds2_11_height(p0 - float2(0, epsilon)) - c0 + ); + float3 n1 = float3( + ds2_11_height(p1 - float2(epsilon, 0)) - c1, + epsilon, + ds2_11_height(p1 - float2(0, epsilon)) - c1 + ); + return normalize(n0 + n1); +#elif 1 + // Full central differences rotated a random amount about the original point. 4 taps. + float epsilon = 8E-4; + float3 pp = p * 64; + float noise = _Gimmick_DS2_Noise.SampleLevel(linear_repeat_s, pp.xz, 0) * TAU; + float2 axis = float2(cos(noise), sin(noise)); + float2 p0 = p.xz + (epsilon * axis) * 1.20710678; + float3 n0 = float3( + ds2_11_height(p0 - float2(epsilon, 0)) - ds2_11_height(p0 + float2(epsilon, 0)), + 2 * epsilon, + ds2_11_height(p0 - float2(0, epsilon)) - ds2_11_height(p0 + float2(0, epsilon)) + ); + return normalize(n0); +#elif 1 + // Abridged central differences along diagonal oriented tangent to circle centered at the origin. 6 taps. + float epsilon = 1E-3; + float2 n2 = normalize(p.xz); + float2 ortho = float2(-n2.y, n2.x); + float2 p0 = p.xz + (epsilon * .7071 * ortho); + float2 p1 = p.xz - (epsilon * .7071 * ortho); + float c0 = ds2_11_height(p0); + float c1 = ds2_11_height(p1); + float3 n0 = float3( + ds2_11_height(p0 - float2(epsilon, 0)) - c0, + epsilon, + ds2_11_height(p0 - float2(0, epsilon)) - c0 + ); + float3 n1 = float3( + ds2_11_height(p1 - float2(epsilon, 0)) - c1, + epsilon, + ds2_11_height(p1 - float2(0, epsilon)) - c1 + ); + return normalize(n0 + n1); +#elif 0 + // Abridged central differences along diagonal oriented normal to circle centered at the origin. 6 taps. + float epsilon = 1E-3; + float2 n2 = normalize(p.xz); + float2 p0 = p.xz + (epsilon * .5 * n2); + float2 p1 = p.xz - (epsilon * .5 * n2); + float c0 = ds2_11_height(p0); + float c1 = ds2_11_height(p1); + float3 n0 = normalize(float3( + c0 - ds2_11_height(p0 - float2(epsilon, 0)), + epsilon, + c0 - ds2_11_height(p0 - float2(0, epsilon)) + )); + float3 n1 = normalize(float3( + c1 - ds2_11_height(p1 - float2(epsilon, 0)), + epsilon, + c1 - ds2_11_height(p1 - float2(0, epsilon)) + )); + return normalize(n0 + n1); +#else + // Abridged central differences. 3 taps. + float epsilon = 1E-3; + float center = ds2_11_height(p.xz); + return normalize(float3( + ds2_11_height(p.xz - float2(epsilon, 0)) - center, + 2 * epsilon, + ds2_11_height(p.xz - float2(0, epsilon)) - center + )); +#endif } Gimmick_DS2_Output Gimmick_DS2_11(inout v2f i, ToonerData tdata) { float3 camera_position = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1)); float3 rd = normalize(i.objPos - camera_position); - float3 ro = camera_position + rd * _Gimmick_DS2_11_March_Initial_Offset * _Gimmick_DS2_11_Simulation_Scale; + float3 ro = camera_position; + + // Raytrace to intersection with sphere of radius _Gimmick_DS2_11_March_Initial_Offset centered at the object space origin. + { + float r = _Gimmick_DS2_11_March_Initial_Offset * _Gimmick_DS2_11_Simulation_Scale; + float3 L = ro; // Sphere center is at the origin + float b = 2.0 * dot(rd, L); + float c = dot(L, L) - r * r; + float discriminant = b * b - 4.0 * c; + + // If discriminant is negative, the ray does not intersect the sphere + if (discriminant > 0.0) + { + // Compute the two points of intersection + float sqrt_discriminant = sqrt(discriminant); + float t0 = (-b - sqrt_discriminant) * 0.5; + float t1 = (-b + sqrt_discriminant) * 0.5; -// 180 degrees is pi radians -// (d/180)*pi + // Choose the nearest positive t + float t_sphere = (t0 > 0.0) ? t0 : ((t1 > 0.0) ? t1 : -1.0); + + // If both t0 and t1 are negative, the sphere is behind the ray origin + if (t_sphere > 0.0) + { + ro += rd * t_sphere; + } + } + } + + // 180 degrees is pi radians + // (d/180)*pi [branch] - //if (dot(rd, UnityObjectToWorldNormal(float3(0, 1, 0))) > cos((60/180)*PI)) { if (dot(rd, UnityObjectToWorldNormal(float3(0, 1, 0))) > _Gimmick_DS2_11_Early_Exit_Cutoff_Cos_Theta) { return (Gimmick_DS2_Output)0; } @@ -734,8 +856,14 @@ Gimmick_DS2_Output Gimmick_DS2_11(inout v2f i, ToonerData tdata) } } + float perspective_divide = 1.0 / i.pos.w; + float2 screen_uv = i.screenPos.xy * perspective_divide * _ScreenParams.xy * _Gimmick_DS2_Noise_TexelSize.xy; + const float noise = _Gimmick_DS2_Noise.SampleLevel(point_repeat_s, screen_uv, 0); + const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x); + const float tnoise = frac(noise + frame * PHI); + float t = 0.0; - float dt0 = 0.01 * _Gimmick_DS2_11_Simulation_Scale; + float dt0 = _Gimmick_DS2_11_March_Initial_Step_Size * _Gimmick_DS2_11_Simulation_Scale; float dt = dt0; // last height, last y float lh = 0; @@ -756,17 +884,34 @@ Gimmick_DS2_Output Gimmick_DS2_11(inout v2f i, ToonerData tdata) lh = h; ly = p.y; } + [branch] if (p.y < h) { hit = true; t = t - dt + dt * (lh - ly) / (p.y - ly - h + lh); + + // Backtrack to find a closer intersection point using binary search + float t0 = t; + //p = ro + rd * t; + //float t1 = t + dt * sign(h - ds2_11_height(p.xz)); + float t1 = t + dt * .5; + for (uint j = 0; j < _Gimmick_DS2_11_March_Backtrack_Steps; j++) { + float tm = (t0 + t1) * 0.5; + float3 pm = ro + rd * tm; + float hm = ds2_11_height(pm.xz); + t1 = (pm.y < hm) ? tm : t1; + t0 = (pm.y < hm) ? t0 : tm; + } + t = t1; // Refined intersection time + p = ro + rd * t; } float3 final_pos = ro + t * rd + (1 - hit) * rd * 1E2; + float3 normal = UnityObjectToWorldNormal(ds2_11_calc_normal(final_pos)); float3 final_pos_world = mul(unity_ObjectToWorld, float4(final_pos, 1)); float4 final_color = 1; float snowline_noise = 0; - float alpha = 0.6; + float alpha = 0.3; float alpha_rcp = 1 / alpha; for (uint ii = 0; ii < _Gimmick_DS2_11_Snowline_Octaves; ii++) { snowline_noise += _Gimmick_DS2_Noise.SampleLevel(linear_repeat_s, final_pos.xz * _Gimmick_DS2_11_Snowline_Noise_Scale * pow(alpha_rcp, ii), 0) * pow(alpha, ii); @@ -806,7 +951,6 @@ Gimmick_DS2_Output Gimmick_DS2_11(inout v2f i, ToonerData tdata) _Gimmick_DS2_11_Fog_Color) * hit; } - float3 normal = UnityObjectToWorldNormal(ds2_11_calc_normal(final_pos)); Gimmick_DS2_Output o; o.albedo = final_color; o.emission = 0; diff --git a/feature_macros.cginc b/feature_macros.cginc index a06128d..79532b4 100644 --- a/feature_macros.cginc +++ b/feature_macros.cginc @@ -241,6 +241,7 @@ #pragma shader_feature_local _ _GIMMICK_EYES_02 #pragma shader_feature_local _ _GIMMICK_DS2 #pragma shader_feature_local _ _GIMMICK_HALO_00 +#pragma shader_feature_local _ _GIMMICK_EPILEPSY_MODE #pragma shader_feature_local _ _PIXELLATE #pragma shader_feature_local _ _TROCHOID #pragma shader_feature_local _ _FACE_ME_WORLD_Y @@ -82,7 +82,9 @@ float map(float3 p, out float3 normal) { #define RADIUS_TRANS_WIDTH_RCP (1.0 / RADIUS_TRANS_WIDTH) // Try to create a smooth transition without doing any length() or other // transcendental ops. - float radius2 = clamp(_Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius - dot(p.xz, p.xz), 0, RADIUS_TRANS_WIDTH) * RADIUS_TRANS_WIDTH_RCP; + float radius2 = (_Gimmick_Fog_00_Boundary_Type == 0) ? + clamp(_Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius - dot(p.xz, p.xz), 0, RADIUS_TRANS_WIDTH) * RADIUS_TRANS_WIDTH_RCP : + 0; float3 pp = p * _Gimmick_Fog_00_Noise_Scale * FOG_PERLIN_NOISE_SCALE; normal = normalize(perlin_noise_3d_tex(pp+t) * 2 - 1); @@ -225,20 +227,21 @@ float fog00_map_dr( } #endif -Fog00PBR getFog00(v2f i, ToonerData tdata) { - float3 cam_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)).xyz; - float3 obj_pos = i.objPos; +Fog00PBR __getFog00(v2f i, ToonerData tdata, + float3 obj_pos_depth_hit, + float2 screen_uv); +Fog00PBR getFog00(v2f i, ToonerData tdata) +{ float3 obj_pos_depth_hit; float2 screen_uv; - float eye_depth_world; { float3 full_vec_eye_to_geometry = i.worldPos - _WorldSpaceCameraPos; float3 world_dir = normalize(i.worldPos - _WorldSpaceCameraPos); float perspective_divide = 1.0 / i.pos.w; float perspective_factor = length(full_vec_eye_to_geometry * perspective_divide); screen_uv = i.screenPos.xy * perspective_divide; - eye_depth_world = + float eye_depth_world = GetLinearZFromZDepth_WorksWithMirrors( SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, tdata.screen_uv), screen_uv) * perspective_factor; @@ -246,26 +249,63 @@ Fog00PBR getFog00(v2f i, ToonerData tdata) { obj_pos_depth_hit = mul(unity_WorldToObject, float4(world_pos_depth_hit, 1.0)).xyz; } + return __getFog00(i, tdata, obj_pos_depth_hit, screen_uv); +} + +Fog00PBR __getFog00(v2f i, ToonerData tdata, + float3 obj_pos_depth_hit, + float2 screen_uv) +{ + float3 cam_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)).xyz; + float3 obj_pos = i.objPos; + const float3 rd = normalize(obj_pos - cam_pos); float3 ro = cam_pos; - bool no_intersection = false; - float distance_to_cylinder = 1E6; - { - float a = dot(rd.xz, rd.xz); - float b = 2 * dot(rd.xz, ro.xz); - float c = dot(ro.xz, ro.xz) - _Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius; - float t0, t1; - if (solveQuadratic(a, b, c, t0, t1)) { - no_intersection = (t0 < 0) * (t1 < 0); - const bool inside_cylinder = (t0 < 0) * (t1 > 0); - if (!inside_cylinder) { - distance_to_cylinder = no_intersection ? distance_to_cylinder : min(max(t0, 0), max(t1, 0)); - ro += distance_to_cylinder * rd; + if (_Gimmick_Fog_00_Boundary_Type == 0) { + // Raytrace distance to cylinder + bool no_intersection = false; + float distance_to_cylinder = 1E6; + { + float a = dot(rd.xz, rd.xz); + float b = 2 * dot(rd.xz, ro.xz); + float c = dot(ro.xz, ro.xz) - _Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius; + float t0, t1; + if (solveQuadratic(a, b, c, t0, t1)) { + no_intersection = (t0 < 0) * (t1 < 0); + const bool inside_cylinder = (t0 < 0) * (t1 > 0); + if (!inside_cylinder) { + distance_to_cylinder = no_intersection ? distance_to_cylinder : min(max(t0, 0), max(t1, 0)); + ro += distance_to_cylinder * rd; + } } } + clip(no_intersection ? -1 : 1); + } else if (_Gimmick_Fog_00_Boundary_Type == 1) { + // Raytrace distance to plane + bool no_intersection = false; + float distance_to_plane = 1E6; + { + // Define the plane by normal and point + float3 n = normalize(mul(unity_WorldToObject, float4(_Gimmick_Fog_00_Plane_Normal, 0.0)).xyz); + float3 p0 = _Gimmick_Fog_00_Plane_Center; + + float denom = dot(n, rd); + if (abs(denom) > 1e-6) { + // The ray is not parallel to the plane + float t = dot(n, (p0 - ro)) / denom; + if (t >= 0) { + distance_to_plane = t; + ro += distance_to_plane * rd; + } else { + no_intersection = true; // Intersection is behind the ray origin + } + } else { + no_intersection = true; // Ray is parallel to the plane + } + } + clip(no_intersection ? -1 : 1); } - clip(no_intersection ? -1 : 1); float density_ss_term = 1 / _Gimmick_Fog_00_Density; //density_ss_term = dclamp(density_ss_term, 0.33, 3.00, 5); @@ -279,8 +319,6 @@ Fog00PBR getFog00(v2f i, ToonerData tdata) { const float raw_noise_sample = _Gimmick_Fog_00_Noise_2D.SampleLevel(point_repeat_s, screen_uv * _ScreenParams.xy * _Gimmick_Fog_00_Noise_2D_TexelSize.xy, 0).x; const float dither_seed = frac(raw_noise_sample + frame * PHI); #elif 1 - // float ign_anim(float2 screen_px, float frame, float speed) { - //const float dither_seed = ign_anim(screen_uv_round, frame, /*speed=*/0.001); const float dither_seed = frac(ign_anim(screen_uv_round, frame, /*speed=*/0.000) + frame * 1.618033989); #else const float dither_seed = rand2(float2(screen_uv_round.x, screen_uv_round.y)*.001); @@ -384,8 +422,10 @@ Fog00PBR getFog00(v2f i, ToonerData tdata) { // For performance, stop if we... // 1. accumulate enough alpha // 2. go outside of the sphere - if (acc.a > _Gimmick_Fog_00_Alpha_Cutoff || - dot(p.xz, p.xz) > _Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius) { + if (acc.a > _Gimmick_Fog_00_Alpha_Cutoff) { + break; + } + if (_Gimmick_Fog_00_Boundary_Type == 0 && dot(p.xz, p.xz) > _Gimmick_Fog_00_Radius * _Gimmick_Fog_00_Radius) { break; } #endif @@ -472,7 +512,6 @@ Fog01PBR getFog01(v2f i, ToonerData tdata) { float activation_radius = _Gimmick_Fog_01_Activation_Radius; float cur_radius = length(_WorldSpaceCameraPos - activation_center); [branch] - //if (cur_radius > activation_radius) { if (getCenterCamPos().y > activation_center.y + activation_radius) { return (Fog01PBR)0; } diff --git a/globals.cginc b/globals.cginc index 9af8300..33f0ae2 100644 --- a/globals.cginc +++ b/globals.cginc @@ -96,6 +96,7 @@ float _Clearcoat_Mask_Invert; texture2D _Clearcoat_Mask2; float _Clearcoat_Mask2_Invert; #endif +float _Clearcoat_Use_Texture_Normals; #endif #if defined(SSR_ENABLED) @@ -775,6 +776,7 @@ float3 _Gimmick_Eyes02_Emission; float _Gimmick_DS2_Enable_Static; texture2D _Gimmick_DS2_Mask; texture2D _Gimmick_DS2_Noise; +float4 _Gimmick_DS2_Noise_TexelSize; float _Gimmick_DS2_Choice; // 00 float _Gimmick_DS2_Albedo_Factor; @@ -818,6 +820,7 @@ float _Gimmick_DS2_11_Snowline_Octaves; float _Gimmick_DS2_11_Snowline_Width; float _Gimmick_DS2_11_Snowline_Noise_Scale; float3 _Gimmick_DS2_11_Snow_Color; +texture2D _Gimmick_DS2_11_FBM; float _Gimmick_DS2_11_Rockline; float _Gimmick_DS2_11_Rockline_Octaves; float _Gimmick_DS2_11_Rockline_Width; @@ -827,8 +830,11 @@ float3 _Gimmick_DS2_11_Grass_Color; float _Gimmick_DS2_11_Alpha; float _Gimmick_DS2_11_Octaves; float _Gimmick_DS2_11_March_Initial_Offset; +float _Gimmick_DS2_11_March_Initial_Step_Size; float _Gimmick_DS2_11_March_Steps; +float _Gimmick_DS2_11_March_Backtrack_Steps; float _Gimmick_DS2_11_Simulation_Scale; +float _Gimmick_DS2_11_Coord_Scale; float _Gimmick_DS2_11_Height_Scale; float3 _Gimmick_DS2_11_XZ_Offset; float _Gimmick_DS2_11_Distance_Culling_Enable; @@ -947,6 +953,9 @@ float _Gimmick_AL_Chroma_00_Hue_Shift_Theta; float _Gimmick_Fog_00_Max_Ray; float _Gimmick_Fog_00_Enable_Area_Lighting; float _Gimmick_Fog_00_Radius; +float _Gimmick_Fog_00_Boundary_Type; +float3 _Gimmick_Fog_00_Plane_Normal; +float3 _Gimmick_Fog_00_Plane_Center; float _Gimmick_Fog_00_Step_Size_Factor; float3 _Gimmick_Fog_00_Noise_Scale; float3 _Gimmick_Fog_00_Motion_Vector; @@ -958,6 +967,7 @@ float _Gimmick_Fog_00_Ray_Origin_Randomization; float _Gimmick_Fog_00_Lod_Half_Life; float _Gimmick_Fog_00_Max_Brightness; float _Gimmick_Fog_00_LTCGI_Brightness; +float _Gimmick_Fog_00_Overlay_Mode; texture3D _Gimmick_Fog_00_Noise; #if defined(_GIMMICK_FOG_00_NOISE_2D) texture2D _Gimmick_Fog_00_Noise_2D; @@ -1044,6 +1054,13 @@ float _Gimmick_Box_Discard_Invert; float _Gimmick_Fog_00_Ray_March_0_Seed; #endif +#if defined(_GIMMICK_EPILEPSY_MODE) +float _Gimmick_Epilepsy_Mode_Enable_Dynamic; +float _Gimmick_Epilepsy_Mode_Luminance_Cutoff; +float _Gimmick_Epilepsy_Mode_Saturation_Cutoff; +float _Gimmick_Epilepsy_Mode_Rolloff_Power; +#endif + #if defined(_RENDERING_CUTOUT_NOISE_MASK) texture2D _Rendering_Cutout_Noise_Mask; float4 _Rendering_Cutout_Noise_Mask_TexelSize; diff --git a/oklab.cginc b/oklab.cginc index 0a354f3..1d255a9 100644 --- a/oklab.cginc +++ b/oklab.cginc @@ -29,7 +29,7 @@ #ifndef __OKLAB_INC #define __OKLAB_INC -#if defined(_OKLAB) || defined(_GIMMICK_LETTER_GRID_COLOR_WAVE) || defined(_GIMMICK_AL_CHROMA_00_HUE_SHIFT) || defined(_GIMMICK_FOG_00) || defined(_GIMMICK_DS2) +#if defined(_OKLAB) || defined(_GIMMICK_LETTER_GRID_COLOR_WAVE) || defined(_GIMMICK_AL_CHROMA_00_HUE_SHIFT) || defined(_GIMMICK_FOG_00) || defined(_GIMMICK_DS2) || defined(_GIMMICK_EPILEPSY_MODE) // Utilities relating to the OKLAB color space, as defined here: // https://bottosson.github.io/posts/oklab/ @@ -423,6 +423,7 @@ float4 getLitColor( } cc_mask *= cc_mask2_tmp; #endif + float3 cc_normal = _Clearcoat_Use_Texture_Normals ? normal : i.normal; // Diffuse specular const float cc_roughness = max(1E-4, _Clearcoat_Roughness); { @@ -431,12 +432,12 @@ float4 getLitColor( // https://google.github.io/filament/Filament.html metallic = 0; smoothness = 1.0 - _Clearcoat_Roughness; - indirect_light.specular = getIndirectSpecular(i, view_dir, normal, smoothness, + indirect_light.specular = getIndirectSpecular(i, view_dir, cc_normal, smoothness, metallic, worldPos, uv); - const float3 l = reflect(-view_dir, normal); + const float3 l = reflect(-view_dir, cc_normal); const float3 h = normalize(l + view_dir); - const float NoH = dot(normal, h); + const float NoH = dot(cc_normal, h); const float LoH = dot(l, h); float Fc; @@ -453,7 +454,7 @@ float4 getLitColor( { const float3 l = direct_light.dir; const float3 h = normalize(l + view_dir); - const float NoH = dot(normal, h); + const float NoH = dot(cc_normal, h); const float LoH = dot(direct_light.dir, h); float Fc; diff --git a/tooner.shader b/tooner.shader index e6502a8..4d8a422 100644 --- a/tooner.shader +++ b/tooner.shader @@ -18,6 +18,7 @@ Shader "yum_food/tooner" _Clearcoat_Mask_Invert("Clearcoat mask invert", Float) = 0 _Clearcoat_Mask2("Clearcoat mask 2", 2D) = "white" {} _Clearcoat_Mask2_Invert("Clearcoat mask 2 invert", Float) = 0 + _Clearcoat_Use_Texture_Normals("Use texture normals", Float) = 1 _Rendering_Cutout_Noise_Mask("Noise mask", 2D) = "white" {} @@ -854,6 +855,7 @@ Shader "yum_food/tooner" _Gimmick_DS2_11_Snowline_Octaves("Snowline octaves", Float) = 1 _Gimmick_DS2_11_Snowline_Width("Snowline width", Float) = 0.1 _Gimmick_DS2_11_Snowline_Noise_Scale("Snowline noise scale", Float) = 1 + _Gimmick_DS2_11_FBM("FBM", 2D) = "white" {} [HDR] _Gimmick_DS2_11_Snow_Color("Snow color", Color) = (1, 1, 1, 1) _Gimmick_DS2_11_Rockline("Rockline", Float) = 0 _Gimmick_DS2_11_Rockline_Octaves("Rockline octaves", Float) = 1 @@ -864,8 +866,11 @@ Shader "yum_food/tooner" _Gimmick_DS2_11_Alpha("Alpha", Range(0, 1)) = 0.5 _Gimmick_DS2_11_Octaves("Octaves", Float) = 12 _Gimmick_DS2_11_March_Steps("March steps", Float) = 24 + _Gimmick_DS2_11_March_Backtrack_Steps("March backtrack steps", Float) = 5 _Gimmick_DS2_11_March_Initial_Offset("March initial offset", Float) = 0 + _Gimmick_DS2_11_March_Initial_Step_Size("March initial step size", Float) = 0.01 _Gimmick_DS2_11_Simulation_Scale("Simulation scale", Float) = 1 + _Gimmick_DS2_11_Coord_Scale("Coord scale", Float) = 1 _Gimmick_DS2_11_Height_Scale("Height scale", Float) = 1 _Gimmick_DS2_11_XZ_Offset("XZ offset", Vector) = (0, 0, 0, 0) _Gimmick_DS2_11_Distance_Culling_Enable("Distance culling enable", Float) = 0 @@ -874,6 +879,12 @@ Shader "yum_food/tooner" _Gimmick_Halo00_Enable_Static("Enable halo", Float) = 0.0 + _Gimmick_Epilepsy_Mode_Enable_Static("Enable epilepsy mode", Float) = 0.0 + _Gimmick_Epilepsy_Mode_Enable_Dynamic("Enable epilepsy mode", Float) = 0.0 + _Gimmick_Epilepsy_Mode_Luminance_Cutoff("Luminance cutoff", Range(0, 1)) = 0.5 + _Gimmick_Epilepsy_Mode_Saturation_Cutoff("Saturation cutoff", Range(0, 1)) = 0.4 + _Gimmick_Epilepsy_Mode_Rolloff_Power("Rolloff power", Range(0, 1)) = 8 + _Gimmick_Pixellate_Enable_Static("Enable pixellation", Float) = 0.0 _Gimmick_Pixellate_Resolution_U("Resolution (U)", Float) = 64 _Gimmick_Pixellate_Resolution_V("Resolution (V)", Float) = 64 @@ -995,10 +1006,14 @@ Shader "yum_food/tooner" _Gimmick_Fog_00_Enable_Static("Enable fog 00", Float) = 0 _Gimmick_Fog_00_Enable_Area_Lighting("Enable fog 00 area lighting", Float) = 1 + // 0 = cylinder, 1 = plane + _Gimmick_Fog_00_Boundary_Type("Boundary type", Float) = 0 + _Gimmick_Fog_00_Radius("Radius", Float) = 25 + _Gimmick_Fog_00_Plane_Normal("Plane normal", Vector) = (0, 1, 0, 0) + _Gimmick_Fog_00_Plane_Center("Plane center", Vector) = (0, 0, 0, 0) _Gimmick_Fog_00_Noise("3D noise", 3D) = "white" {} _Gimmick_Fog_00_Noise_2D("2D noise", 2D) = "black" {} _Gimmick_Fog_00_Max_Ray("Max ray", Float) = 25 - _Gimmick_Fog_00_Radius("Radius", Float) = 25 _Gimmick_Fog_00_Step_Size_Factor("Step size (meters)", Float) = 1 _Gimmick_Fog_00_Noise_Scale("Noise scale", Vector) = (1, 1, 1, 1) _Gimmick_Fog_00_Motion_Vector("Motion vector", Vector) = (0, 0, 0, 0) @@ -1010,7 +1025,7 @@ Shader "yum_food/tooner" _Gimmick_Fog_00_Lod_Half_Life("fog", Float) = 5 _Gimmick_Fog_00_Max_Brightness("max brightness", Range(0, 1)) = 1 _Gimmick_Fog_00_LTCGI_Brightness("LTCGI brightness", Float) = 1 - + _Gimmick_Fog_00_Overlay_Mode("Overlay mode", Float) = 0 _Gimmick_Fog_00_Emitter_Texture("Emitter texture", 2D) = "black" {} _Gimmick_Fog_00_Emitter_Variable_Density("Enable emitter variable density", Float) = 0 _Gimmick_Fog_00_Emitter_Brightness_Diffuse("fog", Float) = 1 diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc index a0a5777..0a2139c 100644 --- a/tooner_lighting.cginc +++ b/tooner_lighting.cginc @@ -959,6 +959,28 @@ float4 pixellate_color(int2 px_res, float2 uv, float4 c) } #endif +#if defined(_GIMMICK_EPILEPSY_MODE) +float4 map_color_epilepsy(float4 color) { + [branch] + if (_Gimmick_Epilepsy_Mode_Enable_Dynamic) { + color.rgb = saturate(color.rgb); + + color.rgb = LRGBtoOKLCH(color.rgb); + color.rgb[0] = dmin(color.rgb[0], _Gimmick_Epilepsy_Mode_Luminance_Cutoff, _Gimmick_Epilepsy_Mode_Rolloff_Power); + color.rgb = OKLCHtoLRGB(color.rgb); + + color.rgb = RGBtoHSV(color.rgb); + color.rgb[1] = dmin(color.rgb[1], _Gimmick_Epilepsy_Mode_Saturation_Cutoff, _Gimmick_Epilepsy_Mode_Rolloff_Power); + color.rgb = HSVtoRGB(color.rgb); + } + + return color; +} +#define FILTER_COLOR(color) map_color_epilepsy(color) +#else +#define FILTER_COLOR(color) color +#endif + float4 effect(inout v2f i, out float depth) { ToonerData tdata; @@ -2130,38 +2152,6 @@ float4 effect(inout v2f i, out float depth) float ao = 1; #endif - float3 diffuse_contrib = 0; -#if defined(_GIMMICK_FOG_00) - { - Fog00PBR pbr = getFog00(i, tdata); - albedo = pbr.albedo; - depth = pbr.depth; -#if defined(_RENDERING_TRANSPARENT) || defined(_RENDERING_TRANSCLIPPING) - albedo.rgb *= albedo.a; -#endif - return albedo; - } -#endif -#if defined(_GIMMICK_FOG_01) - if (!round(_Gimmick_Fog_01_Overlay_Mode)) { - Fog01PBR fog_01_pbr = getFog01(i, tdata); - albedo = fog_01_pbr.albedo; - depth = fog_01_pbr.depth; -#if defined(_RENDERING_TRANSPARENT) || defined(_RENDERING_TRANSCLIPPING) - albedo.rgb *= albedo.a; -#endif - return albedo; - } -#endif -#if defined(_GIMMICK_AURORA) - { - AuroraPBR pbr = getAurora(i); - albedo = pbr.albedo; - depth = pbr.depth; - diffuse_contrib += pbr.diffuse; - } -#endif - #if defined(_GIMMICK_FLAT_COLOR) if (round(_Gimmick_Flat_Color_Enable_Dynamic)) { albedo = _Gimmick_Flat_Color_Color; @@ -2223,10 +2213,48 @@ float4 effect(inout v2f i, out float depth) } #endif + float3 diffuse_contrib = 0; +#if defined(_GIMMICK_FOG_01) + if (!round(_Gimmick_Fog_01_Overlay_Mode)) { + Fog01PBR fog_01_pbr = getFog01(i, tdata); + albedo = fog_01_pbr.albedo; + depth = fog_01_pbr.depth; +#if defined(_RENDERING_TRANSPARENT) || defined(_RENDERING_TRANSCLIPPING) + albedo.rgb *= albedo.a; +#endif + return albedo; + } +#endif +#if defined(_GIMMICK_AURORA) + { + AuroraPBR pbr = getAurora(i); + albedo = pbr.albedo; + depth = pbr.depth; + diffuse_contrib += pbr.diffuse; + } +#endif + float4 lit = getLitColor(vertex_light_color, albedo, i.worldPos, normal, metallic, 1.0 - roughness, i.uv0, ao, /*enable_direct=*/true, diffuse_contrib, i, tdata); +#if defined(_GIMMICK_FOG_00) + { + if (round(_Gimmick_Fog_00_Overlay_Mode)) { + Fog00PBR pbr = __getFog00(i, tdata, mul(unity_WorldToObject, float4(i.worldPos, 1.0)).xyz, tdata.screen_uv); + lit = pbr.albedo + lit * (1 - pbr.albedo.a); + } else { + Fog00PBR pbr = getFog00(i, tdata); + albedo = pbr.albedo; + depth = pbr.depth; +#if defined(_RENDERING_TRANSPARENT) || defined(_RENDERING_TRANSCLIPPING) + albedo.rgb *= albedo.a; +#endif + return albedo; + } + } +#endif + #if defined(_GIMMICK_FLAT_COLOR) if (round(_Gimmick_Flat_Color_Enable_Dynamic)) { #if defined(_RENDERING_CUTOUT) @@ -2353,7 +2381,7 @@ fixed4 frag(v2f i #endif */ - return effect(i, depth); + return FILTER_COLOR(effect(i, depth)); } #endif // TOONER_LIGHTING |
