feat(noise): preserve segment lengths during displacement
The noise node previously displaced each path point's XYZ independently, which stretched/compressed segments and produced kinked edges. After displacement, re-project each point onto the sphere of radius seg_lens[i-1] centered at the previous point — same pattern used by the gravity node. Total path length is now preserved; noise bends the path rather than stretching it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ edition = "2018"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
glam = "0.30.10"
|
||||
nodarium_macros = { version = "0.1.0", path = "../../../../packages/macros" }
|
||||
nodarium_utils = { version = "0.1.0", path = "../../../../packages/utils" }
|
||||
noise = "0.9.0"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use glam::Vec3;
|
||||
use nodarium_macros::nodarium_definition_file;
|
||||
use nodarium_macros::nodarium_execute;
|
||||
use nodarium_utils::{
|
||||
@@ -65,24 +66,70 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
|
||||
|
||||
let length = path.get_length() as f64;
|
||||
|
||||
for i in 0..path.length {
|
||||
// Record original segment lengths so we can re-project after displacement
|
||||
let seg_lens: Vec<f32> = (0..path.length - 1)
|
||||
.map(|k| {
|
||||
let p0 = Vec3::new(
|
||||
path.points[k * 4],
|
||||
path.points[k * 4 + 1],
|
||||
path.points[k * 4 + 2],
|
||||
);
|
||||
let p1 = Vec3::new(
|
||||
path.points[(k + 1) * 4],
|
||||
path.points[(k + 1) * 4 + 1],
|
||||
path.points[(k + 1) * 4 + 2],
|
||||
);
|
||||
(p1 - p0).length()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Displace the first point (fix_bottom=1 → scale=0 here, anchoring the base)
|
||||
let scale0 = lerp(1.0, 0.0, fix_bottom);
|
||||
path.points[0] += noise_x.get([j as f64, 0.0]) as f32
|
||||
* directional_strength[0]
|
||||
* strength
|
||||
* scale0;
|
||||
path.points[1] += noise_y.get([j as f64, 0.0]) as f32
|
||||
* directional_strength[1]
|
||||
* strength
|
||||
* scale0;
|
||||
path.points[2] += noise_z.get([j as f64, 0.0]) as f32
|
||||
* directional_strength[2]
|
||||
* strength
|
||||
* scale0;
|
||||
let mut prev = Vec3::new(path.points[0], path.points[1], path.points[2]);
|
||||
|
||||
for i in 1..path.length {
|
||||
let a = i as f64 / (path.length - 1) as f64;
|
||||
|
||||
let px = j as f64 + a * length * scale;
|
||||
let py = a * scale as f64;
|
||||
|
||||
path.points[i * 4] += noise_x.get([px, py]) as f32
|
||||
* directional_strength[0]
|
||||
* strength
|
||||
* lerp(1.0, a as f32, fix_bottom);
|
||||
path.points[i * 4 + 1] += noise_y.get([px, py]) as f32
|
||||
* directional_strength[1]
|
||||
* strength
|
||||
* lerp(1.0, a as f32, fix_bottom);
|
||||
path.points[i * 4 + 2] += noise_z.get([px, py]) as f32
|
||||
* directional_strength[2]
|
||||
* strength
|
||||
* lerp(1.0, a as f32, fix_bottom);
|
||||
let sf = lerp(1.0, a as f32, fix_bottom);
|
||||
path.points[i * 4] +=
|
||||
noise_x.get([px, py]) as f32 * directional_strength[0] * strength * sf;
|
||||
path.points[i * 4 + 1] +=
|
||||
noise_y.get([px, py]) as f32 * directional_strength[1] * strength * sf;
|
||||
path.points[i * 4 + 2] +=
|
||||
noise_z.get([px, py]) as f32 * directional_strength[2] * strength * sf;
|
||||
|
||||
// Re-project onto sphere of radius seg_lens[i-1] centered at prev
|
||||
let cur = Vec3::new(
|
||||
path.points[i * 4],
|
||||
path.points[i * 4 + 1],
|
||||
path.points[i * 4 + 2],
|
||||
);
|
||||
let dir = cur - prev;
|
||||
let dir_len = dir.length();
|
||||
if dir_len > 0.0001 {
|
||||
let corrected = prev + dir * (seg_lens[i - 1] / dir_len);
|
||||
path.points[i * 4] = corrected.x;
|
||||
path.points[i * 4 + 1] = corrected.y;
|
||||
path.points[i * 4 + 2] = corrected.z;
|
||||
prev = corrected;
|
||||
} else {
|
||||
prev = cur;
|
||||
}
|
||||
}
|
||||
path_data
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user