2.13 转换矩阵

[复制链接]
发表于 2025-12-22 13:39:20 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
转换矩阵引用了库nalgebra,使用时研究详细实现。
  1. use std::ops;
  2. use nalgebra::Perspective3;
  3. use crate::Scalar;
  4. use super::{Aabb, LineSegment, Point, Triangle, Vector};
  5. /// An affine transform
  6. #[repr(C)]
  7. #[derive(Debug, Clone, Copy, Default)]
  8. pub struct Transform(nalgebra::Transform<f64, nalgebra::TAffine, 3>);
  9. impl Transform {
  10.     /// Construct an identity transform
  11.     pub fn identity() -> Self {
  12.         Self(nalgebra::Transform::identity())
  13.     }
  14.     /// Construct a translation
  15.     pub fn translation(offset: impl Into<Vector<3>>) -> Self {
  16.         let offset = offset.into();
  17.         Self(nalgebra::Transform::from_matrix_unchecked(
  18.             nalgebra::OMatrix::new_translation(&offset.to_na()),
  19.         ))
  20.     }
  21.     /// Construct a rotation
  22.     ///
  23.     /// The direction of the vector defines the rotation axis. Its length
  24.     /// defines the angle of the rotation.
  25.     pub fn rotation(axis_angle: impl Into<Vector<3>>) -> Self {
  26.         let axis_angle = axis_angle.into();
  27.         Self(nalgebra::Transform::from_matrix_unchecked(
  28.             nalgebra::OMatrix::<_, nalgebra::Const<4>, _>::new_rotation(
  29.                 axis_angle.to_na(),
  30.             ),
  31.         ))
  32.     }
  33.     /// Construct a scaling
  34.     pub fn scale(scaling_factor: f64) -> Self {
  35.         Self(nalgebra::Transform::from_matrix_unchecked(
  36.             nalgebra::OMatrix::new_scaling(scaling_factor),
  37.         ))
  38.     }
  39.     /// # Extract the "right" vector from the rotational component
  40.     pub fn right(&self) -> Vector<3> {
  41.         let d = self.data();
  42.         Vector::from([d[0], d[1], d[2]])
  43.     }
  44.     /// # Extract the "up" vector from the rotational component
  45.     pub fn up(&self) -> Vector<3> {
  46.         let d = self.data();
  47.         Vector::from([d[4], d[5], d[6]])
  48.     }
  49.     /// Transform the given point
  50.     pub fn transform_point(&self, point: &Point<3>) -> Point<3> {
  51.         Point::from(self.0.transform_point(&point.to_na()))
  52.     }
  53.     /// Inverse transform given point
  54.     pub fn inverse_transform_point(&self, point: &Point<3>) -> Point<3> {
  55.         Point::from(self.0.inverse_transform_point(&point.to_na()))
  56.     }
  57.     /// Transform the given vector
  58.     pub fn transform_vector(&self, vector: &Vector<3>) -> Vector<3> {
  59.         Vector::from(self.0.transform_vector(&vector.to_na()))
  60.     }
  61.     /// Transform the given segment
  62.     pub fn transform_segment(
  63.         &self,
  64.         segment: &LineSegment<3>,
  65.     ) -> LineSegment<3> {
  66.         let [a, b] = &segment.points;
  67.         LineSegment::from([self.transform_point(a), self.transform_point(b)])
  68.     }
  69.     /// Transform the given triangle
  70.     pub fn transform_triangle(&self, triangle: &Triangle<3>) -> Triangle<3> {
  71.         let [a, b, c] = &triangle.points;
  72.         Triangle::from([
  73.             self.transform_point(a),
  74.             self.transform_point(b),
  75.             self.transform_point(c),
  76.         ])
  77.     }
  78.     /// Inverse transform
  79.     pub fn inverse(&self) -> Self {
  80.         Self(self.0.inverse())
  81.     }
  82.     /// Transpose transform
  83.     pub fn transpose(&self) -> Self {
  84.         Self(nalgebra::Transform::from_matrix_unchecked(
  85.             self.0.to_homogeneous().transpose(),
  86.         ))
  87.     }
  88.     /// Project transform according to camera specification, return data as an array.
  89.     /// Used primarily for graphics code.
  90.     pub fn project_to_array(
  91.         &self,
  92.         aspect_ratio: f64,
  93.         fovy: f64,
  94.         znear: f64,
  95.         zfar: f64,
  96.     ) -> [Scalar; 16] {
  97.         let projection = Perspective3::new(aspect_ratio, fovy, znear, zfar);
  98.         let mut array = [0.; 16];
  99.         array.copy_from_slice(
  100.             (projection.to_projective() * self.0).matrix().as_slice(),
  101.         );
  102.         array.map(Scalar::from)
  103.     }
  104.     /// Return a copy of the inner nalgebra transform
  105.     pub fn get_inner(&self) -> nalgebra::Transform<f64, nalgebra::TAffine, 3> {
  106.         self.0
  107.     }
  108.     /// Transform the given axis-aligned bounding box
  109.     pub fn transform_aabb(&self, aabb: &Aabb<3>) -> Aabb<3> {
  110.         Aabb {
  111.             min: self.transform_point(&aabb.min),
  112.             max: self.transform_point(&aabb.max),
  113.         }
  114.     }
  115.     /// Exposes the data of this Transform as a slice of f64.
  116.     pub fn data(&self) -> &[f64] {
  117.         self.0.matrix().data.as_slice()
  118.     }
  119.     /// Extract the rotation component of this transform
  120.     pub fn extract_rotation(&self) -> Self {
  121.         Self(nalgebra::Transform::from_matrix_unchecked(
  122.             self.0.matrix().fixed_resize::<3, 3>(0.).to_homogeneous(),
  123.         ))
  124.     }
  125.     /// Extract the translation component of this transform
  126.     pub fn extract_translation(&self) -> Self {
  127.         *self * self.extract_rotation().inverse()
  128.     }
  129. }
  130. impl ops::Mul<Self> for Transform {
  131.     type Output = Self;
  132.     fn mul(self, rhs: Self) -> Self::Output {
  133.         Self(self.0.mul(rhs.0))
  134.     }
  135. }
  136. #[cfg(test)]
  137. mod tests {
  138.     use approx::assert_abs_diff_eq;
  139.     use crate::{Scalar, Vector};
  140.     use super::Transform;
  141.     #[test]
  142.     fn extract_rotation_translation() {
  143.         let rotation =
  144.             Transform::rotation(Vector::unit_z() * (Scalar::PI / 2.));
  145.         let translation = Transform::translation([1., 2., 3.]);
  146.         assert_abs_diff_eq!(
  147.             (translation * rotation).extract_rotation().data(),
  148.             rotation.data(),
  149.             epsilon = 1e-8,
  150.         );
  151.         assert_abs_diff_eq!(
  152.             (translation * rotation).extract_translation().data(),
  153.             translation.data(),
  154.             epsilon = 1e-8,
  155.         );
  156.         assert_abs_diff_eq!(
  157.             (rotation * translation).extract_rotation().data(),
  158.             rotation.data(),
  159.             epsilon = 1e-8,
  160.         );
  161.         assert_abs_diff_eq!(
  162.             (rotation * translation).extract_translation().data(),
  163.             Transform::translation([-2., 1., 3.]).data(),
  164.             epsilon = 1e-8,
  165.         );
  166.     }
  167. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表