Compare commits
2 Commits
6b25722627
...
2b95e32b13
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b95e32b13 | |||
| 7c8d67c909 |
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -3049,6 +3049,7 @@ dependencies = [
|
|||
"flo_canvas",
|
||||
"flo_draw",
|
||||
"glam 0.27.0",
|
||||
"image",
|
||||
"itertools 0.13.0",
|
||||
"itertools-num",
|
||||
"pollster",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
BIN
models/spacecraft2-shape.png
Normal file
BIN
models/spacecraft2-shape.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
|
|
@ -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
|
||||
|
|
|
|||
BIN
models/spacecraft2.png
Normal file
BIN
models/spacecraft2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
157
src/bin/textured/main.rs
Normal file
157
src/bin/textured/main.rs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
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};
|
||||
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, texture: &RgbImage, 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
|
||||
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
|
||||
};
|
||||
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() != 3 {
|
||||
println!("Usage: {} path/to/model.obj path/to/texture.png", args[0]);
|
||||
exit(1);
|
||||
}
|
||||
let mesh = {
|
||||
let f = File::open(&args[1])?;
|
||||
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 {
|
||||
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(), &texture, |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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<It
|
|||
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]);
|
||||
let w = vec3(1. - rel.x - rel.y, rel.x, rel.y);
|
||||
Some(TraceResult {
|
||||
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,
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user