1use glam::Vec3;
4use super::GeoMesh;
5use crate::math::{MathFunction, ForceField};
6
7#[derive(Debug, Clone)]
9pub enum DeformField {
10 NormalDisplace { amplitude: f32, func: MathFunction },
12 Radial { center: Vec3, amplitude: f32, falloff: f32 },
14 Twist { axis: Vec3, center: Vec3, angle_per_unit: f32 },
16 Bend { axis: Vec3, center: Vec3, angle: f32, region_size: f32 },
18 Noise { amplitude: f32, frequency: f32, time: f32 },
20 Wave { direction: Vec3, amplitude: f32, frequency: f32, phase: f32 },
22 Pinch { center: Vec3, radius: f32, strength: f32 },
24 Spherize { center: Vec3, radius: f32, strength: f32 },
26 Taper { axis: Vec3, center: Vec3, start_scale: f32, end_scale: f32, length: f32 },
28 ForceFieldDisplace { field: ForceField, scale: f32, time: f32 },
30}
31
32pub struct Deformer;
34
35impl Deformer {
36 pub fn apply(mesh: &mut GeoMesh, deform: &DeformField) {
38 match deform {
39 DeformField::NormalDisplace { amplitude, func } => {
40 for i in 0..mesh.vertices.len() {
41 let p = mesh.vertices[i];
42 let n = mesh.normals[i];
43 let scalar = func.evaluate(p.x + p.y + p.z, p.length());
44 mesh.vertices[i] = p + n * scalar * *amplitude;
45 }
46 }
47 DeformField::Radial { center, amplitude, falloff } => {
48 for v in &mut mesh.vertices {
49 let dir = *v - *center;
50 let dist = dir.length();
51 let weight = (-dist * falloff).exp();
52 *v += dir.normalize_or_zero() * weight * *amplitude;
53 }
54 }
55 DeformField::Twist { axis, center, angle_per_unit } => {
56 let axis_n = axis.normalize_or_zero();
57 for v in &mut mesh.vertices {
58 let d = (*v - *center).dot(axis_n);
59 let angle = d * angle_per_unit;
60 let (s, c) = angle.sin_cos();
61 let local = *v - *center;
62 let proj = axis_n * local.dot(axis_n);
63 let perp = local - proj;
64 if perp.length_squared() < 1e-10 { continue; }
65 let t1 = perp.normalize();
66 let t2 = axis_n.cross(t1);
67 let r = perp.length();
68 *v = *center + proj + (t1 * c + t2 * s) * r;
69 }
70 }
71 DeformField::Wave { direction, amplitude, frequency, phase } => {
72 let dir_n = direction.normalize_or_zero();
73 for v in &mut mesh.vertices {
74 let d = v.dot(dir_n);
75 let offset = (d * frequency + phase).sin() * amplitude;
76 *v += Vec3::Y * offset; }
78 }
79 DeformField::Noise { amplitude, frequency, time } => {
80 for v in &mut mesh.vertices {
81 let nx = simple_hash(v.x * frequency + time) * amplitude;
82 let ny = simple_hash(v.y * frequency + time * 1.3) * amplitude;
83 let nz = simple_hash(v.z * frequency + time * 0.7) * amplitude;
84 *v += Vec3::new(nx, ny, nz);
85 }
86 }
87 DeformField::Pinch { center, radius, strength } => {
88 for v in &mut mesh.vertices {
89 let dir = *v - *center;
90 let dist = dir.length();
91 if dist < *radius && dist > 1e-6 {
92 let t = 1.0 - dist / radius;
93 *v = *center + dir * (1.0 - t * strength);
94 }
95 }
96 }
97 DeformField::Spherize { center, radius, strength } => {
98 for v in &mut mesh.vertices {
99 let dir = *v - *center;
100 let dist = dir.length();
101 if dist > 1e-6 {
102 let sphere_pos = *center + dir.normalize() * *radius;
103 *v = v.lerp(sphere_pos, *strength);
104 }
105 }
106 }
107 DeformField::Taper { axis, center, start_scale, end_scale, length } => {
108 let axis_n = axis.normalize_or_zero();
109 for v in &mut mesh.vertices {
110 let d = (*v - *center).dot(axis_n);
111 let t = (d / length.max(1e-6)).clamp(0.0, 1.0);
112 let scale = start_scale + (end_scale - start_scale) * t;
113 let proj = axis_n * d;
114 let perp = *v - *center - proj;
115 *v = *center + proj + perp * scale;
116 }
117 }
118 DeformField::Bend { axis, center, angle, region_size } => {
119 let axis_n = axis.normalize_or_zero();
120 for v in &mut mesh.vertices {
121 let d = (*v - *center).dot(axis_n);
122 let t = (d / region_size.max(1e-6)).clamp(-1.0, 1.0);
123 let bend_angle = t * angle;
124 let (s, c) = bend_angle.sin_cos();
125 let local = *v - *center;
126 let proj = axis_n * local.dot(axis_n);
127 let perp = local - proj;
128 if perp.length_squared() < 1e-10 { continue; }
129 let t1 = perp.normalize();
130 let t2 = axis_n.cross(t1);
131 let r = perp.length();
132 *v = *center + proj + (t1 * c + t2 * s) * r;
133 }
134 }
135 DeformField::ForceFieldDisplace { field, scale, time } => {
136 for v in &mut mesh.vertices {
137 let force = field.force_at(*v, 1.0, 0.0, *time);
138 *v += force * *scale;
139 }
140 }
141 }
142 }
143
144 pub fn apply_chain(mesh: &mut GeoMesh, deforms: &[DeformField]) {
146 for d in deforms {
147 Self::apply(mesh, d);
148 }
149 mesh.recompute_normals();
150 }
151}
152
153fn simple_hash(x: f32) -> f32 {
154 let x = (x * 12.9898).sin() * 43758.5453;
155 x.fract() * 2.0 - 1.0
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use glam::Vec2;
162
163 fn flat_grid() -> GeoMesh {
164 let mut mesh = GeoMesh::new();
165 for z in 0..4 {
166 for x in 0..4 {
167 mesh.add_vertex(Vec3::new(x as f32, 0.0, z as f32), Vec3::Y, Vec2::ZERO);
168 }
169 }
170 for z in 0..3 {
171 for x in 0..3 {
172 let i = (z * 4 + x) as u32;
173 mesh.add_triangle(i, i + 1, i + 5);
174 mesh.add_triangle(i, i + 5, i + 4);
175 }
176 }
177 mesh
178 }
179
180 #[test]
181 fn wave_deforms_vertically() {
182 let mut mesh = flat_grid();
183 let orig_y: Vec<f32> = mesh.vertices.iter().map(|v| v.y).collect();
184 Deformer::apply(&mut mesh, &DeformField::Wave {
185 direction: Vec3::X, amplitude: 1.0, frequency: 1.0, phase: 0.0,
186 });
187 let changed = mesh.vertices.iter().zip(orig_y.iter()).any(|(v, &oy)| (v.y - oy).abs() > 0.01);
188 assert!(changed, "Wave should displace vertices");
189 }
190
191 #[test]
192 fn twist_preserves_on_axis() {
193 let mut mesh = GeoMesh::new();
194 mesh.add_vertex(Vec3::new(0.0, 1.0, 0.0), Vec3::Y, Vec2::ZERO);
196 mesh.add_vertex(Vec3::new(0.0, 2.0, 0.0), Vec3::Y, Vec2::ZERO);
197 mesh.add_vertex(Vec3::new(1.0, 1.0, 0.0), Vec3::Y, Vec2::ZERO);
198 mesh.add_triangle(0, 1, 2);
199
200 let orig = mesh.vertices[0];
201 Deformer::apply(&mut mesh, &DeformField::Twist {
202 axis: Vec3::Y, center: Vec3::ZERO, angle_per_unit: 1.0,
203 });
204 assert!((mesh.vertices[0] - orig).length() < 0.01, "Point on axis shouldn't move");
205 }
206}