From 7c8d67c909e4951550e695fe40508dd197cb0376 Mon Sep 17 00:00:00 2001 From: numzero Date: Sun, 8 Dec 2024 02:44:24 +0300 Subject: [PATCH] Texture? --- models/spacecraft2-shape.png | Bin 0 -> 39173 bytes models/spacecraft2.obj | 111 ++++++++++++++----------- src/bin/textured/main.rs | 153 +++++++++++++++++++++++++++++++++++ src/mesh_loader.rs | 6 +- src/mesh_tracer.rs | 5 +- 5 files changed, 225 insertions(+), 50 deletions(-) create mode 100644 models/spacecraft2-shape.png create mode 100644 src/bin/textured/main.rs diff --git a/models/spacecraft2-shape.png b/models/spacecraft2-shape.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c9965a65bfb69134e86a8b6940b10d2fa90624 GIT binary patch literal 39173 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 IuVn`QKZRXe0{{R3 literal 0 HcmV?d00001 diff --git a/models/spacecraft2.obj b/models/spacecraft2.obj index cd571ee..6a7c9cc 100644 --- a/models/spacecraft2.obj +++ b/models/spacecraft2.obj @@ -1,6 +1,5 @@ # Blender 3.6.5 # www.blender.org -mtllib spacecraft2.mtl o Cube v -1.000000 0.000000 3.000000 v -2.000000 0.000000 2.000000 @@ -60,50 +59,68 @@ vn 0.3487 -0.9300 -0.1162 vn -0.4444 -0.8889 -0.1111 vn -0.3015 -0.9045 0.3015 vn 0.2182 -0.4364 0.8729 -vt 0.000000 0.000000 +vt 0.342147 0.420195 +vt 0.509380 0.482116 +vt 0.342147 0.586861 +vt 0.513220 0.668431 +vt 0.680454 0.813685 +vt 0.000000 0.840390 +vt 0.684294 1.000000 +vt 0.855367 0.914903 +vt 0.855367 0.748236 +vt 0.684294 0.666667 +vt 0.594917 0.481234 +vt 0.680454 0.147018 +vt 0.769831 0.415785 +vt 0.769830 0.582451 +vt 0.513220 0.335097 +vt 0.000000 0.173723 +vt 0.684294 0.000000 +vt 0.855367 0.248236 +vt 0.855367 0.081569 +vt 0.684294 0.333333 s 0 -usemtl Material -f 8/1/1 18/1/1 16/1/1 -f 16/1/2 18/1/2 15/1/2 -f 18/1/3 19/1/3 15/1/3 -f 15/1/4 19/1/4 14/1/4 -f 14/1/5 19/1/5 13/1/5 -f 13/1/6 19/1/6 12/1/6 -f 12/1/7 19/1/7 11/1/7 -f 10/1/8 11/1/8 19/1/8 -f 20/1/9 18/1/9 17/1/9 -f 1/1/7 9/1/7 20/1/7 -f 9/1/10 10/1/10 20/1/10 -f 20/1/11 10/1/11 19/1/11 -f 6/1/12 18/1/12 8/1/12 -f 18/1/13 6/1/13 17/1/13 -f 6/1/14 7/1/14 17/1/14 -f 5/1/15 17/1/15 7/1/15 -f 3/1/7 17/1/7 4/1/7 -f 4/1/8 17/1/8 5/1/8 -f 2/1/6 17/1/6 3/1/6 -f 1/1/16 20/1/16 2/1/16 -f 17/1/17 2/1/17 20/1/17 -f 20/1/9 19/1/9 18/1/9 -f 8/1/18 16/1/18 22/1/18 -f 16/1/19 15/1/19 22/1/19 -f 22/1/20 15/1/20 23/1/20 -f 15/1/21 14/1/21 23/1/21 -f 14/1/22 13/1/22 23/1/22 -f 13/1/23 12/1/23 23/1/23 -f 12/1/24 11/1/24 23/1/24 -f 10/1/25 23/1/25 11/1/25 -f 24/1/26 21/1/26 22/1/26 -f 1/1/24 24/1/24 9/1/24 -f 9/1/27 24/1/27 10/1/27 -f 24/1/28 23/1/28 10/1/28 -f 6/1/29 8/1/29 22/1/29 -f 22/1/30 21/1/30 6/1/30 -f 6/1/31 21/1/31 7/1/31 -f 5/1/32 7/1/32 21/1/32 -f 3/1/24 4/1/24 21/1/24 -f 4/1/25 5/1/25 21/1/25 -f 2/1/23 3/1/23 21/1/23 -f 1/1/33 2/1/33 24/1/33 -f 21/1/34 24/1/34 2/1/34 -f 24/1/26 22/1/26 23/1/26 +f 8/1/1 18/2/1 16/3/1 +f 16/3/2 18/2/2 15/4/2 +f 18/2/3 19/5/3 15/4/3 +f 15/4/4 19/5/4 14/6/4 +f 14/6/5 19/5/5 13/7/5 +f 13/7/6 19/5/6 12/8/6 +f 12/8/7 19/5/7 11/9/7 +f 10/10/8 11/9/8 19/5/8 +f 20/11/9 18/2/9 17/12/9 +f 1/13/7 9/14/7 20/11/7 +f 9/14/10 10/10/10 20/11/10 +f 20/11/11 10/10/11 19/5/11 +f 6/15/12 18/2/12 8/1/12 +f 18/2/13 6/15/13 17/12/13 +f 6/15/14 7/16/14 17/12/14 +f 5/17/15 17/12/15 7/16/15 +f 3/18/7 17/12/7 4/19/7 +f 4/19/8 17/12/8 5/17/8 +f 2/20/6 17/12/6 3/18/6 +f 1/13/16 20/11/16 2/20/16 +f 17/12/17 2/20/17 20/11/17 +f 20/11/9 19/5/9 18/2/9 +f 8/1/18 16/3/18 22/2/18 +f 16/3/19 15/4/19 22/2/19 +f 22/2/20 15/4/20 23/5/20 +f 15/4/21 14/6/21 23/5/21 +f 14/6/22 13/7/22 23/5/22 +f 13/7/23 12/8/23 23/5/23 +f 12/8/24 11/9/24 23/5/24 +f 10/10/25 23/5/25 11/9/25 +f 24/11/26 21/12/26 22/2/26 +f 1/13/24 24/11/24 9/14/24 +f 9/14/27 24/11/27 10/10/27 +f 24/11/28 23/5/28 10/10/28 +f 6/15/29 8/1/29 22/2/29 +f 22/2/30 21/12/30 6/15/30 +f 6/15/31 21/12/31 7/16/31 +f 5/17/32 7/16/32 21/12/32 +f 3/18/24 4/19/24 21/12/24 +f 4/19/25 5/17/25 21/12/25 +f 2/20/23 3/18/23 21/12/23 +f 1/13/33 2/20/33 24/11/33 +f 21/12/34 24/11/34 2/20/34 +f 24/11/26 22/2/26 23/5/26 diff --git a/src/bin/textured/main.rs b/src/bin/textured/main.rs new file mode 100644 index 0000000..b9e19c2 --- /dev/null +++ b/src/bin/textured/main.rs @@ -0,0 +1,153 @@ +use glam::*; +use refraction::mesh_loader::load_mesh; +use refraction::mesh_tracer::{trace_to_mesh, Mesh}; +use show_image::event::{ElementState, VirtualKeyCode, WindowEvent}; +use show_image::{exit, ImageInfo, ImageView, WindowOptions}; +use std::env; +use std::error::Error; +use std::f32::consts::PI; +use std::fs::File; +use std::io::BufReader; +use std::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + +const W: i32 = 320; +const H: i32 = 240; + +#[derive(Copy, Clone)] +struct Color(u8, u8, u8); + +struct Image { + w: i32, + h: i32, + data: Vec, +} + +impl Image { + fn data(&self) -> &[u8] { + self.data.as_slice() + } + + fn put_pixel(&mut self, x: i32, y: i32, color: Color) { + if x < 0 || x >= self.w || y < 0 || y > self.h { + return; + } + let index = 3 * (x + self.w * y) as usize; + self.data[index] = color.0; + self.data[index + 1] = color.1; + self.data[index + 2] = color.2; + } +} + +fn ypr_to_mat(ypr: Vec3) -> Mat3 { + let Vec3 { + x: yaw, + y: pitch, + z: roll, + } = ypr; + let m_roll = mat3( + vec3(roll.cos(), roll.sin(), 0.0), + vec3(-roll.sin(), roll.cos(), 0.0), + vec3(0.0, 0.0, 1.0), + ); + let m_yaw = mat3( + vec3(yaw.cos(), 0.0, yaw.sin()), + vec3(0.0, 1.0, 0.0), + vec3(-yaw.sin(), 0.0, yaw.cos()), + ); + let m_pitch = mat3( + vec3(1.0, 0.0, 0.0), + vec3(0.0, pitch.cos(), -pitch.sin()), + vec3(0.0, pitch.sin(), pitch.cos()), + ); + m_roll * m_pitch * m_yaw +} + +fn render(mesh: &Mesh, camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { + let bkg = vec3(0.0, 0.0, 0.0); + let mut img = Image { + w: W, + h: H, + data: vec![0; (3 * W * H) as usize], + }; + let img_size = vec2(W as f32, H as f32); + for y in 0..H { + for x in 0..W { + let img_coords = vec2(x as f32, y as f32); + let off = (img_coords - img_size * 0.5) / img_size.y; + 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.) + } else { + bkg + }; + let color = (color * 255.0).as_ivec3().clamp(IVec3::splat(0), IVec3::splat(255)); + img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); + } + } + img +} + +fn persp(dist: f32, off: Vec2) -> (Vec3, Vec3) { + (vec3(0., 0., -dist), vec3(off.x, off.y, dist)) +} + +fn ortho(dist: f32, off: Vec2) -> (Vec3, Vec3) { + (vec3(off.x, off.y, -dist), vec3(0., 0., 1.)) +} + +#[test] +fn test_projs() { + fn check(f: fn(dist: f32, off: Vec2) -> (Vec3, Vec3), x: f32, y: f32, z: f32) { + let (base, ray) = f(z, vec2(x, y)); + let at_dist = base + ray * (z / ray.z); + assert_eq!(at_dist, vec3(x, y, 0.)); + } + check(persp, 1., 2., 3.); + check(ortho, 1., 2., 3.); + check(persp, 5., 3., 7.); + check(ortho, 9., 1., 8.); +} + +// add_event_handler wants 'static + Send. Let it be so. +static PROJ_INDEX: AtomicUsize = AtomicUsize::new(0); +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]); + exit(1); + } + let mesh = { + let f = File::open(&args[1])?; + let mut f = BufReader::new(f); + load_mesh(&mut f)? + }; + let window = show_image::create_window("Raytracing", WindowOptions::default())?; + window.add_event_handler(|_wnd, ev, _ctl| { + if let WindowEvent::KeyboardInput(ev) = ev { + if ev.input.state != ElementState::Pressed { + return; + } + if let Some(VirtualKeyCode::Tab) = ev.input.key_code { + PROJ_INDEX.store((PROJ_INDEX.load(Relaxed) + 1) % PROJS.len(), Relaxed); + } + } + })?; + loop { + for phi in 0..360 { + 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 (base, ray) = proj(40., 20. * off); + (m_camera * base, m_camera * ray) + }); + + let image = ImageView::new(ImageInfo::rgb8(W as u32, H as u32), img.data()); + window.set_image("image", image)?; + } + } +} diff --git a/src/mesh_loader.rs b/src/mesh_loader.rs index 16d1f84..6d121a9 100644 --- a/src/mesh_loader.rs +++ b/src/mesh_loader.rs @@ -5,7 +5,7 @@ use std::io; struct ObjVertex { vertex: usize, normal: usize, - // tex_coord: usize, + tex_coord: usize, } #[derive(Copy, Clone, Debug)] @@ -39,7 +39,7 @@ impl ObjMesh { assert_eq!(tokens.len(), 3); ObjVertex { vertex: tokens[0], - // tex_coord: tokens[1], + tex_coord: tokens[1], normal: tokens[2], } } @@ -80,6 +80,7 @@ impl ObjMesh { .iter() .map(|face| Face { vertices: face.vertices.map(|iv| self.vertices[iv.vertex]), + tex_coords: face.vertices.map(|iv| self.tex_coords[iv.tex_coord]), normal: self.normals[face.vertices[0].normal], }) .collect() @@ -89,6 +90,7 @@ impl ObjMesh { #[derive(Copy, Clone, Debug)] pub struct Face { pub vertices: [Vec3; 3], + pub tex_coords: [Vec2; 3], pub normal: Vec3, } diff --git a/src/mesh_tracer.rs b/src/mesh_tracer.rs index 047cbef..753c751 100644 --- a/src/mesh_tracer.rs +++ b/src/mesh_tracer.rs @@ -1,10 +1,11 @@ use crate::mesh_loader::Face; -use glam::{mat3, Vec3}; +use glam::{mat3, vec3, Vec2, Vec3}; pub type Mesh = [Face]; pub struct TraceResult { pub distance: f32, + pub tex_coords: Vec2, pub normal: Vec3, } @@ -17,8 +18,10 @@ pub fn trace_to_mesh_all(mesh: &Mesh, base: Vec3, ray: Vec3) -> impl Iterator