diff options
author | eug-vs <eugene@eug-vs.xyz> | 2021-10-29 22:18:43 +0300 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2021-10-29 22:37:55 +0300 |
commit | 61c757f2499d79efe4066ca2d8c1ff7827604543 (patch) | |
tree | 3593de9b7eba2c390cddc546d0013ef7ac81677d /src/sdf.rs | |
parent | b79ea97978a38fcb2ac7c776a37531d6babcb84e (diff) | |
download | pistol-61c757f2499d79efe4066ca2d8c1ff7827604543.tar.gz |
refactor!: separate rendering functionality
Diffstat (limited to 'src/sdf.rs')
-rw-r--r-- | src/sdf.rs | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/src/sdf.rs b/src/sdf.rs new file mode 100644 index 0000000..00a4a11 --- /dev/null +++ b/src/sdf.rs @@ -0,0 +1,60 @@ +use std::f32::consts::PI; +use cgmath::Vector3; +use cgmath::prelude::*; + +type Vector = Vector3<f32>; + +pub fn sd_sphere(point: Vector, center: Vector, radius: f32) -> f32 { + (point - center).magnitude() - radius +} + +pub fn sd_box(point: Vector, center: Vector, size: Vector) -> f32 { + let diff = center - point; + let q = diff.map(|n| n.abs()) - size / 2.0; + return q.map(|n| n.max(0.0)).magnitude() + (q.y.max(q.z).max(q.x)).min(0.0) +} + +pub fn sd_gear(point: Vector, time: f32, center: Vector, radius: f32, thickness: f32, turn_rate: f32) -> f32 { + let mut dist: f32; + + let thickness_over_2 = thickness / 2.0; + let thickness_over_4 = thickness / 4.0; + + // Ring + { + let cylinder_dist = (Vector::new(0.0, point.y, point.z) - center).magnitude() - (radius - thickness_over_4); + dist = cylinder_dist.abs() - thickness_over_2; // Make cylinder hollow + } + // Teeth + { + let sector_angle: f32 = 2.0 * PI / 12.0; + + // Account for rotation with time + let angle = sector_angle * time / turn_rate; + let rotated_point = Vector::new( + point.x, + point.y * angle.cos() - point.z * angle.sin(), + point.y * angle.sin() + point.z * angle.cos() + ); + + // Map all space to the first sector + let point_angle = (rotated_point.z / rotated_point.y).atan(); + let angle2 = -sector_angle * (point_angle / sector_angle).round(); + + let mapped_point = Vector::new( + rotated_point.x, + (rotated_point.y * angle2.cos() - rotated_point.z * angle2.sin()).abs(), + rotated_point.y * angle2.sin() + rotated_point.z * angle2.cos() + ); + + let center = Vector { x: 0.0, y: radius + thickness_over_2, z: 0.0 }; + let size = Vector::new(thickness, thickness * 2.0, thickness); + // Make teeth smooth by subtracting some amount + dist = dist.min(sd_box(mapped_point, center, size) - thickness_over_4); + } + + // Take a slice + dist = dist.max(point.x.abs() - thickness_over_2); + + return dist; +} |