Playing around with surface patch implementation. Trying out ideas.
This commit is contained in:
parent
4999b31bf5
commit
0c99ce8227
|
@ -1,10 +1,8 @@
|
||||||
use super::Splitable;
|
use super::{point_order, PointOrder, Splitable, MAX_EDGE_DICE};
|
||||||
use crate::math::Point;
|
use crate::{lerp::lerp, math::Point};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct BilinearPatch<'a> {
|
pub struct BilinearPatch<'a> {
|
||||||
time_sample_count: usize,
|
|
||||||
|
|
||||||
// The control points are stored in clockwise order, like this:
|
// The control points are stored in clockwise order, like this:
|
||||||
// u ----->
|
// u ----->
|
||||||
// v 0 1
|
// v 0 1
|
||||||
|
@ -25,6 +23,12 @@ pub struct BilinearPatch<'a> {
|
||||||
must_split: [bool; 4],
|
must_split: [bool; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bilerp_point(patch: [Point; 4], uv: (f32, f32)) -> Point {
|
||||||
|
let a = lerp(patch[0], patch[1], uv.0);
|
||||||
|
let b = lerp(patch[3], patch[2], uv.0);
|
||||||
|
lerp(a, b, uv.1)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct BilinearSubPatch<'a> {
|
pub struct BilinearSubPatch<'a> {
|
||||||
original: &'a BilinearPatch<'a>,
|
original: &'a BilinearPatch<'a>,
|
||||||
|
@ -33,7 +37,73 @@ pub struct BilinearSubPatch<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Splitable for BilinearSubPatch<'a> {
|
impl<'a> Splitable for BilinearSubPatch<'a> {
|
||||||
fn split(&self /* TODO: splitting criteria. */) -> Option<(Self, Self)> {
|
fn split<F>(&self, metric: F) -> Option<(Self, Self)>
|
||||||
unimplemented!()
|
where
|
||||||
|
F: Fn(Point, Point) -> f32,
|
||||||
|
{
|
||||||
|
// Get the points of the sub-patch.
|
||||||
|
let patch = self.original.control_points[0];
|
||||||
|
let points = [
|
||||||
|
bilerp_point(patch, self.clip[0]),
|
||||||
|
bilerp_point(patch, self.clip[1]),
|
||||||
|
bilerp_point(patch, self.clip[2]),
|
||||||
|
bilerp_point(patch, self.clip[3]),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Calculate edge metrics.
|
||||||
|
let edge_metric = [
|
||||||
|
metric(points[0], points[1]),
|
||||||
|
metric(points[1], points[2]),
|
||||||
|
metric(points[2], points[3]),
|
||||||
|
metric(points[3], points[0]),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Do the split, if needed.
|
||||||
|
for i in 0..4 {
|
||||||
|
if self.must_split[i] || edge_metric[i] > MAX_EDGE_DICE as f32 {
|
||||||
|
let edge_1 = (i, (i + 1) % 4);
|
||||||
|
let edge_2 = ((i + 2) % 4, (i + 3) % 4);
|
||||||
|
let new_must_split = {
|
||||||
|
let mut new_must_split = self.must_split;
|
||||||
|
new_must_split[edge_1.0] = false;
|
||||||
|
new_must_split[edge_2.0] = false;
|
||||||
|
new_must_split
|
||||||
|
};
|
||||||
|
|
||||||
|
let midpoint_1 = lerp(self.clip[edge_1.0], self.clip[edge_1.1], 0.5);
|
||||||
|
let midpoint_2 = {
|
||||||
|
let alpha = if self.must_split[edge_2.0]
|
||||||
|
|| edge_metric[edge_2.0] > MAX_EDGE_DICE as f32
|
||||||
|
{
|
||||||
|
0.5
|
||||||
|
} else {
|
||||||
|
let edge_2_dice_rate = edge_metric[edge_2.0].ceil();
|
||||||
|
(edge_2_dice_rate * 0.5).floor() / edge_2_dice_rate
|
||||||
|
};
|
||||||
|
|
||||||
|
match point_order(points[edge_2.0], points[edge_2.1]) {
|
||||||
|
PointOrder::AsIs => lerp(self.clip[edge_2.0], self.clip[edge_2.1], alpha),
|
||||||
|
PointOrder::Flip => lerp(self.clip[edge_2.1], self.clip[edge_2.0], alpha),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build the new sub-patches
|
||||||
|
let mut patch_1 = BilinearSubPatch {
|
||||||
|
original: self.original,
|
||||||
|
clip: self.clip,
|
||||||
|
must_split: new_must_split,
|
||||||
|
};
|
||||||
|
let mut patch_2 = patch_1;
|
||||||
|
patch_1.clip[edge_1.1] = midpoint_1;
|
||||||
|
patch_1.clip[edge_2.0] = midpoint_2;
|
||||||
|
patch_2.clip[edge_1.0] = midpoint_1;
|
||||||
|
patch_2.clip[edge_2.1] = midpoint_2;
|
||||||
|
|
||||||
|
return Some((patch_1, patch_2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No splitting needed to be done.
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ use crate::{
|
||||||
shading::SurfaceShader,
|
shading::SurfaceShader,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MAX_EDGE_DICE: u32 = 128;
|
||||||
|
|
||||||
pub trait Surface: Boundable + Debug + Sync {
|
pub trait Surface: Boundable + Debug + Sync {
|
||||||
fn intersect_rays(
|
fn intersect_rays(
|
||||||
&self,
|
&self,
|
||||||
|
@ -29,7 +31,40 @@ pub trait Surface: Boundable + Debug + Sync {
|
||||||
|
|
||||||
pub trait Splitable: Copy {
|
pub trait Splitable: Copy {
|
||||||
/// Splits the surface into two pieces if necessary.
|
/// Splits the surface into two pieces if necessary.
|
||||||
fn split(&self /* TODO: splitting criteria. */) -> Option<(Self, Self)>;
|
fn split<F>(&self, metric: F) -> Option<(Self, Self)>
|
||||||
|
where
|
||||||
|
F: Fn(Point, Point) -> f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum PointOrder {
|
||||||
|
AsIs,
|
||||||
|
Flip,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn point_order(p1: Point, p2: Point) -> PointOrder {
|
||||||
|
let max_diff = {
|
||||||
|
let v = p2 - p1;
|
||||||
|
let v_abs = v.abs();
|
||||||
|
|
||||||
|
let mut diff = v.x();
|
||||||
|
let mut diff_abs = v_abs.x();
|
||||||
|
if v_abs.y() > diff_abs {
|
||||||
|
diff = v.y();
|
||||||
|
diff_abs = v_abs.y();
|
||||||
|
}
|
||||||
|
if v_abs.z() > diff_abs {
|
||||||
|
diff = v.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
diff
|
||||||
|
};
|
||||||
|
|
||||||
|
if max_diff <= 0.0 {
|
||||||
|
PointOrder::AsIs
|
||||||
|
} else {
|
||||||
|
PointOrder::Flip
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user