Skip to content
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

Export Vertex Groups #1232

Open
canadaduane opened this issue Oct 5, 2020 · 29 comments
Open

Export Vertex Groups #1232

canadaduane opened this issue Oct 5, 2020 · 29 comments
Labels
enhancement New feature or request

Comments

@canadaduane
Copy link

canadaduane commented Oct 5, 2020

Is your feature request related to a problem? Please describe.
In a three.js game, we would like to be able to tell the "hair vertices" from the "skin vertices" of an avatar (as well as clothing, shoes, etc.) so that we can modify the colors of the vertices in-game. To accomplish this, we'd like to be able to see the vertex groups as they exist in Blender; however, it appears vertex groups are not currently exported.

Describe the solution you'd like
When an object's vertices are grouped via Object Data Properties -> Add Vertex Group, we would like to see these vertex groups in the exported glTF file:

image

Describe alternatives you've considered
Multiple UV maps. Dead end due to the way three.js uses UV maps.

Additional context
This file has a vertex group called "vertexgroup" and when exported as a glTF, the vertex group is not present:

vertexgroup.blend.zip

@scurest
Copy link
Contributor

scurest commented Oct 6, 2020

How do you want to see it in the glTF?

@canadaduane
Copy link
Author

I'm open to just about anything, but one way that seems congruent with a previous blender/three.js exporter is to export as an array attribute:

https://github.com/repsac/io_three/blob/56b2f35b7d56aab6df131c7a3aecb43cda915ca3/addons/io_three/exporter/geometry.py#L409

