Add a 3D vector type
This commit is contained in:
parent
b912cbbeb4
commit
521ab3b5ba
|
@ -163,7 +163,7 @@ impl<W> DemoApp<W> where W: Window {
|
||||||
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
let scene_framebuffer = self.scene_framebuffer.as_ref().unwrap();
|
||||||
let scene_texture = self.renderer.device.framebuffer_texture(scene_framebuffer);
|
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);
|
quad_scale.set_z(1.0);
|
||||||
let quad_scale_transform = Transform4F::from_scale(quad_scale);
|
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 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.set_z(ground_scale);
|
||||||
offset = offset * Vector4F::new(-0.5, 1.0, -0.5, 1.0);
|
offset = offset * Vector4F::new(-0.5, 1.0, -0.5, 1.0);
|
||||||
let base_transform = perspective.transform * Transform4F::from_translation(offset);
|
let base_transform = perspective.transform * Transform4F::from_translation(offset);
|
||||||
|
|
|
@ -387,8 +387,7 @@ impl Mul<Vector2F> for Perspective {
|
||||||
type Output = Vector2F;
|
type Output = Vector2F;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, vector: Vector2F) -> Vector2F {
|
fn mul(self, vector: Vector2F) -> Vector2F {
|
||||||
let point = (self.transform * vector.to_3d()).perspective_divide().to_2d() *
|
let point = (self.transform * vector.to_4d()).to_2d() * Vector2F::new(1.0, -1.0);
|
||||||
Vector2F::new(1.0, -1.0);
|
|
||||||
(point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5)
|
(point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,12 @@ impl Vector2F {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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)))
|
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.
|
/// 3D homogeneous points.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct Vector4F(pub F32x4);
|
pub struct Vector4F(pub F32x4);
|
||||||
|
@ -277,7 +360,15 @@ impl Vector4F {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_2d(self) -> Vector2F {
|
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]
|
#[inline]
|
||||||
|
@ -327,11 +418,6 @@ impl Vector4F {
|
||||||
self.0[3] = w
|
self.0[3] = w
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn perspective_divide(self) -> Vector4F {
|
|
||||||
Vector4F(self.0 * F32x4::splat(1.0 / self.w()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn approx_eq(self, other: Vector4F, epsilon: f32) -> bool {
|
pub fn approx_eq(self, other: Vector4F, epsilon: f32) -> bool {
|
||||||
self.0.approx_eq(other.0, epsilon)
|
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 {
|
impl Default for Vector4F {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Vector4F {
|
fn default() -> Vector4F {
|
||||||
|
|
|
@ -75,10 +75,10 @@ impl RenderTransform {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut points = vec![
|
let mut points = vec![
|
||||||
bounds.origin().to_3d(),
|
bounds.origin().to_4d(),
|
||||||
bounds.upper_right().to_3d(),
|
bounds.upper_right().to_4d(),
|
||||||
bounds.lower_right().to_3d(),
|
bounds.lower_right().to_4d(),
|
||||||
bounds.lower_left().to_3d(),
|
bounds.lower_left().to_4d(),
|
||||||
];
|
];
|
||||||
debug!("-----");
|
debug!("-----");
|
||||||
debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
|
debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
|
||||||
|
@ -89,23 +89,22 @@ impl RenderTransform {
|
||||||
|
|
||||||
// Compute depth.
|
// Compute depth.
|
||||||
let quad = [
|
let quad = [
|
||||||
points[0].perspective_divide(),
|
points[0].to_3d().to_4d(),
|
||||||
points[1].perspective_divide(),
|
points[1].to_3d().to_4d(),
|
||||||
points[2].perspective_divide(),
|
points[2].to_3d().to_4d(),
|
||||||
points[3].perspective_divide(),
|
points[3].to_3d().to_4d(),
|
||||||
];
|
];
|
||||||
debug!("... PERSPECTIVE-DIVIDED points = {:?}", quad);
|
debug!("... PERSPECTIVE-DIVIDED points = {:?}", quad);
|
||||||
|
|
||||||
points = PolygonClipper3D::new(points).clip();
|
points = PolygonClipper3D::new(points).clip();
|
||||||
debug!("... CLIPPED quad={:?}", points);
|
debug!("... CLIPPED quad={:?}", points);
|
||||||
for point in &mut points {
|
for point in &mut points {
|
||||||
*point = point.perspective_divide()
|
*point = point.to_3d().to_4d()
|
||||||
}
|
}
|
||||||
|
|
||||||
let inverse_transform = perspective.transform.inverse();
|
let inverse_transform = perspective.transform.inverse();
|
||||||
let clip_polygon = points
|
let clip_polygon = points.into_iter()
|
||||||
.into_iter()
|
.map(|point| (inverse_transform * point).to_2d())
|
||||||
.map(|point| (inverse_transform * point).perspective_divide().to_2d())
|
|
||||||
.collect();
|
.collect();
|
||||||
return PreparedRenderTransform::Perspective {
|
return PreparedRenderTransform::Perspective {
|
||||||
perspective,
|
perspective,
|
||||||
|
|
Loading…
Reference in New Issue