refraction/src/bin/wireframe/scene.rs

191 lines
4.6 KiB
Rust

use glam::*;
use itertools::chain;
use refraction::ifaces::{DebugTraceable, Traceable};
use refraction::tube::metric::Tube;
use refraction::tube::Space;
use refraction::types::{Location, Object, Ray};
use refraction::utils::put_object;
pub enum Line {
Strip(Vec<Ray>),
Loop(Vec<Ray>),
}
pub struct FancyLine {
pub color: Vec3,
pub pts: Vec<Ray>,
}
pub type Face = (Vec3, Vec3, Vec3);
pub enum Mesh {
List(Vec<Face>),
}
pub struct FancyMesh {
pub color: Vec4,
pub tris: Vec<Face>,
}
fn paint(onto: &mut Vec<FancyLine>, color: Vec3, lines: Vec<Line>) {
onto.extend(lines.into_iter().map(move |line| FancyLine {
color,
pts: match line {
Line::Strip(pts) => pts,
Line::Loop(mut pts) => {
pts.push(*pts.first().unwrap());
pts
}
},
}))
}
fn draw_line(a: Vec3, b: Vec3) -> Line {
let dir = (b - a).normalize();
Line::Strip(vec![Ray { pos: a, dir }, Ray { pos: b, dir }])
}
fn draw_mark(pos: Vec3) -> Vec<Line> {
[
vec3(1., 1., 1.),
vec3(1., 1., -1.),
vec3(1., -1., 1.),
vec3(1., -1., -1.),
]
.into_iter()
.map(|off| draw_line(pos - off, pos + off))
.collect()
}
pub fn build() -> (Vec<FancyMesh>, Vec<FancyLine>) {
let tube = Tube {
inner_radius: 30.0,
outer_radius: 50.0,
internal_halflength: 100.0,
external_halflength: 300.0,
};
let objs: Vec<_> = [-1.25, -1.00, -0.85, -0.50, 0.00, 0.40, 0.70, 0.95, 1.05]
.iter()
.enumerate()
.map(|(k, &y)| Object {
id: k as i32,
loc: put_object(
&tube,
vec3(0.0, y * tube.external_halflength, 0.0),
Mat3::from_mat2(Mat2::from_angle(y)),
),
r: 20.0,
})
.collect();
let space = Space { tube, objs };
let cam1 = put_object(&space.tube, vec3(-500., 0., 0.), Mat3::IDENTITY);
let cam2 = put_object(
&space.tube,
vec3(-2.5 * tube.outer_radius, 1.25 * tube.external_halflength, 0.),
mat3(vec3(1., -1., 0.), vec3(1., 1., 0.), vec3(0., 0., 1.)),
);
let cam2l = put_object(
&space.tube,
vec3(-2.5 * tube.outer_radius, 1.25 * tube.external_halflength, 0.),
mat3(vec3(1., -0.825, 0.), vec3(1., 1., 0.), vec3(0., 0., 1.)),
);
let cam3 = put_object(
&space.tube,
vec3(0.25 * tube.inner_radius, 0.25 * tube.external_halflength, 0.),
mat3(vec3(0., -1., 0.), vec3(1., 0., 0.), vec3(0., 0., 1.)),
);
let mut gc = vec![];
gc.push(FancyMesh {
color: vec4(0.3, 0.5, 1.0, 1.0) * 0.2,
tris: tube.render(),
});
let meshes = gc;
let mut gc = vec![];
paint(&mut gc, vec3(0.0, 0.6, 1.0), draw_fan_2(&space, cam3, vec3(0., 1., 0.)));
paint(&mut gc, vec3(0.2, 1.0, 0.0), draw_fan_2(&space, cam2, vec3(0., 1., 0.)));
paint(
&mut gc,
vec3(0.0, 1.0, 0.6),
draw_fan_2(&space, cam2l, vec3(0., 0., 1.)),
);
paint(&mut gc, vec3(1.0, 0.2, 0.0), draw_fan_2(&space, cam1, vec3(0., 1., 0.)));
let lines = gc;
(meshes, lines)
}
fn draw_ray_2(gc: &mut Vec<Line>, space: &Space, camera: Location, dir: Vec3) {
let pos = vec3(0., 0., 0.);
let (hits, path) = space.trace_dbg(camera, Ray { pos, dir });
if true {
let hits2 = space.trace(camera, Ray { pos, dir });
for (a, b) in hits.iter().zip(hits2.into_iter()) {
assert_eq!(a.id, b.id);
assert_eq!(a.pos, b.pos);
assert_eq!(a.rel, b.rel);
}
}
for hit in hits {
gc.extend(draw_mark(hit.pos));
}
let mut pts = path.points;
let end_pos = *pts.last().expect("the starting point is always in the path");
pts.extend(itertools::iterate(end_pos, |r| r.forward(100.0)).take(1000));
gc.push(Line::Strip(pts));
}
fn draw_fan_2(space: &Space, camera: Location, spread: Vec3) -> Vec<Line> {
let mut gc = vec![];
for δ in itertools_num::linspace(-1., 1., 101) {
draw_ray_2(&mut gc, space, camera, vec3(1., 0., 0.) + δ * spread);
}
gc
}
trait Renderable {
fn render(&self) -> Vec<Face>;
}
impl Renderable for Tube {
fn render(&self) -> Vec<Face> {
let sides = 42;
let step = 2. * std::f32::consts::PI / sides as f32;
let dir = |k| {
let d = Vec2::from_angle(k as f32 * step);
vec3(d.x, 0., d.y)
};
let side = vec3(0., self.external_halflength, 0.);
let r1 = self.inner_radius;
let r2 = self.outer_radius;
let inner = (0..sides).flat_map(|k| {
let a = r1 * dir(k);
let b = r1 * dir(k + 1);
[(a - side, b - side, a + side), (b - side, b + side, a + side)]
});
let outer = (0..sides).flat_map(|k| {
let a = r2 * dir(k);
let b = r2 * dir(k + 1);
[(a - side, b - side, a + side), (b - side, b + side, a + side)]
});
let cap = (0..sides).flat_map(|k| {
let a = r1 * dir(k);
let b = r1 * dir(k + 1);
let c = r2 * dir(k + 1);
let d = r2 * dir(k);
[
(a - side, b - side, c - side),
(a - side, c - side, d - side),
(a + side, b + side, c + side),
(a + side, c + side, d + side),
]
});
chain!(inner, outer, cap).collect()
}
}