vpenades / SharpGLTF

glTF reader and writer for .NET Standard
MIT License
470 stars 75 forks source link

Morphing support in MeshBuilder #9

Closed vpenades closed 4 years ago

vpenades commented 5 years ago

I've been considering different options to provide morphing support for MeshBuilder... adding support for morphing targets would add a lot of complexity to the API and to the underlaying code, and I am not sure if it's worth the burden, given that morphing is a feature that is rearely used.

Also, MeshBuilder is designed to play nice with gltf, by creating strided vertex buffers from the very beginning.

But, in gltf, I think the vertex buffers layout is slightly different than standard stride when morphing is supported.

So, given these contraints, I believe the best approach would be to create a new class called MeshBuilderMorphModifier that would encapsulate static MeshBuilders, adding the extra methods for morphing.

Additionally, a CreateMorphableMeshes would be required to fill them in the destination model. this would allow to create separate vertex buffers for the geometry fragments.

BlockBuilder57 commented 5 years ago

Hi! I use SharpGLTF to export game character models, and implementing morphing would be a great help to me in regards to facial flexes. My current method of exporting relies on creating new meshes for each morph target, but natively support morphing would remove the need for that and allow me to bring morphs wherever they need be. While I don't technically need it, having it would be a big help and reduce the hassle of having to apply morphs by hand.

If you would like my assistance in testing, I would be glad to help. Otherwise, I hope you can figure out a good solution to this issue that doesn't cause much development stress. Thank you for reading.

vpenades commented 5 years ago

Hi

It will take a while until I face the morphing issue, since I still have to figure out how to solve several problems.

One of them is how to arrange the vertex attributes; by default, sharpGLTF stores all vertex buffers in interleaved mode, so the GPU only needs to bind a single vertex buffer and a single index buffer to render the geometry. Historically this has always been the most optimized way to store a vertex buffer, although I have seen some debate about it recently. Furthermore, if you use the CreateMeshes(*) method, it creates a single vertex and index buffer for all meshes, which helps reducing the number of GPU command calls.

Vertex Buffers with morph targets are a different story. I asked around about how actual 3D engines handle morphing at the GPU level, and I always get the answer, which is:

Morph targets are binded as vertex attributes and interpolated by the vertex shader

But that would mean that 2 or 3 morph targets would be allowed, since there's a maximum limit of 16 attributes per vertex, and that's not realistic, since gltf does not impose a maximum number of morph targets; I've been told there's gltf around with more than 100 morph targets.

So when meshes use morph targets, it seems a different kind of attribute and vertex buffers layout is required, but haven't figured out yet the optimal layout that would make most engines happy.

vpenades commented 5 years ago

@BlockBuilder57 The morph targets building API is nearly finished and will be available in the next package release.

Morph targets are quite tricky to implement because MeshBuilder might split a given vertex multiple times if the vertex is used inside multiple primitives, (for example a vertex in a materials boundary).

Also, MeshBuilder is a last stage utility class and it doesn't calculate normals and tangents by itself, so if a mesh has normals and tangents, you must also provide normals and tangents for the morpth targets too!

BlockBuilder57 commented 5 years ago

Oh, awesome! That's exactly what I wanted to hear, actually! I have normals for each morph already queued up. I don't know if Blender actually supports per-morph normals yet, but once the API is finished I will implement it in my tool and let you how it works and report any bugs I find. Again, let me know if there's anything I can do to assist in testing.

Thanks for implementing this!

vpenades commented 4 years ago

@BlockBuilder57 morph support has been added to Alpha-12 which has just been published.

Now you can add morph targets to a mesh builder, see example here.

BlockBuilder57 commented 4 years ago

Hi again, been working on my tool some more and just got morphs working, but so far I've been unable to find a way to add names to the morph targets. I'm guessing this something that's already in and I'm completely glossing over, so I'm just adding another comment to this to avoid another issue. If it's not, I can go ahead and make a new issue.

vpenades commented 4 years ago

Hi!

As far as I know, there is no standard way of setting morph target names.

This is also being discussed here: https://github.com/KhronosGroup/glTF/issues/1036