-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Meshes with negative scale transforms are not rendered correctly #4738
Comments
That is likely backface culling which I believe blender has disabled by default while pretty much every game engine has enabled it ny default. |
Exactly that. So unless blender or something else indicates in the glTF that those things need to be rendered double-sided or with front face culling instead, it would have to be fixed up in code. The |
Just to clarify, you both are of the opinion that the asset is incorrect, that it looks correct in blender because blender doesn't back face cull and this is not a bug in bevy? |
I don't know if this was authored in Blender, I imported it to into Blender to examine the node transforms, back face culling was enabled on the tire material. I've inspected this asset in https://gltf-viewer.donmccurdy.com (three.js) and I've imported it into Unreal and Godot, it worked fine in all cases. Unreal and Godot don't support gltf at runtime (Bevy is unusual in this regard) but both have import pipelines that can convert gltf to their native formats. In Unreal's case it only imported the static meshes and materials, not any hierarchy. It imported unique meshes I am not familiar enough with Bevy internals to know what the problem is exactly, but it does seem like Bevy isn't able to handle negative scale gltf nodes correctly. I don't know that this is a render issue, it could be the loading process needs to transform meshes so that they can be rendered correctly. edit1: Godot import workflow docs https://docs.godotengine.org/en/stable/tutorials/assets_pipeline/importing_scenes.html#import-workflows edit2: Unreal imported a copy of each wheel mesh untransformed, so they're all exactly the same mesh but there are 5 of them,.. edit3: https://gltf-viewer.donmccurdy.com uses three.js, no idea what they are doing for culling |
Interesting indeed. I wonder what they all do. Doing anything automatic with front/back face culling based on negative scale feels risky because it could well be that the mesh has negative scale because you’re supposed to be inside it and the negative scale then makes front faces outside the volume of the mesh be front faces inside the volume of the mesh and then flipping that would break such meshes. |
Yeah I'm not sure. I was looking through the Godot importer code, there is a lot of it. Once the scene is imported, I didn't see any way of inspecting it to know if the negative scale was preserved. I think for my use I will split these up into separate meshes and create the hierarchy in code manually, since trying to access the child components of a gltf scene was proving quite difficult. But I think this is pretty common to use negative scale to flip meshes, especially for low poly assets, so it will probably come up again. |
I expect all four wheels are using the same material, and the two wheels with the negative scale are not visible as they are being back-face culled. The way to fix that would be to set the material's cull_mode to Some(Face::Front) as mentioned. However, that would make the right-side non-negative-scale wheels get culled instead. So I think you would have to duplicate the material from the right-side wheels, modify the cull_mode, add this new material asset to the appropriate assets resource to get a new material handle, and then set the material handle component of the left wheels to that. Awkward. Needs more understanding into how other engines manage to handle this without just disabling back face culling. |
In this case I can rotate the wheels instead of reflecting them since they are symmetrical. I found a few suggestions on how to deal with negative scale here https://www.gamedev.net/forums/topic/640616-negative-scaling-flips-face-winding-affects-backface-culling/5045155/. tl;dr:
I suspect this might be an issue in Bevy if I negative scale anything, without needing to go through gltf, I will check that when I have time. |
I applied negative scale to one of the transforms in the
I tried this in the |
My argument so far has been that we can’t absolutely know whether the intention was to use a -1 scale and the thing be viewed from inside its volume with its front faces on the interior, or if like the wheels it is still meant to be viewed from its exterior. That can simply mean that if we detect -1 scaling then we disable face culling for children unless they use -1 scaling again. That could be a simple solution for glTF. It has a performance cost I guess as backfaces won’t be culled, and so I guess rasterisation would happen up to the point of early-z testing at least and hopefully the visible faces were already drawn. But otherwise I guess it would incur an overdraw cost. |
Hi I just found this conversation when I was having this issue in my own renderer (actually not bevy-related). FYI I found out there actually is a correct way to handle this according to the GLTF spec 3.7.4:
https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#indices-and-names So if you want to support this either you can change the winding order / face culling setting when rendering based on the determinant, or create a second set of indices with swapped winding order and choose between those depending on the determinant. |
# Objective according to [khronos](KhronosGroup/glTF#1697), gltf nodes with inverted scales should invert the winding order of the mesh data. this is to allow negative scale to be used for mirrored geometry. ## Solution in the gltf loader, create a separate material with `cull_mode` set to `Face::Front` when the node scale is negative. note/alternatives: this applies for nodes where the scale is negative at gltf import time. that seems like enough for the mentioned use case of mirrored geometry. it doesn't help when scales dynamically go negative at runtime, but you can always set double sided in that case. i don't think there's any practical difference between using front-face culling and setting a clockwise winding order explicitly, but winding order is supported by wgpu so we could add the field to StandardMaterial/StandardMaterialKey and set it directly on the pipeline descriptor if there's a reason to. it wouldn't help with dynamic scale adjustments anyway, and would still require a separate material. fixes #4738, probably fixes #7901. --------- Co-authored-by: François <[email protected]>
# Objective according to [khronos](KhronosGroup/glTF#1697), gltf nodes with inverted scales should invert the winding order of the mesh data. this is to allow negative scale to be used for mirrored geometry. ## Solution in the gltf loader, create a separate material with `cull_mode` set to `Face::Front` when the node scale is negative. note/alternatives: this applies for nodes where the scale is negative at gltf import time. that seems like enough for the mentioned use case of mirrored geometry. it doesn't help when scales dynamically go negative at runtime, but you can always set double sided in that case. i don't think there's any practical difference between using front-face culling and setting a clockwise winding order explicitly, but winding order is supported by wgpu so we could add the field to StandardMaterial/StandardMaterialKey and set it directly on the pipeline descriptor if there's a reason to. it wouldn't help with dynamic scale adjustments anyway, and would still require a separate material. fixes bevyengine#4738, probably fixes bevyengine#7901. --------- Co-authored-by: François <[email protected]>
Bevy version
0.7
Operating system & version
Windows 10
What you did
edit: this was discovered via gltf loading, however a simple way to reproduce it is to modify the
3d_scene
example an apply a negative scale to the cube transform.I downloaded Kenney Car Kit from https://kenney.nl/assets/car-kit and loaded the
Models/GLTF format/suv.glb#Scene0
asset in a bevy project.When examining the vehicle in bevy, the wheels on the left of the car are not visible and the wheel on the back of the car is partially visible.
I opened up this asset in Blender and found that the nodes that we not rendering were using negative scale on the x axis to mirror the wheel.
If you load this asset up in the scene viewer example it is a bit clearer there, the negative scale nodes are rendered, but it looks like back face culling is inverted or something.
What you expected to happen
Negative scaled objects should be rendered correctly.
What actually happened
Negative scaled objects were not rendered correctly.
Additional information
bevy:
blender:
The text was updated successfully, but these errors were encountered: