Closed Waffle1434 closed 1 year ago
This is a tricky one.
If you put the anchored object inside the CesiumGeoreference, and then modify its Transform, the CesiumGlobeAnchor position will update accordingly. And should remember its position from then on.
But if you don't explicitly set the position (after it's nested inside the CesiumGeoreference!), then the CesiumGlobeAnchor thinks that it has an authoritative ECEF position, and it overwrites the transform with one computed from that ECEF position.
Basically the Transform position needs to be set last, and all would be well. But when it's set too early (before the component is enabled, or before it's nested in the CesiumGeoreference), then the position inherited from the prefab is deemed accurate. When you call Instantiate and pass a position, that ends up setting the position too early.
I'm not quite sure what we can do about this. Perhaps if Unity sends some message to the component when it is created from a prefab? But I don't see one. The only other thing I can think of is to serialize the "last known" position, so we can detect a change in it even if a new position is already set by the time OnEnable is called. That will make the object a bit bigger, of course, but I'll have to think through whether there are any more serious consequences of this.
But as a workaround, can you try simply setting the position again after the Instantiate
call returns?
In this case I'm not calling GameObject.Instantiate
.
I have a scene with multiple prefab instances hand-placed as children of the Georeference at edit-time, and I save the scene. They have only existed as children of the Georeference.
It is as if the ECEF positions aren't being saved in the scene file for prefab instances, so when de-serialized the component has no idea it shouldn't use the prefab's default.
If the prefab doesn't contain an anchor, and I add it manually in the scene (my workaround), the _localToGlobeFixedMatrix
is serialized inside the .unity
file and it loads correctly:
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 666272557}
m_Modifications:
- target: {fileID: 319014584688397647, guid: 724ba02cd68e7ca478e49f54efb04ea1,
type: 3}
propertyPath: m_Name
value: AH-64D Cesium (1)
objectReference: {fileID: 0}
...
MonoBehaviour:
...
_adjustOrientationForGlobeWhenMoving: 1
_detectTransformChanges: 1
_localToGlobeFixedMatrix:
c0:
x: 0.6676539270647021
y: -1.2620902257691409
z: -1.4004906604188934
w: 0
c1:
x: -0.6175723941958005
y: -1.5501564798246226
z: 1.102551235083885
w: 0
c2:
x: 1.7812494046963758
y: -0.0643908541531326
z: 0.9072000718682209
w: 0
c3:
x: -1972096.133820307
y: -4948730.1963643925
z: 3496569.9432099764
w: 1
_localToGlobeFixedMatrixIsValid: 1
If I try moving an instance around with the anchor inside the prefab, its never written to the scene. m_Modifications
should have an entry for _localToGlobeFixedMatrix
but it doesn't. Unity is storing modifications/overrides for the Transform's XYZ position though (of course, ignored by Cesium by design). When the scene is played or reloaded, it will use the prefab's default coordinates because no modification in the scene file says otherwise:
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 666272557}
m_Modifications:
- target: {fileID: 319014584688397647, guid: 724ba02cd68e7ca478e49f54efb04ea1,
type: 3}
propertyPath: m_Name
value: AH-64D Cesium
objectReference: {fileID: 0}
...
propertyPath: m_LocalPosition.x
value: -348.56
objectReference: {fileID: 0}
- target: {fileID: 1091716913026111477, guid: 724ba02cd68e7ca478e49f54efb04ea1,
type: 3}
propertyPath: m_LocalPosition.y
value: 20.17
objectReference: {fileID: 0}
- target: {fileID: 1091716913026111477, guid: 724ba02cd68e7ca478e49f54efb04ea1,
type: 3}
propertyPath: m_LocalPosition.z
value: -128.88
objectReference: {fileID: 0}
...
m_SourcePrefab: {fileID: 100100000, guid: 724ba02cd68e7ca478e49f54efb04ea1, type: 3}
--- !u!4 &1261796114 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 1091716913026111477, guid: 724ba02cd68e7ca478e49f54efb04ea1,
type: 3}
m_PrefabInstance: {fileID: 1261796113}
m_PrefabAsset: {fileID: 0}
From Cesium's perspective, in scene edit-time I'm moving the helicopter around the scene and its recalculating the ECEF. However, its not saving it anywhere for some reason when its a prefab instance. I don't think there's anything you can do in regards to being notified, it needs to be fixed at serialization-time.
I've never worked with serializing partial class
's or internal
[SerializeField]
's, maybe this is a bug with that, no idea.
Thanks for the details! I think the problem is that modifying the Transform causes a coroutine to automatically update the ECEF coordinates, but Unity doesn't know about those changes so it doesn't save them as modifications of the prefab. We may be able to fix this by adding a call to https://docs.unity3d.com/ScriptReference/PrefabUtility.RecordPrefabInstancePropertyModifications.html to the coroutine.
That seems to work. I opened a PR for it: #338
If the
CesiumGlobeAnchor
component is on a GameObject in a prefab, the prefab's world coordinates will always be used regardless of coordinate overrides for prefab instances.For example, I have a prefab of a helicopter with a world anchor: It has a default coordinate of
33.4588218, -111.72937073
because that's where I originally made it a prefab.If I place multiple instances of the prefab, all instances will revert back to this coordinate either when "Play" mode enters, or the scene is reloaded:
Two helicopters now overlapping at the same coordinate after play/reload:
Notice how
Scale
has a blue highlight showing its an override, while the globe anchor has nothing marked as changed:I fixed the issue for now by not including the anchor in the prefab, and I manually add the anchor to each instance.