Skip to content
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

Fixed root-level game object transforms inside referenced collections when building from the editor #7504

Merged
merged 2 commits into from Mar 24, 2023

Conversation

matgis
Copy link
Contributor

@matgis matgis commented Mar 24, 2023

Fixes #7126.

User-facing changes

  • Fixed root-level game object transforms inside referenced collections when building from the editor

Technical changes

  • Introduced a Pose type in places where it is important to retain position, rotation, and scale properties.
  • We no longer convert position, rotation, and scale into a Matrix4 which we then decompose into position, rotation, and scale later in the build process. Doing so lost information and resulted in transforms that differ from how Bob was doing it, which was applying parent transforms to position, rotation, and scale in isolation.

@matgis matgis added bug Something is not working as expected editor Issues related to the Defold editor labels Mar 24, 2023
@matgis matgis requested a review from vlaaad March 24, 2023 13:58
Copy link
Contributor

@vlaaad vlaaad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I have some comments, but it's all optional :)

Comment on lines 30 to 50
(defn- significant-translation? [value]
(if-some [[^double x ^double y ^double z] value]
(not (and (zero? x)
(zero? y)
(zero? z)))
false))

(defn- significant-rotation? [value]
(if-some [[^double x ^double y ^double z ^double w] value]
(not (and (zero? x)
(zero? y)
(zero? z)
(== 1.0 w)))
false))

(defn- significant-scale? [value]
(if-some [[^double x ^double y ^double z] value]
(not (and (== 1.0 x)
(== 1.0 y)
(== 1.0 z)))
false))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the nil check semantically should belong higher up the stack, e.g. in a place where some pose attribute might be nil, we do the check before calling these predicates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I'll fix.

Comment on lines +244 to +248
(defn to-map [^Pose pose translation-key rotation-key scale-key]
{:pre [(pose? pose)]}
{translation-key (.-translation pose)
rotation-key (.-rotation pose)
scale-key (.-scale pose)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should instead change the code that uses to-map to expect :translation/:rotation/:scale keys? I worry that this fn enables us to introduce more inconsistencies in pose-related code. The pose record is already a map...

Or maybe the pose should use names :position/:rotation/:scale3?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These inconsistencies are unfortunately placed upon us by the requirements of the existing file formats. Scale is named :scale3 in collections because we used to have a uniform :scale that was a single float, but for game objects the non-uniform (i.e vector triplet) scale field is simply named :scale. Likewise, the translation field for both game objects and collections are named :position, even though it is in fact a translation along the (possibly rotated and scaled) axes of its parent. It is correctly (in my opinion) named :translation in the protobuf Transform message, which our Pose type use-case mirrors.

I would have preferred to call the Pose record Transform in the editor as well. Unfortunately the term transform is used to refer to Matrix4 values everywhere in the editor, and both the Spine and Rive extensions already rely on the transform output of the base SceneNode they subclass to produce a Matrix4. Maybe we can clean this up in the future, but we'd have to do it onto the dev since it is a breaking change requiring projects to update their library dependencies.

For now, I prefer to do the map conversion like this. In fact nothing outside of the unit tests make assumptions about what the record fields are called, or even that the Pose is represented as a record. If we ever get around to migrating away from javax.vecmath, we might want to represent it differently.

Comment on lines +176 to +178
{:pre [(or (nil? translation) (s/valid? ::translation translation))
(or (nil? rotation) (s/valid? ::rotation rotation))
(or (nil? scale) (s/valid? ::scale scale))]}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should create and prioritize an issue about disabling asserts in production, and going through our asserts to separate dev-time contracts like these from user input validation. The spec library is somewhat slow...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we probably should. Disabling asserts did not seem to make a lot of difference at the time I profiled it, but I've started to add more checks since then.

But I'm not really worried about this particular case, since we only create Pose instances when producing build targets.

Comment on lines +66 to +92
(defn- rotate-vector [[^double vx ^double vy ^double vz] [^double qx ^double qy ^double qz ^double qw]]
(vector-of
:double
(- (+ (* vx qw qw)
(* vy qz qw -2.0)
(* vz qy qw 2.0)
(* vx qx qx)
(* vy qx qy 2.0)
(* vz qx qz 2.0))
(* vx qy qy)
(* vx qz qz))
(- (+ (* vx qx qy 2.0)
(* vy qy qy)
(* vz qy qz 2.0)
(* vx qz qw 2.0)
(* vy qw qw)
(* vz qx qw -2.0))
(* vy qx qx)
(* vy qz qz))
(- (+ (* vx qx qz 2.0)
(* vy qy qz 2.0)
(* vz qz qz)
(* vx qy qw -2.0)
(* vy qx qw 2.0)
(* vz qw qw))
(* vz qx qx)
(* vz qy qy))))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you write it yourself? I don't know how to verify this code...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at a couple of implementations of the formula, inlined a bunch of stuff, and reordered the coefficients in a way that made sense to me in prefix notation. I double-checked the math against both implementations I looked at to make sure I didn't mess it up, so I'm pretty confident it should be correct, but I guess time will tell! 😅

@matgis matgis merged commit 3b75bba into editor-dev Mar 24, 2023
4 checks passed
@matgis matgis deleted the DEFEDIT-7126-rotation-build-fix branch March 24, 2023 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is not working as expected editor Issues related to the Defold editor
Projects
No open projects
Status: Done
Development

Successfully merging this pull request may close these issues.

None yet

2 participants