Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ If you want to use the original C++ implementation from Rust, check out the [mes

## Features

`meshoptimizer` v0.18 feature level is the current support target. Planned but currently missing features:
`meshoptimizer` v0.20 feature level is the current support target. Planned but currently missing features:
- [SIMD support](https://github.com/yzsolt/meshopt-rs/issues/1)
- [WASM support](https://github.com/yzsolt/meshopt-rs/issues/2)

Expand Down
12 changes: 6 additions & 6 deletions benches/with_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use meshopt_rs::index::generator::{
use meshopt_rs::index::sequence::{decode_index_sequence, encode_index_sequence, encode_index_sequence_bound};
use meshopt_rs::overdraw::optimize_overdraw;
use meshopt_rs::stripify::{stripify, stripify_bound};
use meshopt_rs::vertex::Position;
use meshopt_rs::vertex::Vertex;
use meshopt_rs::vertex::cache::{optimize_vertex_cache, optimize_vertex_cache_fifo, optimize_vertex_cache_strip};
use meshopt_rs::vertex::fetch::{optimize_vertex_fetch, optimize_vertex_fetch_remap};

Expand All @@ -19,21 +19,21 @@ use std::path::Path;

#[derive(Clone, Copy, Default)]
#[repr(C)]
struct Vertex {
struct BenchVertex {
p: [f32; 3],
n: [f32; 3],
t: [f32; 2],
}

impl Position for Vertex {
impl Vertex for BenchVertex {
fn pos(&self) -> [f32; 3] {
self.p
}
}

#[derive(Clone, Default)]
struct Mesh {
vertices: Vec<Vertex>,
vertices: Vec<BenchVertex>,
indices: Vec<u32>,
}

Expand Down Expand Up @@ -61,7 +61,7 @@ impl Mesh {
indices.extend_from_slice(&mesh.indices);

for i in 0..mesh.indices.len() {
let mut vertex = Vertex::default();
let mut vertex = BenchVertex::default();

let pi = mesh.indices[i] as usize;
vertex.p.copy_from_slice(&mesh.positions[3 * pi..3 * (pi + 1)]);
Expand Down Expand Up @@ -89,7 +89,7 @@ impl Mesh {

result.indices = remap;

result.vertices.resize(total_vertices, Vertex::default());
result.vertices.truncate(total_vertices);
remap_vertex_buffer(&mut result.vertices, &vertices, &result.indices);

Ok(result)
Expand Down
14 changes: 7 additions & 7 deletions bin/codec_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use meshopt_rs::index::IndexEncodingVersion;
use meshopt_rs::index::buffer::{decode_index_buffer, encode_index_buffer, encode_index_buffer_bound};
use meshopt_rs::vertex::Position;
use meshopt_rs::vertex::Vertex;
use meshopt_rs::vertex::VertexEncodingVersion;
use meshopt_rs::vertex::buffer::{decode_vertex_buffer, encode_vertex_buffer, encode_vertex_buffer_bound};
use meshopt_rs::vertex::cache::{optimize_vertex_cache, optimize_vertex_cache_strip};
Expand All @@ -12,11 +12,11 @@ use std::time::Instant;

#[derive(Clone, Copy, Default)]
#[repr(C)]
struct Vertex {
struct BenchVertex {
data: [u16; 16],
}

impl Position for Vertex {
impl Vertex for BenchVertex {
fn pos(&self) -> [f32; 3] {
let get_f32 = |start: usize| {
let a = self.data[start].to_le_bytes();
Expand All @@ -38,11 +38,11 @@ fn murmur3(mut h: u32) -> u32 {
h
}

fn bench_codecs(vertices: &[Vertex], indices: &[u32], bestvd: &mut f64, bestid: &mut f64, verbose: bool) {
let mut vb = vec![Vertex::default(); vertices.len()];
fn bench_codecs(vertices: &[BenchVertex], indices: &[u32], bestvd: &mut f64, bestid: &mut f64, verbose: bool) {
let mut vb = vec![BenchVertex::default(); vertices.len()];
let mut ib = vec![0u32; indices.len()];

let mut vc = vec![0u8; encode_vertex_buffer_bound(vertices.len(), std::mem::size_of::<Vertex>())];
let mut vc = vec![0u8; encode_vertex_buffer_bound(vertices.len(), std::mem::size_of::<BenchVertex>())];
let mut ic = vec![0u8; encode_index_buffer_bound(indices.len(), vertices.len())];

if verbose {
Expand Down Expand Up @@ -203,7 +203,7 @@ fn main() {

for x in 0..=N {
for y in 0..=N {
let mut v = Vertex::default();
let mut v = BenchVertex::default();

for k in 0..16 {
let h = murmur3((x * (N + 1) + y) * 16 + k);
Expand Down
116 changes: 83 additions & 33 deletions examples/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@ use meshopt_rs::index::*;
use meshopt_rs::overdraw::*;
use meshopt_rs::quantize::*;
use meshopt_rs::simplify::*;
use meshopt_rs::spatial_order::*;
use meshopt_rs::stripify::*;
use meshopt_rs::vertex::buffer::*;
use meshopt_rs::vertex::cache::*;
use meshopt_rs::vertex::fetch::*;
use meshopt_rs::vertex::*;
use meshopt_rs::{INVALID_INDEX, Stream};

#[cfg(feature = "experimental")]
use meshopt_rs::spatial_order::*;

use std::env;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
Expand All @@ -26,41 +24,51 @@ use std::time::Instant;

#[derive(Clone, Copy, Default, Debug)]
#[repr(C)]
struct Vertex {
struct DemoVertex {
p: [f32; 3],
n: [f32; 3],
t: [f32; 2],
}

impl Vertex {
impl DemoVertex {
fn as_bytes(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts((self as *const Self) as *const u8, std::mem::size_of::<Self>()) }
}
}

impl Hash for Vertex {
impl Hash for DemoVertex {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(self.as_bytes());
}
}

impl PartialEq for Vertex {
impl PartialEq for DemoVertex {
fn eq(&self, other: &Self) -> bool {
self.as_bytes() == other.as_bytes()
}
}

impl Eq for Vertex {}
impl Eq for DemoVertex {}

impl Position for Vertex {
impl Vertex<3> for DemoVertex {
fn pos(&self) -> [f32; 3] {
self.p
}

fn attrs(&self) -> [f32; 3] {
self.n
}
}

impl Vertex<0> for DemoVertex {
fn pos(&self) -> [f32; 3] {
self.p
}
}

#[derive(Clone, Default)]
struct Mesh {
vertices: Vec<Vertex>,
vertices: Vec<DemoVertex>,
indices: Vec<u32>,
}

Expand Down Expand Up @@ -90,7 +98,7 @@ impl Mesh {
indices.extend_from_slice(&mesh.indices);

for i in 0..mesh.indices.len() {
let mut vertex = Vertex::default();
let mut vertex = DemoVertex::default();

let pi = mesh.indices[i] as usize;
let ni = mesh.normal_indices[i] as usize;
Expand Down Expand Up @@ -122,7 +130,7 @@ impl Mesh {

result.indices = remap;

result.vertices.resize(total_vertices, Vertex::default());
result.vertices.resize(total_vertices, DemoVertex::default());
remap_vertex_buffer(&mut result.vertices, &vertices, &result.indices);

let indexed = start.elapsed();
Expand All @@ -147,7 +155,7 @@ impl Mesh {
self.indices.iter().all(|i| (*i as usize) < self.vertices.len())
}

fn rotate_triangle(t: &mut [Vertex; 3]) -> bool {
fn rotate_triangle(t: &mut [DemoVertex; 3]) -> bool {
use std::cmp::Ordering;

let c01 = t[0].as_bytes().cmp(t[1].as_bytes());
Expand Down Expand Up @@ -202,7 +210,7 @@ impl Mesh {
// skip degenerate triangles since some algorithms don't preserve them
if Self::rotate_triangle(&mut v) {
let data = unsafe {
std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of::<Vertex>() * v.len())
std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of::<DemoVertex>() * v.len())
};

let hash = Self::hash_range(data);
Expand Down Expand Up @@ -304,7 +312,7 @@ struct PackedVertex {
t: [u16; 2],
}

fn pack_mesh(pv: &mut [PackedVertex], vertices: &[Vertex]) {
fn pack_mesh(pv: &mut [PackedVertex], vertices: &[DemoVertex]) {
for i in 0..vertices.len() {
let vi = vertices[i];
let pvi = &mut pv[i];
Expand Down Expand Up @@ -332,7 +340,7 @@ struct PackedVertexOct {
t: [u16; 2],
}

fn pack_mesh_oct(pv: &mut [PackedVertexOct], vertices: &[Vertex]) {
fn pack_mesh_oct(pv: &mut [PackedVertexOct], vertices: &[DemoVertex]) {
for i in 0..vertices.len() {
let vi = vertices[i];
let pvi = &mut pv[i];
Expand Down Expand Up @@ -378,7 +386,7 @@ where
assert_eq!(mesh.hash(), copy.hash());

let vcs = analyze_vertex_cache(&copy.indices, copy.vertices.len(), CACHE_SIZE, 0, 0);
let vfs = analyze_vertex_fetch(&copy.indices, copy.vertices.len(), std::mem::size_of::<Vertex>());
let vfs = analyze_vertex_fetch(&copy.indices, copy.vertices.len(), std::mem::size_of::<DemoVertex>());
let os = analyze_overdraw(&copy.indices, &copy.vertices);

let vcs_nv = analyze_vertex_cache(&copy.indices, copy.vertices.len(), 32, 32, 32);
Expand Down Expand Up @@ -586,14 +594,10 @@ fn simplify_mesh(mesh: &Mesh) {
);
lod.indices.resize(size, 0);

let size = if lod.indices.len() < mesh.vertices.len() {
lod.indices.len()
} else {
mesh.vertices.len()
};
lod.vertices.resize(size, Vertex::default()); // note: this is just to reduce the cost of relen()
let size = lod.indices.len().min(mesh.vertices.len());
lod.vertices.resize(size, DemoVertex::default()); // note: this is just to reduce the cost of resize()
let size = optimize_vertex_fetch(&mut lod.vertices, &mut lod.indices, &mesh.vertices);
lod.vertices.resize(size, Vertex::default());
lod.vertices.resize(size, DemoVertex::default());

let duration = start.elapsed();

Expand All @@ -607,6 +611,49 @@ fn simplify_mesh(mesh: &Mesh) {
);
}

#[cfg(feature = "experimental")]
fn simplify_attr(mesh: &Mesh, threshold: f32) {
let mut lod = Mesh::default();

let start = Instant::now();

let target_index_count = (mesh.indices.len() as f32 * threshold) as usize;
let target_error = 1e-2;
let mut result_error = 0.0;

const NRM_WEIGHT: f32 = 0.01;
const ATTR_WEIGHTS: [f32; 3] = [NRM_WEIGHT, NRM_WEIGHT, NRM_WEIGHT];

lod.indices.resize(mesh.indices.len(), 0); // note: simplify needs space for index_count elements in the destination array, not target_index_count
let size = simplify_with_attributes::<DemoVertex, 3>(
&mut lod.indices,
&mesh.indices,
&mesh.vertices,
&ATTR_WEIGHTS,
target_index_count,
target_error,
SimplificationOptions::empty(),
Some(&mut result_error),
);
lod.indices.truncate(size);

let size = lod.indices.len().min(mesh.vertices.len());
lod.vertices.resize(size, DemoVertex::default()); // note: this is just to reduce the cost of resize()
let size = optimize_vertex_fetch(&mut lod.vertices, &mut lod.indices, &mesh.vertices);
lod.vertices.truncate(size);

let duration = start.elapsed();

println!(
"{:9}: {} triangles => {} triangles ({:.2}% deviation) in {:.2} msec",
"SimplifyAttr",
mesh.indices.len() / 3,
lod.indices.len() / 3,
result_error * 100.0,
duration.as_micros() as f64 / 1000.0
);
}

#[cfg(feature = "experimental")]
fn simplify_mesh_sloppy(mesh: &Mesh, threshold: f32) {
let mut lod = Mesh::default();
Expand Down Expand Up @@ -658,7 +705,7 @@ fn simplify_mesh_points(mesh: &Mesh, threshold: f32) {
let target_vertex_count = (mesh.vertices.len() as f32 * threshold) as usize;

let mut indices = vec![0; target_vertex_count];
let size = simplify_points(&mut indices, &mesh.vertices, target_vertex_count);
let size = simplify_points(&mut indices, &mesh.vertices, target_vertex_count, 0.0);
indices.resize(size, Default::default());

let duration = start.elapsed();
Expand Down Expand Up @@ -782,7 +829,7 @@ fn simplify_mesh_complete(mesh: &Mesh) {
let vfs_0 = analyze_vertex_fetch(
&indices[offset0..offset0 + lod_index_counts[0]],
vertices.len(),
std::mem::size_of::<Vertex>(),
std::mem::size_of::<DemoVertex>(),
);
let offsetn = lod_index_offsets[LOD_COUNT - 1];
let vcs_n = analyze_vertex_cache(
Expand All @@ -795,7 +842,7 @@ fn simplify_mesh_complete(mesh: &Mesh) {
let vfs_n = analyze_vertex_fetch(
&indices[offsetn..offsetn + lod_index_counts[LOD_COUNT - 1]],
vertices.len(),
std::mem::size_of::<Vertex>(),
std::mem::size_of::<DemoVertex>(),
);

let mut pv = vec![PackedVertexOct::default(); vertices.len()];
Expand Down Expand Up @@ -1057,7 +1104,6 @@ fn meshlets(mesh: &Mesh, scan: bool) {
);
}

#[cfg(feature = "experimental")]
fn spatial_sort_mesh(mesh: &Mesh) {
let mut pv = vec![PackedVertexOct::default(); mesh.vertices.len()];
pack_mesh_oct(&mut pv, &mesh.vertices);
Expand Down Expand Up @@ -1308,17 +1354,21 @@ fn process(mesh: &Mesh) {

#[cfg(feature = "experimental")]
{
simplify_attr(mesh, 0.2);
simplify_mesh_sloppy(mesh, 0.2);
simplify_mesh_complete(mesh);
simplify_mesh_points(mesh, 0.2);

spatial_sort_mesh(mesh);
spatial_sort_mesh_triangles(mesh);
}

spatial_sort_mesh(mesh);

#[cfg(feature = "experimental")]
spatial_sort_mesh_triangles(mesh);
}

fn process_dev(mesh: &Mesh) {
meshlets(mesh, false);
fn process_dev(#[allow(unused)] mesh: &Mesh) {
#[cfg(feature = "experimental")]
simplify_attr(mesh, 0.2);
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand Down
Loading