vpenades / SharpGLTF

glTF reader and writer for .NET Standard
MIT License
457 stars 72 forks source link

Support for animating more than 8 morph targets at once. #99

Closed martoko closed 3 years ago

martoko commented 3 years ago

Face animations are usually driven using up to ~50 morph targets at once.

The current limitation in the API restricts us to only 8, making it impossible to export face animations using this library.

From the library documentation

As an animation key in morph targets; a mesh can have many morph targets, but realistically and due to GPU limitations, only up to 8 morph targets can be blended at the same time.

vpenades commented 3 years ago

SharpGLTF API supports storing as many morph targets as you want in the glTF document, you can create a glTF with 2000 morph targets if you wish.

The maximum number of morph targets refers to the number of simultanous morph targets you can blend at the same time, for example:

Morph Target Indices = { 8, 35, 56, 57, 58, 120, 156, 201 }

Which is 8 out of 2000.

Notice that this is done at runtime. If you have a game engine that needs to blend more than 8 morph targets, most probably it will choose the 8 morph targets with the largest weight and discard the rest.

For a more detailed explanation, here's the Khronos glTF specification on morph targets:

Implementation note: The number of morph targets is not limited in glTF. A conformant client implementation must support at least eight morphed attributes. This means that it has to support at least eight morph targets that contain a POSITION attribute, or four morph targets that contain a POSITION and a NORMAL attribute, or two morph targets that contain POSITION, NORMAL and TANGENT attributes. For assets that contain a higher number of morphed attributes, renderers may choose to either fully support them (for example, by performing the morph computations in software), or to only use the eight attributes of the morph targets with the highest weights.

martoko commented 3 years ago

The khronos specification states a minimum of eight, not a max.

I managed to get something working with the attached patch. Add_support_for_animating_more_morph_targets_at_once.txt

I would be more than willing to clean up my code and do a proper pull request if you want.

Also most players actually support blending more than eight morph target at once. Examples include the windows 3d previewer and babylon.js

vpenades commented 3 years ago

Let me review the issue; this kind of changes usually requires changing more code in different places to ensure that 8+ weights pass through all the API without being trimmed down to 8

vpenades commented 3 years ago

@martoko Sorry for the long delay, but it took me a while to do a complete review.

You were right in that this is supported by glTF, but in order to support it, I've had to do a lot more changes than what I expected initially.

Given that animations are used in three different scopes: Schema2, Toolkit and Runtime, I had to write not only the code that supports and blends more than 8 morph targets, but also new curve conversions between the different scopes. Also, in the Toolkit and Runtime namespace I was using SparseWeight8 so I had to add an alternative way to set more than 8 weights, which also has to be a struct. So I chose ArraySegment<float> as the alternate struct.

You can find most of the code changes in this commit.

And also there's a unit test showcasing blending 16 morph targets simultaneously here.

I am not completely satisfied with all the code required to support this feature; Right now I am maintaining two different curve architectures, with several specialised type implementions.... it's just too much code, so if at some point I find a better way to handle all these use cases, I might redesign some underlaying APIs, hopefully without affecting (too much) the surface API.

Let me know if you can try it and it solves your problem.

vpenades commented 3 years ago

Fixed in Alpha0023 package.