From e16a91641302d460cca2ebfe01377b3743305aa2 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Wed, 30 Jul 2025 22:42:13 +0200 Subject: [PATCH] Add AffineTransform --- ray-tracing-core/src/affine_transform.rs | 209 ++++++++++++++++++ ray-tracing-core/src/lib.rs | 1 + .../examples/transformation_test.rs | 9 + 3 files changed, 219 insertions(+) create mode 100644 ray-tracing-core/src/affine_transform.rs create mode 100644 ray-tracing-pbrt-scene/examples/transformation_test.rs diff --git a/ray-tracing-core/src/affine_transform.rs b/ray-tracing-core/src/affine_transform.rs new file mode 100644 index 0000000..8277e46 --- /dev/null +++ b/ray-tracing-core/src/affine_transform.rs @@ -0,0 +1,209 @@ +use std::ops::{Mul, MulAssign}; + +use crate::prelude::*; + +#[derive(Debug, Copy, Clone)] +pub struct AffineTransform { + mat: [[Float; 4]; 3], + inv: [[Float; 3]; 3], +} + +impl AffineTransform { + pub fn identity() -> Self { + Self { + mat: [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 1.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0], + ], + inv: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], + } + } + + pub fn translation(pos: Pos3) -> Self { + Self { + mat: [ + [1.0, 0.0, 0.0, pos.x()], + [0.0, 1.0, 0.0, pos.y()], + [0.0, 0.0, 1.0, pos.z()], + ], + inv: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]], + } + } + + pub fn scale(sx: Float, sy: Float, sz: Float) -> Self { + Self { + mat: [ + [sx, 0.0, 0.0, 0.0], + [0.0, sy, 0.0, 0.0], + [0.0, 0.0, sz, 0.0], + ], + inv: [ + [1.0 / sx, 0.0, 0.0], + [0.0, 1.0 / sy, 0.0], + [0.0, 0.0, 1.0 / sz], + ], + } + } + + pub fn rotation(angle: Float, dir: Dir3) -> Self { + let mat = [ + [ + dir.x() * dir.x() * (1.0 - angle.cos()) + angle.cos(), + dir.x() * dir.y() * (1.0 - angle.cos()) - dir.z() * angle.sin(), + dir.x() * dir.z() * (1.0 - angle.cos()) + dir.y() * angle.sin(), + 0.0, + ], + [ + dir.x() * dir.y() * (1.0 - angle.cos()) + dir.z() * angle.sin(), + dir.y() * dir.y() * (1.0 - angle.cos()) + angle.cos(), + dir.y() * dir.z() * (1.0 - angle.cos()) - dir.x() * angle.sin(), + 0.0, + ], + [ + dir.x() * dir.z() * (1.0 - angle.cos()) - dir.y() * angle.sin(), + dir.y() * dir.z() * (1.0 - angle.cos()) + dir.x() * angle.sin(), + dir.z() * dir.z() * (1.0 - angle.cos()) + angle.cos(), + 0.0, + ], + ]; + Self { + mat, + inv: [ + [mat[0][0], mat[1][0], mat[2][0]], + [mat[0][1], mat[1][1], mat[2][1]], + [mat[0][2], mat[1][2], mat[2][2]], + ], + } + } + + pub fn transform_pos(&self, pos: Pos3) -> Pos3 { + Pos3::new( + self.mat[0][0] * pos.x() + + self.mat[0][1] * pos.y() + + self.mat[0][2] * pos.z() + + self.mat[0][3], + self.mat[1][0] * pos.x() + + self.mat[1][1] * pos.y() + + self.mat[1][2] * pos.z() + + self.mat[1][3], + self.mat[2][0] * pos.x() + + self.mat[2][1] * pos.y() + + self.mat[2][2] * pos.z() + + self.mat[2][3], + ) + } + pub fn transform_normal(&self, pos: Pos3) -> Pos3 { + Pos3::new( + self.inv[0][0] * pos.x() + self.inv[0][1] * pos.y() + self.inv[0][2] * pos.z(), + self.inv[1][0] * pos.x() + self.inv[1][1] * pos.y() + self.inv[1][2] * pos.z(), + self.inv[2][0] * pos.x() + self.inv[2][1] * pos.y() + self.inv[2][2] * pos.z(), + ) + } +} + +impl Mul for AffineTransform { + type Output = AffineTransform; + + fn mul(self, rhs: Self) -> Self::Output { + Self { + mat: [ + [ + self.mat[0][0] * rhs.mat[0][0] + + self.mat[0][1] * rhs.mat[1][0] + + self.mat[0][2] * rhs.mat[2][0] + + self.mat[0][3], + self.mat[0][0] * rhs.mat[0][1] + + self.mat[0][1] * rhs.mat[1][1] + + self.mat[0][2] * rhs.mat[2][1] + + self.mat[0][3], + self.mat[0][0] * rhs.mat[0][2] + + self.mat[0][1] * rhs.mat[1][2] + + self.mat[0][2] * rhs.mat[2][2] + + self.mat[0][3], + self.mat[0][0] * rhs.mat[0][3] + + self.mat[0][1] * rhs.mat[1][3] + + self.mat[0][2] * rhs.mat[2][3] + + self.mat[0][3], + ], + [ + self.mat[1][0] * rhs.mat[0][0] + + self.mat[1][1] * rhs.mat[1][0] + + self.mat[1][2] * rhs.mat[2][0] + + self.mat[1][3], + self.mat[1][0] * rhs.mat[0][1] + + self.mat[1][1] * rhs.mat[1][1] + + self.mat[1][2] * rhs.mat[2][1] + + self.mat[1][3], + self.mat[1][0] * rhs.mat[0][2] + + self.mat[1][1] * rhs.mat[1][2] + + self.mat[1][2] * rhs.mat[2][2] + + self.mat[1][3], + self.mat[1][0] * rhs.mat[0][3] + + self.mat[1][1] * rhs.mat[1][3] + + self.mat[1][2] * rhs.mat[2][3] + + self.mat[1][3], + ], + [ + self.mat[2][0] * rhs.mat[0][0] + + self.mat[2][1] * rhs.mat[1][0] + + self.mat[2][2] * rhs.mat[2][0] + + self.mat[2][3], + self.mat[2][0] * rhs.mat[0][1] + + self.mat[2][1] * rhs.mat[1][1] + + self.mat[2][2] * rhs.mat[2][1] + + self.mat[2][3], + self.mat[2][0] * rhs.mat[0][2] + + self.mat[2][1] * rhs.mat[1][2] + + self.mat[2][2] * rhs.mat[2][2] + + self.mat[2][3], + self.mat[2][0] * rhs.mat[0][3] + + self.mat[2][1] * rhs.mat[1][3] + + self.mat[2][2] * rhs.mat[2][3] + + self.mat[2][3], + ], + ], + inv: [ + [ + rhs.inv[0][0] * self.inv[0][0] + + rhs.inv[0][1] * self.inv[1][0] + + rhs.inv[0][2] * self.inv[2][0], + rhs.inv[0][0] * self.inv[0][1] + + rhs.inv[0][1] * self.inv[1][1] + + rhs.inv[0][2] * self.inv[2][1], + rhs.inv[0][0] * self.inv[0][2] + + rhs.inv[0][1] * self.inv[1][2] + + rhs.inv[0][2] * self.inv[2][2], + ], + [ + rhs.inv[1][0] * self.inv[0][0] + + rhs.inv[1][1] * self.inv[1][0] + + rhs.inv[1][2] * self.inv[2][0], + rhs.inv[1][0] * self.inv[0][1] + + rhs.inv[1][1] * self.inv[1][1] + + rhs.inv[1][2] * self.inv[2][1], + rhs.inv[1][0] * self.inv[0][2] + + rhs.inv[1][1] * self.inv[1][2] + + rhs.inv[1][2] * self.inv[2][2], + ], + [ + rhs.inv[2][0] * self.inv[0][0] + + rhs.inv[2][1] * self.inv[1][0] + + rhs.inv[2][2] * self.inv[2][0], + rhs.inv[2][0] * self.inv[0][1] + + rhs.inv[2][1] * self.inv[1][1] + + rhs.inv[2][2] * self.inv[2][1], + rhs.inv[2][0] * self.inv[0][2] + + rhs.inv[2][1] * self.inv[1][2] + + rhs.inv[2][2] * self.inv[2][2], + ], + ], + } + } +} + +impl MulAssign for AffineTransform { + fn mul_assign(&mut self, rhs: AffineTransform) { + *self = *self * rhs + } +} diff --git a/ray-tracing-core/src/lib.rs b/ray-tracing-core/src/lib.rs index ba5a18b..2000559 100644 --- a/ray-tracing-core/src/lib.rs +++ b/ray-tracing-core/src/lib.rs @@ -1,4 +1,5 @@ pub mod aabb; +pub mod affine_transform; pub mod camera; pub mod color; pub mod light; diff --git a/ray-tracing-pbrt-scene/examples/transformation_test.rs b/ray-tracing-pbrt-scene/examples/transformation_test.rs new file mode 100644 index 0000000..334ed6e --- /dev/null +++ b/ray-tracing-pbrt-scene/examples/transformation_test.rs @@ -0,0 +1,9 @@ +use ray_tracing_core::{affine_transform::AffineTransform, math::Dir3, prelude::*}; + +fn main() { + let mut t = AffineTransform::scale(1.0, 1.0, 2.0); + + t *= AffineTransform::rotation(FloatConsts::PI, Dir3::up()); + + dbg!(t); +}