godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.05k stars 21.18k forks source link

AABB broken on imported meshes with skeletons. #85171

Open viksl opened 11 months ago

viksl commented 11 months ago

Godot version

4.2 RC1

System information

Windows 11 - Vulkan - Nvidia RTX 4070 - intel i5 13600KF

Issue description

As you can see in the images the AABB godot calculates are just broken for various mashes which include a skeleton. This makes it near impossible to work with meshes in the editor since selecting a mesh is based on the AABB (I assume?), for example in the image with the soldier the AABB is so outside the mesh that if you place the soldier on the ground you always select the ground instead and so on.

(the only way is too go through the Scene tab which when working with multiple models is a horrendous workflow)

The test scene includes a blend, gltf (glb), and fbx files. All result in the same issue, the MRP project was made entirely in Blender.

Images from my project: image image

Image from the MRP: image

I've downloaded the windows editor artifact from this PR: https://github.com/godotengine/godot/pull/84451 but the issues where the same as in 4.2 RC1 - I don't know if it's even related to 3D since most of it seems to be 2D but someone suggested it to me.

This is not an issue with only Blender made files, the files in my project were made in Maya, so both editors export various models which have same AABB problems in Godot - probably godot related issue rather than 3D modeling tool I assume. Testing the same files in Unreal Engine works perfectly fine.

Steps to reproduce

  1. Open the MRP
  2. Open the test_aabb.tscn file
  3. Select any of the nodes (TestCube Blend, TestCube2 GLB, Root Scene FBX) (4. for details the nodes are set as editable children so you can go through everything in detail if needed)

Minimal reproduction project

AABBImportTests.zip

EDIT: Also the AABB doesn't seem to be updated correctly during animations, I can provide a short video if anyone wants to see it so let me know :).

clayjohn commented 11 months ago

Related to https://github.com/godotengine/godot/issues/80306. I wonder if the issue is not just FBX files, but rather, files exported from Maya.

viksl commented 11 months ago

@clayjohn I don't think Maya is the issue. The MRP was made in Blender it did not touch Maya at all, same for fbx and gltf both exported straight from Blender so it's not just FBX issue either. I don't have maya on my side only blender but I have purchased models from artists who made them in Maya. So it seems more like both Maya and Blender exports, since these two tools are unrelated I'd guess more likely something on Godot's side? Also I tried dropping the models into Unreal and they work just fine so it again seems more something in Godot?

I can test more but I can't share original models due to its license but the MRP seems to work in this case just fine but feel free to ask me to try anything, I can even build the engine if there's something in particular to test or change in code (if you tell me what :D).

I hope I made my repot clearer this way in case there was some misunderstanding?

EDIT: Also importing the particular FBX into Blender and then exporting it out as gltf (or other formats) results in issues too. One more time, be it original model from Blender, or Maya, or rexports it's broken.

EDIT2: Deleting only the skeleton and keeping the meshes results in correct AABB so it might be something related to skeletons (even skeletons without animations cause issues) perhaps?

In this image I moved the meshes from the skeleton node (which makes the animations no longer work obviously ;)) - the model in the air is the changed one: obrazek Original hierarchy: obrazek After the shift: obrazek

The meshes are rotated for some reason differently when not part of the skeleton, skeleton remained in the orignal position and partially or entirely isn't considered in the AABB calculation. No idea why :-)

Here's how the model looks while dragging it around before I drop it into the scene (releasing the mouse button): obrazek

And here after the drag: obrazek

The position during drag coresponds to the model with correct AABB after I moved the meshes while after the drop it gets rotated.

(All transforms show godot's default values btw)

Is it possible that skeleton and meshes related to it are roatated in different matrix space then how the AABB is calculated?

EDIT3: From this video: https://youtu.be/BzqZIfi1hbI It seems to be pretty clear the bone's properties aren't taken into account (rotating the top bone doesn't seem to have any effect on the AABB)?

Zireael07 commented 11 months ago

I have similar AABB issues with skeletons exported from Blender, so I don't think Maya is a factor

CrayolaEater commented 8 months ago

Did you happen to find a workaround for this? I'm experiencing the same issue for .glb files exported from blender.

viksl commented 8 months ago

No, as far as I can tell there isn't one. It's an issue in godot's internals the transforms are just wrongly applied/calculated when you have skeletons in some situations. Until someone fixes this there's not much you can do.

The only thing you can do for your game is that you can specify a custom AABB so give your characters a rough box shape on your own to at least have semi-decent culling to work, with animations you either just ignore the the parts going out or recalculate it but I'd just ignore it unless you have some animations which push your model far out of that box.

Again this helps in game (not entirely but it's better than nothing ;)) but it doesn't help in the editor at all.

The only reliable solution is to delete the skeleton and not use it :D which I wouldn't really call a solution hehe.

If you come up with something let me know as far as I know as long as you have a model with skeleton no matter which program it is exported from or in which format it can happen and it will at some point happen. (I think there was similar issue in 2d and there was some PR reworking how the box is generated for 2d with skeletons but nothing for 3D as far as I know - well I haven't checked for a while so maybe there's some PR I'm not aware of at this point)

CrayolaEater commented 7 months ago

I found a solution for this. In blender you go in object mode > select the armature > CTRL+A and apply all transforms. Export and re-import in godot and AABB is now properly calculated.

viksl commented 7 months ago

That's not going to work for all models unfortunately. Especially models in FBX format which Blender and many other programs have troubels with so this still needs a solution on the Godot's end.

TheBetaM commented 7 months ago

The skeleton pose doesn't seem to update the AABB of skinned meshes at all (just non-skinned ones), which can be reproduced with the default TubeTrailMesh. aabb_bug

ManasMakde commented 6 months ago

This issue desperately needs to be fixed!

And since the issue I raised was closed I'm posting a makeshift solution here
The code below manually calculates the AABB of a given mesh instance no matter how it's transformed and/or deformed by bones of a Skeleton3D

(Although it feels that there should have been an inbuilt feature for this)

func get_precise_aabb(mesh_instance : MeshInstance3D):

    var skeleton:Skeleton3D = mesh_instance.get_node_or_null(mesh_instance.skeleton)
    var low : Vector3 = Vector3.INF
    var high : Vector3 = -Vector3.INF

    for surface in mesh_instance.mesh.get_surface_count():
        var data := mesh_instance.mesh.surface_get_arrays(surface)
        var vertices:Array = data[Mesh.ARRAY_VERTEX]
        var vert_map := {} # to avoid recalculating

        for vert_idx in len(vertices):
            var vert = vertices[vert_idx]

            if(vert in vert_map):
                continue
            else:
                vert_map[vert]=null

            if(skeleton and mesh_instance.skin):
                var bones:Array = data[Mesh.ARRAY_BONES]
                var weights:Array = data[Mesh.ARRAY_WEIGHTS]
                var bone_count:int = len(weights)/len(vertices)
                var transformed_vert = Vector3.ZERO
                for i in bone_count:
                    var weight = weights[vert_idx * bone_count + i]

                    if(!weight):
                        continue

                    var bone_idx = bones[vert_idx * bone_count + i]
                    var bind_pose = mesh_instance.skin.get_bind_pose(bone_idx)
                    var bone_global_pose = skeleton.get_bone_global_pose(bone_idx)
                    transformed_vert += (bone_global_pose * bind_pose * vert) * weight

                vert = transformed_vert

            vert=mesh_instance.global_transform * vert

            low.x = vert.x if low.x > vert.x else low.x
            high.x = vert.x if vert.x > high.x else high.x

            low.y = vert.y if low.y > vert.y else low.y
            high.y = vert.y if vert.y > high.y else high.y

            low.z = vert.z if low.z > vert.z else low.z
            high.z = vert.z if vert.z > high.z else high.z

    return AABB(low, high - low)

https://github.com/godotengine/godot/assets/73928607/9e53535b-9749-49e5-992c-0fcc0319aa31

The mesh was imported from blender as a .blend file

theraot commented 2 months ago

Perhaps this can allow a cleaner fix, or at least a more elegant workaround: https://github.com/godotengine/godot/pull/85018

smix8 commented 2 months ago

In general to set an appropriated custom AABB for more dynamic and animated objects is an expected step in a game project when new 3d assets are setup. This is also such an ancient discussion since skeleton animations exists and it resurfaces for every single game engine because new people show up that don't know better (yet).

Having the AABB only based on the static mesh is common. For animated meshes other engines either don't care or do it like e.g. Unity only at the asset import stage for the available animations or perma update an asset as if the AABB is inf. Both options are just tradeoffs as they try to solve one issues while adding plenty of others. E.g. if you have 100 animations and a single excotic animation has a very large stage space you now have a performance screwed AABB calculated for 99 other animations.

You can already do that always-update part in Godot when you set the custom aabb to a giant value so it is unlikely to ever be culled.

What imo could be done for skeleton meshes is similar to particles to have a generate AABB function on the MeshInstance3D when it has a skeleton with animation player. That function could run all the available animations on the mesh model as an editor function and sets a custom AABB on this geometry instance.

While this fixes parts of the worst created models and animations it does not fix a lot of other issues as there are just too many permutations possible how vertices can end up outside the AABB and the calculation can not foresee them all. E.g. it falls apart entirely for runtime procedural stuff or animation additive blending or vertex shaders to just name a few and those are all very common in use.

No, recalculating dynamic AABBs for your bones and meshes and blendshapes and animations at runtime while animating is not a solution. Again, there are just too many permutations possible, some stuff is purely gpu visuals and has not even data on the cpu to calculate, and it would waste a hell lot of performance, more than what can be reasonably gained by having a tight AABB.

Just set an appropriated custom AABB that covers the mesh needed stage space and design your animations with culling in mind (if they are not just for cutscenes) is the right way to do this.

Sure with some garbled 3d assets from the internet sometimes one is out of luck but that goes for all faulty created 3d assets, e.g. having the mesh imported face-planted with the wrong axis like in the first image or drastically bone scaled like in the second will give you bad AABBs.

theraot commented 2 months ago

Setting a custom AABB makes sense, but I don't see an option for that import settings, making the process awkward.

I'd argue the advanced import settings dialog should compute an AABB using the default pose automatically, and then go ahead and use it to position the camera correctly.

And no, I don't want Godot to recompute the AABB all the time.