Comments (17)
A nicer interface might be a flag in the import config. Then the primitive parsing code (user side) would not need to distinguish between 'normal' tangents and mikk_tspace
tangents.
I'm not sure re-indexing is worth the effort at the moment - my guess is that big, complex models where it might make a significant performance difference will usually already have tangents.
from gltf.
Not sure about the import config flag. The specification says the client is required to generate tangents when unavailable and also to support at least two texture co-ordinates, and one vertex color (amongst others.)
Removing the distinction between regular and mikktspace tangents is a good point and would be beneficial to the user. I propose, instead of the idea in the OP, that the primitive automatically generates normals / tangents upon creation, and that process is not configurable by the user.
big, complex models where it might make a significant performance difference will usually already have tangents
Agreed, although it isn't a lot of extra effort regenerating the index list - we can use genmesh::LruIndexer
.
from gltf.
Representing all the different Option<Position>
/ Option<Normal>
/ Option<Tangent>
/ Option<TexCoord>
/ Option<Color>
combinations etc. etc. etc. is becoming increasingly difficult through the type system. Perhaps we should provide a basic vertex type that covers all the mandatory elements (with configurable defaults) and provide a bitflags
type to let the user query what was provided / generated at runtime?
from gltf.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vertex {
position: [f32; 3],
normal: [f32; 3],
tangent: [f32; 4],
tex_coord_0: [f32; 2],
tex_coord_1: [f32; 2],
color_0: [f32; 4],
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SkinData {
joints_0: [u16; 4],
weights_0: [f32; 4],
}
bitflags! {
pub struct Flags: u32 {
const POSITION = 1 << 0;
const NORMAL = 1 << 1;
const TANGENT = 1 << 2;
const TEXCOORD_0 = 1 << 3;
const TEXCOORD_1 = 1 << 4;
const TEXCOORD_N = 1 << 5 | TEXCOORD_0 | TEXCOORD_1;
const COLOR_0 = 1 << 6;
const COLOR_N = 1 << 7 | COLOR_0;
const JOINTS_0 = 1 << 8;
const JOINTS_N = 1 << 9 | JOINTS_N;
const WEIGHTS_0 = 1 << 10;
const WEIGHTS_N = 1 << 11 | WEIGHTS_0;
const EXTRAS = 1 << 12;
const GENERATED_NORMALS = 1 << 13 | NORMAL;
const GENERATED_TANGENTS = 1 << 14 | TANGENT;
}
}
from gltf.
Implementation Note: A node definition does not specify whether the node should be treated as a joint. Client implementations may wish to traverse the skins array first, marking each joint node.
Perhaps we should do this too?
from gltf.
What if we split the primitive iterator into four separate iterators?
/// An `Iterator` that visits the primitives of a mesh.
struct Primitives { ... }
impl Iterator for Primitives {
type Item = (Option<Geometry>, Option<Decoration>, Option<Skinning>, Option<Extras>);
fn next(&mut self) -> Option<Self::Item> {
// If positions are provided, generate normals and tangents (if necessary) and return `Some(Geometry)`.
// If texture co-ordinates or vertex colors are provided, return `Some(Decoration)`.
// If joints and weights are provided, return `Some(Skinning)`.
// If anything else is provided, return `Some(Extras)`.
}
}
from gltf.
-
Geometry
POSITION
NORMAL
-
Coloring
COLOR_0
-
Texturing
TANGENT
N.B.TEXCOORD_0
TEXCOORD_1
-
Skinning
JOINTS_0
WEIGHTS_0
-
Extras
TEXCOORD_N
COLOR_N
JOINTS_N
WEIGHTS_N
_USER_XXX
from gltf.
^^ I very much like this idea.
from gltf.
Draft:
/// Splits the primitive into its four major categories.
///
/// * Where `POSITION` is provided, the function will return
/// `Some(Positioning)` with computed flat normals if `NORMAL`
/// was not provided also.
///
/// * Where `TANGENT` is provided, the function will return
/// `Some(Texturing)` along with any provided texture co-ordinates.
///
/// * Where `TANGENT` is not provided but `TEXCOORD_0` and `POSITION` is,
/// the function will return `Some(Texturing)` with computed tangents
/// along with any provided texture co-ordinates.
///
/// * Where `COLOR_0` is provided, the function will return `Some(Coloring)`
///
/// * Where `JOINTS_0` and `WEIGHTS_0` are provided, the function will return
/// `Some(Skinning)`.
pub fn split(&self) -> (
Option<Positioning>,
Option<Texturing>,
Option<Coloring>,
Option<Skinning>,
) {
let positioning = match (self.positions(), self.normals()) {
(Some(positions), Some(normals)) => {
Some(Positioning {
positions: positions,
normals: normals,
})
},
(Some(positions), None) => {
let normals = unimplemented!(/* generate normals */);
Some(Positioning {
positions: positions,
normals: normals,
})
},
_ => None,
};
let (order, texturing) = match (
positioning.as_ref(),
self.tangents(),
self.tex_coords(0),
) {
(_, Some(tangents), Some(tex_coords_0)) => {
let texturing = Texturing {
tangents: tangents,
tex_coords_0: tex_coords_0,
tex_coords_1: self.tex_coords(1),
};
(Order::Regular, Some(texturing))
},
(Some(positioning), None, Some(tex_coords_0)) => {
let (order, tangents) = unimplemented!(/* generate the tangents */);
let texturing = Texturing {
tangents: tangents,
tex_coords_0: tex_coords_0,
tex_coords_1: self.tex_coords(1),
};
(order, Some(texturing))
},
_ => (Order::Regular, None),
};
let coloring = self.colors(0).map(|colors_0| Coloring { colors_0 });
let skinning = match (self.joints(0), self.weights(0)) {
(Some(joints_0), Some(weights_0)) => {
Some(Skinning {
joints_0,
weights_0,
})
},
_ => None,
};
(positioning, texturing, coloring, skinning)
}
/// Geometry to be rendered with the given material.
#[derive(Clone, Debug)]
pub struct Primitive<'a> {
/// The parent `Mesh` struct.
mesh: &'a Mesh<'a>,
/// The corresponding JSON index.
index: usize,
/// The corresponding JSON struct.
json: &'a json::mesh::Primitive,
/// New: Vertex ordering.
order: Order,
}
/// Defines the vertex ordering of a primitive.
pub enum Order {
/// Begin from vertex 0, increasing one-by-one.
Regular,
/// Custom ordering scheme for when mikktspace shuffles our nicely ordered data!
Custom(Vec<u32>),
}
from gltf.
I have a type checked prototype available in the mikk-tspace
branch. The code is getting quite a bit more complex.
from gltf.
After some discussion on gitter, the (Positioning, Texturing, Coloring, Skinning)
properties idea has been dropped in favour of a universal ordering type (currently Order
, but naming is subject to change.) A new draft is coming soon.
from gltf.
A new draft is available - see https://github.com/alteous/gltf/blob/mikk-tspace/src/mesh.rs
from gltf.
Nice! Looks good so far and indices_u32()
/tex_coords_f32()
work as expected.
from gltf.
You've probably noticed this already but N.B you'll run into unimplemented!()
if normals or tangents are unavailable.
from gltf.
I'm really struggling to come up with a suitable abstraction for tangent and normal generation. It's quite straightforward to create an abstraction over normal generation or tangent generation, but not both. Even delegating to the user has its set own problems.
from gltf.
I think this should be delegated to the user and documented as such. We could instead provide a reference implementation in the documentation.
from gltf.
Closed since clone of https://github.com/alteous/gltf/issues/22
from gltf.
Related Issues (20)
- Determinism issue when serializing Primitive::attributes HOT 4
- Add examples of how to use with Glium
- Including crate increases build times by an order of magnitude HOT 4
- Hash for gltf::mesh::Mode
- Should `material` and `variants` in `extensions::mesh::Mapping` be `Index` types?
- `Accessor` implementation not conformant with specification HOT 1
- Fails to parse gltf with scenes without nodes
- How to edit contents of gltf? HOT 1
- gltf-derive fails to build with `edition = 2021`
- Publish 1.0.1 HOT 4
- Don't panic on any malformed glTF input HOT 1
- `gltf_json::extensions::material::Volume` produces incorrect null when serialized
- Is this still alive? HOT 2
- Add emissive KHR_material_emissive_strength extension
- Add helper method for converting image format
- image data formats HOT 2
- Consider transitioning `gltf-derive` to use `syn@2` instead of `syn@1` HOT 1
- Add an option to load R, RG, RGB images as RGBA. HOT 2
- Semver violating change in gltf-json v1.2 HOT 3
- Add Animations? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gltf.