Do clipping in 3D homogeneous space
This commit is contained in:
parent
4801503dd8
commit
89244ba6cf
|
@ -37,7 +37,7 @@ const MAIN_FRAMEBUFFER_WIDTH: u32 = 1067;
|
|||
const MAIN_FRAMEBUFFER_HEIGHT: u32 = 800;
|
||||
|
||||
const MOUSELOOK_ROTATION_SPEED: f32 = 0.01;
|
||||
const CAMERA_VELOCITY: f32 = 0.03;
|
||||
const CAMERA_VELOCITY: f32 = 60.0;
|
||||
|
||||
fn main() {
|
||||
let options = Options::get();
|
||||
|
@ -65,7 +65,7 @@ fn main() {
|
|||
let (drawable_width, drawable_height) = window.drawable_size();
|
||||
let mut renderer = Renderer::new(&Size2D::new(drawable_width, drawable_height));
|
||||
|
||||
let mut camera_position = Point4DF32::new(1.1, 1.0, 3.0, 1.0);
|
||||
let mut camera_position = Point4DF32::new(500.0, 500.0, 3000.0, 1.0);
|
||||
let mut camera_velocity = Point4DF32::new(0.0, 0.0, 0.0, 1.0);
|
||||
let (mut camera_yaw, mut camera_pitch) = (0.0, 0.0);
|
||||
|
||||
|
@ -87,7 +87,11 @@ fn main() {
|
|||
camera_position = camera_position + rotation.transform_point(camera_velocity);
|
||||
|
||||
let mut transform =
|
||||
Transform3DF32::from_perspective(FRAC_PI_4, 4.0 / 3.0, 0.0001, 100.0);
|
||||
Transform3DF32::from_perspective(FRAC_PI_4, 4.0 / 3.0, 0.025, 100.0);
|
||||
|
||||
transform = transform.post_mul(&Transform3DF32::from_scale(1.0 / 800.0,
|
||||
1.0 / 800.0,
|
||||
1.0 / 800.0));
|
||||
transform = transform.post_mul(&Transform3DF32::from_rotation(camera_yaw,
|
||||
camera_pitch,
|
||||
0.0));
|
||||
|
@ -95,8 +99,6 @@ fn main() {
|
|||
transform.post_mul(&Transform3DF32::from_translation(-camera_position.x(),
|
||||
-camera_position.y(),
|
||||
-camera_position.z()));
|
||||
transform =
|
||||
transform.post_mul(&Transform3DF32::from_scale(1.0 / 800.0, 1.0 / 800.0, 1.0));
|
||||
|
||||
let perspective = Perspective::new(&transform, &window_size);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use crate::line_segment::LineSegmentF32;
|
||||
use crate::outline::{Contour, PointFlags};
|
||||
use crate::point::{Point2DF32, Point3DF32};
|
||||
use crate::point::{Point2DF32, Point4DF32};
|
||||
use crate::segment::{CubicSegment, Segment};
|
||||
use crate::util::lerp;
|
||||
use arrayvec::ArrayVec;
|
||||
|
@ -268,18 +268,6 @@ impl ContourClipper {
|
|||
prev = next;
|
||||
}
|
||||
|
||||
/*
|
||||
let top = Point2DF32::new(lerp(self.clip_rect.origin.x, self.clip_rect.max_x(), 0.5),
|
||||
self.clip_rect.origin.y);
|
||||
self.clip_against(Edge(LineSegmentF32::new(&Point2DF32::from_euclid(self.clip_rect
|
||||
.bottom_left()),
|
||||
&top)));
|
||||
self.clip_against(Edge(LineSegmentF32::new(&top,
|
||||
&Point2DF32::from_euclid(self.clip_rect
|
||||
.bottom_right()))));
|
||||
self.clip_against(Edge::bottom(&self.clip_rect));
|
||||
*/
|
||||
|
||||
self.contour
|
||||
}
|
||||
|
||||
|
@ -335,27 +323,12 @@ impl ContourClipper {
|
|||
if let Some(last_position) = contour.last_position() {
|
||||
if last_position != segment.baseline.from() {
|
||||
// Add a line to join up segments.
|
||||
//check_point(&segment.baseline.from(), edge);
|
||||
contour.push_point(segment.baseline.from(), PointFlags::empty());
|
||||
}
|
||||
}
|
||||
|
||||
//check_point(&segment.baseline.to(), edge);
|
||||
contour.push_segment(*segment);
|
||||
}
|
||||
|
||||
/*
|
||||
fn check_point(point: &Point2DF32, edge: Edge) {
|
||||
match edge {
|
||||
Edge::Left(x) if point.x() + 0.1 >= x => return,
|
||||
Edge::Top(y) if point.y() + 0.1 >= y => return,
|
||||
Edge::Right(x) if point.x() - 0.1 <= x => return,
|
||||
Edge::Bottom(y) if point.y() - 0.1 <= y => return,
|
||||
_ => {}
|
||||
}
|
||||
panic!("point {:?} outside edge {:?}", point, edge);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,24 +341,31 @@ enum EdgeRelativeLocation {
|
|||
// 3D quad clipping
|
||||
|
||||
pub struct PolygonClipper3D {
|
||||
subject: Vec<Point3DF32>,
|
||||
subject: Vec<Point4DF32>,
|
||||
}
|
||||
|
||||
impl PolygonClipper3D {
|
||||
#[inline]
|
||||
pub fn new(subject: Vec<Point3DF32>) -> PolygonClipper3D {
|
||||
pub fn new(subject: Vec<Point4DF32>) -> PolygonClipper3D {
|
||||
PolygonClipper3D { subject }
|
||||
}
|
||||
|
||||
pub fn clip(mut self) -> Vec<Point3DF32> {
|
||||
pub fn clip(mut self) -> Vec<Point4DF32> {
|
||||
// TODO(pcwalton): Fast path for completely contained polygon?
|
||||
|
||||
self.clip_against(Edge3D::Left);
|
||||
self.clip_against(Edge3D::Right);
|
||||
//println!("before clipping against bottom: {:?}", self.subject);
|
||||
self.clip_against(Edge3D::Bottom);
|
||||
//println!("before clipping against top: {:?}", self.subject);
|
||||
self.clip_against(Edge3D::Top);
|
||||
self.clip_against(Edge3D::Near);
|
||||
//println!("before clipping against left: {:?}", self.subject);
|
||||
self.clip_against(Edge3D::Left);
|
||||
//println!("before clipping against right: {:?}", self.subject);
|
||||
self.clip_against(Edge3D::Right);
|
||||
//println!("before clipping against far: {:?}", self.subject);
|
||||
self.clip_against(Edge3D::Far);
|
||||
//println!("before clipping against near: {:?}", self.subject);
|
||||
self.clip_against(Edge3D::Near);
|
||||
//println!("after clipping: {:?}", self.subject);
|
||||
|
||||
self.subject
|
||||
}
|
||||
|
@ -422,24 +402,28 @@ enum Edge3D {
|
|||
|
||||
impl Edge3D {
|
||||
#[inline]
|
||||
fn point_is_inside(self, point: Point3DF32) -> bool {
|
||||
fn point_is_inside(self, point: Point4DF32) -> bool {
|
||||
let w = point.w();
|
||||
match self {
|
||||
Edge3D::Left => point.x() >= -1.0, Edge3D::Right => point.x() <= 1.0,
|
||||
Edge3D::Bottom => point.y() >= -1.0, Edge3D::Top => point.y() <= 1.0,
|
||||
Edge3D::Near => point.z() >= -1.0, Edge3D::Far => point.z() <= 1.0,
|
||||
Edge3D::Left => point.x() >= -w, Edge3D::Right => point.x() <= w,
|
||||
Edge3D::Bottom => point.y() >= -w, Edge3D::Top => point.y() <= w,
|
||||
Edge3D::Near => point.z() >= -w, Edge3D::Far => point.z() <= w,
|
||||
}
|
||||
}
|
||||
|
||||
fn line_intersection(self, prev: Point3DF32, next: Point3DF32) -> Point3DF32 {
|
||||
// Blinn & Newell, "Clipping using homogeneous coordinates", SIGGRAPH 1978.
|
||||
fn line_intersection(self, prev: Point4DF32, next: Point4DF32) -> Point4DF32 {
|
||||
let (x0, x1) = match self {
|
||||
Edge3D::Left | Edge3D::Right => (prev.x(), next.x()),
|
||||
Edge3D::Bottom | Edge3D::Top => (prev.y(), next.y()),
|
||||
Edge3D::Near | Edge3D::Far => (prev.z(), next.z()),
|
||||
};
|
||||
let x = match self {
|
||||
let (w0, w1) = (prev.w(), next.w());
|
||||
let sign = match self {
|
||||
Edge3D::Left | Edge3D::Bottom | Edge3D::Near => -1.0,
|
||||
Edge3D::Right | Edge3D::Top | Edge3D::Far => 1.0,
|
||||
};
|
||||
prev.lerp(next, (x - x0) / (x1 - x0))
|
||||
let alpha = ((x0 - sign * w0) as f64) / ((sign * (w1 - w0) - (x1 - x0)) as f64);
|
||||
prev.lerp(next, alpha as f32)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -179,6 +179,11 @@ impl Point4DF32 {
|
|||
Point4DF32(F32x4::new(x, y, z, w))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_euclid_2d(point: &Point2D<f32>) -> Point4DF32 {
|
||||
Point4DF32::new(point.x, point.y, 0.0, 1.0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn splat(value: f32) -> Point4DF32 {
|
||||
Point4DF32(F32x4::splat(value))
|
||||
|
@ -247,6 +252,11 @@ impl Point4DF32 {
|
|||
pub fn is_zero(self) -> bool {
|
||||
self.x() == 0.0 && self.y() == 0.0 && self.z() == 0.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn lerp(self, other: Point4DF32, t: f32) -> Point4DF32 {
|
||||
Point4DF32(self.0 + (other.0 - self.0) * F32x4::splat(t))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Point4DF32> for Point4DF32 {
|
||||
|
|
|
@ -181,7 +181,8 @@ impl Transform3DF32 {
|
|||
|
||||
#[inline]
|
||||
pub fn transform_point_3d(&self, point: Point3DF32) -> Point3DF32 {
|
||||
self.transform_point(point.to_4d()).perspective_divide()
|
||||
let point4d = self.transform_point(point.to_4d());
|
||||
point4d.perspective_divide()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -18,7 +18,7 @@ use euclid::Rect;
|
|||
use hashbrown::HashMap;
|
||||
use pathfinder_geometry::clip::PolygonClipper3D;
|
||||
use pathfinder_geometry::outline::Outline;
|
||||
use pathfinder_geometry::point::{Point2DF32, Point3DF32};
|
||||
use pathfinder_geometry::point::{Point2DF32, Point3DF32, Point4DF32};
|
||||
use pathfinder_geometry::transform3d::Perspective;
|
||||
use pathfinder_geometry::transform::Transform2DF32;
|
||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator};
|
||||
|
@ -170,19 +170,20 @@ impl Scene {
|
|||
|
||||
fn clip_bounding_quad_with_perspective(&self, perspective: &Perspective) -> Vec<Point3DF32> {
|
||||
let mut points = vec![
|
||||
Point3DF32::from_euclid_2d(&self.bounds.origin),
|
||||
Point3DF32::from_euclid_2d(&self.bounds.top_right()),
|
||||
Point3DF32::from_euclid_2d(&self.bounds.bottom_right()),
|
||||
Point3DF32::from_euclid_2d(&self.bounds.bottom_left()),
|
||||
Point4DF32::from_euclid_2d(&self.bounds.origin),
|
||||
Point4DF32::from_euclid_2d(&self.bounds.top_right()),
|
||||
Point4DF32::from_euclid_2d(&self.bounds.bottom_right()),
|
||||
Point4DF32::from_euclid_2d(&self.bounds.bottom_left()),
|
||||
];
|
||||
//println!("-----");
|
||||
//println!("bounds={:?} ORIGINAL quad={:?}", self.bounds, points);
|
||||
for point in &mut points {
|
||||
*point = perspective.transform.transform_point_3d(*point);
|
||||
*point = perspective.transform.transform_point(*point);
|
||||
}
|
||||
//println!("PERSPECTIVE quad={:?}", points);
|
||||
//points
|
||||
PolygonClipper3D::new(points).clip()
|
||||
//println!("... PERSPECTIVE quad={:?}", points);
|
||||
points = PolygonClipper3D::new(points).clip();
|
||||
//println!("... CLIPPED quad={:?}", points);
|
||||
points.into_iter().map(|point| point.perspective_divide()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue