Probably wrong bilinear patch intersection
This commit is contained in:
parent
6d363aecd0
commit
76448ed442
2 changed files with 126 additions and 18 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::ops::{Add, Index, Sub};
|
use std::ops::{Add, Index, Mul, Sub};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Pos3 {
|
pub struct Pos3 {
|
||||||
|
|
@ -32,6 +32,14 @@ impl Pos3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_dir(self) -> Dir3 {
|
||||||
|
Dir3 {
|
||||||
|
x: self.x,
|
||||||
|
y: self.y,
|
||||||
|
z: self.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_barycentric(vertices: [Self; 3], coordinates: [Float; 3]) -> Self {
|
pub fn from_barycentric(vertices: [Self; 3], coordinates: [Float; 3]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: vertices[0].x() * coordinates[0]
|
x: vertices[0].x() * coordinates[0]
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,103 @@ pub(crate) enum ShapeType {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn quadratic(a: Float, b: Float, c: Float) -> (Option<Float>, Option<Float>) {
|
||||||
|
if a == 0.0 {
|
||||||
|
if b == 0.0 {
|
||||||
|
return (None, None);
|
||||||
|
}
|
||||||
|
return (Some(-c / b), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let discrim = b * b - 4.0 * a * c;
|
||||||
|
|
||||||
|
if discrim < 0.0 {
|
||||||
|
return (None, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let root_discrim = Float::sqrt(discrim);
|
||||||
|
|
||||||
|
let q = if b < 0.0 {
|
||||||
|
-0.5 * (b - root_discrim)
|
||||||
|
} else {
|
||||||
|
-0.5 * (b + root_discrim)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut t0 = q / a;
|
||||||
|
let mut t1 = c / q;
|
||||||
|
|
||||||
|
if t1 < t0 {
|
||||||
|
std::mem::swap(&mut t1, &mut t0);
|
||||||
|
}
|
||||||
|
|
||||||
|
(Some(t0), Some(t1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bilinear_intersection(
|
||||||
|
ray: Ray,
|
||||||
|
min: Float,
|
||||||
|
max: Float,
|
||||||
|
patch: [Pos3; 4],
|
||||||
|
) -> Option<(Float, Float, Float)> {
|
||||||
|
let a = Dir3::dot(
|
||||||
|
Dir3::cross(patch[2] - patch[0], patch[1] - patch[3]),
|
||||||
|
ray.dir(),
|
||||||
|
);
|
||||||
|
let c = Dir3::dot(
|
||||||
|
Dir3::cross(patch[0] - ray.start(), ray.dir()),
|
||||||
|
patch[1] - patch[0],
|
||||||
|
);
|
||||||
|
let b = Dir3::dot(
|
||||||
|
Dir3::cross(patch[2] - ray.start(), ray.dir()),
|
||||||
|
patch[3] - patch[2],
|
||||||
|
) - (a + c);
|
||||||
|
|
||||||
|
let (u0, u1) = quadratic(a, b, c);
|
||||||
|
|
||||||
|
[u0, u1]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.filter(|&u| {
|
||||||
|
if 0.0 <= u && u <= 1.0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.filter_map(|u| {
|
||||||
|
let uo = patch[0].as_dir() * u + patch[2].as_dir() * (1.0 - u);
|
||||||
|
let ud = patch[1].as_dir() * u + patch[3].as_dir() * (1.0 - u) - uo;
|
||||||
|
|
||||||
|
let deltao = uo - ray.start().as_dir();
|
||||||
|
|
||||||
|
let perp = Dir3::cross(ray.dir(), ud);
|
||||||
|
|
||||||
|
let p2 = perp.length_squared();
|
||||||
|
|
||||||
|
let v1 = deltao.x() * ray.dir().y()
|
||||||
|
+ perp.z()
|
||||||
|
+ ray.dir().x() * perp.y() * deltao.z()
|
||||||
|
+ perp.x() * deltao.y() * ray.dir().z()
|
||||||
|
- deltao.x() * perp.y() * deltao.z()
|
||||||
|
- ray.dir().x() * deltao.y() * perp.z()
|
||||||
|
- perp.x() * ray.dir().y() * deltao.z();
|
||||||
|
|
||||||
|
let t1 = deltao.x() * ud.y()
|
||||||
|
+ perp.z()
|
||||||
|
+ ud.x() * perp.y() * deltao.z()
|
||||||
|
+ perp.x() * deltao.y() * ud.z()
|
||||||
|
- deltao.x() * perp.y() * deltao.z()
|
||||||
|
- ud.x() * deltao.y() * perp.z()
|
||||||
|
- perp.x() * ud.y() * deltao.z();
|
||||||
|
|
||||||
|
if t1 > 0.0 && 0.0 < v1 && v1 <= p2 {
|
||||||
|
Some((t1 / p2, u, v1 / p2))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
impl Shape {
|
impl Shape {
|
||||||
pub(crate) fn intersect<R: Rng>(
|
pub(crate) fn intersect<R: Rng>(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -100,23 +197,19 @@ impl Shape {
|
||||||
std::mem::swap(&mut t1, &mut t0);
|
std::mem::swap(&mut t1, &mut t0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(t) = [t0, t1]
|
if let Some(t) = [t0, t1].into_iter().find(|&t| {
|
||||||
.into_iter()
|
if min <= t && t <= max {
|
||||||
.filter(|&t| {
|
let p = ray.at(t0);
|
||||||
if min <= t && t <= max {
|
let mut phi = Float::atan2(p.y(), p.x());
|
||||||
let p = ray.at(t0);
|
if phi < 0.0 {
|
||||||
let mut phi = Float::atan2(p.y(), p.x());
|
phi += 2.0 * FloatConsts::PI;
|
||||||
if phi < 0.0 {
|
|
||||||
phi += 2.0 * FloatConsts::PI;
|
|
||||||
}
|
|
||||||
if zmin <= p.z() && p.z() <= zmax && phi <= phimax {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
false
|
if zmin <= p.z() && p.z() <= zmax && phi <= phimax {
|
||||||
})
|
return true;
|
||||||
.next()
|
}
|
||||||
{
|
}
|
||||||
|
false
|
||||||
|
}) {
|
||||||
return Some(Intersection::new(
|
return Some(Intersection::new(
|
||||||
t,
|
t,
|
||||||
(ray.at(t) - Pos3::zero()).normalize(),
|
(ray.at(t) - Pos3::zero()).normalize(),
|
||||||
|
|
@ -134,7 +227,14 @@ impl Shape {
|
||||||
s,
|
s,
|
||||||
uv,
|
uv,
|
||||||
} => (),
|
} => (),
|
||||||
ShapeType::BilinearMesh { indices, p, n, uv } => (),
|
ShapeType::BilinearMesh { indices, p, n, uv } => {
|
||||||
|
if indices.is_empty()
|
||||||
|
&& let Some((t, _u, _v)) =
|
||||||
|
bilinear_intersection(ray, min, max, [p[0], p[1], p[2], p[3]])
|
||||||
|
{
|
||||||
|
return Some(Intersection::new(t, Dir3::up(), None, None, 0.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
ShapeType::LoopSubDiv { levels, indices, p } => todo!(),
|
ShapeType::LoopSubDiv { levels, indices, p } => todo!(),
|
||||||
ShapeType::Disk {
|
ShapeType::Disk {
|
||||||
height,
|
height,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue