-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
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
FBXLoader morphAttributes.position[n].count is less than attributes.position.count #28378
Comments
|
@RemusMar thanks for feedback. For this mesh the count 86082 is for In Blender they are equal: (the base and the shoulder.L variant ) I mean it makes sense to be equal since they have to be interpolated vertex by vertex. This one to one relation I'm also trying to apply when selecting vertices grouped by group.materialIndex from Am i missing something ? |
@RemusMar from your first answer my understanding of your explanation is that 86082 count represents the total of those 6 parts while 34902 count represents the morph part. To be on the same page regarding what is what for this asset: "https://raw.githubusercontent.com/catalin-enache/threejs-inspector/master/public/models/__free/fbx/Asuna/2/FreeTestAnimations_reexport.fbx".
I updated the fiddle to load both of them (Note: it takes very long to load): If I load them both in Blender they have the same structure (fbx left / gltf right): If I load them in ThreeJS I can observe that: The GLTFLoaderis optimizing the one mesh with 3 materials by creating 3 meshes, one for each material. Each extracted mesh has morph information.
This is as expected to me, a morph array should have the same length as the base from which it derives because they are interleaved one to one for each vertex in the base geometry. The FBXLoadermaintains the original structure as one mesh with 3 materials. but the The same numbers as before 86082 (for base geometry) / 34902 (first morph variant). I believe that in translation from fbx format into Three format the length of morphs has been preserved since most likely the fbx format optimises and gets rid of redundant vertices (those that are not involved in morphing). However, as I @donmccurdy confirmed my expectation here https://discourse.threejs.org/t/how-are-related-morphattributes-position-arrays-to-attributes-position/65533 the final Three format should get back the redundancy making the base shape and any derived morph arrays equal. @donmccurdy can you please add your input here about the expectation that in final Three format, any morph variant array should have the same length as the base geometry from which it derives ? If not, then there should be some mapper in the Three object that should tell us the correspondence between a morph vertex and the base position vertex (so that we can rebuild the morph array to be the same length as the base geometry - adding back redundancies) for scenarios when we want to split the base geometry by material carrying on the morph information along. |
@catalin-enache
good luck |
The fbx exporter used is the one from Blender 4.1. My problem is, how do I carry the morph information (which is less than the base shape) when I want to optimize an initial Three mesh having multiple materials by splitting it into multiple meshes (one for each material). For the base shape it is straight forward. But the same logic cannot be applied to morphs for @RemusMar |
Your problem has nothing to do with three.js My advice to you here: good luck again |
Let's limit the scope of the issue to this: FBXLoader produces a THREE.BufferGeometry instance in which a base attribute has 86,082 vertices, and a morph attribute has 34,902 vertices. We understand why the FBX file format would contain a shorter morphed vertex list — not all vertices are morphed — but I'm not aware that varying attribute lengths is allowed or functional in THREE.BufferGeometry. Is it supported by three.js? If not, then FBXLoader should produce valid THREE.BufferGeometry instances, regardless of the FBX file's internal structure. |
@RemusMar , I'm working an a threejs-inspector app (hobby for the moment, whishing to make it a reliable tool). I see that as a nice to have tool in development when you can play around with properties (by twisting a material value or or object position/rotation), find something you like then burn it in code. It also allows you to import assets into the scene. So,
It is not for nothing if it allows asset optimization on the fly. |
It is not. The count of the morph target buffer attribute must match the count of the target attribute that is going to be morphed. If the morph target attribute is too small, the shader will still try to fetch data for the current |
For testing: https://jsfiddle.net/8p9tyga0/ Noticed how the animation is broken if the morph target buffer is too small. |
I get the same result for
and
So the same result for different morphAttribute lengths. |
The result is platform dependent. That's why I say the data are |
What do I see here (the latest Firefox version) is the same result for different morphAttribute lengths. |
If |
But is it correct to fill it with zeroes ? Shouldn't it be filled with the actual values (redundant values) from the base position ? |
Correct. But the fix must be applied in @RemusMar Are you open for a PR? |
Yes.
LOL |
If in the fiddle example the intended morph attributes would have been like this:
how would one know, at runtime, where should the blanks be filled in ? |
No, that isn't right. If you only want the first two vertices to animate, the subsequent two must have the same value like in the
|
@RemusMar @donmccurdy @Mugen87 , guys, I appreciate a lot the time you spent looking into this and that we come up with a resolution. |
There's also the option of using |
Michael, that's not how Morphing works. |
That's the only correct option here. |
@Mugen87 , you are saying that the morph array in its current form, even if shorter is continuous ? I can assume that all vertices in the morph match one to one with the vertices in the base position ? and what is remaining in the base position is not involved in morph ? If only the last vertex in the base position would need to be morphed then all the previous vertices would be pushed into the morph array even they are redundant ? leading to no possible memory optimisation ? |
Using a different value for
Using zero or the real values from the position attribute has no effect on memory since the underlying buffer will have the same size. |
@donmccurdy , I observed in all imported assets If the asset creator wants it to be absolute (unchecks it), and tweaks the morphs with it unchecked, export the asset like that, I believe it should be treated as such. I believe this option is inferred at asset parsing from the asset file itself, and it makes sense to not be changed after that or it will break how the asset is supposed to look when morphed. Controlling that value without breaking anything I think is only safe if we generate the asset programatically. Of course it could be changed to relative at asset parsing in Three, even it was saved as absolute, but that would imply recalculating the values for all vertices to be indeed relative |
I have a character with 1,000,000 vertices involved in Bones animation and only 1000 of them involved in Morphing (facial animation). |
I think we're overcomplicating this: If FBXLoader produces a BufferGeometry in which attributes and morphAttributes have different lengths, that is a bug. The lengths of the attributes should match, and FBXLoader should do whatever it needs to do, as efficiently as possible, to produce a valid geometry from the PRs for that fix would be welcome, from anyone interested. 🙂
Right, we certainly cannot just change |
I forked that nice fiddle, changing it so that only the last vertex is morphed: |
I'm not very interested in the FBX Loader (I did never use it so far), but I can try to find a few hours this weekend in no one else ... ;) For now this is all I know about this loader: |
I can try but I'm a total outsider. |
In three.js, these lengths must match. The ith base vertex corresponds to the ith morph vertex. The morph attribute must contain an entry for every vertex in the base geometry, redundant or not. |
Thanks Don, this is how they should be which I totally agree. |
To conclude: |
@RemusMar, thanks for the hints. |
Guys, are there already some unit tests for FBX Loader ? I created this PR and I thought maybe to add a test for it but I could't find a place where to add it eventually. The intention for the test would be to commit a small FBX file with partial morphs and inside the test, load it from the disk and check if the base geometry buffer and morph buffer have the same length. I made this fbx asset in Blender The asset was loaded but the morph was not doing anything (as expected since there was nothing in morph array). With the fix it doesn't throw any error and the morph works fine. |
How about enhancing the default FBX example (https://threejs.org/examples/webgl_loader_fbx) with a GUI that allow to select assets for testing? We use this approach in other loaders as well, e.g. https://threejs.org/examples/webgl_loader_3mf You can then add your test file to the repository. That makes it indeed easier to test the changes. |
I pushed a change to https://threejs.org/examples/webgl_loader_fbx along with uploading my morph example asset. |
At this time we don't maintain unit tests for the |
Fixed via #28397. |
Description
Hello,
I'm inspecting this model:
https://raw.githubusercontent.com/catalin-enache/threejs-inspector/master/public/models/__free/fbx/Asuna/2/FreeTestAnimations_reexport.fbx
and I observed thatmorphAttributes.position[n].count
is less thanattributes.position.count
.I have a fiddle here:
https://codesandbox.io/p/sandbox/condescending-swanson-4fypcn?file=%2Fsrc%2Findex.js%3A81%2C4-81%2C142
I'm printing the loaded fbx. Please check the console for these 2 fields in the
AsunaBodyMesh
(the last skinned mesh of the root children).It can be observed that
attributes.position.count
is86082
andmorphAttributes.position[0].count
is34902
.I'm trying to optimize the object by reconstructing new skinned meshes grouped by materialIndex from groups.
I'm extracting slices from attributes , push them into an array for that material then make a new geometry and skinned mesh for that material. I then replace the original mesh with as many meshes as materials the original mesh had.
The problem is that when I try to port the morphAttributes into new skinned meshes, since they have a different count,
I have no ideea how to slice them to match the attributes slices.
I asked here: https://discourse.threejs.org/t/how-are-related-morphattributes-position-arrays-to-attributes-position/65533
maybe my expectation (that the count should be the same between attributes and morphs) is wrong but I understand they should be equal.
Then I thought probably I should raise this issue here.
Reproduction steps
Just load the fbx asset and inspect the result:
morphAttributes.position[n].count
andattributes.position.count
Code
no code required
Live example
https://codesandbox.io/p/sandbox/condescending-swanson-4fypcn?file=%2Fsrc%2Findex.js%3A81%2C4-81%2C142
Screenshots
Provided in description
Version
0.164.1
Device
Desktop
Browser
Edge
OS
MacOS
The text was updated successfully, but these errors were encountered: