Skip to content

Commit

Permalink
Fixed root-level game object transforms inside referenced collections…
Browse files Browse the repository at this point in the history
… when building from the editor (#7504)

* Fix bad rotations that could occur in some situations when building

* Review fixes
  • Loading branch information
matgis committed Mar 24, 2023
1 parent be51bb0 commit 3b75bba
Show file tree
Hide file tree
Showing 11 changed files with 555 additions and 76 deletions.
8 changes: 4 additions & 4 deletions editor/src/clj/editor/camera.clj
Expand Up @@ -473,7 +473,7 @@

(defn find-perspective-frame-distance
^double [points point->coord ^double fov-deg]
(let [^double half-fov-rad (math/deg->rad (* fov-deg 0.5))
(let [half-fov-rad (math/deg->rad (* fov-deg 0.5))
comp-half-fov-rad (- ^double math/half-pi half-fov-rad)
tan-comp-half-fov-rad (Math/tan comp-half-fov-rad)]
(reduce (fn [^double max-distance ^Point3d point]
Expand Down Expand Up @@ -538,7 +538,7 @@
(assert (= :orthographic (:type camera)))
(let [^double fov-x-distance (:fov-x camera)
^double fov-y-distance (:fov-y camera)
^double half-fov-y-rad (math/deg->rad (* fov-y-deg 0.5))
half-fov-y-rad (math/deg->rad (* fov-y-deg 0.5))
aspect (/ fov-x-distance fov-y-distance)
focus-distance (/ fov-y-distance 2.0 (Math/tan half-fov-y-rad))
focus-pos (camera-focus-point camera)
Expand All @@ -559,8 +559,8 @@
focus-distance (.length (math/subtract-vector focus-pos (:position camera)))
^double fov-x-deg (:fov-x camera)
^double fov-y-deg (:fov-y camera)
^double half-fov-x-rad (math/deg->rad (* fov-x-deg 0.5))
^double half-fov-y-rad (math/deg->rad (* fov-y-deg 0.5))
half-fov-x-rad (math/deg->rad (* fov-x-deg 0.5))
half-fov-y-rad (math/deg->rad (* fov-y-deg 0.5))
fov-x-distance (* focus-distance 2.0 (Math/tan half-fov-x-rad))
fov-y-distance (* focus-distance 2.0 (Math/tan half-fov-y-rad))
cam-forward (camera-forward-vector camera)
Expand Down
8 changes: 4 additions & 4 deletions editor/src/clj/editor/collection.clj
Expand Up @@ -177,7 +177,7 @@
:icon ""
:label ""})

(g/defnk produce-go-build-targets [_node-id build-error build-resource ddf-message resource-property-build-targets source-build-targets transform]
(g/defnk produce-go-build-targets [_node-id build-error build-resource ddf-message resource-property-build-targets source-build-targets pose]
;; Create a build-target for the referenced or embedded game object. Also tag
;; on :instance-data with the overrides for this instance. This will later be
;; extracted and compiled into the Collection - the overrides do not end up in
Expand All @@ -195,7 +195,7 @@
(let [game-object-build-target (first source-build-targets)
proj-path->resource-property-build-target (bt/make-proj-path->build-target resource-property-build-targets)
instance-desc-with-go-props (dissoc ddf-message :data)] ; GameObject$InstanceDesc or GameObject$EmbeddedInstanceDesc in map format. We don't need the :data from GameObject$EmbeddedInstanceDesc.
[(collection-common/game-object-instance-build-target build-resource instance-desc-with-go-props transform game-object-build-target proj-path->resource-property-build-target)])))
[(collection-common/game-object-instance-build-target build-resource instance-desc-with-go-props pose game-object-build-target proj-path->resource-property-build-target)])))

(g/defnode GameObjectInstanceNode
(inherits scene/SceneNode)
Expand Down Expand Up @@ -463,7 +463,7 @@
(update res id (fn [id] (inc (or id 0)))))
{} ids))))

(g/defnk produce-coll-inst-build-targets [_node-id source-resource id transform build-targets resource-property-build-targets ddf-properties]
(g/defnk produce-coll-inst-build-targets [_node-id source-resource id pose build-targets resource-property-build-targets ddf-properties]
(if-some [errors
(not-empty
(concat
Expand All @@ -476,7 +476,7 @@
(let [proj-path->resource-property-build-target (bt/make-proj-path->build-target resource-property-build-targets)]
(update build-targets 0
(fn [collection-build-target]
(collection-common/collection-instance-build-target id transform ddf-properties collection-build-target proj-path->resource-property-build-target))))))
(collection-common/collection-instance-build-target id pose ddf-properties collection-build-target proj-path->resource-property-build-target))))))

(g/defnk produce-coll-inst-outline [_node-id id source-outline source-resource]
(-> {:node-id _node-id
Expand Down
41 changes: 17 additions & 24 deletions editor/src/clj/editor/collection_common.clj
Expand Up @@ -18,7 +18,7 @@
[editor.game-object-common :as game-object-common]
[editor.geom :as geom]
[editor.gl.pass :as pass]
[editor.math :as math]
[editor.pose :as pose]
[editor.properties :as properties]
[editor.protobuf :as protobuf]
[editor.resource :as resource]
Expand All @@ -29,7 +29,7 @@
[service.log :as log])
(:import [com.dynamo.gameobject.proto GameObject$CollectionDesc GameObject$PrototypeDesc]
[java.io StringReader]
[javax.vecmath Matrix4d Point3d Quat4d Vector3d]))
[javax.vecmath Matrix4d]))

(set! *warn-on-reflection* true)

Expand Down Expand Up @@ -119,11 +119,11 @@
nil))))
(:embedded-instances source-value))))))

(defn game-object-instance-build-target [build-resource instance-desc-with-go-props ^Matrix4d transform-matrix game-object-build-target proj-path->resource-property-build-target]
(defn game-object-instance-build-target [build-resource instance-desc-with-go-props pose game-object-build-target proj-path->resource-property-build-target]
{:pre [(workspace/build-resource? build-resource)
(map? instance-desc-with-go-props) ; GameObject$InstanceDesc or GameObject$EmbeddedInstanceDesc in map format, but GameObject$PropertyDescs must have a :clj-value.
(not (contains? instance-desc-with-go-props :data)) ; We don't need the :data from GameObject$EmbeddedInstanceDescs.
(instance? Matrix4d transform-matrix)
(pose/pose? pose)
(map? game-object-build-target)
(ifn? proj-path->resource-property-build-target)]}
;; Create a build-target for the referenced or embedded game object. Also tag
Expand Down Expand Up @@ -151,7 +151,7 @@
(util/distinct-by (comp resource/proj-path :resource)))
component-property-infos)
game-object-instance-data {:resource build-resource
:transform transform-matrix
:pose pose
:property-deps go-prop-dep-build-targets
:instance-msg (if (seq component-property-descs)
(assoc instance-desc-with-go-props :component-properties component-property-descs)
Expand All @@ -173,8 +173,8 @@
(vals)
(vec)))

(defn- flatten-game-object-instance-data [game-object-instance-data collection-instance-id ^Matrix4d collection-instance-transform child-game-object-instance-id? game-object-instance-id->component-property-descs proj-path->resource-property-build-target]
(let [{:keys [resource instance-msg ^Matrix4d transform]} game-object-instance-data
(defn- flatten-game-object-instance-data [game-object-instance-data collection-instance-id collection-instance-pose child-game-object-instance-id? game-object-instance-id->component-property-descs proj-path->resource-property-build-target]
(let [{:keys [resource instance-msg pose]} game-object-instance-data
{:keys [id children component-properties]} instance-msg
build-target-go-props (partial properties/build-target-go-props proj-path->resource-property-build-target)
component-properties (map source-resource-component-property-desc component-properties)
Expand All @@ -191,18 +191,17 @@
instance-msg {:id (str collection-instance-id path-sep id)
:children (mapv #(str collection-instance-id path-sep %) children)
:component-properties component-property-descs}
transform (if (child-game-object-instance-id? id)
transform
(doto (Matrix4d. collection-instance-transform)
(.mul transform)))]
pose (if (child-game-object-instance-id? id)
pose
(pose/pre-multiply pose collection-instance-pose))]
{:resource resource
:instance-msg instance-msg
:transform transform
:pose pose
:property-deps go-prop-dep-build-targets}))

(defn collection-instance-build-target [collection-instance-id ^Matrix4d transform-matrix instance-property-descs collection-build-target proj-path->resource-property-build-target]
(defn collection-instance-build-target [collection-instance-id pose instance-property-descs collection-build-target proj-path->resource-property-build-target]
{:pre [(string? collection-instance-id)
(instance? Matrix4d transform-matrix)
(pose/pose? pose)
(seqable? instance-property-descs) ; GameObject$InstancePropertyDescs in map format.
(map? collection-build-target)
(ifn? proj-path->resource-property-build-target)]}
Expand All @@ -220,17 +219,11 @@
(bt/with-content-hash
(assoc-in collection-build-target [:user-data :instance-data]
(mapv (fn [game-object-instance-data]
(flatten-game-object-instance-data game-object-instance-data collection-instance-id transform-matrix child-game-object-instance-id? game-object-instance-id->component-property-descs proj-path->resource-property-build-target))
(flatten-game-object-instance-data game-object-instance-data collection-instance-id pose child-game-object-instance-id? game-object-instance-id->component-property-descs proj-path->resource-property-build-target))
game-object-instance-datas)))))

(defn- matrix->transform-properties [^Matrix4d transform-matrix]
(let [position (Point3d.)
rotation (Quat4d.)
scale (Vector3d.)]
(math/split-mat4 transform-matrix position rotation scale)
{:position (math/vecmath->clj position)
:rotation (math/vecmath->clj rotation)
:scale3 (math/vecmath->clj scale)}))
(defn- pose->transform-properties [pose]
(pose/to-map pose :position :rotation :scale3))

(defn- build-collection [build-resource dep-resources user-data]
;; Please refer to `/engine/gameobject/proto/gameobject/gameobject_ddf.proto`
Expand All @@ -250,7 +243,7 @@
(let [{:keys [name instance-data scale-along-z]} user-data
build-go-props (partial properties/build-go-props dep-resources)
go-instance-msgs (map :instance-msg instance-data)
go-instance-transform-properties (map (comp matrix->transform-properties :transform) instance-data)
go-instance-transform-properties (map (comp pose->transform-properties :pose) instance-data)
go-instance-build-resource-paths (map (comp resource/proj-path dep-resources :resource) instance-data)
go-instance-component-go-props (map (fn [instance-desc] ; GameObject$InstanceDesc in map form
(map (fn [component-property-desc] ; GameObject$ComponentPropertyDesc in map form
Expand Down
43 changes: 26 additions & 17 deletions editor/src/clj/editor/collection_non_editable.clj
Expand Up @@ -20,8 +20,8 @@
[editor.game-object-common :as game-object-common]
[editor.game-object-non-editable :as game-object-non-editable]
[editor.graph-util :as gu]
[editor.math :as math]
[editor.outline :as outline]
[editor.pose :as pose]
[editor.properties :as properties]
[editor.protobuf :as protobuf]
[editor.resource :as resource]
Expand All @@ -46,14 +46,23 @@
referenced-component-build-targets
resource-property-build-targets)))

(defn- any-instance-desc->pose [{:keys [position rotation scale3] :as any-instance-desc}]
;; GameObject$InstanceDesc, GameObject$EmbeddedInstanceDesc, or GameObject$CollectionInstanceDesc in map format.
(let [scale (if (or (nil? scale3)
(protobuf/default-read-scale-value? scale3))

;; Legacy file format - use uniform scale.
(let [uniform-scale (or (:scale any-instance-desc) 1.0)]
[uniform-scale uniform-scale uniform-scale])

;; Modern file format.
scale3)]
(pose/make position rotation scale)))

(defn- any-instance-desc->transform-matrix
^Matrix4d [{:keys [position rotation scale3] :as any-instance-desc}]
^Matrix4d [any-instance-desc]
;; GameObject$InstanceDesc, GameObject$EmbeddedInstanceDesc, or GameObject$CollectionInstanceDesc in map format.
(let [corrected-scale (if (or (nil? scale3)
(protobuf/default-read-scale-value? scale3))
(or (:scale any-instance-desc) 1.0) ; Legacy file format - use uniform scale.
scale3)]
(math/clj->mat4 position rotation corrected-scale)))
(pose/to-mat4 (any-instance-desc->pose any-instance-desc)))

(defn- component-property-desc-with-go-props [component-property-desc proj-path->source-resource]
;; GameObject$ComponentPropertyDesc in map format.
Expand All @@ -73,20 +82,20 @@
(assoc instance-property-desc :properties (mapv #(component-property-desc-with-go-props % proj-path->source-resource) component-property-descs))
(dissoc instance-property-desc :properties)))

(defn- game-object-instance-build-target [build-resource instance-desc ^Matrix4d transform-matrix game-object-build-target proj-path->resource-property-build-target]
(defn- game-object-instance-build-target [build-resource instance-desc pose game-object-build-target proj-path->resource-property-build-target]
;; GameObject$InstanceDesc or GameObject$EmbeddedInstanceDesc in map format.
(let [proj-path->source-resource (comp :resource :resource proj-path->resource-property-build-target)
instance-desc-with-go-props (cond-> (instance-desc-with-go-props instance-desc proj-path->source-resource)

(empty? (:children instance-desc))
(dissoc :children))]
(collection-common/game-object-instance-build-target build-resource instance-desc-with-go-props transform-matrix game-object-build-target proj-path->resource-property-build-target)))
(collection-common/game-object-instance-build-target build-resource instance-desc-with-go-props pose game-object-build-target proj-path->resource-property-build-target)))

(defn- instance-desc->game-object-instance-build-target [instance-desc game-object-build-target proj-path->build-target]
;; GameObject$InstanceDesc in map format.
(let [build-resource (:resource game-object-build-target)
transform-matrix (any-instance-desc->transform-matrix instance-desc)]
(game-object-instance-build-target build-resource instance-desc transform-matrix game-object-build-target proj-path->build-target)))
pose (any-instance-desc->pose instance-desc)]
(game-object-instance-build-target build-resource instance-desc pose game-object-build-target proj-path->build-target)))

(g/defnk produce-referenced-game-object-instance-build-targets [_node-id collection-desc proj-path->build-target resource]
(let [build-targets
Expand All @@ -108,8 +117,8 @@
embedded-game-object-build-target (game-object-common/game-object-build-target nil collection-node-id component-instance-datas component-build-targets)
embedded-game-object-resource (workspace/make-embedded-resource workspace :non-editable "go" (:content-hash embedded-game-object-build-target)) ; Content determines hash for merging with embedded components in other .go files.
embedded-game-object-build-resource (workspace/make-build-resource embedded-game-object-resource)
transform-matrix (any-instance-desc->transform-matrix embedded-instance-desc)]
(game-object-instance-build-target embedded-game-object-build-resource embedded-instance-desc transform-matrix embedded-game-object-build-target proj-path->build-target)))
pose (any-instance-desc->pose embedded-instance-desc)]
(game-object-instance-build-target embedded-game-object-build-resource embedded-instance-desc pose embedded-game-object-build-target proj-path->build-target)))

