Compare commits

..

No commits in common. "c1b505356cd2f425ab1a12bb004eceabb08cb144" and "dbdcdde80d9a1bb5babeea5655821cfc423d3362" have entirely different histories.

5 changed files with 65 additions and 373 deletions

View File

@ -10,7 +10,6 @@ use winit::{
mod camera;
mod lines;
mod meshes;
mod scene;
mod viewport;
@ -19,17 +18,11 @@ mod viewport;
// * Y: left
// * Z: up
fn prepare_scene(device: &wgpu::Device) -> (Vec<meshes::Mesh>, Vec<lines::Line>) {
let (meshes, lines) = scene::build();
let meshes = meshes
.into_iter()
.map(|mesh| meshes::Mesh::new_list(device, meshes::Attrs { color: mesh.color }, mesh.tris))
.collect();
let lines = lines
fn prepare_scene(device: &wgpu::Device) -> Vec<lines::Line> {
scene::build()
.into_iter()
.map(|line| lines::Line::new_strip(device, lines::Attrs { color: line.color }, line.pts))
.collect();
(meshes, lines)
.collect()
}
#[cfg(any())]
@ -167,10 +160,8 @@ struct State<'a> {
cam_loc: camctl::CameraLocation,
cam_obj: camera::Camera,
line_rend: lines::LineRenderer,
mesh_rend: meshes::Renderer,
lines: Vec<lines::Line>,
meshes: Vec<meshes::Mesh>,
scene: Vec<lines::Line>,
window: &'a Window,
}
@ -215,43 +206,17 @@ impl<'a> State<'a> {
let cam_loc = camctl::CameraLocation::new();
let t1 = Instant::now();
let cam_obj = camera::Camera::new(&device);
let line_rend = lines::LineRenderer::new(
&device,
cam_obj.bind_group_layout(),
viewport.format(),
Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24Plus,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::LessEqual,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
wgpu::MultisampleState {
count: viewport.sample_count(),
mask: !0,
alpha_to_coverage_enabled: false,
},
);
let mesh_rend = meshes::Renderer::new(
&device,
cam_obj.bind_group_layout(),
viewport.format(),
Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24Plus,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::LessEqual,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
wgpu::MultisampleState {
count: viewport.sample_count(),
mask: !0,
alpha_to_coverage_enabled: false,
},
);
let depth = None;
let msaa = wgpu::MultisampleState {
count: viewport.sample_count(),
mask: !0,
alpha_to_coverage_enabled: false,
};
let (meshes, lines) = prepare_scene(&device);
let cam_obj = camera::Camera::new(&device);
let line_rend = lines::LineRenderer::new(&device, cam_obj.bind_group_layout(), viewport.format(), depth, msaa);
let scene = prepare_scene(&device);
let fps = fps::Counter::new();
@ -260,14 +225,12 @@ impl<'a> State<'a> {
queue,
viewport,
line_rend,
mesh_rend,
kbd,
fps,
cam_loc,
cam_obj,
t1,
lines,
meshes,
scene,
window,
}
}
@ -303,10 +266,8 @@ impl<'a> State<'a> {
.set_title(&format!("Space Refraction ({:.1} FPS)", self.fps.get()));
self.viewport
.render_single_pass(&self.device, &self.queue, |mut render_pass| {
self.mesh_rend
.render(&mut render_pass, self.cam_obj.bind_group(), self.meshes.iter());
self.line_rend
.render(&mut render_pass, self.cam_obj.bind_group(), self.lines.iter());
.render(&mut render_pass, self.cam_obj.bind_group(), self.scene.iter());
})
}
}

View File

