Fix bugs for pbrt bilinear patch

This commit is contained in:
hal8174 2025-08-27 19:06:47 +02:00
parent bb2089477e
commit 0480e041cd
Signed by: hal8174
SSH key fingerprint: SHA256:NN98ZYwnrreQLSOV/g+amY7C3yL/mS1heD7bi5t6PPw
6 changed files with 85 additions and 33 deletions

View file

@ -224,6 +224,23 @@ impl AffineTransform {
+ self.mat[2][3], + self.mat[2][3],
) )
} }
pub fn inverse_transform_pos(&self, pos: Pos3) -> Pos3 {
Pos3::new(
self.inv[0][0] * pos.x()
+ self.inv[0][1] * pos.y()
+ self.inv[0][2] * pos.z()
+ self.inv[0][3],
self.inv[1][0] * pos.x()
+ self.inv[1][1] * pos.y()
+ self.inv[1][2] * pos.z()
+ self.inv[1][3],
self.inv[2][0] * pos.x()
+ self.inv[2][1] * pos.y()
+ self.inv[2][2] * pos.z()
+ self.inv[2][3],
)
}
pub fn transform_dir(&self, dir: Dir3) -> Dir3 { pub fn transform_dir(&self, dir: Dir3) -> Dir3 {
Dir3::new( Dir3::new(
self.mat[0][0] * dir.x() + self.mat[0][1] * dir.y() + self.mat[0][2] * dir.z(), self.mat[0][0] * dir.x() + self.mat[0][1] * dir.y() + self.mat[0][2] * dir.z(),
@ -231,13 +248,27 @@ impl AffineTransform {
self.mat[2][0] * dir.x() + self.mat[2][1] * dir.y() + self.mat[2][2] * dir.z(), self.mat[2][0] * dir.x() + self.mat[2][1] * dir.y() + self.mat[2][2] * dir.z(),
) )
} }
pub fn transform_normal(&self, pos: Pos3) -> Pos3 { pub fn inverse_transform_dir(&self, dir: Dir3) -> Dir3 {
Pos3::new( Dir3::new(
self.inv[0][0] * dir.x() + self.inv[0][1] * dir.y() + self.inv[0][2] * dir.z(),
self.inv[1][0] * dir.x() + self.inv[1][1] * dir.y() + self.inv[1][2] * dir.z(),
self.inv[2][0] * dir.x() + self.inv[2][1] * dir.y() + self.inv[2][2] * dir.z(),
)
}
pub fn transform_normal(&self, pos: Dir3) -> Dir3 {
Dir3::new(
self.inv[0][0] * pos.x() + self.inv[0][1] * pos.y() + self.inv[0][2] * pos.z(), self.inv[0][0] * pos.x() + self.inv[0][1] * pos.y() + self.inv[0][2] * pos.z(),
self.inv[1][0] * pos.x() + self.inv[1][1] * pos.y() + self.inv[1][2] * pos.z(), self.inv[1][0] * pos.x() + self.inv[1][1] * pos.y() + self.inv[1][2] * pos.z(),
self.inv[2][0] * pos.x() + self.inv[2][1] * pos.y() + self.inv[2][2] * pos.z(), self.inv[2][0] * pos.x() + self.inv[2][1] * pos.y() + self.inv[2][2] * pos.z(),
) )
} }
pub fn inverse_transform_normal(&self, pos: Dir3) -> Dir3 {
Dir3::new(
self.mat[0][0] * pos.x() + self.mat[0][1] * pos.y() + self.mat[0][2] * pos.z(),
self.mat[1][0] * pos.x() + self.mat[1][1] * pos.y() + self.mat[1][2] * pos.z(),
self.mat[2][0] * pos.x() + self.mat[2][1] * pos.y() + self.mat[2][2] * pos.z(),
)
}
pub fn transform_ray(&self, ray: Ray) -> Ray { pub fn transform_ray(&self, ray: Ray) -> Ray {
Ray::new( Ray::new(
@ -302,7 +333,7 @@ impl Mul<AffineTransform> for AffineTransform {
self.mat[2][0] * rhs.mat[0][2] self.mat[2][0] * rhs.mat[0][2]
+ self.mat[2][1] * rhs.mat[1][2] + self.mat[2][1] * rhs.mat[1][2]
+ self.mat[2][2] * rhs.mat[2][2] + self.mat[2][2] * rhs.mat[2][2]
+ self.mat[2][3] * rhs.mat[3][3], + self.mat[2][3] * rhs.mat[3][2],
self.mat[2][0] * rhs.mat[0][3] self.mat[2][0] * rhs.mat[0][3]
+ self.mat[2][1] * rhs.mat[1][3] + self.mat[2][1] * rhs.mat[1][3]
+ self.mat[2][2] * rhs.mat[2][3] + self.mat[2][2] * rhs.mat[2][3]
@ -376,7 +407,7 @@ impl Mul<AffineTransform> for AffineTransform {
rhs.inv[2][0] * self.inv[0][2] rhs.inv[2][0] * self.inv[0][2]
+ rhs.inv[2][1] * self.inv[1][2] + rhs.inv[2][1] * self.inv[1][2]
+ rhs.inv[2][2] * self.inv[2][2] + rhs.inv[2][2] * self.inv[2][2]
+ rhs.inv[2][3] * self.inv[3][3], + rhs.inv[2][3] * self.inv[3][2],
rhs.inv[2][0] * self.inv[0][3] rhs.inv[2][0] * self.inv[0][3]
+ rhs.inv[2][1] * self.inv[1][3] + rhs.inv[2][1] * self.inv[1][3]
+ rhs.inv[2][2] * self.inv[2][3] + rhs.inv[2][2] * self.inv[2][3]

View file

@ -483,7 +483,11 @@ fn parse_transform(input: &mut Tokenizer) -> Result<AffineTransform> {
} }
fn parse_translate<R>(iter: &mut Tokenizer) -> Result<Statement<R>> { fn parse_translate<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
let pos = Pos3::new(iter.parse_next()?, iter.parse_next()?, iter.parse_next()?); let pos = Pos3::new(
-iter.parse_next()?,
-iter.parse_next()?,
-iter.parse_next()?,
);
Ok(Statement::ConcatTransform(AffineTransform::translation( Ok(Statement::ConcatTransform(AffineTransform::translation(
pos, pos,
@ -592,7 +596,7 @@ impl<R: Rng> Pbrt<R> {
scene: PbrtScene { scene: PbrtScene {
shapes: Vec::new(), shapes: Vec::new(),
infinite_light: Some(scene::PbrtInfiniteLight { infinite_light: Some(scene::PbrtInfiniteLight {
color: Color::white(), color: Color::new(0.4, 0.45, 0.5),
}), }),
}, },
} }

View file

@ -98,6 +98,34 @@ impl<R: Rng> PbrtMaterial<R> for PbrtDielectricMaterial {
let _ = u; let _ = u;
Color::black() Color::black()
} }
fn sample(&self, u: Float, v: Float, w_in: Dir3, rng: &mut R) -> SampleResult {
let _ = rng;
let _ = v;
let _ = u;
let _ = match self.eta {
Either::A(Either::A(eta)) => eta,
_ => todo!(),
};
// let c = w_in.y();
// let w_out = -w_in * eta
// + (eta * c - Float::sqrt(1.0 - eta * eta * (1.0 - c * c))) * Dir3::new(0.0, -1.0, 1.0);
SampleResult::new(
Dir3::new(0.0, 2.0 * w_in.y(), 0.0) - w_in,
Color::white(),
true,
)
}
fn pdf(&self, u: Float, v: Float, w_in: Dir3, w_out: Dir3) -> Float {
let _ = w_in;
let _ = v;
let _ = u;
let _ = w_out;
0.0
}
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -77,11 +77,7 @@ fn quadratic(a: Float, b: Float, c: Float) -> (Option<Float>, Option<Float>) {
let root_discrim = Float::sqrt(discrim); let root_discrim = Float::sqrt(discrim);
let q = if b < 0.0 { let q = -0.5 * (b + Float::copysign(root_discrim, b));
-0.5 * (b - root_discrim)
} else {
-0.5 * (b + root_discrim)
};
let mut t0 = q / a; let mut t0 = q / a;
let mut t1 = c / q; let mut t1 = c / q;
@ -124,8 +120,10 @@ fn bilinear_intersection(
false false
}) })
.filter_map(|u| { .filter_map(|u| {
let uo = patch[0].as_dir() * u + patch[2].as_dir() * (1.0 - u); // dbg!(a, b, c, u, a * u * u + b * u + c);
let ud = patch[1].as_dir() * u + patch[3].as_dir() * (1.0 - u) - uo;
let uo = patch[0].as_dir() * (1.0 - u) + patch[2].as_dir() * u;
let ud = patch[1].as_dir() * (1.0 - u) + patch[3].as_dir() * u - uo;
let deltao = uo - ray.start().as_dir(); let deltao = uo - ray.start().as_dir();
@ -133,23 +131,22 @@ fn bilinear_intersection(
let p2 = perp.length_squared(); let p2 = perp.length_squared();
let v1 = deltao.x() * ray.dir().y() let v1 = deltao.x() * ray.dir().y() * perp.z()
+ perp.z()
+ ray.dir().x() * perp.y() * deltao.z() + ray.dir().x() * perp.y() * deltao.z()
+ perp.x() * deltao.y() * ray.dir().z() + perp.x() * deltao.y() * ray.dir().z()
- deltao.x() * perp.y() * deltao.z() - deltao.x() * perp.y() * ray.dir().z()
- ray.dir().x() * deltao.y() * perp.z() - ray.dir().x() * deltao.y() * perp.z()
- perp.x() * ray.dir().y() * deltao.z(); - perp.x() * ray.dir().y() * deltao.z();
let t1 = deltao.x() * ud.y() let t1 = deltao.x() * ud.y() * perp.z()
+ perp.z()
+ ud.x() * perp.y() * deltao.z() + ud.x() * perp.y() * deltao.z()
+ perp.x() * deltao.y() * ud.z() + perp.x() * deltao.y() * ud.z()
- deltao.x() * perp.y() * deltao.z() - deltao.x() * perp.y() * ud.z()
- ud.x() * deltao.y() * perp.z() - ud.x() * deltao.y() * perp.z()
- perp.x() * ud.y() * deltao.z(); - perp.x() * ud.y() * deltao.z();
if t1 >= min && t1 <= max && 0.0 < v1 && v1 <= p2 { // dbg!(t1 / p2, v1 / p2);
if min * p2 <= t1 && t1 <= max * p2 && 0.0 <= v1 && v1 <= p2 {
Some((t1 / p2, u, v1 / p2)) Some((t1 / p2, u, v1 / p2))
} else { } else {
None None
@ -220,7 +217,8 @@ impl<R: Rng + std::fmt::Debug> Shape<R> {
} }
return Some(Intersection::new( return Some(Intersection::new(
t, t,
(ray.at(t) - Pos3::zero()).normalize(), self.ctm
.inverse_transform_normal((ray.at(t).as_dir()).normalize()),
Some(UVMaterial { Some(UVMaterial {
u: phi, u: phi,
v: Float::acos(p.z() / radius), v: Float::acos(p.z() / radius),
@ -245,7 +243,7 @@ impl<R: Rng + std::fmt::Debug> Shape<R> {
{ {
return Some(Intersection::new( return Some(Intersection::new(
t, t,
Dir3::up(), Dir3::new(0.0, 0.0, 1.0),
Some(UVMaterial { Some(UVMaterial {
u, u,
v, v,

View file

@ -49,16 +49,7 @@ pub(super) struct SpectrumCheckerboardTexture2d {
impl Pbrt2dSpectrumTexture for SpectrumCheckerboardTexture2d { impl Pbrt2dSpectrumTexture for SpectrumCheckerboardTexture2d {
fn get(&self, u: Float, v: Float) -> Color { fn get(&self, u: Float, v: Float) -> Color {
let (u, v) = self.mapping.map(u, v); let (u, v) = self.mapping.map(u, v);
let even = (u.floor() as i64 + v.floor() as i64) % 2 == 0;
let even = if u >= 0.0 {
u.fract() >= 0.5
} else {
u.fract() >= -0.5
} ^ if v >= 0.0 {
v.fract() >= 0.5
} else {
v.fract() >= -0.5
};
match &self.tex[even as usize] { match &self.tex[even as usize] {
Either::A(v) => *v, Either::A(v) => *v,

View file

@ -230,7 +230,7 @@ fn main() {
Pos3::new(3.0, 4.0, 1.5), Pos3::new(3.0, 4.0, 1.5),
Pos3::new(0.5, 0.5, 0.0), Pos3::new(0.5, 0.5, 0.0),
Dir3::new(0.0, 0.0, 1.0), Dir3::new(0.0, 0.0, 1.0),
Float::to_radians(45.0), Float::to_radians(90.0),
); );
let s = &pbrt.scene; let s = &pbrt.scene;