diff options
| author | yum <yum.food.vr@gmail.com> | 2024-07-13 16:33:25 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2024-07-13 16:33:25 -0700 |
| commit | 3dcb2fd0e240f3c0141e65c32bc2c4a7f8e9fd20 (patch) | |
| tree | 3972c678d7f01022a31c6eadffc1dcff50c9f83c | |
| parent | bf4457b96cd46ed2d3d61bde2eb4d58d3114730b (diff) | |
Integration pixellation and trochoid shaders
Trochoid is a WIP. Need to do some magic to make it properly shear. In
short: it's currently implemented as a standalone Mesh Renderer object
which I place on my avatar's neck bone. Since its object origin is not
at the hip bone like everything else, it behaves weirdly when shearing.
Solution is to implement it as a regular skinned mesh renderer. Requires
some careful analysis to get right.
| -rw-r--r-- | Editor/tooner.cs | 74 | ||||
| -rw-r--r-- | feature_macros.cginc | 2 | ||||
| -rw-r--r-- | globals.cginc | 17 | ||||
| -rw-r--r-- | shear_math.cginc | 60 | ||||
| -rw-r--r-- | tooner.shader | 14 | ||||
| -rw-r--r-- | tooner_lighting.cginc | 122 | ||||
| -rw-r--r-- | tooner_outline_pass.cginc | 41 | ||||
| -rw-r--r-- | trochoid_math.cginc | 90 |
8 files changed, 412 insertions, 8 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs index 23a93ef..ba45a5d 100644 --- a/Editor/tooner.cs +++ b/Editor/tooner.cs @@ -916,6 +916,24 @@ public class ToonerGUI : ShaderGUI { bc = FindProperty("_Gimmick_Shear_Location_Strength"); editor.VectorProperty(bc, "Strength"); + bc = FindProperty("_Gimmick_Shear_Location_Mesh_Renderer_Fix"); + enabled = (bc.floatValue != 0.0); + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Mesh renderer fix", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + + if (enabled) { + EditorGUI.indentLevel += 1; + bc = FindProperty("_Gimmick_Shear_Location_Mesh_Renderer_Offset"); + editor.VectorProperty(bc, "Offset"); + bc = FindProperty("_Gimmick_Shear_Location_Mesh_Renderer_Rotation"); + editor.VectorProperty(bc, "Rotation"); + bc = FindProperty("_Gimmick_Shear_Location_Mesh_Renderer_Scale"); + editor.VectorProperty(bc, "Scale"); + EditorGUI.indentLevel -= 1; + } + EditorGUI.indentLevel -= 1; } @@ -943,12 +961,68 @@ public class ToonerGUI : ShaderGUI { EditorGUI.indentLevel -= 1; } + void DoGimmickPixellate() { + MaterialProperty bc; + bc = FindProperty("_Gimmick_Pixellate_Enable_Static"); + bool enabled = (bc.floatValue != 0.0); + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Pixellate", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + SetKeyword("_PIXELLATE", enabled); + + if (!enabled) { + return; + } + + EditorGUI.indentLevel += 1; + + bc = FindProperty("_Gimmick_Pixellate_Resolution_U"); + editor.FloatProperty(bc, "Resolution (U)"); + bc = FindProperty("_Gimmick_Pixellate_Resolution_V"); + editor.FloatProperty(bc, "Resolution (V)"); + bc = FindProperty("_Gimmick_Pixellate_Effect_Mask"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Effect mask"), + bc); + + EditorGUI.indentLevel -= 1; + } + + void DoGimmickTrochoid() { + MaterialProperty bc; + bc = FindProperty("_Trochoid_Enable_Static"); + bool enabled = (bc.floatValue != 0.0); + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Trochoid", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + SetKeyword("_TROCHOID", enabled); + + if (!enabled) { + return; + } + + EditorGUI.indentLevel += 1; + + bc = FindProperty("_Trochoid_R"); + editor.FloatProperty(bc, "R"); + bc = FindProperty("_Trochoid_r"); + editor.FloatProperty(bc, "r"); + bc = FindProperty("_Trochoid_d"); + editor.FloatProperty(bc, "d"); + + EditorGUI.indentLevel -= 1; + } + void DoGimmicks() { DoGimmickFlatColor(); DoGimmickQuantizeLocation(); DoGimmickShearLocation(); DoGimmickEyes00(); + DoGimmickPixellate(); + DoGimmickTrochoid(); } enum RenderingMode { diff --git a/feature_macros.cginc b/feature_macros.cginc index 66f626f..ea9edf8 100644 --- a/feature_macros.cginc +++ b/feature_macros.cginc @@ -89,6 +89,8 @@ #pragma shader_feature_local _ _GIMMICK_QUANTIZE_LOCATION_AUDIOLINK #pragma shader_feature_local _ _GIMMICK_SHEAR_LOCATION #pragma shader_feature_local _ _GIMMICK_EYES_00 +#pragma shader_feature_local _ _PIXELLATE +#pragma shader_feature_local _ _TROCHOID #endif // __FEATURE_MACROS_INC diff --git a/globals.cginc b/globals.cginc index 6f7b434..bec4b01 100644 --- a/globals.cginc +++ b/globals.cginc @@ -315,6 +315,10 @@ float _Gimmick_Quantize_Location_Audiolink_Strength; float _Gimmick_Shear_Location_Enable_Static; float _Gimmick_Shear_Location_Enable_Dynamic; float4 _Gimmick_Shear_Location_Strength; +float _Gimmick_Shear_Location_Mesh_Renderer_Fix; +float4 _Gimmick_Shear_Location_Mesh_Renderer_Offset; +float4 _Gimmick_Shear_Location_Mesh_Renderer_Rotation; +float4 _Gimmick_Shear_Location_Mesh_Renderer_Scale; #endif #if defined(_GIMMICK_EYES_00) @@ -322,5 +326,18 @@ float _Gimmick_Eyes00_Enable_Static; texture2D _Gimmick_Eyes00_Effect_Mask; #endif +#if defined(_PIXELLATE) +float _Gimmick_Pixellate_Enable_Static; +float _Gimmick_Pixellate_Resolution_U; +float _Gimmick_Pixellate_Resolution_V; +texture2D _Gimmick_Pixellate_Effect_Mask; +#endif + +#if defined(_TROCHOID) +float _Trochoid_R; +float _Trochoid_r; +float _Trochoid_d; +#endif + #endif diff --git a/shear_math.cginc b/shear_math.cginc new file mode 100644 index 0000000..a2eded2 --- /dev/null +++ b/shear_math.cginc @@ -0,0 +1,60 @@ +#ifndef __SHEAR_MATH_INC +#define __SHEAR_MATH_INC + +#if defined(_GIMMICK_SHEAR_LOCATION) + +void getMeshRendererMatrices(bool invert, out float3x3 rot_fix, + out float4x4 ts_fix) { + if (_Gimmick_Shear_Location_Mesh_Renderer_Fix) { + float3 theta = float3( + _Gimmick_Shear_Location_Mesh_Renderer_Rotation.x, + _Gimmick_Shear_Location_Mesh_Renderer_Rotation.y, + _Gimmick_Shear_Location_Mesh_Renderer_Rotation.z); + theta = invert ? -theta : theta; + float3x3 rotate_x = float3x3( + 1, 0, 0, + 0, cos(theta.x), -sin(theta.x), + 0, sin(theta.x), cos(theta.x)); + float3x3 rotate_y = float3x3( + cos(theta.y), 0, sin(theta.y), + 0, 1, 0, + -sin(theta.y), 0, cos(theta.y)); + float3x3 rotate_z = float3x3( + cos(theta.z), -sin(theta.z), 0, + sin(theta.z), cos(theta.z), 0, + 0, 0, 1); + rot_fix = invert ? + mul(rotate_x, mul(rotate_y, rotate_z)) : + mul(rotate_z, mul(rotate_y, rotate_x)); + float3 scale = float3( + _Gimmick_Shear_Location_Mesh_Renderer_Scale.x, + _Gimmick_Shear_Location_Mesh_Renderer_Scale.y, + _Gimmick_Shear_Location_Mesh_Renderer_Scale.z); + scale = invert ? 1 / scale : scale; + float3 offset = float3( + _Gimmick_Shear_Location_Mesh_Renderer_Offset.x, + _Gimmick_Shear_Location_Mesh_Renderer_Offset.y, + _Gimmick_Shear_Location_Mesh_Renderer_Offset.z); + offset = invert ? -offset : offset; + ts_fix = float4x4( + scale.x, 0, 0, offset.x, + 0, scale.y, 0, offset.y, + 0, 0, scale.z, offset.z, + 0, 0, 0, 1); + } else { + rot_fix = float3x3( + 1, 0, 0, + 0, 1, 0, + 0, 0, 1); + ts_fix = float4x4( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + } +} + +#endif // _GIMMICK_SHEAR_LOCATION + +#endif // __SHEAR_MATH_INC + diff --git a/tooner.shader b/tooner.shader index 61304e1..a9f5ca7 100644 --- a/tooner.shader +++ b/tooner.shader @@ -250,6 +250,10 @@ Shader "yum_food/tooner" _Gimmick_Shear_Location_Enable_Static("Enable shear location gimmick", Float) = 0.0 _Gimmick_Shear_Location_Enable_Dynamic("Enable shear location gimmick", Float) = 0.0 _Gimmick_Shear_Location_Strength("Strength", Vector) = (1, 1, 1, 1) + _Gimmick_Shear_Location_Mesh_Renderer_Fix("Mesh renderer fix", Float) = 0.0 + _Gimmick_Shear_Location_Mesh_Renderer_Offset("Mesh renderer offset", Vector) = (0, 0, 0, 0) + _Gimmick_Shear_Location_Mesh_Renderer_Rotation("Mesh renderer rotation", Vector) = (0, 0, 0, 0) + _Gimmick_Shear_Location_Mesh_Renderer_Scale("Mesh renderer scale", Vector) = (0, 0, 0, 0) _Gimmick_Vertex_Normal_Slide_Enable_Static("Enable vertex normal slide", Float) = 0.0 _Gimmick_Vertex_Normal_Slide_Enable_Dynamic("Enable vertex normal slide", Float) = 0.0 @@ -257,6 +261,16 @@ Shader "yum_food/tooner" _Gimmick_Eyes00_Enable_Static("Enable eyes 00", Float) = 0.0 _Gimmick_Eyes00_Effect_Mask("Effect mask", 2D) = "white" + + _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 + _Gimmick_Pixellate_Effect_Mask("Effect mask", 2D) = "white" + + _Trochoid_Enable_Static("Enable trochoid", Float) = 0.0 + _Trochoid_R("R", Float) = 5.0 + _Trochoid_r("r", Float) = 3.0 + _Trochoid_d("d", Float) = 5.0 } SubShader { diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc index 8eae8ef..4288293 100644 --- a/tooner_lighting.cginc +++ b/tooner_lighting.cginc @@ -11,7 +11,9 @@ #include "motion.cginc" #include "pbr.cginc" #include "poi.cginc" +#include "shear_math.cginc" #include "tooner_scroll.cginc" +#include "trochoid_math.cginc" #include "oklab.cginc" struct tess_data @@ -90,14 +92,39 @@ v2f vert(appdata v) } #endif -#if defined(_GIMMICK_SHEAR_LOCATION) +#if defined(_TROCHOID) + { +#define PI 3.14159265 +#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); + } +#endif + +#if !defined(_SCROLL) && defined(_GIMMICK_SHEAR_LOCATION) if (_Gimmick_Shear_Location_Enable_Dynamic) { - v.vertex = mul(float4x4( - _Gimmick_Shear_Location_Strength.x, 0, 0, 0, - 0, _Gimmick_Shear_Location_Strength.y, 0, 0, - 0, 0, _Gimmick_Shear_Location_Strength.z, 0, - 0, 0, 0, _Gimmick_Shear_Location_Strength.w), - v.vertex); + float3 p = v.vertex.xyz; + float3x3 shear_matrix = float3x3( + _Gimmick_Shear_Location_Strength.x, 0, 0, + 0, _Gimmick_Shear_Location_Strength.y, 0, + 0, 0, _Gimmick_Shear_Location_Strength.z); +#if 0 + float3x3 rot_fix, rot_fixi; + float4x4 ts_fix, ts_fixi; + getMeshRendererMatrices(/*invert=*/false, rot_fix, ts_fix); + getMeshRendererMatrices(/*invert=*/true, rot_fixi, ts_fixi); + if (_Gimmick_Shear_Location_Mesh_Renderer_Fix) { + p = mul(ts_fixi, float4(p, 1)).xyz; + } +#endif + p = mul(shear_matrix, p); + v.vertex.xyz = p; } #endif @@ -341,6 +368,29 @@ void geom(triangle v2f tri_in[3], float3 v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1)); float3 v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1)); +#if defined(_GIMMICK_SHEAR_LOCATION) + if (_Gimmick_Shear_Location_Enable_Dynamic) { + v0_objPos = mul(float3x3( + _Gimmick_Shear_Location_Strength.x, 0, 0, + 0, _Gimmick_Shear_Location_Strength.y, 0, + 0, 0, _Gimmick_Shear_Location_Strength.z), + v0_objPos); + v1_objPos = mul(float3x3( + _Gimmick_Shear_Location_Strength.x, 0, 0, + 0, _Gimmick_Shear_Location_Strength.y, 0, + 0, 0, _Gimmick_Shear_Location_Strength.z), + v1_objPos); + v2_objPos = mul(float3x3( + _Gimmick_Shear_Location_Strength.x, 0, 0, + 0, _Gimmick_Shear_Location_Strength.y, 0, + 0, 0, _Gimmick_Shear_Location_Strength.z), + v2_objPos); + v0.worldPos.xyz = mul(unity_ObjectToWorld, v0_objPos); + v1.worldPos.xyz = mul(unity_ObjectToWorld, v1_objPos); + v2.worldPos.xyz = mul(unity_ObjectToWorld, v2_objPos); + } +#endif + v0.vertex = UnityObjectToClipPos(v0_objPos); v1.vertex = UnityObjectToClipPos(v1_objPos); v2.vertex = UnityObjectToClipPos(v2_objPos); @@ -694,12 +744,52 @@ float3 getOverlayEmission(PbrOverlay ov, v2f i, float iddx, float iddy) return em; } +#if defined(_PIXELLATE) +float2 pixellate_uv(int2 px_res, float2 uv) +{ + return floor(uv * px_res) / px_res; +} + +float4 pixellate_color(int2 px_res, float2 uv, float4 c) +{ + float2 px_intra_uv = fmod(uv * px_res, 1.0); + float2 px_extra_uv = floor(uv * px_res) / px_res; + + float2 px_uv = floor(uv * px_res) / px_res; + if (px_intra_uv.y > 0.1 && px_intra_uv.y < 0.9) { + if (px_intra_uv.x < 0.333) { + c.xyz = float3(1, 0, 0); + } else if (px_intra_uv.x < 0.666) { + c.yxz = float3(1, 0, 0); + } else { + c.zxy = float3(1, 0, 0); + } + c *= 3; + } else { + c = 0; + } + + return c; +} +#endif + float4 effect(inout v2f i) { float iddx = ddx(i.uv.x) * _Mip_Multiplier; float iddy = ddx(i.uv.y) * _Mip_Multiplier; const float3 view_dir = normalize(_WorldSpaceCameraPos - i.worldPos); +#if defined(_TROCHOID) + { + i.normal = trochoid_normal(i.objPos.xyz, i.uv); + + float theta = i.uv.x * TAU; + float r0 = length(i.objPos.xyz); + float z = i.objPos.z; + i.objPos.xyz = trochoid_map(theta, r0, z); + } +#endif + #if defined(_UVSCROLL) float2 orig_uv = i.uv; float uv_scroll_mask = round(_UVScroll_Mask.SampleGrad(linear_repeat_s, i.uv, iddx, iddy)); @@ -720,6 +810,24 @@ float4 effect(inout v2f i) } #endif +#if defined(_PIXELLATE) + { + const int2 px_res = int2( + _Gimmick_Pixellate_Resolution_U, + _Gimmick_Pixellate_Resolution_V); + + float2 uv = pixellate_uv(px_res, i.uv); + const float2 duv = float2(ddx(i.uv.x), ddy(i.uv.y)) / 16; + float4 color = _Gimmick_Pixellate_Effect_Mask.SampleGrad(linear_clamp_s, uv, duv.x, duv.y); + float2 fw = float2(fwidth(i.uv.x), fwidth(i.uv.y)); + float fwm = max(fw.x, fw.y); + color.rgb *= albedo; + float4 px_color = pixellate_color(px_res, i.uv, color); + albedo = lerp(albedo, px_color, pow(0.9, fwm * 100)); + } +#endif + + #if defined(_RENDERING_CUTOUT) #if defined(_RENDERING_CUTOUT_STOCHASTIC) float ar = rand2(i.uv); diff --git a/tooner_outline_pass.cginc b/tooner_outline_pass.cginc index c7b6ded..72deee6 100644 --- a/tooner_outline_pass.cginc +++ b/tooner_outline_pass.cginc @@ -8,6 +8,7 @@ #include "globals.cginc" #include "math.cginc" #include "pbr.cginc" +#include "trochoid_math.cginc" #include "tooner_scroll.cginc" #include "UnityCG.cginc" @@ -25,7 +26,22 @@ struct tess_factors { v2f vert(appdata v) { -#if defined(_GIMMICK_SHEAR_LOCATION) +#if defined(_TROCHOID) + { +#define PI 3.14159265 +#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); + } +#endif + +#if !defined(_SCROLL) && defined(_GIMMICK_SHEAR_LOCATION) if (_Gimmick_Shear_Location_Enable_Dynamic) { v.vertex = mul(float4x4( _Gimmick_Shear_Location_Strength.x, 0, 0, 0, @@ -270,6 +286,29 @@ void geom(triangle v2f tri_in[3], float3 v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1)); float3 v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1)); +#if defined(_GIMMICK_SHEAR_LOCATION) + if (_Gimmick_Shear_Location_Enable_Dynamic) { + v0_objPos = mul(float3x3( + _Gimmick_Shear_Location_Strength.x, 0, 0, + 0, _Gimmick_Shear_Location_Strength.y, 0, + 0, 0, _Gimmick_Shear_Location_Strength.z), + v0_objPos); + v1_objPos = mul(float3x3( + _Gimmick_Shear_Location_Strength.x, 0, 0, + 0, _Gimmick_Shear_Location_Strength.y, 0, + 0, 0, _Gimmick_Shear_Location_Strength.z), + v1_objPos); + v2_objPos = mul(float3x3( + _Gimmick_Shear_Location_Strength.x, 0, 0, + 0, _Gimmick_Shear_Location_Strength.y, 0, + 0, 0, _Gimmick_Shear_Location_Strength.z), + v2_objPos); + v0.worldPos.xyz = mul(unity_ObjectToWorld, v0_objPos); + v1.worldPos.xyz = mul(unity_ObjectToWorld, v1_objPos); + v2.worldPos.xyz = mul(unity_ObjectToWorld, v2_objPos); + } +#endif + v0.vertex = UnityObjectToClipPos(v0_objPos); v1.vertex = UnityObjectToClipPos(v1_objPos); v2.vertex = UnityObjectToClipPos(v2_objPos); diff --git a/trochoid_math.cginc b/trochoid_math.cginc new file mode 100644 index 0000000..f116db0 --- /dev/null +++ b/trochoid_math.cginc @@ -0,0 +1,90 @@ +#ifndef __TROCHOID_MATH +#define __TROCHOID_MATH + +#if defined(_TROCHOID) + +#include "globals.cginc" + +#define PI 3.14159265 +#define TAU PI * 2.0 + +float3 trochoid_map(float theta, float r0, float3 vert_z) +{ + r0 *= r0; + r0 *= 100; + + 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_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; + + float3 result = float3(x, y, z) * r0; + result.xy *= 0.1; + return result; +} + +float trochoid_normal(float3 objPos, float2 uv) +{ + 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); +} + +#endif // _TROCHOID + +#endif // __TROCHOID_MATH + |
