diff --git a/Cargo.lock b/Cargo.lock index 0950020..35bbdd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3049,6 +3049,7 @@ dependencies = [ "flo_canvas", "flo_draw", "glam 0.27.0", + "image", "itertools 0.13.0", "itertools-num", "pollster", diff --git a/Cargo.toml b/Cargo.toml index 813c97a..7e4991a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ itertools = "0.13.0" wgpu = "22.1.0" bytemuck = { version = "1.18.0", features = ["derive"] } pollster = "0.3.0" +image = {version = "0.23", default-features = false, features = ["png"] } [dev-dependencies] approx = "0.5.1" diff --git a/models/spacecraft2.png b/models/spacecraft2.png new file mode 100644 index 0000000..320a7e6 Binary files /dev/null and b/models/spacecraft2.png differ diff --git a/src/bin/textured/main.rs b/src/bin/textured/main.rs index b9e19c2..331fb1c 100644 --- a/src/bin/textured/main.rs +++ b/src/bin/textured/main.rs @@ -1,4 +1,5 @@ use glam::*; +use image::RgbImage; use refraction::mesh_loader::load_mesh; use refraction::mesh_tracer::{trace_to_mesh, Mesh}; use show_image::event::{ElementState, VirtualKeyCode, WindowEvent}; @@ -62,7 +63,7 @@ fn ypr_to_mat(ypr: Vec3) -> Mat3 { m_roll * m_pitch * m_yaw } -fn render(mesh: &Mesh, camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { +fn render(mesh: &Mesh, texture: &RgbImage, camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { let bkg = vec3(0.0, 0.0, 0.0); let mut img = Image { w: W, @@ -77,7 +78,9 @@ fn render(mesh: &Mesh, camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { let (base, ray) = camera(off); let color = if let Some(r) = trace_to_mesh(mesh, base, ray.normalize()) { // to_vec3(0.45) * dot(r.normal, normalize(vec3(-1.0, 1.0, -1.0))) + 0.50 - vec3(r.tex_coords.x, r.tex_coords.y, 0.) + let x = (r.tex_coords.x * texture.width() as f32) as u32; + let y = (r.tex_coords.y * texture.height() as f32) as u32; + texture.get_pixel(x, y).0.map(|channel| channel as f32 / 255.).into() } else { bkg }; @@ -116,8 +119,8 @@ static PROJS: [fn(dist: f32, off: Vec2) -> (Vec3, Vec3); 2] = [persp, ortho]; #[show_image::main] fn main() -> Result<(), Box> { let args: Vec = env::args().collect(); - if args.len() != 2 { - println!("Usage: {} path/to/model.obj", args[0]); + if args.len() != 3 { + println!("Usage: {} path/to/model.obj path/to/texture.png", args[0]); exit(1); } let mesh = { @@ -125,6 +128,7 @@ fn main() -> Result<(), Box> { let mut f = BufReader::new(f); load_mesh(&mut f)? }; + let texture = image::io::Reader::open(&args[2])?.decode()?.into_rgb8(); let window = show_image::create_window("Raytracing", WindowOptions::default())?; window.add_event_handler(|_wnd, ev, _ctl| { if let WindowEvent::KeyboardInput(ev) = ev { @@ -141,7 +145,7 @@ fn main() -> Result<(), Box> { let proj = PROJS[PROJ_INDEX.load(Relaxed)]; let m_view = ypr_to_mat(vec3((135.0 + phi as f32) * PI / 180.0, -30.0 * PI / 180.0, 0.0f32)); let m_camera = m_view.transpose(); - let img = render(mesh.as_slice(), |off| { + let img = render(mesh.as_slice(), &texture, |off| { let (base, ray) = proj(40., 20. * off); (m_camera * base, m_camera * ray) });