-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add more examples #14
Comments
Thanks for taking a look and for the feedback! Documentation is certainly lacking. This is largely because Plexus is still a bit of an experiment and is quite far from being ready for production. Many fundamental features are missing and there is still too much churn to make user guides just yet. Documentation will be a major goal before reaching a stable |
Bump! :) Making examples is also eating your own dogfood. From my experience it can help with designing APIs – even if you have to change the example code later. |
Sorry for the radio silence on this. I'm debating using GitHub's wiki feature to write a few minimal examples. In the meantime, have you taken a look at the crate documentation? There are various short examples in the comments. They're very small, but Plexus isn't capable of much just yet and they cover some of the basics of generators, buffers, and meshes. |
Bump. :) P.S.: Happy New Year. |
@virtualritz While waiting for plexus to mature I would recommend taking a look at https://github.com/huxingyi/meshlite Happy New Year ⭐️ |
I'm currently working on a website with a user guide in a separate repository using mkdocs. The user guide is still sparse, but I'm planning on offloading visualizations and more in-depth explanations from the API documentation (i.e., I'm hoping this kind of user guide will be helpful. Once I complete some more features, I hope to add more comprehensive examples to the repository, but there's still a lot to do. :-) |
Could you add an example on how to get index buffers for a mesh that is made of n-gons (with n being non-uniform over the mesh)? I would like to use plexus with my nsi crate to render generative graphs as subdivision surfaces with creases and corners. I need one buffer with face vertex numbers and the index and vertex buffers. The docs mention the latter two but I do not grok how to get the first buffer (number of vertices of each face) from a |
The structure of a To get a Here's an example of a use decorum::R64;
use nalgebra::Point2;
use plexus::buffer::MeshBuffer;
use plexus::prelude::*;
use plexus::primitive::{Tetragon, Trigon};
pub type E2 = Point2<R64>;
let buffer = MeshBuffer::<Polygon<usize>, E2>::from_raw_buffers(
// Index data is composed of `Polygon`s (formed from `Trigon`s and `Tetragon`s).
vec![
Trigon::new(...).into(),
Trigon::new(...).into(),
Tetragon::new(...).into(),
Tetragon::new(...).into(),
],
// Vertex data is composed of `E2`s (positional data).
vec![...],
)
.unwrap();
for polygon in buffer.as_index_slice() {
match *polygon {
Polygon::N3(trigon) => { // Triangle of indices.
let [a, b, c] = trigon.into_array();
...
}
Polygon::N4(tetragon) => { // Quadrilateral of indices.
let [a, b, c, d] = tetragon.into_array();
...
}
}
}
|
That's totally cool for now. I guess this limitation will be lifted at some stage? |
Agreed. |
|
Ohh ... amazing. So is the |
There's no special function; use decorum::R64;
use nalgebra::Point2;
use plexus::buffer::MeshBuffer;
use plexus::prelude::*;
use plexus::primitive::UnboundedPolygon;
pub type E2 = Point2<R64>;
let buffer = MeshBuffer::<UnboundedPolygon<usize>, E2>::from_raw_buffers(
// Index data is composed of arbitrary polygons.
vec![
UnboundedPolygon::try_from_slice(...).unwrap(),
UnboundedPolygon::trigon(...),
UnboundedPolygon::tetragon(...),
...,
],
// Vertex data is composed of `E2`s (positional data).
vec![...],
)
.unwrap();
for polygon in buffer.as_index_slice() {
for index in polygon.as_ref() {
...
}
} It is not possible to Here's an example of collecting into a buffer: type E3 = Point3<R64>;
type IndexPolygon = UnboundedPolygon<usize>;
let buffer: MeshBuffer<IndexPolygon, E3> = Cube::new()
.polygons::<Position<E3>>()
.collect(); Importantly, Of course, this is work in progress, so some of this could change a bit. 😄 |
I tried this to pull a use decorum::R64;
use itertools::Itertools;
use nalgebra::Point3;
use plexus::prelude::*;
use plexus::{buffer::MeshBuffer, graph::MeshGraph, primitive::UnboundedPolygon};
use std::convert::TryFrom;
use tobj::load_obj;
type E3 = Point3<R64>;
let object = tobj::load_obj(
"test.obj", false, // Do not triangulate on import
);
let (models, _) = object.unwrap();
let models: Vec<MeshGraph> = models
.into_iter()
.filter_map(|model| {
let mesh = model.mesh;
let mut end = 0usize;
let buffer = MeshBuffer::<UnboundedPolygon<u32>, E3>::from_raw_buffers(
mesh.num_face_indices
.into_iter()
.filter_map(|face_arity| {
let start = end;
end += face_arity as usize;
UnboundedPolygon::try_from_slice(&mesh.indices[start..end])
})
.collect::<Vec<_>>(),
mesh.positions
.into_iter()
.tuples::<(_, _, _)>()
.map(|p| {
E3::new(
R64::try_from(p.0 as f64).unwrap(),
R64::try_from(p.1 as f64).unwrap(),
R64::try_from(p.2 as f64).unwrap(),
)
})
.collect::<Vec<_>>(),
)
.unwrap();
MeshGraph::try_from(&buffer).ok()
})
.collect(); The I'm building against current |
Ideally I would like to skip the intermediate step of using a |
Interesting, thanks for sharing! At some point I'll try building the code you've shared so I can see what errors you've encountered. Plexus leans heavily toward abstraction and one big downside is that type errors can get gnarly pretty fast. 😞 I've created a (temporary) branch and gist with a working example that loads the Newell teapot from an OBJ file. To accomplish this, OBJ meshes are converted into raw buffers. Because As noted in that code, I encountered an issue while trying this. For that specific model, the resulting |
Was that part of the example fixed in // TODO: This particular model seems to corrupt the resulting graph! The
// arc circulator for a particular vertex never terminates. For
// example, computing the vertex normal hangs. This does not seem
// to happen with other similar models. It sounded to me like while it may work mostly it wouldn't work sometimes. For my application this is a deal breaker. |
Not yet, no. This is one of the next things I'd like to work on once I find the time (probably after shenanigans with stable constant generics).
I only tried this with three OBJ files, so it isn't clear how often this breaks (or why, for that matter). I think this boils down to two broad possibilities: (1) the model data is corrupt or incompatible and this is not detected or (2) there is a bug in |
Cool. I had to implement automatic detection of subdivision surface creases/corners from (discontinuous) per face per vertex normals on indexed meshes yesterday. And that wasn't nearly as much fun as it could have been if I could use Plexus. OpenMesh allows fixing non-manifold topology on-the-fly as a graph is built. This is a nice feature. Wings3D also does this, when importing such geometry. I see three possibilities:
Any user-selectable combination of those three is also nice, ofc. |
FWIW as both a rust noob and geometry noob I couldn't figure out how to use plexus. I looked through the user guide, read through the code for plexus and theon. My current understanding is that to fully benefit from plexus you'd need to implement custom types for it right? It's not a plug/play library? |
Plexus leans pretty heavily toward abstraction and leverages Rust's type system to do so. I would expect that to be a non-trivial barrier to folks that aren't too familiar with Rust (and there's stuff that I think those familiar with Rust would still find a bit gnarly, to be honest). This isn't always great, but my aim has been to provide a sort of middleware that is flexible and composable and, if possible, simplify things later. Sorry that it's been difficult to grok. That all being said, if you have a specific question, then I'm happy to offer my two cents!
Custom types and trait implementations aren't required. I've taken a bit of a hiatus on Plexus and Theon for a while, but if you're willing to use older versions of the supported crates, then all that is needed is to enable the appropriate Cargo features and everythign should Just Work™. For example, if you'd like to use On the other hand, if you'd like to use unsupported types or roll your own, then you'll need to either implement the geometric traits for them in Theon or use functions that are agnostic to geometry and do the computations via ad-hoc user code (generally via functions or closures). For example, rather than using Just for some additional context: Theon is an attempt to provide a set of Euclidean geometry traits that can be implemented throughout the Rust ecosystem. This is sort of the opposite approach from Mint, which provides datagrams and conversions for interopability. That's pretty hard to get right, so I decided to initially provide implementations for third-party crates myself gated by Cargo features so I could develop it freely (as opposed to asking upstream crates to provide an integration). Unfortunately, that's difficult to maintain, so those implementations tend to fall behind. I'm working on splitting Theon into a trait-only crate and a more agile layer on top with geometric structures and algorithms. If and when that lands, it will likely include implementations for much more recent versions of those crates. |
@olson-sean-k are you aware of any third party projects that use plexus and/or theon in the wild whose source is available? Looking at such code is usually my first stop to grok stuff when I use a new crate whose documentation eludes me in some way. |
I'm a Rust n00b but I have 25+ years of experience working with geometry in C/C++ (e.g. using libs like OpenMesh). The reference docs for Plexus are extremely thin even for someone like me. I.e. I have to do a lot of trial and error when using this crate.
It would really be helpful if there were some more examples. Maybe some code that shows how to convert an indexed mesh, loaded e.g. from an OBJ, into a graph and then perform some basic topology modifying operation on it – like collapsing an edge or extruding a face.
The text was updated successfully, but these errors were encountered: