This commit is contained in:
numzero 2024-12-08 02:44:24 +03:00
parent 6b25722627
commit 7c8d67c909
5 changed files with 225 additions and 50 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -1,6 +1,5 @@
# Blender 3.6.5 # Blender 3.6.5
# www.blender.org # www.blender.org
mtllib spacecraft2.mtl
o Cube o Cube
v -1.000000 0.000000 3.000000 v -1.000000 0.000000 3.000000
v -2.000000 0.000000 2.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.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.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 s 0
usemtl Material f 8/1/1 18/2/1 16/3/1
f 8/1/1 18/1/1 16/1/1 f 16/3/2 18/2/2 15/4/2
f 16/1/2 18/1/2 15/1/2 f 18/2/3 19/5/3 15/4/3
f 18/1/3 19/1/3 15/1/3 f 15/4/4 19/5/4 14/6/4
f 15/1/4 19/1/4 14/1/4 f 14/6/5 19/5/5 13/7/5
f 14/1/5 19/1/5 13/1/5 f 13/7/6 19/5/6 12/8/6
f 13/1/6 19/1/6 12/1/6 f 12/8/7 19/5/7 11/9/7
f 12/1/7 19/1/7 11/1/7 f 10/10/8 11/9/8 19/5/8
f 10/1/8 11/1/8 19/1/8 f 20/11/9 18/2/9 17/12/9
f 20/1/9 18/1/9 17/1/9 f 1/13/7 9/14/7 20/11/7
f 1/1/7 9/1/7 20/1/7 f 9/14/10 10/10/10 20/11/10
f 9/1/10 10/1/10 20/1/10 f 20/11/11 10/10/11 19/5/11
f 20/1/11 10/1/11 19/1/11 f 6/15/12 18/2/12 8/1/12
f 6/1/12 18/1/12 8/1/12 f 18/2/13 6/15/13 17/12/13
f 18/1/13 6/1/13 17/1/13 f 6/15/14 7/16/14 17/12/14
f 6/1/14 7/1/14 17/1/14 f 5/17/15 17/12/15 7/16/15
f 5/1/15 17/1/15 7/1/15 f 3/18/7 17/12/7 4/19/7
f 3/1/7 17/1/7 4/1/7 f 4/19/8 17/12/8 5/17/8
f 4/1/8 17/1/8 5/1/8 f 2/20/6 17/12/6 3/18/6
f 2/1/6 17/1/6 3/1/6 f 1/13/16 20/11/16 2/20/16
f 1/1/16 20/1/16 2/1/16 f 17/12/17 2/20/17 20/11/17
f 17/1/17 2/1/17 20/1/17 f 20/11/9 19/5/9 18/2/9
f 20/1/9 19/1/9 18/1/9 f 8/1/18 16/3/18 22/2/18
f 8/1/18 16/1/18 22/1/18 f 16/3/19 15/4/19 22/2/19
f 16/1/19 15/1/19 22/1/19 f 22/2/20 15/4/20 23/5/20
f 22/1/20 15/1/20 23/1/20 f 15/4/21 14/6/21 23/5/21
f 15/1/21 14/1/21 23/1/21 f 14/6/22 13/7/22 23/5/22
f 14/1/22 13/1/22 23/1/22 f 13/7/23 12/8/23 23/5/23
f 13/1/23 12/1/23 23/1/23 f 12/8/24 11/9/24 23/5/24
f 12/1/24 11/1/24 23/1/24 f 10/10/25 23/5/25 11/9/25
f 10/1/25 23/1/25 11/1/25 f 24/11/26 21/12/26 22/2/26
f 24/1/26 21/1/26 22/1/26 f 1/13/24 24/11/24 9/14/24
f 1/1/24 24/1/24 9/1/24 f 9/14/27 24/11/27 10/10/27
f 9/1/27 24/1/27 10/1/27 f 24/11/28 23/5/28 10/10/28
f 24/1/28 23/1/28 10/1/28 f 6/15/29 8/1/29 22/2/29
f 6/1/29 8/1/29 22/1/29 f 22/2/30 21/12/30 6/15/30
f 22/1/30 21/1/30 6/1/30 f 6/15/31 21/12/31 7/16/31
f 6/1/31 21/1/31 7/1/31 f 5/17/32 7/16/32 21/12/32
f 5/1/32 7/1/32 21/1/32 f 3/18/24 4/19/24 21/12/24
f 3/1/24 4/1/24 21/1/24 f 4/19/25 5/17/25 21/12/25
f 4/1/25 5/1/25 21/1/25 f 2/20/23 3/18/23 21/12/23
f 2/1/23 3/1/23 21/1/23 f 1/13/33 2/20/33 24/11/33
f 1/1/33 2/1/33 24/1/33 f 21/12/34 24/11/34 2/20/34
f 21/1/34 24/1/34 2/1/34 f 24/11/26 22/2/26 23/5/26
f 24/1/26 22/1/26 23/1/26

153
src/bin/textured/main.rs Normal file
View File

@ -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<u8>,
}
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<dyn Error>> {
let args: Vec<String> = 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)?;
}
}
}

View File

@ -5,7 +5,7 @@ use std::io;
struct ObjVertex { struct ObjVertex {
vertex: usize, vertex: usize,
normal: usize, normal: usize,
// tex_coord: usize, tex_coord: usize,
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -39,7 +39,7 @@ impl ObjMesh {
assert_eq!(tokens.len(), 3); assert_eq!(tokens.len(), 3);
ObjVertex { ObjVertex {
vertex: tokens[0], vertex: tokens[0],
// tex_coord: tokens[1], tex_coord: tokens[1],
normal: tokens[2], normal: tokens[2],
} }
} }
@ -80,6 +80,7 @@ impl ObjMesh {
.iter() .iter()
.map(|face| Face { .map(|face| Face {
vertices: face.vertices.map(|iv| self.vertices[iv.vertex]), 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], normal: self.normals[face.vertices[0].normal],
}) })
.collect() .collect()
@ -89,6 +90,7 @@ impl ObjMesh {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct Face { pub struct Face {
pub vertices: [Vec3; 3], pub vertices: [Vec3; 3],
pub tex_coords: [Vec2; 3],
pub normal: Vec3, pub normal: Vec3,
} }

View File

@ -1,10 +1,11 @@
use crate::mesh_loader::Face; use crate::mesh_loader::Face;
use glam::{mat3, Vec3}; use glam::{mat3, vec3, Vec2, Vec3};
pub type Mesh = [Face]; pub type Mesh = [Face];
pub struct TraceResult { pub struct TraceResult {
pub distance: f32, pub distance: f32,
pub tex_coords: Vec2,
pub normal: Vec3, pub normal: Vec3,
} }
@ -17,8 +18,10 @@ pub fn trace_to_mesh_all(mesh: &Mesh, base: Vec3, ray: Vec3) -> impl Iterator<It
let m = mat3(f.vertices[1] - f.vertices[0], f.vertices[2] - f.vertices[0], -ray); let m = mat3(f.vertices[1] - f.vertices[0], f.vertices[2] - f.vertices[0], -ray);
let m = m.inverse(); let m = m.inverse();
let rel = m * (base - f.vertices[0]); let rel = m * (base - f.vertices[0]);
let w = vec3(1. - rel.x - rel.y, rel.x, rel.y);
Some(TraceResult { Some(TraceResult {
distance: rel.z, distance: rel.z,
tex_coords: w.x * f.tex_coords[0] + w.y * f.tex_coords[1] + w.z * f.tex_coords[2],
normal: f.normal, normal: f.normal,
}) })
}) })