diff options
| author | yum <yum.food.vr@gmail.com> | 2025-01-14 21:01:26 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2025-01-14 21:01:28 -0800 |
| commit | 333562544ef1b71a7a4d7ce1ece533bef98ce0da (patch) | |
| tree | c9620943f8a772db0da777e1aa759b30adb17925 | |
| parent | ab441140208d6dd8317f328f40a25c6054f1a304 (diff) | |
im going to kill myself
attempt to fix hypotrochoid normals
key insight is that multiplying normal by transpose(invert(jacobian)) of
transform should work, but it fucking doesn't
| -rw-r--r-- | Editor/tooner.cs | 8 | ||||
| -rw-r--r-- | fog.cginc | 15 | ||||
| -rw-r--r-- | globals.cginc | 4 | ||||
| -rw-r--r-- | interpolators.cginc | 8 | ||||
| -rw-r--r-- | mochie_shadow_caster.cginc | 8 | ||||
| -rw-r--r-- | tooner.shader | 4 | ||||
| -rw-r--r-- | tooner_lighting.cginc | 28 | ||||
| -rw-r--r-- | tooner_outline_pass.cginc | 10 | ||||
| -rw-r--r-- | trochoid_math.cginc | 195 |
9 files changed, 192 insertions, 88 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs index 1f759c2..0d15a3a 100644 --- a/Editor/tooner.cs +++ b/Editor/tooner.cs @@ -1981,6 +1981,14 @@ public class ToonerGUI : ShaderGUI { FloatProperty(bc, "r"); bc = FindProperty("_Trochoid_d"); FloatProperty(bc, "d"); + bc = FindProperty("_Trochoid_Speed"); + FloatProperty(bc, "Speed"); + bc = FindProperty("_Trochoid_Radius_Power"); + FloatProperty(bc, "Radius power"); + bc = FindProperty("_Trochoid_Radius_Scale"); + FloatProperty(bc, "Radius scale"); + bc = FindProperty("_Trochoid_Height_Scale"); + FloatProperty(bc, "Height scale"); EditorGUI.indentLevel -= 1; } @@ -257,10 +257,7 @@ Fog00PBR getFog00(v2f i, ToonerData tdata) { 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 : max(t0, t1); - distance_to_cylinder = min(distance_to_cylinder, length(obj_pos_depth_hit - ro)); - } else { + if (!inside_cylinder) { distance_to_cylinder = no_intersection ? distance_to_cylinder : min(max(t0, 0), max(t1, 0)); ro += distance_to_cylinder * rd; } @@ -306,7 +303,7 @@ Fog00PBR getFog00(v2f i, ToonerData tdata) { float4 acc = 0; uint step_count = floor(min(_Gimmick_Fog_00_Max_Ray, depth_hit_l) / step_size); //step_count *= (1 - no_intersection); -#define FOG_MAX_LOOP 10 +#define FOG_MAX_LOOP 20 step_count = min(step_count, FOG_MAX_LOOP); #if defined(_GIMMICK_FOG_00_EMITTER_TEXTURE) @@ -401,8 +398,7 @@ Fog00PBR getFog00(v2f i, ToonerData tdata) { Fog00PBR pbr; pbr.albedo = acc; - pbr.albedo.a *= 1; - pbr.albedo.a = smooth_min(pbr.albedo.a, .99, 1); + pbr.albedo.a = smooth_min(pbr.albedo.a, .999, 1); // Add some dithering to lit color to break up banding //const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x); @@ -419,6 +415,11 @@ Fog00PBR getFog00(v2f i, ToonerData tdata) { float4 clip_pos = mul(UNITY_MATRIX_VP, float4(mul(unity_ObjectToWorld, float4(ro, 1.0)))); pbr.depth = clip_pos.z / clip_pos.w; +#if 0 + pbr.albedo.rgb = eye_depth_world / 100; + pbr.albedo.a = 1; +#endif + return pbr; } diff --git a/globals.cginc b/globals.cginc index 9574043..0b1308f 100644 --- a/globals.cginc +++ b/globals.cginc @@ -801,6 +801,10 @@ texture2D _Gimmick_Pixellate_Effect_Mask; float _Trochoid_R; float _Trochoid_r; float _Trochoid_d; +float _Trochoid_Speed; +float _Trochoid_Radius_Power; +float _Trochoid_Radius_Scale; +float _Trochoid_Height_Scale; #endif #if defined(_FACE_ME_WORLD_Y) diff --git a/interpolators.cginc b/interpolators.cginc index 4955415..2193339 100644 --- a/interpolators.cginc +++ b/interpolators.cginc @@ -50,6 +50,10 @@ struct v2f float2 screenPos : TEXCOORD14; +#if defined(_TROCHOID) + float3 objPos_pre_trochoid : TEXCOORD15; +#endif + UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; @@ -108,6 +112,10 @@ struct v2f float3 vertexLightColor : TEXCOORD16; #endif +#if defined(_TROCHOID) + float3 objPos_pre_trochoid : TEXCOORD17; +#endif + UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; diff --git a/mochie_shadow_caster.cginc b/mochie_shadow_caster.cginc index 64f6350..0d15d41 100644 --- a/mochie_shadow_caster.cginc +++ b/mochie_shadow_caster.cginc @@ -1,5 +1,8 @@ +#include "UnityCG.cginc" + #include "atrix256.cginc" #include "gerstner.cginc" +#include "trochoid_math.cginc" #ifndef __MOCHIE_SHADOW_CASTER_INC #define __MOCHIE_SHADOW_CASTER_INC @@ -60,6 +63,11 @@ v2f vert (appdata v){ return (v2f) (0.0 / 0.0); } #endif +#if defined(_TROCHOID) + { + v.vertex.xyz = cyl2_to_troch_map(cyl_to_cyl2_map(cart_to_cyl_map(v.vertex.xyz))); + } +#endif #if !defined(_SCROLL) && defined(_GIMMICK_GERSTNER_WATER) { GerstnerParams p = getGerstnerParams(); diff --git a/tooner.shader b/tooner.shader index e192644..b2bdedd 100644 --- a/tooner.shader +++ b/tooner.shader @@ -849,6 +849,10 @@ Shader "yum_food/tooner" _Trochoid_R("R", Float) = 5.0 _Trochoid_r("r", Float) = 3.0 _Trochoid_d("d", Float) = 5.0 + _Trochoid_Speed("Speed", Float) = 1.0 + _Trochoid_Radius_Power("Radius power", Float) = 1.0 + _Trochoid_Radius_Scale("Radius scale", Float) = 1.0 + _Trochoid_Height_Scale("Height scale", Float) = 1.0 _FaceMeWorldY_Enable_Static("Enable face me gimmick", Float) = 0.0 _FaceMeWorldY_Enable_Dynamic("Enable face me gimmick", Float) = 0.0 diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc index e088c17..adf7890 100644 --- a/tooner_lighting.cginc +++ b/tooner_lighting.cginc @@ -137,9 +137,8 @@ v2f vert(appdata v) #if defined(_TROCHOID) { - float theta = v.uv0.x * TAU; - float r0 = length(v.vertex.xyz); - v.vertex.xyz = trochoid_map(theta, r0, v.vertex.z); + o.objPos_pre_trochoid = v.vertex.xyz; + v.vertex.xyz = cyl2_to_troch_map(cyl_to_cyl2_map(cart_to_cyl_map(v.vertex.xyz))); } #endif #if defined(_FACE_ME_WORLD_Y) @@ -1598,12 +1597,23 @@ float4 effect(inout v2f i, out float depth) #if defined(_TROCHOID) { - i.normal = trochoid_normal(i.objPos.xyz, i.uv0); - - float theta = i.uv0.x * TAU; - float r0 = length(i.objPos.xyz); - float z = i.objPos.z; - i.objPos.xyz = trochoid_map(theta, r0, z); + // Let h(v) be the trochoid of the cartesian coordinates v. + // We evaluate h(v) by first mapping it to cylindrical coordinates, then applying a trochoid function defined on those coordinates: + // h(v) = h_cyl(g(v)) + // g(v) maps v to cylindrical coordinates. + // h_cyl(v) evaluates the trochoid function on cylindrical coordinates. + // We want to compute h'(v), i.e. its Jacobian. + // By the chain rule: + // h'(v) = h_cyl'(g(v)) * g'(v) + // The reality is a little more complex: we also apply a distortion to the cylindrical coordinates: + // h(v) = h_cyl(f(g(v))) + // where f(v) is that distortion. + // Again, by the chain rule: + // h'(v) = h_cyl'(f(g(v))) * f'(g(v)) * g'(v) + float3x3 j0 = cart_to_cyl_jacobian(i.objPos_pre_trochoid); + float3x3 j1 = cyl_to_cyl2_jacobian(cart_to_cyl_map(i.objPos_pre_trochoid)); + float3x3 j2 = cyl2_to_troch_jacobian(cyl_to_cyl2_map(cart_to_cyl_map(i.objPos_pre_trochoid))); + i.normal = normalize(mul(transpose(invert(mul(j0, mul(j1, j2)))), i.normal)); } #endif diff --git a/tooner_outline_pass.cginc b/tooner_outline_pass.cginc index a318c5f..02b6497 100644 --- a/tooner_outline_pass.cginc +++ b/tooner_outline_pass.cginc @@ -36,15 +36,7 @@ v2f vert(appdata v) #if defined(_TROCHOID) { -#define TAU PI * 2.0 - float theta = v.uv0.x * TAU; - float r0 = length(v.vertex.xyz); - - float x = v.vertex.x; - float y = v.vertex.y; - float z = v.vertex.z; - - v.vertex.xyz = trochoid_map(theta, r0, z); + v.vertex.xyz = cyl2_to_troch_map(cyl_to_cyl2_map(cart_to_cyl_map(v.vertex.xyz))); } #endif diff --git a/trochoid_math.cginc b/trochoid_math.cginc index 7a4e7e2..dd6d69c 100644 --- a/trochoid_math.cginc +++ b/trochoid_math.cginc @@ -6,83 +6,152 @@ #if defined(_TROCHOID) -float3 trochoid_map(float theta, float r0, float3 vert_z) +#define TROCH_POSITION_SCALE 0.1 +#define TROCH_Z_THETA_SCALE 0.0002 +#define TROCH_EPSILON 1e-5 + +float3 cyl2_to_troch_map(float3 pos) { - r0 *= r0; - r0 *= 100; + float theta = pos.x; float R = _Trochoid_R; float r = _Trochoid_r; float d = _Trochoid_d; - theta *= max(R, r); - float theta_t = theta + _Time[2]; + float x = ((R - r) * cos(theta * R) + d * cos((R - r) * theta * R / r)) * pos.y * TROCH_POSITION_SCALE; + float y = ((R - r) * sin(theta * R) - d * sin((R - r) * theta * R / r)) * pos.y * TROCH_POSITION_SCALE; + float z = (pos.z + cos(theta * R * 5) * TROCH_POSITION_SCALE + theta * R * TROCH_Z_THETA_SCALE) * pos.y; - float x = (R - r) * cos(theta_t) + d * cos((R - r) * theta_t / r); - float y = (R - r) * sin(theta_t) - d * sin((R - r) * theta_t / r); - float z = vert_z + cos(theta_t * 5) * .1 + theta * .0002; + return float3(x, y, z); +} - float3 result = float3(x, y, z) * r0; - result.xy *= 0.1; - return result; +float3 cyl_to_cyl2_map(float3 v) +{ + return float3(v.x, pow(v.y, _Trochoid_Radius_Power) * _Trochoid_Radius_Scale, v.z * _Trochoid_Height_Scale); } -float trochoid_normal(float3 objPos, float2 uv) +float3 cart_to_cyl_map(float3 v) { - float theta = uv.x * TAU; - float r0 = length(objPos.xyz); - - float x = objPos.x; - float y = objPos.y; - float z = objPos.z; - - float e = 5E-2; - float small_step = 1E-2 * e; - float du_dt = (trochoid_map(theta + small_step, r0, z) - trochoid_map(theta - small_step, r0, z)) / small_step; - small_step = 1E-4 * e; - float du_dr = (trochoid_map(theta, r0 + small_step, z) - trochoid_map(theta, r0 - small_step, z)) / small_step; - small_step = 1E-5 * e; - float du_dz = (trochoid_map(theta, r0, z + small_step) - trochoid_map(theta, r0, z - small_step)) / small_step; - - // U(T(x, y, z), R(x, y, z), Z(x, y, z)) - // T(x, y, z) = atan2(y, x) - // R(x, y, z) = length(float3(x, y, z)) - // Z(x, y, z) = z - // U(a, b, c) = trochoid_map(a, b, c) - // dU/dx = dU/dT dT/dx + dU/dR dR/dx + dU/dZ dZ/dx - // dU/dy = dU/dT dT/dy + dU/dR dR/dy + dU/dZ dZ/dy - // dU/dz = dU/dT dT/dz + dU/dR dR/dz + dU/dZ dZ/dz - // dT/dx = d/dx atan2(y, x) = -y / (x**2 + y**2) - // dT/dy = d/dx atan2(y, x) = x / (x**2 + y**2) - // dT/dz = d/dz atan2(y, x) = 0 - // dR/dx = d/dx sqrt(x**2 + y**2 + z**2) = x / sqrt(x**2 + y**2 + z**2) - // dR/dy = d/dy sqrt(x**2 + y**2 + z**2) = y / sqrt(x**2 + y**2 + z**2) - // dR/dz = d/dy sqrt(x**2 + y**2 + z**2) = z / sqrt(x**2 + y**2 + z**2) - // dZ/dx = 0 - // dZ/dy = 0 - // dZ/dz = 1 - float xy_norm = sqrt(x * x + y * y); - float dt_dx = -y / xy_norm; - float dt_dy = x / xy_norm; - float dt_dz = 0; - float xyz_norm = sqrt(x * x + y * y + z * z); - float dr_dx = x / xyz_norm; - float dr_dy = y / xyz_norm; - float dr_dz = z / xyz_norm; - float dz_dx = 0; - float dz_dy = 0; - float dz_dz = 1; - - float3 normal = - normalize( - float3( - du_dt * dt_dx + du_dr * dr_dx + du_dz * dz_dx, - du_dt * dt_dy + du_dr * dr_dy + du_dz * dz_dy, - du_dt * dt_dz + du_dr * dr_dz + du_dz * dz_dz)); - return UnityObjectToWorldNormal(normal); + return float3(atan2(v.y, v.x), length(v.xy), v.z); +} + +// Compute partial derivatives of trochoid function with respect to cylindrical coordinates +float3x3 cyl2_to_troch_jacobian(float3 pos) +{ + float theta = pos.x; + + float R = _Trochoid_R; + float r = _Trochoid_r; + float d = _Trochoid_d; + +#if 1 + float3 df_dt = float3( + ((R * (r - R) * (d * sin(R * theta * (R - r) / r) + r * sin(R * theta))) / r) * pos.y * TROCH_POSITION_SCALE, + ((R * (r - R) * (-d * cos(R * theta * (R - r) / r) + r * cos(R * theta))) / r) * pos.y * TROCH_POSITION_SCALE, + (-R * 5 * sin(theta * R * 5) * TROCH_POSITION_SCALE + R * TROCH_Z_THETA_SCALE) * pos.y); + float3 df_dr = float3( + ((R - r) * cos(theta * R) + d * cos((R - r) * theta * R / r)) * TROCH_POSITION_SCALE, + ((R - r) * sin(theta * R) - d * sin((R - r) * theta * R / r)) * TROCH_POSITION_SCALE, + (pos.z + cos(theta * R * 5) * TROCH_POSITION_SCALE + theta * R * TROCH_Z_THETA_SCALE)); + float3 df_dz = float3( + 0, + 0, + pos.y); +#else + float3 df_dt = (cyl2_to_troch_map(pos + float3(TROCH_EPSILON, 0, 0)) - cyl2_to_troch_map(pos - float3(TROCH_EPSILON, 0, 0))) / (2 * TROCH_EPSILON); + float3 df_dr = (cyl2_to_troch_map(pos + float3(0, TROCH_EPSILON, 0)) - cyl2_to_troch_map(pos - float3(0, TROCH_EPSILON, 0))) / (2 * TROCH_EPSILON); + float3 df_dz = (cyl2_to_troch_map(pos + float3(0, 0, TROCH_EPSILON)) - cyl2_to_troch_map(pos - float3(0, 0, TROCH_EPSILON))) / (2 * TROCH_EPSILON); +#endif + float3x3 jacobian_cyl; + jacobian_cyl[0] = df_dt; + jacobian_cyl[1] = df_dr; + jacobian_cyl[2] = df_dz; + return transpose(jacobian_cyl); +} + +float3x3 cyl_to_cyl2_jacobian(float3 pos) +{ + // f(x, y, z) = <x, (y^_Trochoid_Radius_Power) * _Trochoid_Radius_Scale, z * _Trochoid_Height_Scale> +#if 1 + float3 df_dx = float3(1, 0, 0); + float3 df_dy = float3(0, _Trochoid_Radius_Power * pow(pos.y, _Trochoid_Radius_Power - 1) * _Trochoid_Radius_Scale, 0); + float3 df_dz = float3(0, 0, _Trochoid_Height_Scale); +#else + float3 df_dx = (cyl_to_cyl2_map(pos + float3(TROCH_EPSILON, 0, 0)) - cyl_to_cyl2_map(pos - float3(TROCH_EPSILON, 0, 0))) / (2 * TROCH_EPSILON); + float3 df_dy = (cyl_to_cyl2_map(pos + float3(0, TROCH_EPSILON, 0)) - cyl_to_cyl2_map(pos - float3(0, TROCH_EPSILON, 0))) / (2 * TROCH_EPSILON); + float3 df_dz = (cyl_to_cyl2_map(pos + float3(0, 0, TROCH_EPSILON)) - cyl_to_cyl2_map(pos - float3(0, 0, TROCH_EPSILON))) / (2 * TROCH_EPSILON); +#endif + float3x3 jacobian_cyl_to_cyl2; + jacobian_cyl_to_cyl2[0] = df_dx; + jacobian_cyl_to_cyl2[1] = df_dy; + jacobian_cyl_to_cyl2[2] = df_dz; + return transpose(jacobian_cyl_to_cyl2); +} + +// Compute partial derivatives of transform from cartesian to cylindrical coordinates +float3x3 cart_to_cyl_jacobian(float3 pos) +{ + // Compute partial derivatives of transform from cartesian to cylindrical coordinates + // return float3(atan2(v.y, v.x), length(v.xy), v.z); + // theta = atan2(y, x) +#if 1 + float3 dtheta_dcart = float3( + -pos.y / dot(pos.xy, pos.xy), + pos.x / dot(pos.xy, pos.xy), + 0); +#else + float3 dtheta_dcart = (cart_to_cyl_map(pos + float3(TROCH_EPSILON, 0, 0)) - cart_to_cyl_map(pos - float3(TROCH_EPSILON, 0, 0))) / (2 * TROCH_EPSILON); +#endif + + // radius = (x^2 + y^2)^(1/2) +#if 1 + float3 dr_dcart = float3( + pos.x / sqrt(pos.x * pos.x + pos.y * pos.y), + pos.y / sqrt(pos.x * pos.x + pos.y * pos.y), + 0); +#else + float3 dr_dcart = (cart_to_cyl_map(pos + float3(0, TROCH_EPSILON, 0)) - cart_to_cyl_map(pos - float3(0, TROCH_EPSILON, 0))) / (2 * TROCH_EPSILON); +#endif + +#if 1 + float3 dz_dcart = float3( + 0, + 0, + 1); +#else + float3 dz_dcart = (cart_to_cyl_map(pos + float3(0, 0, TROCH_EPSILON)) - cart_to_cyl_map(pos - float3(0, 0, TROCH_EPSILON))) / (2 * TROCH_EPSILON); +#endif + float3x3 jacobian_cart_to_cyl; + jacobian_cart_to_cyl[0] = dtheta_dcart; + jacobian_cart_to_cyl[1] = dr_dcart; + jacobian_cart_to_cyl[2] = dz_dcart; + return transpose(jacobian_cart_to_cyl); +} + +float3x3 invert(float3x3 m) +{ + float det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) + - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); + + float3x3 adj; + adj[0][0] = (m[1][1] * m[2][2] - m[1][2] * m[2][1]); + adj[0][1] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]); + adj[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]); + + adj[1][0] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]); + adj[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]); + adj[1][2] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]); + + adj[2][0] = (m[1][0] * m[2][1] - m[1][1] * m[2][0]); + adj[2][1] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]); + adj[2][2] = (m[0][0] * m[1][1] - m[0][1] * m[1][0]); + + return adj * (1.0 / det); } #endif // _TROCHOID #endif // __TROCHOID_MATH + |
