Skip to content

Commit 5145c0b

Browse files
authoredAug 13, 2021
Schweeble/4 (#13)
* WIP * Camera models loading into view * cargofmt fix * Caste usize to u32 for face_indices * Changed where caste takes place
1 parent f9ca907 commit 5145c0b

File tree

9 files changed

+257
-35
lines changed

9 files changed

+257
-35
lines changed
 

‎Cargo.lock

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ structopt = "0.3.22"
2323
eyre = "0.6.5"
2424
log = "0.4.14"
2525
image = "0.23.14"
26+
itertools = "0.10.1"
2627

2728
[profile.release]
2829
opt-level = 2 # fast and small wasm

‎icon.jpg

9.78 KB
Loading

‎src/face.rs

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use wgpu::{
2+
util::DeviceExt, Buffer, Device, PipelineLayout, RenderPipeline, ShaderModule,
3+
SwapChainDescriptor,
4+
};
5+
6+
use crate::{import::PlyData, state::Vertex};
7+
8+
#[derive(Debug)]
9+
pub struct Face {
10+
pub vertex_index: Vec<i32>,
11+
}
12+
13+
pub struct FaceState {
14+
pub pipeline: RenderPipeline,
15+
pub vertex_buffer: Buffer,
16+
pub index_buffer: Buffer,
17+
pub num_indices: u32,
18+
}
19+
20+
impl FaceState {
21+
pub fn new(
22+
sc_desc: &SwapChainDescriptor,
23+
device: &Device,
24+
render_pipeline_layout: &PipelineLayout,
25+
point_shader: &ShaderModule,
26+
) -> Self {
27+
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
28+
label: Some("Face Render Pipeline"),
29+
layout: Some(render_pipeline_layout),
30+
vertex: wgpu::VertexState {
31+
module: point_shader,
32+
entry_point: "vs_main",
33+
buffers: &[Vertex::desc()],
34+
},
35+
fragment: Some(wgpu::FragmentState {
36+
module: point_shader,
37+
entry_point: "fs_main",
38+
targets: &[sc_desc.format.into()],
39+
}),
40+
primitive: wgpu::PrimitiveState {
41+
topology: wgpu::PrimitiveTopology::TriangleList,
42+
polygon_mode: wgpu::PolygonMode::Line,
43+
..Default::default()
44+
},
45+
depth_stencil: None,
46+
multisample: wgpu::MultisampleState::default(),
47+
});
48+
49+
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
50+
label: Some("Face Vertex Buffer"),
51+
contents: bytemuck::cast_slice(&[Vertex {
52+
position: [0.0, 0.0, 0.0],
53+
color: [0.0, 0.0, 0.0],
54+
}]),
55+
usage: wgpu::BufferUsage::VERTEX,
56+
});
57+
58+
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
59+
label: Some("Face Index Buffer"),
60+
contents: &[],
61+
usage: wgpu::BufferUsage::INDEX,
62+
});
63+
let num_indices = 0;
64+
Self {
65+
vertex_buffer,
66+
index_buffer,
67+
num_indices,
68+
pipeline,
69+
}
70+
}
71+
72+
pub fn import_faces(&mut self, device: &Device, ply: &PlyData) {
73+
self.vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
74+
label: Some("Face Vertex Buffer"),
75+
contents: bytemuck::cast_slice(&ply.face_vertices),
76+
usage: wgpu::BufferUsage::VERTEX,
77+
});
78+
self.num_indices = ply.face_indices.len() as u32;
79+
self.index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
80+
label: Some("Face Index Buffer"),
81+
contents: bytemuck::cast_slice(&ply.face_indices),
82+
usage: wgpu::BufferUsage::INDEX,
83+
});
84+
}
85+
}

‎src/import.rs