(extra_vertex_groups defined here: https://github.com/repsac/io_three/blob/master/addons/io_three/exporter/api/mesh.py#L182)

(See also a long ago discussion at https://stackoverflow.com/questions/38451346/blender-buffergeometry-access-vertices-from-vertex-group)

It was a long time ago though (5 years). Does that seem reasonable today?

@scurest
Copy link
Contributor

scurest commented Oct 6, 2020

This branch should export a SCALAR attribute array for every non-skinning vertex group.

@canadaduane
Copy link
Author

Wow, that was quick! I'm unfamiliar with testing glTF-Blender-IO but I will give it a shot and report back. Thanks!

@canadaduane
Copy link
Author

canadaduane commented Oct 6, 2020

Thanks again for this addition @scurest!

After looking at the output, I think the export could be used in its current state. However, is it exporting data in a format that uses more memory than it needs to?

For example, here is a blender file with two exported vertex groups. Each vertex group is comprised of 4 selected vertices (at least, visually in Blender) so I would expect to see 4 vertices * 3 dimensions = 12 values in each group. On the output, however, there are 24 data points, which matches the total number of vertices in the mesh (8 vertices * 3 dimensions = 24).
twovertexgroups.blend.zip

Here, I'm using Don McCurdy's gltfviewer to see the glTF, with the JS console open on the right showing "_group" (the first vertex group). Vertices in this group are highlighted RED:
gltf-export1

Here is the second vertex group, "_group2", also with vertices highlighted RED:
gltf-export2

It looks like there is redundant data in three ways:

  1. It appears we're using a Float32Array for what amounts to binary set inclusion: 0s for "not in the vertex group" and 1s for "in the vertex group".
  2. The set inclusivity data (binary 1 or 0) is repeated for each XYZ dimension.
  3. The entire mesh's vertices are being mapped--could we perhaps employ just a list of indices of vertices in the group? This would amount to 4 data points in my case.

Would it make sense to compress this data/remove redundancies in some way?

@scurest
Copy link
Contributor

scurest commented Oct 6, 2020

could we perhaps employ just a list of indices of vertices in the group

There's nothing like that in glTF but you can modify the exporter to stuff the indices into extensions/extras or something.

@canadaduane
Copy link
Author

There's nothing like that in glTF but you can modifier the exporter to stuff the indices into extensions/extras or something.

Ok, well, I think it would be more useful to people if it's more or less the "standard" way.

What do you think about reducing redundant data (numbers 1 and 2 in the list above)?

Thanks again for your help--I wouldn't have known where to even start :)

@scurest
Copy link
Contributor

scurest commented Oct 6, 2020

As long as the data is stored as an attribute array, I think it's already as small as possible based on the fact all attribute arrays in a primitive have to have to same count, and the elements must align to four byte values.

re 1: The _Group array contains the weight each vertex was assigned in Group, so it isn't just set inclusion. But even if you wanted to store something smaller than a float, the alignment requirements (accessor.byteOffset and bufferView.byteStride must be multiples of 4) make it so you'd have to pad to 4 bytes anyway.

re 2: I don't understand what you mean by "repeated for each XYZ dimension". If you mean there are 24 vertices in glTF, rather than the 8 you see in Blender, that's because we need three verts (with three different normals) for each single corner of the cube. If you turn off export of normals/UVs you'll get the same 8 verts as Blender. It doesn't have anything to do with vertex groups.

@canadaduane
Copy link
Author

I see. Thank you for the clarifications! It looks like it's working as intended & to spec.

@donmccurdy
Copy link
Contributor

donmccurdy commented Oct 8, 2020

@scurest am I understanding correctly that if the mesh has three vertex groups, A, B, and C, each with optional weights, the branch would write custom vertex attributes to the mesh named _A, _B, and _C, each with values derived from the weights (or zero if the vertex is not in that group)? If so, then for my $0.02, I closed #807 because I thought the approach you've taken here would be better, but I never found time to implement it.

I think it should probably be behind an export option, but would you want to open a PR?

@scurest
Copy link
Contributor

scurest commented Oct 8, 2020

@donmccurdy That's correct. I'm not interested in doing a PR for this.

@julienduroure julienduroure added the enhancement New feature or request label Oct 13, 2020
@Queatz
Copy link

Queatz commented Jan 2, 2021

Looking for this!

@donmccurdy
Copy link
Contributor

@Queatz could you say a bit more about how you'd like to use vertex groups in an exported glTF? Other software does not have a concept of vertex groups, and the only concrete proposal here is #1232 (comment), which would preserve the weights from vertex groups, but not really preserve the groups themselves.

@Queatz
Copy link

Queatz commented Jan 9, 2021

@donmccurdy I want to use Vertex Groups to paint where grass will be spawned on my terrain. I ended up making it work using Vertex Colors, however it would still be nice to be able to use Vertex Groups since that's how it's normally done (in Blender at least.)

@donmccurdy
Copy link
Contributor

Ok, thanks — I believe @scurest's suggestion master...scurest:custom-data would handle that case well.

@scurest
Copy link
Contributor

scurest commented Jan 10, 2021

(Sorta OT)

It occurred to me if the custom data accessors are mostly zero it would be better to write a sparse accessor, so I pushed a commit to the custom-data branch that calculates when a sparse accessor would be smaller and writes that instead. I haven't tested it extensively though.

@canadaduane This can serve as a partial response to your question about "employing just a list of indices of vertices in the group".

@canadaduane
Copy link
Author

canadaduane commented Jan 10, 2021 via email

@canadaduane
Copy link
Author

canadaduane commented Mar 12, 2021

I have @donmccurdy's GLTF viewer working with vertex groups:

image

Code at canadaduane/three-gltf-viewer@2735497

This capability is exactly what we were looking for. Thanks @scurest!

@canadaduane
Copy link
Author

@scurest I'm curious how difficult it would be to export Face Maps as well. I recently learned about this feature (Blender 2.8+, apparently). It's even more ideal than vertex groups for our use case, since it means we would not need to double up on certain vertices to get a "clean edge" when coloring based on vertex.

@scurest
Copy link
Contributor

scurest commented Mar 13, 2021

Here is a branch that should export facemaps.

  • For the purpose of exporting a vertex attribute, the facemap index is turned from a property of polys to a property of their corners: the corner of a face assigned to the ith facemap is assigned i. Then it's treated like any other per-corner data (UVs, vertex colors, normals).
  • Meshes with facemaps will have a _FACEMAPS attribute (scalar, float32) in glTF, holding the facemap index or -1 for "not assigned to any facemap".
  • Nodes have an extras property face_maps holding an array of the facemap names. (Note that this is stored on the glTF node, not the glTF mesh. That's because the names are also stored on the Blender object, not the Blender mesh.)

@canadaduane
Copy link
Author

canadaduane commented Mar 13, 2021

Thanks @scurest! I combined both of your excellent contributions, so that one may export both vertex groups & facemaps if desired:

https://github.com/canadaduane/glTF-Blender-IO/tree/custom-data

NOTE: I changed the _FACEMAPS attribute to FACEMAPS so that the underscore prefix can continue to have special meaning, i.e. to flag mesh attributes as named vertex groups.

@scurest
Copy link
Contributor

scurest commented Mar 13, 2021

I changed the _FACEMAPS attribute to FACEMAPS so that the underscore prefix can continue to have special meaning, i.e. to flag mesh attributes as named vertex groups.

The underscore is because the spec requires that "application-specific semantics must start with an underscore, e.g., _TEMPERATURE". The validator will reject an attribute named FACEMAPS.

@canadaduane
Copy link
Author

canadaduane commented Mar 13, 2021 via email

@canadaduane
Copy link
Author

I added the _vg_* prefix and restored the _ prefix to _facemaps. (Thanks!)

@fknfilewalker
Copy link

are there plans to merge this into the official exporter?

@donmccurdy
Copy link
Contributor

We'd be happy to review PRs for either Face Maps or Vertex Groups — ideally with added unit tests since this is a less common case and it would be easy to miss regressions.

@julienduroure
Copy link
Collaborator

Facemaps are now longer part of Blender (removed for 4.0)
See https://projects.blender.org/blender/blender/commit/46cf09327001331c77bcd54ceab73404a1733172

@globglob3D
Copy link

+1 for vertex group export.
We need a way to tag parts of a mesh in a Blender for later manipulation in threejs. This would open a lot of possibilities for parametric modeling and is less cumbersome than a full armature rig.

If not vertex groups then having the ability to export custom attributes on mesh components would be great. But I guess that can already be done with vertex color?

@canadaduane
Copy link
Author

It can be done with vertex color, if you don't care about coloring vertices :) In our case (Relm) we wanted both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants