bevy: Coordinate system mismatch between Bevy and glTF

Bevy version

0.8.0

What you did

  1. Spawn entity from glTF scene with recognizable forward direction (e.g. character, vehicle).
  2. Transform the entity along the Transform::forward() direction.
  3. Observe model moving backward.

What you expected

Model moves forward.

What went wrong

Both Bevy and glTF use a right-handed Y-up coordinate system. They do however disagree on what direction is forward and right:

Possible solutions

  1. glTF importer negates X and Z coordinates during import (breaking change for all bevy apps that use glTF import).
  2. Bevy Transform is changed to follow the glTF convention (breaking change for all bevy apps that use one of the Transform’s direction functions).
  3. Bevy stops defining a forward, back, left, right direction and leaves it up to the user (e.g. by changing the forward, back, left, right functions on Transform to local_neg_z, local_z, local_x, local_neg_x).

In any case, Bevy should be consistent regarding its coordinate system. Currently, the look_at function follows the glTF convention and not the Transform’s definition of forward and right (see https://github.com/bevyengine/bevy/issues/1153)

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 4
  • Comments: 17 (15 by maintainers)

Most upvoted comments

We definitely want to honor format intentions to the best of our abilities. If after we resolve the “z-forward” conversation we continue considering z-negative as forward, I think we should add a “flip z axis” setting to the GLTF importer, which defaults to true. (Note that importer settings have been added in my asset system rework, which I’ll be submitting for discussion and review shortly)

I actually prefer proposal 1 over the other two. My reasoning is as follows:

Ideally, the direction that is forward in the modelling application (e.g Blender has a front, top and right view which determine this) is preserved through the asset pipeline (export + possibly some intermediate conversions + import) such that in Bevy Transform::forward() aligns with this direction. Why drop this information somewhere along the way (proposal 3) if you have it and can make use of it.

Therefore for every conversion, when both the previous and the new format have such a convention, the conversion needs to preserve the forward direction (Blender certainly does so for it’s export). This includes the import from a given model format into Bevy. I assume you agree that if Bevy were to support a Z-up file format, the loader should definitely do some coordinate transformation instead of just taking X, Y and Z as is. So it only makes sense for the glTF loader to transform from the glTF convention to the Bevy convention.

The question then is, what the Bevy convention should be. You presented a reason for -Z being forward in Bevy which already matches the current Transform implementation. I don’t think there is any reason to mix conventions when it is avoidable.

Looking at https://github.com/bevyengine/bevy/issues/1153 it might however also require a change to the look_at implementation to be consistent there.

Generally I think it sounds like the proposed preprocessing will provide a really solid catch all for any asset pipeline and would be an upgrade to Unity and Unreal, where often tech artists are writing adhoc equivalents. However, mismatching coord systems is consistently a pain point for artists and non-eng in my experience.

Actually gltf 2.0 has different requirements for assets:

This is a great callout. I see some conflation of the viewer’s space and world space for what the asset coordinate space should be. The biggest pain points in game production for coordinate spaces in my experience (and anybody I’ve talked with in the industry) come from rigged assets, i.e. Root Motion, runtime bone attachment. I understand that there are whole swaths of games that won’t have to deal with these problems, but transforms are typically easier to solve for in those cases. And since there’s a pretty solid standard for rig coordinate spaces across film and games I’d like to see that standard get more direct support in Bevy.

Choosing -z as forward came from the following;

With right handed y-up and x-right, the “default” view (ex: the view in 2d and 3d) points in the negative z direction, with positive z coming out of the screen. In this context, if I move anything in 2d or 3d (a sprite, a 3d model, a UI element) “forward” (relative to the camera view) it is moving in the negative z direction.

This made sense to me. Treating z-positive as forward would mean a “default” camera (standard orthographic projection with identity transform matrix) would be facing “backward”.

But if somebody does a survey of popular right handed y-up software in the gamedev space and finds a reasonably consistent z-positive-is-forward, I’m happy to revisit this. I’d also like to know how they handle default cameras in that context though. (ex: do they spawn them rotated 180 degrees around the y axis? do they just let them face backward by default?)

The convention is that the camera is looking at the front of the asset. And for purpose of viewing and constructing assets this is pretty helpful. For the most part only 1st/3rd person player characters/entities would be accurately represented by a forward facing camera, and even then only by the owning player. For this reason I prefer +z forward.