+80-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1+
use crate::{face::Face, state::Vertex};
12
use eyre::{eyre, Result};
2-
use std::path::Path;
3-
4-
use crate::state::Vertex;
3+
use itertools::Itertools;
54
use nalgebra::{distance, Point3, Vector3};
65
use ply_rs::{parser::Parser, ply};
6+
use std::{collections::HashMap, path::Path};
77

88
pub enum Import {
9-
Ply(Vec<Vertex>),
9+
Ply(PlyData),
1010
Image(image::DynamicImage),
1111
}
1212

13+
pub struct PlyData {
14+
pub point_vertices: Vec<Vertex>,
15+
pub face_vertices: Vec<Vertex>,
16+
pub face_indices: Vec<u32>,
17+
}
18+
1319
pub fn import(path: &Path) -> Result<Import> {
1420
let f = std::fs::File::open(path).unwrap();
1521
let mut buf_read = std::io::BufReader::new(f);
@@ -21,17 +27,69 @@ pub fn import(path: &Path) -> Result<Import> {
2127
match extension {
2228
"ply" => {
2329
let vertex_parser = Parser::<Vertex>::new();
30+
let face_parser = Parser::<Face>::new();
2431
let header = vertex_parser.read_header(&mut buf_read)?;
2532

26-
let mut vertex_list = Vec::new();
33+
let mut all_vertices = Vec::new();
34+
let mut faces = Vec::new();
2735

2836
for (_, element) in &header.elements {
2937
if element.name == "vertex" {
30-
vertex_list =
38+
all_vertices =
3139
vertex_parser.read_payload_for_element(&mut buf_read, element, &header)?;
3240
}
41+
if element.name == "face" {
42+
faces =
43+
face_parser.read_payload_for_element(&mut buf_read, element, &header)?;
44+
}
45+
}
46+
47+
// maps from ply vertex indices to face vertex indices
48+
let mut all_vertices_to_face_vertices = HashMap::new();
49+
let mut face_vertices = Vec::new();
50+
let mut face_indices = Vec::new();
51+
// looks up face vertex index or creates face vertex for ply vertex
52+
let mut get_or_insert_vertex = |index| {
53+
*all_vertices_to_face_vertices
54+
.entry(index)
55+
.or_insert_with(|| {
56+
let pos = face_vertices.len() as u32;
57+
face_vertices.push(all_vertices[index]);
58+
pos
59+
})
60+
};
61+
// tesselate faces
62+
for face in faces {
63+
// turns ply vertices into face vertices
64+
let mut face_iter = face
65+
.vertex_index
66+
.iter()
67+
.map(|&i| get_or_insert_vertex(i as usize));
68+
// first vertex is center of triangle fan and first vertex
69+
// of all triangles
70+
if let Some(first) = face_iter.next() {
71+
for (second, third) in face_iter.tuple_windows() {
72+
// each set of 2 indicies is a new triangle in the triangle fan.
73+
face_indices.extend_from_slice(&[first, second, third]);
74+
}
75+
}
3376
}
34-
Ok(Import::Ply(vertex_list))
77+
78+
// set of vertices that do not corrispond to faces.
79+
let point_vertices = all_vertices
80+
.iter()
81+
.enumerate()
82+
.filter(|(i, _)| !all_vertices_to_face_vertices.contains_key(i))
83+
.map(|(_, &v)| v)
84+
.collect_vec();
85+
86+
let ply_data = PlyData {
87+
point_vertices,
88+
face_vertices,
89+
face_indices,
90+
};
91+
92+
Ok(Import::Ply(ply_data))
3593
}
3694
"png" | "jpg" | "jpeg" => {
3795
// let img = image::load_from_memory(buf_read)?;
@@ -69,6 +127,21 @@ impl ply::PropertyAccess for Vertex {
69127
}
70128
}
71129

130+
impl ply::PropertyAccess for Face {
131+
fn new() -> Self {
132+
Face {
133+
vertex_index: Vec::new(),
134+
}
135+
}
136+
137+
fn set_property(&mut self, key: String, property: ply::Property) {
138+
match (key.as_ref(), property) {
139+
("vertex_index", ply::Property::ListInt(vec)) => self.vertex_index = vec,
140+
(k, _) => panic!("Face: Unexpected key/value combination: key: {}", k),
141+
}
142+
}
143+
}
144+
72145
/// Calculates the average position of all vertices provided in the list
73146
pub fn avg_vertex_position(vertices: &[Vertex]) -> Point3<f32> {
74147
let mut center = Point3::<f64>::new(0.0, 0.0, 0.0);

‎src/main.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![warn(clippy::all, rust_2018_idioms)]
22

33
mod camera;
4+
mod face;
45
mod import;
56
mod interface;
67
mod state;
@@ -71,15 +72,15 @@ fn main() -> Result<()> {
7172
);
7273

7374
if let Some(f) = opt.input_file {
74-
let points = import::import(&f)?;
75-
if let import::Import::Ply(points) = points {
76-
let avg_pos = import::avg_vertex_position(&points);
77-
let avg_dist = import::avg_vertex_distance(avg_pos, &points);
75+
let import = import::import(&f)?;
76+
if let import::Import::Ply(gpu_data) = import {
77+
let avg_pos = import::avg_vertex_position(&gpu_data.point_vertices);
78+
let avg_dist = import::avg_vertex_distance(avg_pos, &gpu_data.point_vertices);
7879

7980
camera.set_camera_facing(avg_pos, avg_dist * 5.0);
8081
app.set_camera_scale(avg_dist);
8182

82-
state.import_vertices(&points);
83+
state.import_ply_data(&gpu_data);
8384
} else {
8485
log::warn!("Ignoring `input_file` option. Can't parse as PLY.");
8586
}
@@ -146,14 +147,18 @@ fn main() -> Result<()> {
146147
WindowEvent::DroppedFile(path) => {
147148
match import::import(path) {
148149
Ok(imported) => match imported {
149-
import::Import::Ply(points) => {
150-
let avg_pos = import::avg_vertex_position(&points);
151-
let avg_dist = import::avg_vertex_distance(avg_pos, &points);
150+
import::Import::Ply(ply_data) => {
151+
let avg_pos =
152+
import::avg_vertex_position(&ply_data.point_vertices);
153+
let avg_dist = import::avg_vertex_distance(
154+
avg_pos,
155+
&ply_data.point_vertices,
156+
);
152157

153158
camera.set_camera_facing(avg_pos, avg_dist * 5.0);
154159
app.set_camera_scale(avg_dist);
155160

156-
state.import_vertices(&points);
161+
state.import_ply_data(&ply_data);
157162
}
158163
import::Import::Image(img) => {
159164
state.import_image(img, &mut app);
File renamed without changes.

‎src/shaders/points.wgsl

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[[block]]
2+
struct Uniforms {
3+
view_proj: mat4x4<f32>;
4+
};
5+
6+
[[group(0), binding(0)]]
7+
var<uniform> uniforms: Uniforms;
8+
9+
struct VertexOutput {
10+
[[builtin(position)]]
11+
out_position: vec4<f32>;
12+
[[location(0)]]
13+
f_color: vec3<f32>;
14+
};
15+
16+
[[stage(vertex)]]
17+
fn vs_main(
18+
[[location(0)]] position: vec3<f32>,
19+
[[location(1)]] color: vec3<f32>,
20+
) -> VertexOutput {
21+
var out: VertexOutput;
22+
out.f_color = color;
23+
out.out_position = uniforms.view_proj * vec4<f32>(position, 1.0);
24+
return out;
25+
}
26+
27+
28+
[[stage(fragment)]]
29+
fn fs_main(
30+
in: VertexOutput
31+
) -> [[location(0)]] vec4<f32> {
32+
return vec4<f32>(in.f_color, 1.0);
33+
}

0 commit comments

Comments
 (0)
Please sign in to comment.