From a0046b6f33b8fc4f5b2b95bf8d8f8bbeb5a17b0e Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 23 Mar 2024 21:15:33 +0300 Subject: [PATCH 01/25] Works... almost --- .gitignore | 1 + Cargo.toml | 10 +++ spacecraft2.1.obj | 140 +++++++++++++++++++++++++++++ spacecraft2.2.obj | 77 ++++++++++++++++ spacecraft2.obj | 107 ++++++++++++++++++++++ src/main.rs | 220 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 555 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 spacecraft2.1.obj create mode 100644 spacecraft2.2.obj create mode 100644 spacecraft2.obj create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e2a2e19 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" +glm = "0.2.3" diff --git a/spacecraft2.1.obj b/spacecraft2.1.obj new file mode 100644 index 0000000..11dcbf2 --- /dev/null +++ b/spacecraft2.1.obj @@ -0,0 +1,140 @@ +# Blender 3.6.5 +# www.blender.org +mtllib spacecraft2.1.mtl +o Cube +v -1.000000 0.000000 5.000000 +v -3.000000 0.000000 4.000000 +v -4.000000 0.000000 7.000000 +v -8.000000 0.000000 7.000000 +v -9.000000 0.000000 4.000000 +v -3.000000 0.000000 0.000000 +v -6.000000 0.000000 -7.000000 +v -2.000000 0.000000 -3.000000 +v -7.000000 1.000000 4.000000 +v 0.000000 2.000000 0.000000 +v 0.000000 2.000000 2.000000 +v 0.000000 0.000000 6.000000 +v 0.000000 0.000000 -4.000000 +v -5.000000 0.000000 2.000000 +v 1.000000 0.000000 5.000000 +v 3.000000 0.000000 4.000000 +v 4.000000 0.000000 7.000000 +v 8.000000 0.000000 7.000000 +v 9.000000 0.000000 4.000000 +v 3.000000 0.000000 0.000000 +v 6.000000 0.000000 -7.000000 +v 2.000000 0.000000 -3.000000 +v 7.000000 1.000000 4.000000 +v 5.000000 0.000000 2.000000 +v -7.000000 -1.000000 4.000000 +v 0.000000 -2.000000 0.000000 +v 0.000000 -2.000000 2.000000 +v 7.000000 -1.000000 4.000000 +vn -0.5455 0.8182 -0.1818 +vn -0.4851 0.4851 -0.7276 +vn -0.4439 0.8878 -0.1211 +vn -0.0000 0.9487 0.3162 +vn -0.4423 0.8847 0.1474 +vn 0.2417 0.9670 0.0806 +vn 0.2408 -0.8427 -0.4815 +vn 0.1455 0.5819 0.8001 +vn -0.1414 0.9899 -0.0000 +vn -0.2182 0.8729 -0.4364 +vn 0.4082 -0.8165 -0.4082 +vn -0.4851 0.7276 -0.4851 +vn 0.4099 0.9110 -0.0455 +vn -0.0000 -1.0000 -0.0000 +vn 0.5455 0.8182 -0.1818 +vn 0.4851 0.4851 -0.7276 +vn 0.4439 0.8878 -0.1211 +vn 0.4423 0.8847 0.1474 +vn -0.2417 0.9670 0.0806 +vn -0.2408 -0.8427 -0.4815 +vn -0.1455 0.5819 0.8001 +vn 0.1414 0.9899 -0.0000 +vn 0.2182 0.8729 -0.4364 +vn -0.4082 -0.8165 -0.4082 +vn 0.4851 0.7276 -0.4851 +vn -0.4099 0.9110 -0.0455 +vn -0.5455 -0.8182 -0.1818 +vn -0.4851 -0.4851 -0.7276 +vn -0.4439 -0.8878 -0.1211 +vn -0.0000 -0.9487 0.3162 +vn -0.4423 -0.8847 0.1474 +vn 0.2417 -0.9670 0.0806 +vn 0.2408 0.8427 -0.4815 +vn 0.1455 -0.5819 0.8001 +vn -0.1414 -0.9899 -0.0000 +vn -0.2182 -0.8729 -0.4364 +vn 0.4082 0.8165 -0.4082 +vn -0.4851 -0.7276 -0.4851 +vn 0.4099 -0.9110 -0.0455 +vn 0.5455 -0.8182 -0.1818 +vn 0.4851 -0.4851 -0.7276 +vn 0.4439 -0.8878 -0.1211 +vn 0.4423 -0.8847 0.1474 +vn -0.2417 -0.9670 0.0806 +vn -0.2408 0.8427 -0.4815 +vn -0.1455 -0.5819 0.8001 +vn 0.1414 -0.9899 -0.0000 +vn 0.2182 -0.8729 -0.4364 +vn -0.4082 0.8165 -0.4082 +vn 0.4851 -0.7276 -0.4851 +vn -0.4099 -0.9110 -0.0455 +vt 0.000000 0.000000 +s 0 +usemtl Material +f 6/1/1 10/1/1 8/1/1 +f 10/1/2 14/1/2 9/1/2 +f 5/1/3 9/1/3 7/1/3 +f 3/1/4 9/1/4 4/1/4 +f 4/1/5 9/1/5 5/1/5 +f 2/1/6 9/1/6 3/1/6 +f 1/1/7 2/1/7 11/1/7 +f 9/1/8 2/1/8 11/1/8 +f 9/1/9 11/1/9 10/1/9 +f 8/1/10 10/1/10 13/1/10 +f 1/1/11 11/1/11 12/1/11 +f 10/1/12 6/1/12 14/1/12 +f 7/1/13 9/1/13 14/1/13 +f 7/1/14 14/1/14 5/1/14 +f 20/1/15 22/1/15 10/1/15 +f 10/1/16 23/1/16 24/1/16 +f 19/1/17 21/1/17 23/1/17 +f 17/1/4 18/1/4 23/1/4 +f 18/1/18 19/1/18 23/1/18 +f 16/1/19 17/1/19 23/1/19 +f 15/1/20 11/1/20 16/1/20 +f 23/1/21 11/1/21 16/1/21 +f 23/1/22 10/1/22 11/1/22 +f 22/1/23 13/1/23 10/1/23 +f 15/1/24 12/1/24 11/1/24 +f 10/1/25 24/1/25 20/1/25 +f 21/1/26 24/1/26 23/1/26 +f 21/1/14 19/1/14 24/1/14 +f 6/1/27 8/1/27 26/1/27 +f 26/1/28 25/1/28 14/1/28 +f 5/1/29 7/1/29 25/1/29 +f 3/1/30 4/1/30 25/1/30 +f 4/1/31 5/1/31 25/1/31 +f 2/1/32 3/1/32 25/1/32 +f 1/1/33 27/1/33 2/1/33 +f 25/1/34 27/1/34 2/1/34 +f 25/1/35 26/1/35 27/1/35 +f 8/1/36 13/1/36 26/1/36 +f 1/1/37 12/1/37 27/1/37 +f 26/1/38 14/1/38 6/1/38 +f 7/1/39 14/1/39 25/1/39 +f 20/1/40 26/1/40 22/1/40 +f 26/1/41 24/1/41 28/1/41 +f 19/1/42 28/1/42 21/1/42 +f 17/1/30 28/1/30 18/1/30 +f 18/1/43 28/1/43 19/1/43 +f 16/1/44 28/1/44 17/1/44 +f 15/1/45 16/1/45 27/1/45 +f 28/1/46 16/1/46 27/1/46 +f 28/1/47 27/1/47 26/1/47 +f 22/1/48 26/1/48 13/1/48 +f 15/1/49 27/1/49 12/1/49 +f 26/1/50 20/1/50 24/1/50 +f 21/1/51 28/1/51 24/1/51 diff --git a/spacecraft2.2.obj b/spacecraft2.2.obj new file mode 100644 index 0000000..216dd57 --- /dev/null +++ b/spacecraft2.2.obj @@ -0,0 +1,77 @@ +# Blender 3.6.5 +# www.blender.org +mtllib spacecraft2.2.mtl +o Cube +v -1.000000 0.000000 5.000000 +v -3.000000 0.000000 4.000000 +v -3.000000 0.000000 0.000000 +v -2.000000 0.000000 -3.000000 +v -7.000000 0.000000 4.000000 +v 0.000000 2.000000 0.000000 +v 0.000000 2.000000 2.000000 +v 0.000000 0.000000 6.000000 +v 0.000000 0.000000 -4.000000 +v 1.000000 0.000000 5.000000 +v 3.000000 0.000000 4.000000 +v 3.000000 0.000000 0.000000 +v 2.000000 0.000000 -3.000000 +v 7.000000 0.000000 4.000000 +v 0.000000 -2.000000 0.000000 +v 0.000000 -2.000000 2.000000 +vn -0.5455 0.8182 -0.1818 +vn -0.4851 0.7276 -0.4851 +vn 0.2408 -0.8427 -0.4815 +vn -0.0000 0.7071 0.7071 +vn -0.2747 0.9615 -0.0000 +vn -0.2182 0.8729 -0.4364 +vn 0.4082 -0.8165 -0.4082 +vn 0.5455 0.8182 -0.1818 +vn 0.4851 0.7276 -0.4851 +vn -0.2408 -0.8427 -0.4815 +vn 0.2747 0.9615 -0.0000 +vn 0.2182 0.8729 -0.4364 +vn -0.4082 -0.8165 -0.4082 +vn -0.5455 -0.8182 -0.1818 +vn -0.4851 -0.7276 -0.4851 +vn 0.2408 0.8427 -0.4815 +vn -0.0000 -0.7071 0.7071 +vn -0.2747 -0.9615 -0.0000 +vn -0.2182 -0.8729 -0.4364 +vn 0.4082 0.8165 -0.4082 +vn 0.5455 -0.8182 -0.1818 +vn 0.4851 -0.7276 -0.4851 +vn -0.2408 0.8427 -0.4815 +vn 0.2747 -0.9615 -0.0000 +vn 0.2182 -0.8729 -0.4364 +vn -0.4082 0.8165 -0.4082 +vt 0.000000 0.000000 +s 0 +usemtl Material +f 3/1/1 6/1/1 4/1/1 +f 6/1/2 3/1/2 5/1/2 +f 1/1/3 2/1/3 7/1/3 +f 5/1/4 2/1/4 7/1/4 +f 5/1/5 7/1/5 6/1/5 +f 4/1/6 6/1/6 9/1/6 +f 1/1/7 7/1/7 8/1/7 +f 12/1/8 13/1/8 6/1/8 +f 6/1/9 14/1/9 12/1/9 +f 10/1/10 7/1/10 11/1/10 +f 14/1/4 7/1/4 11/1/4 +f 14/1/11 6/1/11 7/1/11 +f 13/1/12 9/1/12 6/1/12 +f 10/1/13 8/1/13 7/1/13 +f 3/1/14 4/1/14 15/1/14 +f 15/1/15 5/1/15 3/1/15 +f 1/1/16 16/1/16 2/1/16 +f 5/1/17 16/1/17 2/1/17 +f 5/1/18 15/1/18 16/1/18 +f 4/1/19 9/1/19 15/1/19 +f 1/1/20 8/1/20 16/1/20 +f 12/1/21 15/1/21 13/1/21 +f 15/1/22 12/1/22 14/1/22 +f 10/1/23 11/1/23 16/1/23 +f 14/1/17 11/1/17 16/1/17 +f 14/1/24 16/1/24 15/1/24 +f 13/1/25 15/1/25 9/1/25 +f 10/1/26 16/1/26 8/1/26 diff --git a/spacecraft2.obj b/spacecraft2.obj new file mode 100644 index 0000000..ad509cb --- /dev/null +++ b/spacecraft2.obj @@ -0,0 +1,107 @@ +# 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 +v -3.000000 0.000000 4.000000 +v -5.000000 0.000000 4.000000 +v -6.000000 0.000000 2.000000 +v -2.000000 0.000000 0.000000 +v -4.000000 0.000000 -6.000000 +v -1.000000 0.000000 -2.000000 +v 1.000000 0.000000 3.000000 +v 2.000000 0.000000 2.000000 +v 3.000000 0.000000 4.000000 +v 5.000000 0.000000 4.000000 +v 6.000000 0.000000 2.000000 +v 4.000000 0.000000 -6.000000 +v 2.000000 0.000000 0.000000 +v 1.000000 0.000000 -2.000000 +v -4.000000 1.000000 2.000000 +v 0.000000 1.000000 0.000000 +v 4.000000 1.000000 2.000000 +v 0.000000 1.000000 1.000000 +v -4.000000 -1.000000 2.000000 +v 0.000000 -1.000000 0.000000 +v 4.000000 -1.000000 2.000000 +v 0.000000 -1.000000 1.000000 +vn -0.0000 0.8944 -0.4472 +vn 0.4364 0.8729 -0.2182 +vn 0.3333 0.6667 -0.6667 +vn -0.3487 0.9300 -0.1162 +vn 0.4444 0.8889 -0.1111 +vn 0.4364 0.8729 0.2182 +vn -0.0000 0.8944 0.4472 +vn -0.4364 0.8729 0.2182 +vn -0.0000 1.0000 -0.0000 +vn -0.0000 -0.8944 -0.4472 +vn -0.3015 -0.9045 -0.3015 +vn -0.2182 0.4364 0.8729 +vn -0.4364 0.8729 -0.2182 +vn -0.3333 0.6667 -0.6667 +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 +vn 0.4364 -0.8729 -0.2182 +vn 0.3333 -0.6667 -0.6667 +vn -0.3487 -0.9300 -0.1162 +vn 0.4444 -0.8889 -0.1111 +vn 0.4364 -0.8729 0.2182 +vn -0.0000 -0.8944 0.4472 +vn -0.4364 -0.8729 0.2182 +vn -0.0000 -1.0000 -0.0000 +vn -0.3015 0.9045 -0.3015 +vn -0.2182 -0.4364 0.8729 +vn -0.4364 -0.8729 -0.2182 +vn -0.3333 -0.6667 -0.6667 +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 +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 17/1/9 20/1/9 19/1/9 18/1/9 +f 1/1/10 20/1/10 9/1/10 +f 9/1/11 20/1/11 10/1/11 +f 20/1/12 10/1/12 19/1/12 +f 6/1/13 18/1/13 8/1/13 +f 18/1/14 6/1/14 17/1/14 +f 6/1/15 7/1/15 17/1/15 +f 5/1/16 17/1/16 7/1/16 +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/17 2/1/17 20/1/17 +f 17/1/18 2/1/18 20/1/18 +f 8/1/10 16/1/10 22/1/10 +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 21/1/26 22/1/26 23/1/26 24/1/26 +f 1/1/1 9/1/1 24/1/1 +f 9/1/27 10/1/27 24/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 24/1/33 2/1/33 +f 21/1/34 24/1/34 2/1/34 diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7651296 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,220 @@ +use std::fs::File; +use std::{env, io}; +use std::f32::consts::PI; +use std::io::{BufRead, BufReader, BufWriter}; +use std::io::Write; +use rand::Rng; +use glm; +use glm::{dot, ivec2, IVec2, ivec3, to_ivec3, vec2, Vec2, Vec3}; + +#[derive(Copy, Clone, Debug)] +struct ObjVertex { + vertex: usize, + normal: usize, + tex_coord: usize, +} + +#[derive(Copy, Clone, Debug)] +struct ObjFace { + vertices: [ObjVertex; 3], +} + +#[derive(Debug)] +struct ObjMesh { + vertices: Vec, + normals: Vec, + tex_coords: Vec, + faces: Vec, +} + +impl ObjMesh { + fn parse_v2(tokens: &[&str]) -> Vec2 { + assert_eq!(tokens.len(), 2); + let tokens: Vec<_> = tokens.iter().map(|&t| t.parse().unwrap()).collect(); + vec2(tokens[0], tokens[1]) + } + + fn parse_v3(tokens: &[&str]) -> Vec3 { + assert_eq!(tokens.len(), 3); + let tokens: Vec<_> = tokens.iter().map(|&t| t.parse().unwrap()).collect(); + glm::vec3(tokens[0], tokens[1], tokens[2]) + } + + fn parse_fv(desc: &&str) -> ObjVertex { + let tokens: Vec<_> = desc.split('/').map(|s| s.parse::().unwrap() - 1).collect(); + assert_eq!(tokens.len(), 3); + ObjVertex { vertex: tokens[0], tex_coord: tokens[1], normal: tokens[2] } + } + + fn parse_f(tokens: &[&str]) -> ObjFace { + let vertices: Vec<_> = tokens.iter().map(ObjMesh::parse_fv).collect(); + ObjFace { vertices: vertices.as_slice().try_into().unwrap() } + } + + fn read(f: &mut impl BufRead) -> io::Result { + let mut result = ObjMesh { + vertices: Vec::new(), + normals: Vec::new(), + tex_coords: Vec::new(), + faces: Vec::new(), + }; + loop { + let mut line = String::new(); + if f.read_line(&mut line)? == 0 { + break; + } + let tokens: Vec<&str> = line + .trim() + .split('#') + .next() + .unwrap() + .split(' ') + .collect(); + match tokens[0] { + "v" => result.vertices.push(Self::parse_v3(&tokens[1..])), + "vn" => result.normals.push(Self::parse_v3(&tokens[1..])), + "vt" => result.tex_coords.push(Self::parse_v2(&tokens[1..])), + "f" => result.faces.push(Self::parse_f(&tokens[1..])), + _ => (), + } + } + Ok(result) + } +} + +const W: i32 = 800; +const H: i32 = 600; +const SCALE: f32 = 30.0; + +#[derive(Copy, Clone)] +struct Color(u8, u8, u8); + +#[derive(Copy, Clone)] +struct Comparer { + coef: Vec2, + thr: f32, +} + +impl Comparer { + fn new(a: Vec2, b: Vec2) -> Comparer { + let d = b - a; + let ortho = vec2(-d.y, d.x); + Comparer { + coef: ortho, + thr: dot(a, ortho), + } + } + + fn dist(&self, p: Vec2) -> f32 { + dot(p, self.coef) - self.thr + } + + fn test(&self, p: Vec2) -> bool { + self.dist(p) > 0.0 + } +} + +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 draw_line(&mut self, a: IVec2, b: IVec2, color: Color) {} + fn draw_tri(&mut self, a: Vec2, b: Vec2, c: Vec2, color: Color) { + let u = Comparer::new(a, b); + let v = Comparer::new(b, c); + let w = Comparer::new(c, a); + for y in 0..self.h { + for x in 0..self.w { + let p = vec2(x as f32, y as f32); + if u.test(p) && v.test(p) && w.test(p) || !u.test(p) && !v.test(p) && !w.test(p) { + self.put_pixel(x, y, color); + } + } + } + } +} + +fn main() -> io::Result<()> { + let args: Vec = env::args().collect(); + let mesh = { + let f = File::open(&args[1])?; + let mut f = BufReader::new(f); + ObjMesh::read(&mut f)? + }; + dbg!(&mesh); + let mut img = Image { + w: W, + h: H, + data: vec![0; (3 * W * H) as usize], + }; + let yaw = PI / 4.0; + let pitch = PI / 6.0; + let roll = 0.0f32; + let m_roll = glm::mat3( + roll.cos(), roll.sin(), 0.0, + -roll.sin(), roll.cos(), 0.0, + 0.0, 0.0, 1.0); + let m_yaw = glm::mat3( + yaw.cos(), 0.0, yaw.sin(), + 0.0, 1.0, 0.0, + -yaw.sin(), 0.0, yaw.cos()); + let m_pitch = glm::mat3( + 1.0, 0.0, 0.0, + 0.0, pitch.cos(), -pitch.sin(), + 0.0, pitch.sin(), pitch.cos()); + let m1 = m_roll * m_pitch * m_yaw; + for f in mesh.faces { + let vs = f.vertices + .map(|v| m1 * mesh.vertices[v.vertex]) + .map(|v| vec2(W as f32 * 0.5 + v.x * SCALE, H as f32 * 0.5 + v.y * SCALE)); + let n = mesh.normals[f.vertices[0].normal]; + if (m1 * mesh.normals[f.vertices[0].normal]).z < 0.0 { + continue; + } + /* + let r: u8 = rand::thread_rng().gen_range(0..255); + let g: u8 = rand::thread_rng().gen_range(0..255); + let b: u8 = rand::thread_rng().gen_range(0..255); + + */ + let color = glm::clamp(to_ivec3(n * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); + img.draw_tri(vs[0], vs[1], vs[2], Color(color.x as u8, color.y as u8, color.z as u8)); + } + /* + for v in mesh.vertices { + img.put_pixel(W / 2 + (v.x * SCALE) as i32, H / 2 + (v.z * SCALE) as i32, Color(255, 255, 255)); + } + + for y in 0..H { + for x in 0..W { + let r = (x * 256 / W).clamp(0, 255) as u8; + let g = (y * 256 / H).clamp(0, 255) as u8; + let b = rand::thread_rng().gen_range(128 - 16..128 + 16); + img.put_pixel(x, y, Color(r, g, b)); + } + } + */ + let f = File::create("1.ppm")?; + let mut f = BufWriter::new(f); + write!(f, "P6\n")?; + write!(f, "{W} {H} 255\n")?; + f.write(img.data()); + Ok(()) +} From 1c306058553871e950733a487eeb43f45c7c7124 Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 25 Mar 2024 18:29:59 +0300 Subject: [PATCH 02/25] Fix winding --- spacecraft2.1.obj | 32 ++++++++++++++++---------------- spacecraft2.2.obj | 32 ++++++++++++++++---------------- spacecraft2.obj | 42 ++++++++++++++++++++++-------------------- 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/spacecraft2.1.obj b/spacecraft2.1.obj index 11dcbf2..8a38f7a 100644 --- a/spacecraft2.1.obj +++ b/spacecraft2.1.obj @@ -36,11 +36,11 @@ vn -0.4439 0.8878 -0.1211 vn -0.0000 0.9487 0.3162 vn -0.4423 0.8847 0.1474 vn 0.2417 0.9670 0.0806 -vn 0.2408 -0.8427 -0.4815 +vn -0.2408 0.8427 0.4815 vn 0.1455 0.5819 0.8001 vn -0.1414 0.9899 -0.0000 vn -0.2182 0.8729 -0.4364 -vn 0.4082 -0.8165 -0.4082 +vn -0.4082 0.8165 0.4082 vn -0.4851 0.7276 -0.4851 vn 0.4099 0.9110 -0.0455 vn -0.0000 -1.0000 -0.0000 @@ -49,11 +49,11 @@ vn 0.4851 0.4851 -0.7276 vn 0.4439 0.8878 -0.1211 vn 0.4423 0.8847 0.1474 vn -0.2417 0.9670 0.0806 -vn -0.2408 -0.8427 -0.4815 +vn 0.2408 0.8427 0.4815 vn -0.1455 0.5819 0.8001 vn 0.1414 0.9899 -0.0000 vn 0.2182 0.8729 -0.4364 -vn -0.4082 -0.8165 -0.4082 +vn 0.4082 0.8165 0.4082 vn 0.4851 0.7276 -0.4851 vn -0.4099 0.9110 -0.0455 vn -0.5455 -0.8182 -0.1818 @@ -62,11 +62,11 @@ vn -0.4439 -0.8878 -0.1211 vn -0.0000 -0.9487 0.3162 vn -0.4423 -0.8847 0.1474 vn 0.2417 -0.9670 0.0806 -vn 0.2408 0.8427 -0.4815 +vn -0.2408 -0.8427 0.4815 vn 0.1455 -0.5819 0.8001 vn -0.1414 -0.9899 -0.0000 vn -0.2182 -0.8729 -0.4364 -vn 0.4082 0.8165 -0.4082 +vn -0.4082 -0.8165 0.4082 vn -0.4851 -0.7276 -0.4851 vn 0.4099 -0.9110 -0.0455 vn 0.5455 -0.8182 -0.1818 @@ -74,11 +74,11 @@ vn 0.4851 -0.4851 -0.7276 vn 0.4439 -0.8878 -0.1211 vn 0.4423 -0.8847 0.1474 vn -0.2417 -0.9670 0.0806 -vn -0.2408 0.8427 -0.4815 +vn 0.2408 -0.8427 0.4815 vn -0.1455 -0.5819 0.8001 vn 0.1414 -0.9899 -0.0000 vn 0.2182 -0.8729 -0.4364 -vn -0.4082 0.8165 -0.4082 +vn 0.4082 -0.8165 0.4082 vn 0.4851 -0.7276 -0.4851 vn -0.4099 -0.9110 -0.0455 vt 0.000000 0.000000 @@ -90,11 +90,11 @@ f 5/1/3 9/1/3 7/1/3 f 3/1/4 9/1/4 4/1/4 f 4/1/5 9/1/5 5/1/5 f 2/1/6 9/1/6 3/1/6 -f 1/1/7 2/1/7 11/1/7 +f 1/1/7 11/1/7 2/1/7 f 9/1/8 2/1/8 11/1/8 f 9/1/9 11/1/9 10/1/9 f 8/1/10 10/1/10 13/1/10 -f 1/1/11 11/1/11 12/1/11 +f 1/1/11 12/1/11 11/1/11 f 10/1/12 6/1/12 14/1/12 f 7/1/13 9/1/13 14/1/13 f 7/1/14 14/1/14 5/1/14 @@ -104,11 +104,11 @@ f 19/1/17 21/1/17 23/1/17 f 17/1/4 18/1/4 23/1/4 f 18/1/18 19/1/18 23/1/18 f 16/1/19 17/1/19 23/1/19 -f 15/1/20 11/1/20 16/1/20 +f 15/1/20 16/1/20 11/1/20 f 23/1/21 11/1/21 16/1/21 f 23/1/22 10/1/22 11/1/22 f 22/1/23 13/1/23 10/1/23 -f 15/1/24 12/1/24 11/1/24 +f 15/1/24 11/1/24 12/1/24 f 10/1/25 24/1/25 20/1/25 f 21/1/26 24/1/26 23/1/26 f 21/1/14 19/1/14 24/1/14 @@ -118,11 +118,11 @@ f 5/1/29 7/1/29 25/1/29 f 3/1/30 4/1/30 25/1/30 f 4/1/31 5/1/31 25/1/31 f 2/1/32 3/1/32 25/1/32 -f 1/1/33 27/1/33 2/1/33 +f 1/1/33 2/1/33 27/1/33 f 25/1/34 27/1/34 2/1/34 f 25/1/35 26/1/35 27/1/35 f 8/1/36 13/1/36 26/1/36 -f 1/1/37 12/1/37 27/1/37 +f 1/1/37 27/1/37 12/1/37 f 26/1/38 14/1/38 6/1/38 f 7/1/39 14/1/39 25/1/39 f 20/1/40 26/1/40 22/1/40 @@ -131,10 +131,10 @@ f 19/1/42 28/1/42 21/1/42 f 17/1/30 28/1/30 18/1/30 f 18/1/43 28/1/43 19/1/43 f 16/1/44 28/1/44 17/1/44 -f 15/1/45 16/1/45 27/1/45 +f 15/1/45 27/1/45 16/1/45 f 28/1/46 16/1/46 27/1/46 f 28/1/47 27/1/47 26/1/47 f 22/1/48 26/1/48 13/1/48 -f 15/1/49 27/1/49 12/1/49 +f 15/1/49 12/1/49 27/1/49 f 26/1/50 20/1/50 24/1/50 f 21/1/51 28/1/51 24/1/51 diff --git a/spacecraft2.2.obj b/spacecraft2.2.obj index 216dd57..550ad51 100644 --- a/spacecraft2.2.obj +++ b/spacecraft2.2.obj @@ -20,58 +20,58 @@ v 0.000000 -2.000000 0.000000 v 0.000000 -2.000000 2.000000 vn -0.5455 0.8182 -0.1818 vn -0.4851 0.7276 -0.4851 -vn 0.2408 -0.8427 -0.4815 +vn -0.2408 0.8427 0.4815 vn -0.0000 0.7071 0.7071 vn -0.2747 0.9615 -0.0000 vn -0.2182 0.8729 -0.4364 -vn 0.4082 -0.8165 -0.4082 +vn -0.4082 0.8165 0.4082 vn 0.5455 0.8182 -0.1818 vn 0.4851 0.7276 -0.4851 -vn -0.2408 -0.8427 -0.4815 +vn 0.2408 0.8427 0.4815 vn 0.2747 0.9615 -0.0000 vn 0.2182 0.8729 -0.4364 -vn -0.4082 -0.8165 -0.4082 +vn 0.4082 0.8165 0.4082 vn -0.5455 -0.8182 -0.1818 vn -0.4851 -0.7276 -0.4851 -vn 0.2408 0.8427 -0.4815 +vn -0.2408 -0.8427 0.4815 vn -0.0000 -0.7071 0.7071 vn -0.2747 -0.9615 -0.0000 vn -0.2182 -0.8729 -0.4364 -vn 0.4082 0.8165 -0.4082 +vn -0.4082 -0.8165 0.4082 vn 0.5455 -0.8182 -0.1818 vn 0.4851 -0.7276 -0.4851 -vn -0.2408 0.8427 -0.4815 +vn 0.2408 -0.8427 0.4815 vn 0.2747 -0.9615 -0.0000 vn 0.2182 -0.8729 -0.4364 -vn -0.4082 0.8165 -0.4082 +vn 0.4082 -0.8165 0.4082 vt 0.000000 0.000000 s 0 usemtl Material f 3/1/1 6/1/1 4/1/1 f 6/1/2 3/1/2 5/1/2 -f 1/1/3 2/1/3 7/1/3 +f 1/1/3 7/1/3 2/1/3 f 5/1/4 2/1/4 7/1/4 f 5/1/5 7/1/5 6/1/5 f 4/1/6 6/1/6 9/1/6 -f 1/1/7 7/1/7 8/1/7 +f 1/1/7 8/1/7 7/1/7 f 12/1/8 13/1/8 6/1/8 f 6/1/9 14/1/9 12/1/9 -f 10/1/10 7/1/10 11/1/10 +f 10/1/10 11/1/10 7/1/10 f 14/1/4 7/1/4 11/1/4 f 14/1/11 6/1/11 7/1/11 f 13/1/12 9/1/12 6/1/12 -f 10/1/13 8/1/13 7/1/13 +f 10/1/13 7/1/13 8/1/13 f 3/1/14 4/1/14 15/1/14 f 15/1/15 5/1/15 3/1/15 -f 1/1/16 16/1/16 2/1/16 +f 1/1/16 2/1/16 16/1/16 f 5/1/17 16/1/17 2/1/17 f 5/1/18 15/1/18 16/1/18 f 4/1/19 9/1/19 15/1/19 -f 1/1/20 8/1/20 16/1/20 +f 1/1/20 16/1/20 8/1/20 f 12/1/21 15/1/21 13/1/21 f 15/1/22 12/1/22 14/1/22 -f 10/1/23 11/1/23 16/1/23 +f 10/1/23 16/1/23 11/1/23 f 14/1/17 11/1/17 16/1/17 f 14/1/24 16/1/24 15/1/24 f 13/1/25 15/1/25 9/1/25 -f 10/1/26 16/1/26 8/1/26 +f 10/1/26 8/1/26 16/1/26 diff --git a/spacecraft2.obj b/spacecraft2.obj index ad509cb..cd571ee 100644 --- a/spacecraft2.obj +++ b/spacecraft2.obj @@ -35,15 +35,15 @@ vn 0.4364 0.8729 0.2182 vn -0.0000 0.8944 0.4472 vn -0.4364 0.8729 0.2182 vn -0.0000 1.0000 -0.0000 -vn -0.0000 -0.8944 -0.4472 -vn -0.3015 -0.9045 -0.3015 +vn 0.3015 0.9045 0.3015 vn -0.2182 0.4364 0.8729 vn -0.4364 0.8729 -0.2182 vn -0.3333 0.6667 -0.6667 vn 0.3487 0.9300 -0.1162 vn -0.4444 0.8889 -0.1111 -vn 0.3015 -0.9045 -0.3015 +vn -0.3015 0.9045 0.3015 vn 0.2182 0.4364 0.8729 +vn -0.0000 -0.8944 -0.4472 vn 0.4364 -0.8729 -0.2182 vn 0.3333 -0.6667 -0.6667 vn -0.3487 -0.9300 -0.1162 @@ -52,13 +52,13 @@ vn 0.4364 -0.8729 0.2182 vn -0.0000 -0.8944 0.4472 vn -0.4364 -0.8729 0.2182 vn -0.0000 -1.0000 -0.0000 -vn -0.3015 0.9045 -0.3015 +vn 0.3015 -0.9045 0.3015 vn -0.2182 -0.4364 0.8729 vn -0.4364 -0.8729 -0.2182 vn -0.3333 -0.6667 -0.6667 vn 0.3487 -0.9300 -0.1162 vn -0.4444 -0.8889 -0.1111 -vn 0.3015 0.9045 -0.3015 +vn -0.3015 -0.9045 0.3015 vn 0.2182 -0.4364 0.8729 vt 0.000000 0.000000 s 0 @@ -71,20 +71,21 @@ 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 17/1/9 20/1/9 19/1/9 18/1/9 -f 1/1/10 20/1/10 9/1/10 -f 9/1/11 20/1/11 10/1/11 -f 20/1/12 10/1/12 19/1/12 -f 6/1/13 18/1/13 8/1/13 -f 18/1/14 6/1/14 17/1/14 -f 6/1/15 7/1/15 17/1/15 -f 5/1/16 17/1/16 7/1/16 +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/17 2/1/17 20/1/17 -f 17/1/18 2/1/18 20/1/18 -f 8/1/10 16/1/10 22/1/10 +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 @@ -92,9 +93,9 @@ 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 21/1/26 22/1/26 23/1/26 24/1/26 -f 1/1/1 9/1/1 24/1/1 -f 9/1/27 10/1/27 24/1/27 +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 @@ -103,5 +104,6 @@ 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 24/1/33 2/1/33 +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 From 48cf277b08dc7424c7ac78f7cac5c3ff13c58193 Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 25 Mar 2024 18:30:58 +0300 Subject: [PATCH 03/25] Reduce --- src/main.rs | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7651296..68d545d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -158,7 +158,6 @@ fn main() -> io::Result<()> { let mut f = BufReader::new(f); ObjMesh::read(&mut f)? }; - dbg!(&mesh); let mut img = Image { w: W, h: H, @@ -179,38 +178,17 @@ fn main() -> io::Result<()> { 1.0, 0.0, 0.0, 0.0, pitch.cos(), -pitch.sin(), 0.0, pitch.sin(), pitch.cos()); - let m1 = m_roll * m_pitch * m_yaw; + let m_camera = m_roll * m_pitch * m_yaw; for f in mesh.faces { let vs = f.vertices - .map(|v| m1 * mesh.vertices[v.vertex]) + .map(|v| mesh.vertices[v.vertex]); + let vs = vs + .map(|v| m_camera * v) .map(|v| vec2(W as f32 * 0.5 + v.x * SCALE, H as f32 * 0.5 + v.y * SCALE)); let n = mesh.normals[f.vertices[0].normal]; - if (m1 * mesh.normals[f.vertices[0].normal]).z < 0.0 { - continue; - } - /* - let r: u8 = rand::thread_rng().gen_range(0..255); - let g: u8 = rand::thread_rng().gen_range(0..255); - let b: u8 = rand::thread_rng().gen_range(0..255); - - */ let color = glm::clamp(to_ivec3(n * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); img.draw_tri(vs[0], vs[1], vs[2], Color(color.x as u8, color.y as u8, color.z as u8)); } - /* - for v in mesh.vertices { - img.put_pixel(W / 2 + (v.x * SCALE) as i32, H / 2 + (v.z * SCALE) as i32, Color(255, 255, 255)); - } - - for y in 0..H { - for x in 0..W { - let r = (x * 256 / W).clamp(0, 255) as u8; - let g = (y * 256 / H).clamp(0, 255) as u8; - let b = rand::thread_rng().gen_range(128 - 16..128 + 16); - img.put_pixel(x, y, Color(r, g, b)); - } - } - */ let f = File::create("1.ppm")?; let mut f = BufWriter::new(f); write!(f, "P6\n")?; From 2ec43c822ddddf96a7570cdd3821978987f7a1af Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 25 Mar 2024 18:41:49 +0300 Subject: [PATCH 04/25] Flatten --- src/main.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 68d545d..8e2db3c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,6 +80,21 @@ impl ObjMesh { } Ok(result) } + + fn flatten(&self) -> Vec { + self.faces.iter().map(|face| { + Face { + vertices: face.vertices.map(|iv| self.vertices[iv.vertex]), + normal: self.normals[face.vertices[0].normal], + } + }).collect() + } +} + +#[derive(Copy, Clone, Debug)] +struct Face { + vertices: [Vec3; 3], + normal: Vec3, } const W: i32 = 800; @@ -157,6 +172,7 @@ fn main() -> io::Result<()> { let f = File::open(&args[1])?; let mut f = BufReader::new(f); ObjMesh::read(&mut f)? + .flatten() }; let mut img = Image { w: W, @@ -179,14 +195,11 @@ fn main() -> io::Result<()> { 0.0, pitch.cos(), -pitch.sin(), 0.0, pitch.sin(), pitch.cos()); let m_camera = m_roll * m_pitch * m_yaw; - for f in mesh.faces { + for f in mesh { let vs = f.vertices - .map(|v| mesh.vertices[v.vertex]); - let vs = vs .map(|v| m_camera * v) .map(|v| vec2(W as f32 * 0.5 + v.x * SCALE, H as f32 * 0.5 + v.y * SCALE)); - let n = mesh.normals[f.vertices[0].normal]; - let color = glm::clamp(to_ivec3(n * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); + let color = glm::clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); img.draw_tri(vs[0], vs[1], vs[2], Color(color.x as u8, color.y as u8, color.z as u8)); } let f = File::create("1.ppm")?; From af5322a47eee4e2732303cfc67e32ce5ebf38a14 Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 25 Mar 2024 19:00:04 +0300 Subject: [PATCH 05/25] Extract the mesh loader --- src/main.rs | 96 ++-------------------------------------------- src/mesh_loader.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 92 deletions(-) create mode 100644 src/mesh_loader.rs diff --git a/src/main.rs b/src/main.rs index 8e2db3c..b228c1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +mod mesh_loader; + use std::fs::File; use std::{env, io}; use std::f32::consts::PI; @@ -6,96 +8,7 @@ use std::io::Write; use rand::Rng; use glm; use glm::{dot, ivec2, IVec2, ivec3, to_ivec3, vec2, Vec2, Vec3}; - -#[derive(Copy, Clone, Debug)] -struct ObjVertex { - vertex: usize, - normal: usize, - tex_coord: usize, -} - -#[derive(Copy, Clone, Debug)] -struct ObjFace { - vertices: [ObjVertex; 3], -} - -#[derive(Debug)] -struct ObjMesh { - vertices: Vec, - normals: Vec, - tex_coords: Vec, - faces: Vec, -} - -impl ObjMesh { - fn parse_v2(tokens: &[&str]) -> Vec2 { - assert_eq!(tokens.len(), 2); - let tokens: Vec<_> = tokens.iter().map(|&t| t.parse().unwrap()).collect(); - vec2(tokens[0], tokens[1]) - } - - fn parse_v3(tokens: &[&str]) -> Vec3 { - assert_eq!(tokens.len(), 3); - let tokens: Vec<_> = tokens.iter().map(|&t| t.parse().unwrap()).collect(); - glm::vec3(tokens[0], tokens[1], tokens[2]) - } - - fn parse_fv(desc: &&str) -> ObjVertex { - let tokens: Vec<_> = desc.split('/').map(|s| s.parse::().unwrap() - 1).collect(); - assert_eq!(tokens.len(), 3); - ObjVertex { vertex: tokens[0], tex_coord: tokens[1], normal: tokens[2] } - } - - fn parse_f(tokens: &[&str]) -> ObjFace { - let vertices: Vec<_> = tokens.iter().map(ObjMesh::parse_fv).collect(); - ObjFace { vertices: vertices.as_slice().try_into().unwrap() } - } - - fn read(f: &mut impl BufRead) -> io::Result { - let mut result = ObjMesh { - vertices: Vec::new(), - normals: Vec::new(), - tex_coords: Vec::new(), - faces: Vec::new(), - }; - loop { - let mut line = String::new(); - if f.read_line(&mut line)? == 0 { - break; - } - let tokens: Vec<&str> = line - .trim() - .split('#') - .next() - .unwrap() - .split(' ') - .collect(); - match tokens[0] { - "v" => result.vertices.push(Self::parse_v3(&tokens[1..])), - "vn" => result.normals.push(Self::parse_v3(&tokens[1..])), - "vt" => result.tex_coords.push(Self::parse_v2(&tokens[1..])), - "f" => result.faces.push(Self::parse_f(&tokens[1..])), - _ => (), - } - } - Ok(result) - } - - fn flatten(&self) -> Vec { - self.faces.iter().map(|face| { - Face { - vertices: face.vertices.map(|iv| self.vertices[iv.vertex]), - normal: self.normals[face.vertices[0].normal], - } - }).collect() - } -} - -#[derive(Copy, Clone, Debug)] -struct Face { - vertices: [Vec3; 3], - normal: Vec3, -} +use crate::mesh_loader::load_mesh; const W: i32 = 800; const H: i32 = 600; @@ -171,8 +84,7 @@ fn main() -> io::Result<()> { let mesh = { let f = File::open(&args[1])?; let mut f = BufReader::new(f); - ObjMesh::read(&mut f)? - .flatten() + load_mesh(&mut f)? }; let mut img = Image { w: W, diff --git a/src/mesh_loader.rs b/src/mesh_loader.rs new file mode 100644 index 0000000..ed2e259 --- /dev/null +++ b/src/mesh_loader.rs @@ -0,0 +1,96 @@ +use std::io; +use glm::{vec2, vec3, Vec2, Vec3}; + +#[derive(Copy, Clone, Debug)] +struct ObjVertex { + vertex: usize, + normal: usize, + tex_coord: usize, +} + +#[derive(Copy, Clone, Debug)] +struct ObjFace { + vertices: [ObjVertex; 3], +} + +#[derive(Debug)] +struct ObjMesh { + vertices: Vec, + normals: Vec, + tex_coords: Vec, + faces: Vec, +} + +impl ObjMesh { + fn parse_v2(tokens: &[&str]) -> Vec2 { + assert_eq!(tokens.len(), 2); + let tokens: Vec<_> = tokens.iter().map(|&t| t.parse().unwrap()).collect(); + vec2(tokens[0], tokens[1]) + } + + fn parse_v3(tokens: &[&str]) -> Vec3 { + assert_eq!(tokens.len(), 3); + let tokens: Vec<_> = tokens.iter().map(|&t| t.parse().unwrap()).collect(); + vec3(tokens[0], tokens[1], tokens[2]) + } + + fn parse_fv(desc: &&str) -> ObjVertex { + let tokens: Vec<_> = desc.split('/').map(|s| s.parse::().unwrap() - 1).collect(); + assert_eq!(tokens.len(), 3); + ObjVertex { vertex: tokens[0], tex_coord: tokens[1], normal: tokens[2] } + } + + fn parse_f(tokens: &[&str]) -> ObjFace { + let vertices: Vec<_> = tokens.iter().map(ObjMesh::parse_fv).collect(); + ObjFace { vertices: vertices.as_slice().try_into().unwrap() } + } + + fn read(f: &mut impl io::BufRead) -> io::Result { + let mut result = ObjMesh { + vertices: Vec::new(), + normals: Vec::new(), + tex_coords: Vec::new(), + faces: Vec::new(), + }; + loop { + let mut line = String::new(); + if f.read_line(&mut line)? == 0 { + break; + } + let tokens: Vec<&str> = line + .trim() + .split('#') + .next() + .unwrap() + .split(' ') + .collect(); + match tokens[0] { + "v" => result.vertices.push(Self::parse_v3(&tokens[1..])), + "vn" => result.normals.push(Self::parse_v3(&tokens[1..])), + "vt" => result.tex_coords.push(Self::parse_v2(&tokens[1..])), + "f" => result.faces.push(Self::parse_f(&tokens[1..])), + _ => (), + } + } + Ok(result) + } + + fn flatten(&self) -> Vec { + self.faces.iter().map(|face| { + Face { + vertices: face.vertices.map(|iv| self.vertices[iv.vertex]), + normal: self.normals[face.vertices[0].normal], + } + }).collect() + } +} + +#[derive(Copy, Clone, Debug)] +pub struct Face { + pub vertices: [Vec3; 3], + pub normal: Vec3, +} + +pub fn load_mesh(f: &mut impl io::BufRead) -> io::Result> { + Ok(ObjMesh::read(f)?.flatten()) +} From 6c56a31726ab47c78557549789117b6d42300b63 Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 26 Mar 2024 00:42:22 +0300 Subject: [PATCH 06/25] Use ray tracing --- src/main.rs | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index b228c1e..e0a40d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,8 +6,7 @@ use std::f32::consts::PI; use std::io::{BufRead, BufReader, BufWriter}; use std::io::Write; use rand::Rng; -use glm; -use glm::{dot, ivec2, IVec2, ivec3, to_ivec3, vec2, Vec2, Vec3}; +use glm::*; use crate::mesh_loader::load_mesh; const W: i32 = 800; @@ -106,13 +105,34 @@ fn main() -> io::Result<()> { 1.0, 0.0, 0.0, 0.0, pitch.cos(), -pitch.sin(), 0.0, pitch.sin(), pitch.cos()); - let m_camera = m_roll * m_pitch * m_yaw; - for f in mesh { - let vs = f.vertices - .map(|v| m_camera * v) - .map(|v| vec2(W as f32 * 0.5 + v.x * SCALE, H as f32 * 0.5 + v.y * SCALE)); - let color = glm::clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); - img.draw_tri(vs[0], vs[1], vs[2], Color(color.x as u8, color.y as u8, color.z as u8)); + let m_view = m_roll * m_pitch * m_yaw; + let m_camera = transpose(&m_view); + let img_size = vec2(W as f32, H as f32); + for y in 0..H { + for x in 0..W { + let img_coords: Vec2 = vec2(x as f32, y as f32); + + // perspective projection + let off = (img_coords - img_size * 0.5) / (img_size.y * 0.5); + let base = vec3(0.0, 0.0, -10.0); + let ray = vec3(off.x, off.y, 1.0); + + // orthographic projection + let off = (img_coords - img_size * 0.5) / SCALE; + let base = vec3(off.x, off.y, -10.0); + let ray = vec3(0.0, 0.0, 1.0); + + let base = m_camera * base; + let ray = m_camera * normalize(ray); + + for f in &mesh { + let color = glm::clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); + let ds = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); + if ds.into_iter().all(|d| d > 0.0) { + img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); + } + } + } } let f = File::create("1.ppm")?; let mut f = BufWriter::new(f); @@ -121,3 +141,8 @@ fn main() -> io::Result<()> { f.write(img.data()); Ok(()) } + +fn edge_dist(a: Vec3, b: Vec3, base: Vec3, dir: Vec3) -> f32 { + let edge = normalize(b - a); + dot(edge, cross(base - a, base + dir - a)) +} From 7c74469324ba13a0793a59b55d379eaa4d8fd06c Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 20 Apr 2024 17:53:24 +0300 Subject: [PATCH 07/25] Remove useless prefix --- src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index e0a40d3..dcb6806 100644 --- a/src/main.rs +++ b/src/main.rs @@ -93,15 +93,15 @@ fn main() -> io::Result<()> { let yaw = PI / 4.0; let pitch = PI / 6.0; let roll = 0.0f32; - let m_roll = glm::mat3( + let m_roll = mat3( roll.cos(), roll.sin(), 0.0, -roll.sin(), roll.cos(), 0.0, 0.0, 0.0, 1.0); - let m_yaw = glm::mat3( + let m_yaw = mat3( yaw.cos(), 0.0, yaw.sin(), 0.0, 1.0, 0.0, -yaw.sin(), 0.0, yaw.cos()); - let m_pitch = glm::mat3( + let m_pitch = mat3( 1.0, 0.0, 0.0, 0.0, pitch.cos(), -pitch.sin(), 0.0, pitch.sin(), pitch.cos()); @@ -126,7 +126,7 @@ fn main() -> io::Result<()> { let ray = m_camera * normalize(ray); for f in &mesh { - let color = glm::clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); + let color = clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); let ds = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); if ds.into_iter().all(|d| d > 0.0) { img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); From 78689ba8c23d0bfa66c62a6b11bba50614a7a1b3 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 20 Apr 2024 17:53:46 +0300 Subject: [PATCH 08/25] =?UTF-8?q?Small=20Fixes=E2=84=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index dcb6806..145ff5a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,14 +113,14 @@ fn main() -> io::Result<()> { let img_coords: Vec2 = vec2(x as f32, y as f32); // perspective projection - let off = (img_coords - img_size * 0.5) / (img_size.y * 0.5); - let base = vec3(0.0, 0.0, -10.0); + let off = (img_coords - img_size * 0.5) / img_size.y; + let base = vec3(0.0, 0.0, -20.0); let ray = vec3(off.x, off.y, 1.0); // orthographic projection - let off = (img_coords - img_size * 0.5) / SCALE; - let base = vec3(off.x, off.y, -10.0); - let ray = vec3(0.0, 0.0, 1.0); + // let off = (img_coords - img_size * 0.5) / SCALE; + // let base = vec3(off.x, off.y, -10.0); + // let ray = vec3(0.0, 0.0, 1.0); let base = m_camera * base; let ray = m_camera * normalize(ray); @@ -138,11 +138,10 @@ fn main() -> io::Result<()> { let mut f = BufWriter::new(f); write!(f, "P6\n")?; write!(f, "{W} {H} 255\n")?; - f.write(img.data()); + f.write(img.data())?; Ok(()) } fn edge_dist(a: Vec3, b: Vec3, base: Vec3, dir: Vec3) -> f32 { - let edge = normalize(b - a); - dot(edge, cross(base - a, base + dir - a)) + Mat3 { c0: b - a, c1: base - a, c2: dir }.determinant() } From e3c99349a596bc5664c0ff6518f1babd466ab519 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 20 Apr 2024 18:46:49 +0300 Subject: [PATCH 09/25] Fix the coordinate system --- src/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 145ff5a..7774631 100644 --- a/src/main.rs +++ b/src/main.rs @@ -98,13 +98,13 @@ fn main() -> io::Result<()> { -roll.sin(), roll.cos(), 0.0, 0.0, 0.0, 1.0); let m_yaw = mat3( - yaw.cos(), 0.0, yaw.sin(), + -yaw.cos(), 0.0, yaw.sin(), 0.0, 1.0, 0.0, - -yaw.sin(), 0.0, yaw.cos()); + -yaw.sin(), 0.0, -yaw.cos()); let m_pitch = mat3( 1.0, 0.0, 0.0, - 0.0, pitch.cos(), -pitch.sin(), - 0.0, pitch.sin(), pitch.cos()); + 0.0, pitch.cos(), pitch.sin(), + 0.0, -pitch.sin(), pitch.cos()); let m_view = m_roll * m_pitch * m_yaw; let m_camera = transpose(&m_view); let img_size = vec2(W as f32, H as f32); @@ -144,4 +144,5 @@ fn main() -> io::Result<()> { fn edge_dist(a: Vec3, b: Vec3, base: Vec3, dir: Vec3) -> f32 { Mat3 { c0: b - a, c1: base - a, c2: dir }.determinant() + Mat3 { c0: b - a, c1: base - a, c2: -dir }.determinant() } From 971bb171bedacb6409aba460d8a72f5c50029767 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 20 Apr 2024 18:47:10 +0300 Subject: [PATCH 10/25] Depth sorting --- src/main.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7774631..68312f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -124,11 +124,22 @@ fn main() -> io::Result<()> { let base = m_camera * base; let ray = m_camera * normalize(ray); + let mut dist = f32::INFINITY; for f in &mesh { let color = clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); - let ds = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); - if ds.into_iter().all(|d| d > 0.0) { + let fs = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); + if fs.into_iter().all(|f| f > 0.0) { + let m = Mat3 { c0: f.vertices[1] - f.vertices[0], c1: f.vertices[2] - f.vertices[0], c2: -ray }; + if let Some(m) = m.inverse() { + let rel = m * (base - f.vertices[0]); + if rel.z > dist { + continue; + } + dist = rel.z; + } else { + continue; + } img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); } } From a4ea2977ce27ffdc194c2def893344c878a960b7 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 20 Apr 2024 18:47:31 +0300 Subject: [PATCH 11/25] Use coarser output, to speed up preview --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 68312f8..928f43c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,8 +9,8 @@ use rand::Rng; use glm::*; use crate::mesh_loader::load_mesh; -const W: i32 = 800; -const H: i32 = 600; +const W: i32 = 320; +const H: i32 = 240; const SCALE: f32 = 30.0; #[derive(Copy, Clone)] From 264601b8c7e0993585ccf2c99d00631bcffa5db5 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 20 Apr 2024 18:47:40 +0300 Subject: [PATCH 12/25] Note to myself --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 928f43c..f01b02e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -154,6 +154,6 @@ fn main() -> io::Result<()> { } fn edge_dist(a: Vec3, b: Vec3, base: Vec3, dir: Vec3) -> f32 { - Mat3 { c0: b - a, c1: base - a, c2: dir }.determinant() + // Note: given that the input is not arbitrary but comes from a cartesian product of certain (a, b) pairs and certain (base, dir) pairs, this can be optimized from Cnm to an+bm+cnm with c Date: Sun, 21 Apr 2024 17:23:45 +0300 Subject: [PATCH 13/25] Remove obsolete drawing code --- src/main.rs | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/src/main.rs b/src/main.rs index f01b02e..2ed15ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,31 +16,6 @@ const SCALE: f32 = 30.0; #[derive(Copy, Clone)] struct Color(u8, u8, u8); -#[derive(Copy, Clone)] -struct Comparer { - coef: Vec2, - thr: f32, -} - -impl Comparer { - fn new(a: Vec2, b: Vec2) -> Comparer { - let d = b - a; - let ortho = vec2(-d.y, d.x); - Comparer { - coef: ortho, - thr: dot(a, ortho), - } - } - - fn dist(&self, p: Vec2) -> f32 { - dot(p, self.coef) - self.thr - } - - fn test(&self, p: Vec2) -> bool { - self.dist(p) > 0.0 - } -} - struct Image { w: i32, h: i32, @@ -61,21 +36,6 @@ impl Image { self.data[index + 1] = color.1; self.data[index + 2] = color.2; } - - fn draw_line(&mut self, a: IVec2, b: IVec2, color: Color) {} - fn draw_tri(&mut self, a: Vec2, b: Vec2, c: Vec2, color: Color) { - let u = Comparer::new(a, b); - let v = Comparer::new(b, c); - let w = Comparer::new(c, a); - for y in 0..self.h { - for x in 0..self.w { - let p = vec2(x as f32, y as f32); - if u.test(p) && v.test(p) && w.test(p) || !u.test(p) && !v.test(p) && !w.test(p) { - self.put_pixel(x, y, color); - } - } - } - } } fn main() -> io::Result<()> { From 675d9f837d1753d40f7f259c9b3f93d1629ad4b5 Mon Sep 17 00:00:00 2001 From: numzero Date: Sun, 21 Apr 2024 20:17:58 +0300 Subject: [PATCH 14/25] Extract yaw-pitch-roll processing into a function --- src/main.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2ed15ce..eb0ab86 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,23 @@ impl Image { } } +fn ypr_to_mat(ypr: Vec3) -> Mat3 { + let Vec3 { x: yaw, y: pitch, z: roll } = ypr; + let m_roll = mat3( + roll.cos(), roll.sin(), 0.0, + -roll.sin(), roll.cos(), 0.0, + 0.0, 0.0, 1.0); + let m_yaw = mat3( + yaw.cos(), 0.0, yaw.sin(), + 0.0, 1.0, 0.0, + -yaw.sin(), 0.0, yaw.cos()); + let m_pitch = mat3( + 1.0, 0.0, 0.0, + 0.0, pitch.cos(), -pitch.sin(), + 0.0, pitch.sin(), pitch.cos()); + m_roll * m_pitch * m_yaw +} + fn main() -> io::Result<()> { let args: Vec = env::args().collect(); let mesh = { @@ -50,22 +67,7 @@ fn main() -> io::Result<()> { h: H, data: vec![0; (3 * W * H) as usize], }; - let yaw = PI / 4.0; - let pitch = PI / 6.0; - let roll = 0.0f32; - let m_roll = mat3( - roll.cos(), roll.sin(), 0.0, - -roll.sin(), roll.cos(), 0.0, - 0.0, 0.0, 1.0); - let m_yaw = mat3( - -yaw.cos(), 0.0, yaw.sin(), - 0.0, 1.0, 0.0, - -yaw.sin(), 0.0, -yaw.cos()); - let m_pitch = mat3( - 1.0, 0.0, 0.0, - 0.0, pitch.cos(), pitch.sin(), - 0.0, -pitch.sin(), pitch.cos()); - let m_view = m_roll * m_pitch * m_yaw; + let m_view = ypr_to_mat(vec3(135.0 * PI / 180.0, -30.0 * PI / 180.0, 0.0f32)); let m_camera = transpose(&m_view); let img_size = vec2(W as f32, H as f32); for y in 0..H { From 354135949f4c54ab307da82f4ef0d219a6fb5f9b Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 27 Apr 2024 18:52:15 +0300 Subject: [PATCH 15/25] Show the image in a window --- Cargo.toml | 1 + src/main.rs | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e2a2e19..c06c2b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ edition = "2021" [dependencies] rand = "0.8.5" glm = "0.2.3" +show-image = "0.14.0" diff --git a/src/main.rs b/src/main.rs index eb0ab86..d77e81d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,14 @@ mod mesh_loader; use std::fs::File; -use std::{env, io}; +use std::{env}; +use std::error::Error; use std::f32::consts::PI; -use std::io::{BufRead, BufReader, BufWriter}; +use std::io::{BufRead, BufReader}; use std::io::Write; use rand::Rng; use glm::*; +use show_image::{ImageInfo, ImageView, WindowOptions}; use crate::mesh_loader::load_mesh; const W: i32 = 320; @@ -55,7 +57,8 @@ fn ypr_to_mat(ypr: Vec3) -> Mat3 { m_roll * m_pitch * m_yaw } -fn main() -> io::Result<()> { +#[show_image::main] +fn main() -> Result<(), Box> { let args: Vec = env::args().collect(); let mesh = { let f = File::open(&args[1])?; @@ -107,11 +110,11 @@ fn main() -> io::Result<()> { } } } - let f = File::create("1.ppm")?; - let mut f = BufWriter::new(f); - write!(f, "P6\n")?; - write!(f, "{W} {H} 255\n")?; - f.write(img.data())?; + + let window = show_image::create_window("Raytracing", WindowOptions::default())?; + let image = ImageView::new(ImageInfo::rgb8(W as u32, H as u32), img.data()); + window.set_image("image", image)?; + window.wait_until_destroyed()?; Ok(()) } From be6f8888e0f08f69e3a5bac1157484f4b0464d38 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 27 Apr 2024 18:54:32 +0300 Subject: [PATCH 16/25] =?UTF-8?q?Small=20Fixes=E2=84=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 3 +++ src/main.rs | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c06c2b1..8de0f57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[profile.dev] +opt-level = 3 + [dependencies] rand = "0.8.5" glm = "0.2.3" diff --git a/src/main.rs b/src/main.rs index d77e81d..d745198 100644 --- a/src/main.rs +++ b/src/main.rs @@ -79,8 +79,8 @@ fn main() -> Result<(), Box> { // perspective projection let off = (img_coords - img_size * 0.5) / img_size.y; - let base = vec3(0.0, 0.0, -20.0); - let ray = vec3(off.x, off.y, 1.0); + let base = vec3(0.0, 0.0, -40.0); + let ray = vec3(off.x, off.y, 2.0); // orthographic projection // let off = (img_coords - img_size * 0.5) / SCALE; @@ -94,7 +94,7 @@ fn main() -> Result<(), Box> { for f in &mesh { let color = clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); let fs = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); - if fs.into_iter().all(|f| f > 0.0) { + if fs.into_iter().all(|f| f >= 0.0) { let m = Mat3 { c0: f.vertices[1] - f.vertices[0], c1: f.vertices[2] - f.vertices[0], c2: -ray }; if let Some(m) = m.inverse() { let rel = m * (base - f.vertices[0]); From afc497002353c9069df30c2e6f0700515305e8a8 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 27 Apr 2024 19:28:01 +0300 Subject: [PATCH 17/25] Extract rendering into a function --- src/main.rs | 55 ++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/main.rs b/src/main.rs index d745198..d267182 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use std::io::Write; use rand::Rng; use glm::*; use show_image::{ImageInfo, ImageView, WindowOptions}; -use crate::mesh_loader::load_mesh; +use crate::mesh_loader::{Face, load_mesh}; const W: i32 = 320; const H: i32 = 240; @@ -57,41 +57,20 @@ fn ypr_to_mat(ypr: Vec3) -> Mat3 { m_roll * m_pitch * m_yaw } -#[show_image::main] -fn main() -> Result<(), Box> { - let args: Vec = env::args().collect(); - let mesh = { - let f = File::open(&args[1])?; - let mut f = BufReader::new(f); - load_mesh(&mut f)? - }; +fn render(mesh: &[Face], camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { let mut img = Image { w: W, h: H, data: vec![0; (3 * W * H) as usize], }; - let m_view = ypr_to_mat(vec3(135.0 * PI / 180.0, -30.0 * PI / 180.0, 0.0f32)); - let m_camera = transpose(&m_view); let img_size = vec2(W as f32, H as f32); for y in 0..H { for x in 0..W { - let img_coords: Vec2 = vec2(x as f32, y as f32); - - // perspective projection + let img_coords = vec2(x as f32, y as f32); let off = (img_coords - img_size * 0.5) / img_size.y; - let base = vec3(0.0, 0.0, -40.0); - let ray = vec3(off.x, off.y, 2.0); - - // orthographic projection - // let off = (img_coords - img_size * 0.5) / SCALE; - // let base = vec3(off.x, off.y, -10.0); - // let ray = vec3(0.0, 0.0, 1.0); - - let base = m_camera * base; - let ray = m_camera * normalize(ray); + let (base, ray) = camera(off); let mut dist = f32::INFINITY; - - for f in &mesh { + for f in mesh { let color = clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); let fs = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); if fs.into_iter().all(|f| f >= 0.0) { @@ -110,6 +89,30 @@ fn main() -> Result<(), Box> { } } } + img +} + +#[show_image::main] +fn main() -> Result<(), Box> { + let args: Vec = env::args().collect(); + let mesh = { + let f = File::open(&args[1])?; + let mut f = BufReader::new(f); + load_mesh(&mut f)? + }; + let m_view = ypr_to_mat(vec3(135.0 * PI / 180.0, -30.0 * PI / 180.0, 0.0f32)); + let m_camera = transpose(&m_view); + let img = render(mesh.as_slice(), |off| { + // perspective projection + let base = vec3(0.0, 0.0, -40.0); + let ray = vec3(off.x, off.y, 2.0); + + // orthographic projection + // let base = vec3(off.x, off.y, -10.0); + // let ray = vec3(0.0, 0.0, 1.0); + + (m_camera * base, m_camera * ray) + }); let window = show_image::create_window("Raytracing", WindowOptions::default())?; let image = ImageView::new(ImageInfo::rgb8(W as u32, H as u32), img.data()); From 8a5bce290c093a5c9997cb7bb116602ec852ad00 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 27 Apr 2024 19:59:17 +0300 Subject: [PATCH 18/25] Animate! --- src/main.rs | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index d267182..c58146a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -100,25 +100,27 @@ fn main() -> Result<(), Box> { let mut f = BufReader::new(f); load_mesh(&mut f)? }; - let m_view = ypr_to_mat(vec3(135.0 * PI / 180.0, -30.0 * PI / 180.0, 0.0f32)); - let m_camera = transpose(&m_view); - let img = render(mesh.as_slice(), |off| { - // perspective projection - let base = vec3(0.0, 0.0, -40.0); - let ray = vec3(off.x, off.y, 2.0); - - // orthographic projection - // let base = vec3(off.x, off.y, -10.0); - // let ray = vec3(0.0, 0.0, 1.0); - - (m_camera * base, m_camera * ray) - }); - let window = show_image::create_window("Raytracing", WindowOptions::default())?; - let image = ImageView::new(ImageInfo::rgb8(W as u32, H as u32), img.data()); - window.set_image("image", image)?; - window.wait_until_destroyed()?; - Ok(()) + loop { + for phi in 0..360 { + 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 = transpose(&m_view); + let img = render(mesh.as_slice(), |off| { + // perspective projection + let base = vec3(0.0, 0.0, -40.0); + let ray = vec3(off.x, off.y, 2.0); + + // orthographic projection + // let base = vec3(off.x, off.y, -10.0); + // let ray = vec3(0.0, 0.0, 1.0); + + (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)?; + } + } } fn edge_dist(a: Vec3, b: Vec3, base: Vec3, dir: Vec3) -> f32 { From a59f217b2b7a9be95184900f4f1c15dd7c88f37c Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 27 Apr 2024 20:06:09 +0300 Subject: [PATCH 19/25] Cleanup --- src/main.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index c58146a..f13beb1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,13 @@ use std::fs::File; use std::{env}; use std::error::Error; use std::f32::consts::PI; -use std::io::{BufRead, BufReader}; -use std::io::Write; -use rand::Rng; +use std::io::{BufReader}; use glm::*; use show_image::{ImageInfo, ImageView, WindowOptions}; use crate::mesh_loader::{Face, load_mesh}; const W: i32 = 320; const H: i32 = 240; -const SCALE: f32 = 30.0; #[derive(Copy, Clone)] struct Color(u8, u8, u8); From ea6836901262828beafa27560534e902aada9fd7 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 27 Apr 2024 20:06:27 +0300 Subject: [PATCH 20/25] More concern separation --- src/main.rs | 50 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index f13beb1..bef1f0c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,6 +54,36 @@ fn ypr_to_mat(ypr: Vec3) -> Mat3 { m_roll * m_pitch * m_yaw } +struct TraceResult { + distance: f32, + normal: Vec3, +} + +fn trace_to_mesh(mesh: &[Face], base: Vec3, ray: Vec3) -> Option { + let mut ret: Option = None; + let mut dist = f32::INFINITY; + for f in mesh { + let fs = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); + if fs.into_iter().all(|f| f >= 0.0) { + let m = Mat3 { c0: f.vertices[1] - f.vertices[0], c1: f.vertices[2] - f.vertices[0], c2: -ray }; + if let Some(m) = m.inverse() { + let rel = m * (base - f.vertices[0]); + if rel.z > dist { + continue; + } + dist = rel.z; + ret = Some(TraceResult { + distance: rel.z, + normal: f.normal, + }); + } else { + continue; + } + } + } + ret +} + fn render(mesh: &[Face], camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { let mut img = Image { w: W, @@ -66,23 +96,9 @@ fn render(mesh: &[Face], camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { 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 mut dist = f32::INFINITY; - for f in mesh { - let color = clamp(to_ivec3(f.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); - let fs = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); - if fs.into_iter().all(|f| f >= 0.0) { - let m = Mat3 { c0: f.vertices[1] - f.vertices[0], c1: f.vertices[2] - f.vertices[0], c2: -ray }; - if let Some(m) = m.inverse() { - let rel = m * (base - f.vertices[0]); - if rel.z > dist { - continue; - } - dist = rel.z; - } else { - continue; - } - img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); - } + if let Some(r) = trace_to_mesh(mesh, base, ray) { + let color = clamp(to_ivec3(r.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); + img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); } } } From 5be9b616f21ef43ff62e8a4225e66f689f4b1a02 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 27 Apr 2024 20:17:14 +0300 Subject: [PATCH 21/25] Move color conversion out of color calculation --- src/main.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index bef1f0c..b102f18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,6 +85,7 @@ fn trace_to_mesh(mesh: &[Face], base: Vec3, ray: Vec3) -> Option { } fn render(mesh: &[Face], camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { + let bkg = vec3(0.0, 0.0, 0.0); let mut img = Image { w: W, h: H, @@ -96,10 +97,13 @@ fn render(mesh: &[Face], camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { 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); - if let Some(r) = trace_to_mesh(mesh, base, ray) { - let color = clamp(to_ivec3(r.normal * 120.0 + 128.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); - img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); - } + let color = if let Some(r) = trace_to_mesh(mesh, base, normalize(ray)) { + r.normal * 0.45 + 0.50 + } else { + bkg + }; + let color = clamp(to_ivec3(color * 255.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); + img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); } } img From 83b41f4a65c343bc74e84eb7fdbfebffa6b8e15e Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 2 Jul 2024 11:00:45 +0300 Subject: [PATCH 22/25] Simplify --- src/main.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index b102f18..42c356f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,12 +54,14 @@ fn ypr_to_mat(ypr: Vec3) -> Mat3 { m_roll * m_pitch * m_yaw } +type Mesh = [Face]; + struct TraceResult { distance: f32, normal: Vec3, } -fn trace_to_mesh(mesh: &[Face], base: Vec3, ray: Vec3) -> Option { +fn trace_to_mesh(mesh: &Mesh, base: Vec3, ray: Vec3) -> Option { let mut ret: Option = None; let mut dist = f32::INFINITY; for f in mesh { @@ -84,7 +86,7 @@ fn trace_to_mesh(mesh: &[Face], base: Vec3, ray: Vec3) -> Option { ret } -fn render(mesh: &[Face], camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { +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, @@ -102,7 +104,7 @@ fn render(mesh: &[Face], camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { } else { bkg }; - let color = clamp(to_ivec3(color * 255.0), ivec3(0, 0, 0), ivec3(255, 255, 255)); + let color = clamp_s(to_ivec3(color * 255.0), 0, 255); img.put_pixel(x, y, Color(color.x as u8, color.y as u8, color.z as u8)); } } From 11d2022544c3d0b7511b7625772656e583704e34 Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 2 Jul 2024 11:00:58 +0300 Subject: [PATCH 23/25] WIP --- src/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.rs b/src/main.rs index 42c356f..015845d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,6 +86,11 @@ fn trace_to_mesh(mesh: &Mesh, base: Vec3, ray: Vec3) -> Option { ret } +struct Location { + pos: Vec3, + rot: Vec4, +} + fn render(mesh: &Mesh, camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { let bkg = vec3(0.0, 0.0, 0.0); let mut img = Image { @@ -100,6 +105,7 @@ fn render(mesh: &Mesh, camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { 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, normalize(ray)) { + // to_vec3(0.45) * dot(r.normal, normalize(vec3(-1.0, 1.0, -1.0))) + 0.50 r.normal * 0.45 + 0.50 } else { bkg From 09299b05a4a897a81183575faf6cb0876006de82 Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 2 Jul 2024 11:13:07 +0300 Subject: [PATCH 24/25] Move to subdirs --- spacecraft2.1.obj => models/spacecraft2.1.obj | 0 spacecraft2.2.obj => models/spacecraft2.2.obj | 0 spacecraft2.obj => models/spacecraft2.obj | 0 src/{ => bin/mesh}/main.rs | 0 src/{ => bin/mesh}/mesh_loader.rs | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename spacecraft2.1.obj => models/spacecraft2.1.obj (100%) rename spacecraft2.2.obj => models/spacecraft2.2.obj (100%) rename spacecraft2.obj => models/spacecraft2.obj (100%) rename src/{ => bin/mesh}/main.rs (100%) rename src/{ => bin/mesh}/mesh_loader.rs (100%) diff --git a/spacecraft2.1.obj b/models/spacecraft2.1.obj similarity index 100% rename from spacecraft2.1.obj rename to models/spacecraft2.1.obj diff --git a/spacecraft2.2.obj b/models/spacecraft2.2.obj similarity index 100% rename from spacecraft2.2.obj rename to models/spacecraft2.2.obj diff --git a/spacecraft2.obj b/models/spacecraft2.obj similarity index 100% rename from spacecraft2.obj rename to models/spacecraft2.obj diff --git a/src/main.rs b/src/bin/mesh/main.rs similarity index 100% rename from src/main.rs rename to src/bin/mesh/main.rs diff --git a/src/mesh_loader.rs b/src/bin/mesh/mesh_loader.rs similarity index 100% rename from src/mesh_loader.rs rename to src/bin/mesh/mesh_loader.rs From 97c089a7bc88322f5774bc214935d3845a9d16fd Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 2 Jul 2024 12:00:51 +0300 Subject: [PATCH 25/25] Port to GLAM --- Cargo.toml | 2 +- src/bin/mesh/main.rs | 49 +++++++++++++++++-------------------- src/bin/mesh/mesh_loader.rs | 2 +- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8de0f57..6a1ae01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,5 @@ opt-level = 3 [dependencies] rand = "0.8.5" -glm = "0.2.3" +glam = "0.27.0" show-image = "0.14.0" diff --git a/src/bin/mesh/main.rs b/src/bin/mesh/main.rs index 015845d..04a44d6 100644 --- a/src/bin/mesh/main.rs +++ b/src/bin/mesh/main.rs @@ -5,7 +5,7 @@ use std::{env}; use std::error::Error; use std::f32::consts::PI; use std::io::{BufReader}; -use glm::*; +use glam::*; use show_image::{ImageInfo, ImageView, WindowOptions}; use crate::mesh_loader::{Face, load_mesh}; @@ -40,17 +40,17 @@ impl Image { fn ypr_to_mat(ypr: Vec3) -> Mat3 { let Vec3 { x: yaw, y: pitch, z: roll } = ypr; let m_roll = mat3( - roll.cos(), roll.sin(), 0.0, - -roll.sin(), roll.cos(), 0.0, - 0.0, 0.0, 1.0); + 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( - yaw.cos(), 0.0, yaw.sin(), - 0.0, 1.0, 0.0, - -yaw.sin(), 0.0, yaw.cos()); + 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( - 1.0, 0.0, 0.0, - 0.0, pitch.cos(), -pitch.sin(), - 0.0, pitch.sin(), pitch.cos()); + 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 } @@ -67,20 +67,17 @@ fn trace_to_mesh(mesh: &Mesh, base: Vec3, ray: Vec3) -> Option { for f in mesh { let fs = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray)); if fs.into_iter().all(|f| f >= 0.0) { - let m = Mat3 { c0: f.vertices[1] - f.vertices[0], c1: f.vertices[2] - f.vertices[0], c2: -ray }; - if let Some(m) = m.inverse() { - let rel = m * (base - f.vertices[0]); - if rel.z > dist { - continue; - } - dist = rel.z; - ret = Some(TraceResult { - distance: rel.z, - normal: f.normal, - }); - } else { + let m = mat3(f.vertices[1] - f.vertices[0], f.vertices[2] - f.vertices[0], -ray); + let m = m.inverse(); + let rel = m * (base - f.vertices[0]); + if rel.z > dist { continue; } + dist = rel.z; + ret = Some(TraceResult { + distance: rel.z, + normal: f.normal, + }); } } ret @@ -104,13 +101,13 @@ fn render(mesh: &Mesh, camera: impl Fn(Vec2) -> (Vec3, Vec3)) -> Image { 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, normalize(ray)) { + 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 r.normal * 0.45 + 0.50 } else { bkg }; - let color = clamp_s(to_ivec3(color * 255.0), 0, 255); + 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)); } } @@ -129,7 +126,7 @@ fn main() -> Result<(), Box> { loop { for phi in 0..360 { 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 = transpose(&m_view); + let m_camera = m_view.transpose(); let img = render(mesh.as_slice(), |off| { // perspective projection let base = vec3(0.0, 0.0, -40.0); @@ -150,5 +147,5 @@ fn main() -> Result<(), Box> { fn edge_dist(a: Vec3, b: Vec3, base: Vec3, dir: Vec3) -> f32 { // Note: given that the input is not arbitrary but comes from a cartesian product of certain (a, b) pairs and certain (base, dir) pairs, this can be optimized from Cnm to an+bm+cnm with c