@ -1,63 +0,0 @@
struct CameraUniform {
mvp: mat4x4<f32>,
scale: vec2<f32>,
}
@group(0) @binding(0)
var<uniform> camera: CameraUniform;
struct MeshUniform {
color: vec4<f32>,
}
var<push_constant> mesh: MeshUniform;
struct VertexInput {
@location(0) position: vec3<f32>,
@location(1) normal: vec3<f32>,
}
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) vertex_color: vec4<f32>,
}
struct FragmentOutput {
@location(0) color: vec4<f32>,
@builtin(sample_mask) mask: u32,
}
fn hash(key : u32) -> u32 {
var v = key;
v *= 0xb384af1bu;
v ^= v >> 15u;
return v;
}
@vertex
fn vs_main(ver: VertexInput) -> VertexOutput {
var out: VertexOutput;
var light = dot(ver.normal, normalize(vec3(1., 1., 1.)));
light = .7 + .3 * light;
out.vertex_color = vec4(light * mesh.color.xyz, mesh.color.w);
out.clip_position = camera.mvp * vec4(ver.position, 1.);
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> FragmentOutput {
var out: FragmentOutput;
out.color = vec4(in.vertex_color.xyz, 1.);
var x = bitcast<u32>(in.clip_position.x);
var y = bitcast<u32>(in.clip_position.y);
var z = bitcast<u32>(in.clip_position.z);
var alpha = in.vertex_color.w;
var seed = hash(hash(hash(x) ^ y) ^ z);
var mask = 0u;
for (var sample = 0u; sample < 8u; sample++) {
var threshold = f32(hash(seed ^ sample)) / 0x1p32;
if (alpha > threshold) {
mask |= 1u << sample;
}
}
out.mask = mask;
return out;
}

View File

@ -1,168 +0,0 @@
use std::mem;
use bytemuck::{bytes_of, cast_slice, Pod, Zeroable};
use glam::{Vec3, Vec4};
use wgpu::util::DeviceExt as _;
#[repr(C)]
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
struct Vertex {
pub position: [f32; 3],
pub normal: [f32; 3],
}
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
struct PushConsts {
pub color: [f32; 4],
}
#[derive(Copy, Clone)]
pub struct Attrs {
pub color: Vec4,
}
impl Attrs {
fn consts(&self) -> PushConsts {
PushConsts {
color: self.color.to_array(),
}
}
}
pub struct Mesh {
consts: PushConsts,
npoints: u32,
buf: wgpu::Buffer,
}
impl Mesh {
pub fn new_list(device: &wgpu::Device, attrs: Attrs, tris: Vec<(Vec3, Vec3, Vec3)>) -> Self {
let data: Vec<Vertex> = tris
.into_iter()
.flat_map(|(a, b, c)| {
let n = (b - a).cross(c - a).normalize();
[
Vertex {
position: a.into(),
normal: n.into(),
},
Vertex {
position: b.into(),
normal: n.into(),
},
Vertex {
position: c.into(),
normal: n.into(),
},
]
})
.collect();
let buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Mesh Vertex Buffer"),
contents: cast_slice(&data),
usage: wgpu::BufferUsages::VERTEX,
});
Mesh {
consts: attrs.consts(),
npoints: data.len() as u32,
buf,
}
}
}
pub struct Renderer {
pipeline: wgpu::RenderPipeline,
}
static SHADER: &'static str = include_str!("mesh.wgsl");
impl Renderer {
pub fn new(
device: &wgpu::Device,
cam_layout: &wgpu::BindGroupLayout,
target_format: wgpu::TextureFormat,
depth_stencil: Option<wgpu::DepthStencilState>,
multisample: wgpu::MultisampleState,
) -> Renderer {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Mesh Shader"),
source: wgpu::ShaderSource::Wgsl(SHADER.into()),
});
let consts_range = wgpu::PushConstantRange {
stages: wgpu::ShaderStages::VERTEX,
range: 0..mem::size_of::<PushConsts>() as u32,
};
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Mesh RenderPipelineLayout"),
bind_group_layouts: &[cam_layout],
push_constant_ranges: &[consts_range],
});
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Mesh RenderPipeline"),
layout: Some(&layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[wgpu::VertexBufferLayout {
array_stride: mem::size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
offset: mem::offset_of!(Vertex, position) as u64,
shader_location: 0,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: mem::offset_of!(Vertex, normal) as u64,
shader_location: 1,
format: wgpu::VertexFormat::Float32x3,
},
],
}],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent::OVER,
alpha: wgpu::BlendComponent::OVER,
}),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
..Default::default()
},
depth_stencil,
multisample,
multiview: None,
cache: None,
});
Renderer { pipeline }
}
pub fn render<'a>(
&self,
pass: &mut wgpu::RenderPass,
cam_bind: &wgpu::BindGroup,
meshes: impl Iterator<Item = &'a Mesh>,
) {
pass.set_pipeline(&self.pipeline);
pass.set_bind_group(0, cam_bind, &[]);
for mesh in meshes {
pass.set_push_constants(wgpu::ShaderStages::VERTEX, 0, bytes_of(&mesh.consts));
pass.set_vertex_buffer(0, mesh.buf.slice(..));
pass.draw(0..mesh.npoints, 0..1);
}
}
}

View File

