Use operator overloading for 3D matrix multiplication

This commit is contained in:
Patrick Walton 2019-07-11 13:59:39 -07:00
parent abf97c9adb
commit eb0a61679d
5 changed files with 66 additions and 64 deletions

View File

@ -153,15 +153,13 @@ impl CameraTransform3D {
pub fn to_transform(&self) -> Transform3DF {
let mut transform = Transform3DF::from_rotation(self.yaw, self.pitch, 0.0);
transform = transform.post_mul(&Transform3DF::from_uniform_scale(2.0 * self.scale));
transform = transform.post_mul(&Transform3DF::from_translation(
-self.position.x(),
-self.position.y(),
-self.position.z(),
));
transform *= Transform3DF::from_uniform_scale(2.0 * self.scale);
transform *= Transform3DF::from_translation(-self.position.x(),
-self.position.y(),
-self.position.z());
// Flip Y.
transform = transform.post_mul(&Transform3DF::from_scale(1.0, -1.0, 1.0));
transform *= Transform3DF::from_scale(1.0, -1.0, 1.0);
transform
}

View File

@ -256,10 +256,9 @@ impl<W> DemoApp<W> where W: Window {
if modelview_transform.offset(*velocity) {
self.dirty = true;
}
let perspective = scene_transform
.perspective
.post_mul(&scene_transform.modelview_to_eye)
.post_mul(&modelview_transform.to_transform());
let perspective = scene_transform.perspective *
scene_transform.modelview_to_eye *
modelview_transform.to_transform();
Some(RenderTransform::Perspective(perspective))
}
Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)),
@ -356,13 +355,20 @@ impl<W> DemoApp<W> where W: Window {
*scene_transform = eye_transforms[0];
for (index, eye_transform) in eye_transforms.iter().enumerate().skip(1) {
let weight = 1.0 / (index + 1) as f32;
scene_transform.perspective.transform = scene_transform.perspective.transform.lerp(weight, &eye_transform.perspective.transform);
scene_transform.modelview_to_eye = scene_transform.modelview_to_eye.lerp(weight, &eye_transform.modelview_to_eye);
scene_transform.perspective.transform =
scene_transform.perspective
.transform
.lerp(weight, &eye_transform.perspective.transform);
scene_transform.modelview_to_eye =
scene_transform.modelview_to_eye
.lerp(weight, &eye_transform.modelview_to_eye);
}
// TODO: calculate the eye offset from the eye transforms?
let z_offset = -DEFAULT_EYE_OFFSET * scene_transform.perspective.transform.c0.x();
scene_transform.modelview_to_eye = scene_transform.modelview_to_eye
.pre_mul(&Transform3DF::from_translation(0.0, 0.0, z_offset));
let z_offset = -DEFAULT_EYE_OFFSET *
scene_transform.perspective.transform.c0.x();
scene_transform.modelview_to_eye =
Transform3DF::from_translation(0.0, 0.0, z_offset) *
scene_transform.modelview_to_eye;
}
}
Event::KeyDown(Keycode::Alphanumeric(b'w')) => {

View File

@ -169,18 +169,16 @@ impl<W> DemoApp<W> where W: Window {
1.0,
);
let scene_transform_matrix = scene_transform
.perspective
.post_mul(&scene_transform.modelview_to_eye)
.post_mul(&modelview_transform.to_transform())
.post_mul(&quad_scale_transform);
let scene_transform_matrix = scene_transform.perspective *
scene_transform.modelview_to_eye *
modelview_transform.to_transform() *
quad_scale_transform;
let eye_transform = &eye_transforms[render_scene_index as usize];
let eye_transform_matrix = eye_transform
.perspective
.post_mul(&eye_transform.modelview_to_eye)
.post_mul(&modelview_transform.to_transform())
.post_mul(&quad_scale_transform);
let eye_transform_matrix = eye_transform.perspective *
eye_transform.modelview_to_eye *
modelview_transform.to_transform() *
quad_scale_transform;
debug!(
"eye transform({}).modelview_to_eye={:?}",
@ -214,17 +212,13 @@ impl<W> DemoApp<W> where W: Window {
let ground_scale = self.scene_metadata.view_box.max_x() * 2.0;
let mut base_transform = perspective.transform;
base_transform = base_transform.post_mul(&Transform3DF::from_translation(
-0.5 * self.scene_metadata.view_box.max_x(),
self.scene_metadata.view_box.max_y(),
-0.5 * ground_scale,
));
let base_transform = perspective.transform *
Transform3DF::from_translation(-0.5 * self.scene_metadata.view_box.max_x(),
self.scene_metadata.view_box.max_y(),
-0.5 * ground_scale);
// Fill ground.
let mut transform = base_transform;
transform =
transform.post_mul(&Transform3DF::from_scale(ground_scale, 1.0, ground_scale));
let transform = base_transform * Transform3DF::from_scale(ground_scale, 1.0, ground_scale);
// Don't clear the first scene after drawing it.
let clear_color = if render_scene_index == 0 {

View File

@ -14,7 +14,7 @@ use crate::vector::{Vector2F, Vector2I, Vector4F};
use crate::rect::RectF;
use crate::transform2d::Matrix2x2F;
use pathfinder_simd::default::F32x4;
use std::ops::{Add, Neg};
use std::ops::{Add, Mul, MulAssign, Neg};
/// An transform, optimized with SIMD.
///
@ -218,31 +218,6 @@ impl Transform3DF {
}
}
// FIXME(pcwalton): Is this right, due to transposition? I think we may have to reverse the
// two.
//
// https://stackoverflow.com/a/18508113
#[inline]
pub fn pre_mul(&self, other: &Transform3DF) -> Transform3DF {
return Transform3DF {
c0: mul_col(self.c0, other),
c1: mul_col(self.c1, other),
c2: mul_col(self.c2, other),
c3: mul_col(self.c3, other),
};
fn mul_col(a_col: F32x4, b: &Transform3DF) -> F32x4 {
let (a0, a1) = (F32x4::splat(a_col[0]), F32x4::splat(a_col[1]));
let (a2, a3) = (F32x4::splat(a_col[2]), F32x4::splat(a_col[3]));
a0 * b.c0 + a1 * b.c1 + a2 * b.c2 + a3 * b.c3
}
}
#[inline]
pub fn post_mul(&self, other: &Transform3DF) -> Transform3DF {
other.pre_mul(self)
}
#[inline]
pub fn transform_point(&self, point: Vector4F) -> Vector4F {
let term0 = self.c0 * F32x4::splat(point.x());
@ -313,6 +288,32 @@ impl Transform3DF {
}
}
impl Mul<Transform3DF> for Transform3DF {
type Output = Transform3DF;
// https://stackoverflow.com/a/18508113
#[inline]
fn mul(self, other: Transform3DF) -> Transform3DF {
return Transform3DF {
c0: mul_col(&self, other.c0),
c1: mul_col(&self, other.c1),
c2: mul_col(&self, other.c2),
c3: mul_col(&self, other.c3),
};
#[inline]
fn mul_col(a: &Transform3DF, b_col: F32x4) -> F32x4 {
a.c0 * b_col.xxxx() + a.c1 * b_col.yyyy() + a.c2 * b_col.zzzz() + a.c3 * b_col.wwww()
}
}
}
impl MulAssign<Transform3DF> for Transform3DF {
fn mul_assign(&mut self, other: Transform3DF) {
*self = *self * other
}
}
impl Add<Matrix2x2F> for Matrix2x2F {
type Output = Matrix2x2F;
#[inline]
@ -366,11 +367,14 @@ impl Perspective {
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
RectF::from_points(min_point, max_point)
}
}
impl Mul<Transform3DF> for Perspective {
type Output = Perspective;
#[inline]
pub fn post_mul(&self, other: &Transform3DF) -> Perspective {
fn mul(self, other: Transform3DF) -> Perspective {
Perspective {
transform: self.transform.post_mul(other),
transform: self.transform * other,
window_size: self.window_size,
}
}

View File

@ -472,7 +472,7 @@ where
let draw_viewport = self.draw_viewport().size().to_f32();
let scale = F32x2::new(2.0 / draw_viewport.x(), -2.0 / draw_viewport.y());
let transform = Transform3DF::from_scale(scale.x(), scale.y(), 1.0);
Transform3DF::from_translation(-1.0, 1.0, 0.0).post_mul(&transform)
Transform3DF::from_translation(-1.0, 1.0, 0.0) * transform
}
fn draw_alpha_tiles(&mut self, count: u32) {