(g/defnk produce-embedded-game-object-instance-build-targets [_node-id collection-desc embedded-component-resource-data->index embedded-component-build-targets referenced-component-build-targets resource proj-path->build-target]
(let [workspace (resource/workspace resource)
Expand Down Expand Up @@ -141,10 +150,10 @@
collection-instance-build-targets
(mapv (fn [collection-instance-desc]
(let [collection-instance-id (:id collection-instance-desc)
transform-matrix (any-instance-desc->transform-matrix collection-instance-desc)
pose (any-instance-desc->pose collection-instance-desc)
referenced-collection-build-target (proj-path->build-target (:collection collection-instance-desc))
instance-property-descs (mapv #(instance-property-desc-with-go-props % proj-path->source-resource) (:instance-properties collection-instance-desc))]
(collection-common/collection-instance-build-target collection-instance-id transform-matrix instance-property-descs referenced-collection-build-target proj-path->build-target)))
(collection-common/collection-instance-build-target collection-instance-id pose instance-property-descs referenced-collection-build-target proj-path->build-target)))
collection-instance-descs)]
[(collection-common/collection-build-target build-resource _node-id name scale-along-z game-object-instance-build-targets collection-instance-build-targets)]))))

Expand Down Expand Up @@ -275,9 +284,9 @@
(ifn? child-id->desc)]}
(letfn [(desc->instance-scene [desc]
(let [id (:id desc)
transform (any-instance-desc->transform-matrix desc)
transform-matrix (any-instance-desc->transform-matrix desc)
source-scene (desc->source-scene desc)
instance-scene (collection-common/any-instance-scene node-id id transform source-scene)
instance-scene (collection-common/any-instance-scene node-id id transform-matrix source-scene)
child-instance-scenes (map (comp desc->instance-scene child-id->desc)
(:children desc))]
(cond-> instance-scene
Expand Down
6 changes: 3 additions & 3 deletions editor/src/clj/editor/game_object.clj
Expand Up @@ -140,7 +140,7 @@
(update :display-order (fn [display-order]
(vec (distinct (concat display-order (:display-order source-properties))))))))

(g/defnk produce-component-build-targets [_node-id build-resource ddf-message transform resource-property-build-targets source-build-targets]
(g/defnk produce-component-build-targets [_node-id build-resource ddf-message pose resource-property-build-targets source-build-targets]
;; Create a build-target for the referenced or embedded component. Also tag on
;; :instance-data with the overrides for this instance. This will later be
;; extracted and compiled into the GameObject - the overrides do not end up in
Expand All @@ -157,9 +157,9 @@
(wrap-if-raw-sound _node-id))
build-resource (:resource build-target) ; The wrap-if-raw-sound call might have changed this.
instance-data (if is-embedded
(game-object-common/embedded-component-instance-data build-resource ddf-message transform)
(game-object-common/embedded-component-instance-data build-resource ddf-message pose)
(let [proj-path->resource-property-build-target (bt/make-proj-path->build-target resource-property-build-targets)]
(game-object-common/referenced-component-instance-data build-resource ddf-message transform proj-path->resource-property-build-target)))
(game-object-common/referenced-component-instance-data build-resource ddf-message pose proj-path->resource-property-build-target)))
build-target (assoc build-target :instance-data instance-data)]
[(bt/with-content-hash build-target)]))))

Expand Down

0 comments on commit 3b75bba

Please sign in to comment.