@ -1,5 +1,5 @@
use glam::*;
use itertools::chain;
use itertools::{chain, iproduct};
use refraction::ifaces::{DebugTraceable, Traceable};
use refraction::tube::metric::Tube;
@ -17,17 +17,6 @@ pub struct FancyLine {
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,
@ -46,6 +35,29 @@ fn draw_line(a: Vec3, b: Vec3) -> Line {
Line::Strip(vec![Ray { pos: a, dir }, Ray { pos: b, dir }])
}
fn draw_rect(center: Vec3, u: Vec3, v: Vec3) -> Vec<Line> {
let a = center - u - v;
let b = center + u - v;
let c = center + u + v;
let d = center - u + v;
vec![draw_line(a, b), draw_line(b, c), draw_line(c, d), draw_line(d, a)]
}
fn draw_ellipse(center: Vec3, u: Vec3, v: Vec3) -> Line {
let segments = 47;
let step = 2. * std::f32::consts::PI / segments as f32;
Line::Loop(
(0..segments)
.map(|k| k as f32 * step)
.map(Vec2::from_angle)
.map(|d| Ray {
pos: center + d.x * u + d.y * v,
dir: -d.y * u + d.x * v,
})
.collect(),
)
}
fn draw_mark(pos: Vec3) -> Vec<Line> {
[
vec3(1., 1., 1.),
@ -58,7 +70,7 @@ fn draw_mark(pos: Vec3) -> Vec<Line> {
.collect()
}
pub fn build() -> (Vec<FancyMesh>, Vec<FancyLine>) {
pub fn build() -> Vec<FancyLine> {
let tube = Tube {
inner_radius: 30.0,
outer_radius: 50.0,
@ -98,13 +110,7 @@ pub fn build() -> (Vec<FancyMesh>, Vec<FancyLine>) {
);
let mut gc = vec![];
gc.push(FancyMesh {
color: vec4(0.10, 0.12, 0.15, 0.8),
tris: tube.render(),
});
let meshes = gc;
let mut gc = vec![];
paint(&mut gc, vec3(0.6, 0.6, 0.6), tube.render());
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(
@ -113,9 +119,7 @@ pub fn build() -> (Vec<FancyMesh>, Vec<FancyLine>) {
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)
gc
}
fn draw_ray_2(gc: &mut Vec<Line>, space: &Space, camera: Location, dir: Vec3) {
@ -149,42 +153,23 @@ fn draw_fan_2(space: &Space, camera: Location, spread: Vec3) -> Vec<Line> {
}
trait Renderable {
fn render(&self) -> Vec<Face>;
fn render(&self) -> Vec<Line>;
}
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()
fn render(&self) -> Vec<Line> {
let lines = 4;
let step = 2. * std::f32::consts::PI / lines as f32;
let r = 0.5 * (self.outer_radius + self.inner_radius);
let w = 0.5 * (self.outer_radius - self.inner_radius);
let l = vec3(0., self.external_halflength, 0.);
let along = (0..lines)
.map(|k| k as f32 * step)
.map(Vec2::from_angle)
.map(|d| vec3(d.x, 0., d.y))
.flat_map(|d| draw_rect(r * d, w * d, l));
let caps = iproduct!([self.inner_radius, self.outer_radius], [-l, l])
.map(|(r, l)| draw_ellipse(l, vec3(r, 0., 0.), vec3(0., 0., r)));
chain!(along, caps).collect()
}
}

View File

@ -75,7 +75,7 @@ impl<'a> Viewport<'a> {
let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("RenderPass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &self.multisample.color,
view: &self.multisample.view,
resolve_target: Some(&view),
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
@ -87,14 +87,7 @@ impl<'a> Viewport<'a> {
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.multisample.depth,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(1.),
store: wgpu::StoreOp::Discard,
}),
stencil_ops: None,
}),
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
});
@ -106,14 +99,13 @@ impl<'a> Viewport<'a> {
}
struct Multisample {
color: wgpu::TextureView,
depth: wgpu::TextureView,
view: wgpu::TextureView,
}
impl Multisample {
fn new(device: &wgpu::Device, format: wgpu::TextureFormat, size: UVec2, sample_count: u32) -> Multisample {
let color = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Multisample color texture"),
let tex = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Multisample texture"),
size: wgpu::Extent3d {
width: size.x,
height: size.y,
@ -126,22 +118,7 @@ impl Multisample {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let color = color.create_view(&wgpu::TextureViewDescriptor::default());
let depth = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Multisample depth texture"),
size: wgpu::Extent3d {
width: size.x,
height: size.y,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth24Plus,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let depth = depth.create_view(&wgpu::TextureViewDescriptor::default());
Multisample { color, depth }
let view = tex.create_view(&wgpu::TextureViewDescriptor::default());
Multisample { view }
}
}