summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2025-01-21 19:58:34 -0800
committeryum <yum.food.vr@gmail.com>2025-01-21 19:58:34 -0800
commit4ec13bd7513f29e16ab22b7ffe7d06724c92a912 (patch)
treee82920d170455fbfade69f7487ae5f6f4d0c1dd0
parente2911359e5acf79beb5c8359145669b96a931ab0 (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.cs90
-rw-r--r--downstairs_02.cginc164
-rw-r--r--feature_macros.cginc1
-rw-r--r--fog.cginc89
-rw-r--r--globals.cginc17
-rw-r--r--oklab.cginc2
-rw-r--r--pbr.cginc9
-rw-r--r--tooner.shader19
-rw-r--r--tooner_lighting.cginc94
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
diff --git a/fog.cginc b/fog.cginc
index 5d6137f..8f9c0e3 100644
--- a/fog.cginc
+++ b/fog.cginc
@@ -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/
diff --git a/pbr.cginc b/pbr.cginc
index c839dcc..3d74dc6 100644
--- a/pbr.cginc
+++ b/pbr.cginc
@@ -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