Add a 3D vector type

This commit is contained in:
Patrick Walton 2019-12-07 11:51:47 -08:00
parent b912cbbeb4
commit 521ab3b5ba
4 changed files with 116 additions and 24 deletions

View File

@ -163,7 +163,7 @@ impl<W> DemoApp<W> where W: Window {
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
let mut quad_scale = self.scene_metadata.view_box.size().to_3d();
let mut quad_scale = self.scene_metadata.view_box.size().to_4d();
quad_scale.set_z(1.0);
let quad_scale_transform = Transform4F::from_scale(quad_scale);
@ -210,7 +210,7 @@ impl<W> DemoApp<W> where W: Window {
let ground_scale = self.scene_metadata.view_box.max_x() * 2.0;
let mut offset = self.scene_metadata.view_box.lower_right().to_3d();
let mut offset = self.scene_metadata.view_box.lower_right().to_4d();
offset.set_z(ground_scale);
offset = offset * Vector4F::new(-0.5, 1.0, -0.5, 1.0);
let base_transform = perspective.transform * Transform4F::from_translation(offset);

View File

@ -387,8 +387,7 @@ impl Mul<Vector2F> for Perspective {
type Output = Vector2F;
#[inline]
fn mul(self, vector: Vector2F) -> Vector2F {
let point = (self.transform * vector.to_3d()).perspective_divide().to_2d() *
Vector2F::new(1.0, -1.0);
let point = (self.transform * vector.to_4d()).to_2d() * Vector2F::new(1.0, -1.0);
(point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5)
}
}

View File

@ -29,7 +29,12 @@ impl Vector2F {
}
#[inline]
pub fn to_3d(self) -> Vector4F {
pub fn to_3d(self) -> Vector3F {
Vector3F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 0.0)))
}
#[inline]
pub fn to_4d(self) -> Vector4F {
Vector4F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 1.0)))
}
@ -260,6 +265,84 @@ impl PartialEq for Vector2I {
}
}
/// 3D points.
///
/// The w value in the SIMD vector is always 0.0.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Vector3F(pub F32x4);
impl Vector3F {
#[inline]
pub fn new(x: f32, y: f32, z: f32) -> Vector3F {
Vector3F(F32x4::new(x, y, z, 0.0))
}
#[inline]
pub fn splat(x: f32) -> Vector3F {
let mut vector = F32x4::splat(x);
vector.set_w(0.0);
Vector3F(vector)
}
/// Truncates this vector to 2D.
#[inline]
pub fn to_2d(self) -> Vector2F {
Vector2F(self.0.xy())
}
/// Converts this vector to an equivalent 3D homogeneous one with a w component of 1.0.
#[inline]
pub fn to_4d(self) -> Vector4F {
let mut vector = self.0;
vector.set_w(1.0);
Vector4F(vector)
}
#[inline]
pub fn cross(self, other: Vector3F) -> Vector3F {
Vector3F(self.0.yzxw() * other.0.zxyw() - self.0.zxyw() * other.0.yzxw())
}
#[inline]
pub fn square_length(self) -> f32 {
let squared = self.0 * self.0;
squared[0] + squared[1] + squared[2]
}
#[inline]
pub fn length(self) -> f32 {
f32::sqrt(self.square_length())
}
#[inline]
pub fn normalize(self) -> Vector3F {
Vector3F(self.0 * F32x4::splat(1.0 / self.length()))
}
}
impl Add<Vector3F> for Vector3F {
type Output = Vector3F;
#[inline]
fn add(self, other: Vector3F) -> Vector3F {
Vector3F(self.0 + other.0)
}
}
impl AddAssign for Vector3F {
#[inline]
fn add_assign(&mut self, other: Vector3F) {
self.0 += other.0
}
}
impl Sub<Vector3F> for Vector3F {
type Output = Vector3F;
#[inline]
fn sub(self, other: Vector3F) -> Vector3F {
Vector3F(self.0 - other.0)
}
}
/// 3D homogeneous points.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vector4F(pub F32x4);
@ -277,7 +360,15 @@ impl Vector4F {
#[inline]
pub fn to_2d(self) -> Vector2F {
Vector2F(self.0.xy())
self.to_3d().to_2d()
}
/// Performs perspective division to convert this vector to 3D.
#[inline]
pub fn to_3d(self) -> Vector3F {
let mut vector = self.0 * F32x4::splat(1.0 / self.w());
vector.set_w(0.0);
Vector3F(vector)
}
#[inline]
@ -327,11 +418,6 @@ impl Vector4F {
self.0[3] = w
}
#[inline]
pub fn perspective_divide(self) -> Vector4F {
Vector4F(self.0 * F32x4::splat(1.0 / self.w()))
}
#[inline]
pub fn approx_eq(self, other: Vector4F, epsilon: f32) -> bool {
self.0.approx_eq(other.0, epsilon)
@ -385,6 +471,14 @@ impl Neg for Vector4F {
}
}
impl Sub<Vector4F> for Vector4F {
type Output = Vector4F;
#[inline]
fn sub(self, other: Vector4F) -> Vector4F {
Vector4F(self.0 - other.0)
}
}
impl Default for Vector4F {
#[inline]
fn default() -> Vector4F {

View File

@ -75,10 +75,10 @@ impl RenderTransform {
};
let mut points = vec![
bounds.origin().to_3d(),
bounds.upper_right().to_3d(),
bounds.lower_right().to_3d(),
bounds.lower_left().to_3d(),
bounds.origin().to_4d(),
bounds.upper_right().to_4d(),
bounds.lower_right().to_4d(),
bounds.lower_left().to_4d(),
];
debug!("-----");
debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
@ -89,24 +89,23 @@ impl RenderTransform {
// Compute depth.
let quad = [
points[0].perspective_divide(),
points[1].perspective_divide(),
points[2].perspective_divide(),
points[3].perspective_divide(),
points[0].to_3d().to_4d(),
points[1].to_3d().to_4d(),
points[2].to_3d().to_4d(),
points[3].to_3d().to_4d(),
];
debug!("... PERSPECTIVE-DIVIDED points = {:?}", quad);
points = PolygonClipper3D::new(points).clip();
debug!("... CLIPPED quad={:?}", points);
for point in &mut points {
*point = point.perspective_divide()
*point = point.to_3d().to_4d()
}
let inverse_transform = perspective.transform.inverse();
let clip_polygon = points
.into_iter()
.map(|point| (inverse_transform * point).perspective_divide().to_2d())
.collect();
let clip_polygon = points.into_iter()
.map(|point| (inverse_transform * point).to_2d())
.collect();
return PreparedRenderTransform::Perspective {
perspective,
clip_polygon,