Closed lexaknyazev closed 7 years ago
Related: #744, CC @mre4ce
From skinning perspective, this means that all primitives
of the same mesh
share the same joints/bones scope (because skin
is defined per-node).
On the other hand, each primitive could have different set of attributes, material
and even use different program.
Was such usage intended?
It's hard to tell "THE" reason for certain decisions. Particularly for me, because I've not been involved in many of the early discussions. So to be taken with a grain of salt:
From looking at the git history, the mesh.primitives
have been there since the beginning of time (~2012). I can't imagine that they have never been questioned before. But during my search, I did not find a clear reason of why they exist at all. They might stem from a time where the mesh
basically contained attribute
objects, and each primitive
combined some of these attributes. But this is just a guess based on the examples in https://github.com/KhronosGroup/glTF/issues/71 . (Obviously, the attribute
objects have been moved up and became accessor
objects)
There are some issues and comments related to the interplay of mesh
/ mesh.primitives
, and skin
. These mainly seem to be about how to cope with the given structures, and less about why they exist (e.g. https://github.com/KhronosGroup/glTF/issues/442). However, one of these issues mentions a few points in https://github.com/KhronosGroup/glTF/issues/100#issuecomment-28130224 that might be relevant here - mainly, the case where a single mesh had to be split into multiple parts due to the 64k indices limit.
So I can't give a profound answer here. I think that at least the 64k-splitting-case may be a justification to have the primitives
. Beyond that, I don't see why they should strictly be necessary, but it's easy to overlook some border case or application pattern that may be a justification for the current state.
the case where a single mesh had to be split into multiple parts due to the 64k indices limit
This sounds reasonable, but I'm sure it doesn't apply anymore. Right now all desktop and almost all mobile WebGL 1.0 implementations support 32-bit indices. I think that mesh.primitives
originates from the lack of universal 32-bit indices support at the time when collada2gltf was written.
What bothers me most is that such layout inevitably complicates state management, in worst case: different attributes layout of primitives of the same mesh - skinning/morphing issues, different drawing modes from different index buffers, different materials - possible program switching, etc.
Of course, runtime could workaround most of that stuff (reorder objects, build caches, etc) but, maybe, we could sacrifice 5% of use cases in favor of simplifying other 95%?
If the only purpose of having several mesh.primitive
s is to allow mesh "splitting" (to workaround indices limit), wouldn't it be better to move material
out of array and require that all primitives must have the same set of attributes (so skinning/morphing would be more predictable)?
Otherwise, I can't see any reason why same mesh parts couldn't be represented as separate "meshes".
Maybe an @fabrobinet may be appropriate, in view of https://github.com/KhronosGroup/glTF/issues/161 , where the concept of accessor
objects was introduced. Again, that was before I started tracking glTF more actively, so just the question: Could it be that the main justifications for having the mesh.primitives
became obsolete when the attribute
objects have been replaced with accessor
objects, but this potential simplification remained unnoticed?
Otherwise, the role of the mesh
now only is that it is used for "grouping" several mesh.primitives
. Considering the questions about skinning that arise from that, a simplification or additional constraints may be reasonable, but I'm still not sure whether I'm overlooking something.
mesh.primitives
is there to allow converters and exporters to preserve their semantic hierarchy of objects in the scene. I definitely questioned it years ago myself and I'm pretty sure it is required if, for example, you want to have a clean conversions from COLLADA.
My 2cents.
In light of these observation, I would suggest the following things.
a. Either remove mesh entirely or maybe add a "groupname" property for nodes. b. If there is interest, create an extension that preserve better topolgy information and per-face attributes to help data exchange for editing application. This would allow lossless conversion between glTF and OBJ, which in turn might help a lot with adoption. Not the conversion OBJ->glTF change entirely mesh topolgy. One way to do this is to look at the RIB API and OpenSubdiv. I plan to support one for our research efforts in yocto_gltf.
This is just me, but since glTF 2 is backward incompatible, trying to simplify some of its indirections might be helpful for adoption.
Looking into this more with @lasalvavida, it is likely that node.meshes
could go from an array to just one property: node.mesh
, or maybe even make it an array of Primitives
(and rename Primitive
to Mesh
, and remove the current Mesh
). Let me confirm with a few more users.
@xelatihy the extension could have potential once someone has the bandwidth to investigate.
Sounds good. I think if Mesh is kept, than an additional extension cab certainly by done to add in topology preseving meshes and subdivs.
From offline WG discussions:
mesh.primitives
exist to allow having multiple materials per-"object" (this also allows vertex data re-usage), and splitting big meshes for platforms without 32-bit indices.
A node with multiple meshes
could be easily replaced with multiple nodes having the same parent. This should simplify asset loading in general, and especially skinning / morphing bindings.
While re-editing skinning part of specification, I've found that spec requires that node can contain only one skinned mesh, however number of
mesh.primitives
isn't limited.So the question is, why exactly do we have two ways of specifying the same geometry layout?
and
CC @pjcozzi @tparisi @javagl