From 10c26cc23b97afbc7534db950e3eff7119be437f Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 28 Aug 2024 12:21:25 -0400 Subject: [PATCH] Add 'True Origin' placement mode --- CHANGES.md | 1 + Editor/CesiumGeoreferenceEditor.cs | 64 +++++++++- Runtime/CesiumGeoreference.cs | 117 +++++++++++++++--- Runtime/ConfigureReinterop.cs | 1 + .../Runtime/src/CesiumGeoreferenceImpl.cpp | 20 ++- 5 files changed, 177 insertions(+), 26 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 18b1dead..a4350270 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ ##### Additions :tada: - Editor builds for macOS now target macOS 10.15+. Previously, macOS 12.7+ was required. +- Added `originPlacement` property to `CesiumGeoreference` to toggle between "Cartographic Origin" and "True Origin" reference modes. Whereas "Cartographic Origin" is the default for georeferenced tilesets, "True Origin" may be used for non-georeferenced tilesets centered at the origin. ##### Fixes :wrench: diff --git a/Editor/CesiumGeoreferenceEditor.cs b/Editor/CesiumGeoreferenceEditor.cs index 1b259dc1..644e21a7 100644 --- a/Editor/CesiumGeoreferenceEditor.cs +++ b/Editor/CesiumGeoreferenceEditor.cs @@ -8,6 +8,19 @@ public class CesiumGeoreferenceEditor : Editor { private CesiumGeoreference _georeference; + private SerializedProperty _originPlacement; + + // Converts the SerializedProperty's value to the CesiumGeoreferenceOriginPlacement + // enum it corresponds to, for convenience. + internal CesiumGeoreferenceOriginPlacement originPlacement + { + get + { + return (CesiumGeoreferenceOriginPlacement) + this._originPlacement.enumValueIndex; + } + } + private SerializedProperty _originAuthority; // Converts the SerializedProperty's value to the CesiumGeoreferenceOriginAuthority @@ -37,6 +50,8 @@ private void OnEnable() this._georeference = (CesiumGeoreference)this.target; this._ellipsoidOverride = this.serializedObject.FindProperty("_ellipsoidOverride"); + this._originPlacement = + this.serializedObject.FindProperty("_originPlacement"); this._originAuthority = this.serializedObject.FindProperty("_originAuthority"); @@ -58,15 +73,16 @@ public override void OnInspectorGUI() DrawInspectorButtons(); EditorGUILayout.Space(5); - this.DrawEllipsoidOverrideProperty(); - EditorGUILayout.Space(5); - this.DrawScaleProperty(); - EditorGUILayout.Space(5); + this.DrawOriginPlacementProperty(); this.DrawOriginAuthorityProperty(); EditorGUILayout.Space(5); this.DrawLongitudeLatitudeHeightProperties(); EditorGUILayout.Space(5); this.DrawEarthCenteredEarthFixedProperties(); + EditorGUILayout.Space(5); + this.DrawScaleProperty(); + EditorGUILayout.Space(5); + this.DrawEllipsoidOverrideProperty(); this.serializedObject.ApplyModifiedProperties(); } @@ -93,23 +109,48 @@ private void DrawInspectorButtons() CesiumEditorUtility.PlaceGeoreferenceAtCameraPosition(this._georeference); } + EditorGUI.BeginDisabledGroup( + this.originPlacement != CesiumGeoreferenceOriginPlacement.CartographicOrigin); GUIContent createSubSceneContent = new GUIContent( "Create Sub-Scene Here", "Creates a child GameObject with a \"CesiumSubScene\" component whose origin " + "is set to the camera's current location. A \"CesiumSubScene\" describes a " + "corresponding world location that can be jumped to, and only one sub-scene " + - "can be worked on in the editor at a time."); + "can be worked on in the editor at a time." + + "\n\n" + + "This is disabled when \"Origin Placement\" is set to \"True Origin\"."); if (GUILayout.Button("Create Sub-Scene Here")) { CesiumEditorUtility.CreateSubScene(this._georeference); } + EditorGUI.EndDisabledGroup(); + GUILayout.EndHorizontal(); EditorGUI.EndDisabledGroup(); } + private void DrawOriginPlacementProperty() + { + GUIContent originPlacementContent = new GUIContent( + "Origin Placement", + "The placement of this GameObject's origin (0,0,0) within the tileset." + + "\n\n" + + "3D Tiles tilesets often use Earth-centered, Earth-fixed coordinates, such that " + + "the tileset content is in a small bounding volume 6-7 million meters " + + "(the radius of the Earth) away from the coordinate system origin. This property " + + "allows an alternative position, other than the tileset's true origin, to be " + + "treated as the origin for the purpose of this GameObject. Using this property will " + + "preserve vertex precision (and thus avoid jittering) much better than setting the " + + "GameObject's Transform property."); + EditorGUILayout.PropertyField(this._originPlacement, originPlacementContent); + } + private void DrawEllipsoidOverrideProperty() { + EditorGUI.BeginDisabledGroup( + this.originPlacement != CesiumGeoreferenceOriginPlacement.CartographicOrigin); + GUIContent ellipsoidOverrideContent = new GUIContent( "Ellipsoid Override", "The ellipsoid definition to use for this tileset. If this is left blank, " + @@ -117,11 +158,13 @@ private void DrawEllipsoidOverrideProperty() "doesn't list an ellipsoid to use."); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(this._ellipsoidOverride, ellipsoidOverrideContent); - if(EditorGUI.EndChangeCheck()) + if (EditorGUI.EndChangeCheck()) { this.serializedObject.ApplyModifiedProperties(); this._georeference.ReloadEllipsoid(); } + + EditorGUI.EndDisabledGroup(); } private void DrawScaleProperty() @@ -137,17 +180,24 @@ private void DrawScaleProperty() private void DrawOriginAuthorityProperty() { + EditorGUI.BeginDisabledGroup( + this.originPlacement != CesiumGeoreferenceOriginPlacement.CartographicOrigin); + GUIContent originAuthorityContent = new GUIContent( "Origin Authority", "The set of coordinates that authoritatively define the origin of " + "this georeference."); EditorGUILayout.PropertyField(this._originAuthority, originAuthorityContent); + + EditorGUI.EndDisabledGroup(); } private void DrawLongitudeLatitudeHeightProperties() { + CesiumGeoreferenceOriginPlacement placement = this.originPlacement; CesiumGeoreferenceOriginAuthority authority = this.originAuthority; EditorGUI.BeginDisabledGroup( + placement != CesiumGeoreferenceOriginPlacement.CartographicOrigin || authority != CesiumGeoreferenceOriginAuthority.LongitudeLatitudeHeight); GUILayout.Label( @@ -187,8 +237,10 @@ private void DrawLongitudeLatitudeHeightProperties() private void DrawEarthCenteredEarthFixedProperties() { + CesiumGeoreferenceOriginPlacement placement = this.originPlacement; CesiumGeoreferenceOriginAuthority authority = this.originAuthority; EditorGUI.BeginDisabledGroup( + placement != CesiumGeoreferenceOriginPlacement.CartographicOrigin || authority != CesiumGeoreferenceOriginAuthority.EarthCenteredEarthFixed); GUILayout.Label( diff --git a/Runtime/CesiumGeoreference.cs b/Runtime/CesiumGeoreference.cs index d07d5146..dc7e898d 100644 --- a/Runtime/CesiumGeoreference.cs +++ b/Runtime/CesiumGeoreference.cs @@ -6,6 +6,30 @@ namespace CesiumForUnity { + /// + /// An enumeration of the possible strategies for placing the origin of a . + /// + public enum CesiumGeoreferenceOriginPlacement + { + /// + /// Use the tileset's true origin as the GameObject's origin. + /// + /// + /// For georeferenced tilesets, this usually means the GameObject's origin will be + /// at the center of the Earth, which is not recommended. For a non-georeferenced + /// tileset, however, such as a detailed building with a local origin, putting the + /// GameObject's origin at the same location as the tileset's origin can be useful. + /// + TrueOrigin, + /// + /// Use a custom position within the tileset as the GameObject's origin. The + /// position is expressed as cartographic coordinates determined by the + /// , and that position within + /// the tileset will be at coordinate (0,0,0) in the GameObject's coordinate system. + /// + CartographicOrigin + } + /// /// Identifies the set of the coordinates that authoritatively define /// the origin of a . @@ -68,6 +92,9 @@ public partial class CesiumGeoreference : MonoBehaviour [SerializeField] private CesiumEllipsoid _ellipsoidOverride = null; + [SerializeField] + private CesiumGeoreferenceOriginPlacement _originPlacement = CesiumGeoreferenceOriginPlacement.CartographicOrigin; + [SerializeField] private CesiumGeoreferenceOriginAuthority _originAuthority = CesiumGeoreferenceOriginAuthority.LongitudeLatitudeHeight; @@ -113,26 +140,55 @@ public partial class CesiumGeoreference : MonoBehaviour #endregion + /// + /// The placement of this GameObject's origin (coordinate 0,0,0) within the tileset. + /// + /// + /// 3D Tiles tilesets often use Earth-centered, Earth-fixed coordinates, such + /// that the tileset content is in a small bounding volume 6-7 million meters + /// (the radius of the Earth) away from the coordinate system origin. This + /// property allows an alternative position, other than the tileset's true + /// origin, to be treated as the origin for the purpose of this GameObject. Using + /// this property will preserve vertex precision (and thus avoid jittering) + /// much better than setting the GameObject's Transform property. + /// + public CesiumGeoreferenceOriginPlacement originPlacement + { + get => this._originPlacement; + set + { + this._originPlacement = value; + this.MoveOrigin(); + } + } + /// /// Identifies which set of coordinates authoritatively defines the origin /// of this georeference. /// + /// + /// Setting this property changes the accordingly. + /// public CesiumGeoreferenceOriginAuthority originAuthority { get => this._originAuthority; set { this._originAuthority = value; - this.MoveOrigin(); + this.originPlacement = CesiumGeoreferenceOriginPlacement.CartographicOrigin; } } /// /// The latitude of the origin of the coordinate system, in degrees, in the range -90 to 90. - /// This property is ignored unless is + /// + /// + /// This property only takes effect if is set to + /// and + /// is set to /// . /// Setting this property changes the accordingly. - /// + /// public double latitude { get => this._latitude; @@ -145,10 +201,14 @@ public double latitude /// /// The longitude of the origin of the coordinate system, in degrees, in the range -180 to 180. - /// This property is ignored unless is + /// + /// + /// This property only takes effect if is set to + /// and + /// is set to /// . /// Setting this property changes the accordingly. - /// + /// public double longitude { get => this._longitude; @@ -162,11 +222,15 @@ public double longitude /// /// The height in the origin of the coordinate system, in meters above the ellipsoid. Do not /// confuse this with a geoid height or height above mean sea level, which can be tens of - /// meters higher or lower depending on where in the world the object is located. This - /// property is ignored unless is + /// meters higher or lower depending on where in the world the object is located. + /// + /// + /// This property only takes effect if is set to + /// and + /// is set to /// . /// Setting this property changes the accordingly. - /// + /// public double height { get => this._height; @@ -179,10 +243,14 @@ public double height /// /// The Earth-Centered, Earth-Fixed X coordinate of the origin of the coordinate system, in meters. - /// This property is ignored unless is + /// + /// + /// This property only takes effect if is set to + /// and + /// is set to /// . /// Setting this property changes the accordingly. - /// + /// public double ecefX { get => this._ecefX; @@ -195,10 +263,14 @@ public double ecefX /// /// The Earth-Centered, Earth-Fixed Y coordinate of the origin of the coordinate system, in meters. - /// This property is ignored unless is + /// + /// + /// This property only takes effect if is set to + /// and + /// is set to /// . /// Setting this property changes the accordingly. - /// + /// public double ecefY { get => this._ecefY; @@ -211,10 +283,14 @@ public double ecefY /// /// The Earth-Centered, Earth-Fixed Z coordinate of the origin of the coordinate system, in meters. - /// This property is ignored unless is + /// + /// + /// This property only takes effect if is set to + /// and + /// is set to /// . /// Setting this property changes the accordingly. - /// + /// public double ecefZ { get => this._ecefZ; @@ -227,10 +303,12 @@ public double ecefZ /// /// The scale of the globe in the Unity world. If this value is 0.5, for example, one - /// meter on the globe occupies half a meter in the Unity world. The globe can also - /// be scaled by modifying the georeference's Transform, but setting this property instead - /// will do a better job of preserving precision. + /// meter on the globe occupies half a meter in the Unity world. /// + /// + /// The globe can also be scaled by modifying the georeference's Transform, but setting + /// this property instead will do a better job of preserving precision. + /// public double scale { get => this._scale; @@ -259,6 +337,9 @@ public double4x4 ecefToLocalMatrix } } + /// + /// The that is referenced. + /// public CesiumEllipsoid ellipsoid { get @@ -391,7 +472,7 @@ public void ReloadEllipsoid() this.UpdateOtherCoordinates(); Cesium3DTileset[] tilesets = GetComponentsInChildren(); - foreach(var tileset in tilesets) + foreach (var tileset in tilesets) { tileset.RecreateTileset(); } diff --git a/Runtime/ConfigureReinterop.cs b/Runtime/ConfigureReinterop.cs index c674fbc0..a5e26ab5 100644 --- a/Runtime/ConfigureReinterop.cs +++ b/Runtime/ConfigureReinterop.cs @@ -393,6 +393,7 @@ public void ExposeToCPP() georeference.ecefX = georeference.ecefX; georeference.ecefY = georeference.ecefY; georeference.ecefZ = georeference.ecefZ; + georeference.originPlacement = georeference.originPlacement; georeference.originAuthority = georeference.originAuthority; georeference.scale = georeference.scale; double4x4 ecefToLocal = georeference.ecefToLocalMatrix; diff --git a/native~/Runtime/src/CesiumGeoreferenceImpl.cpp b/native~/Runtime/src/CesiumGeoreferenceImpl.cpp index 192fb80e..bc069dfa 100644 --- a/native~/Runtime/src/CesiumGeoreferenceImpl.cpp +++ b/native~/Runtime/src/CesiumGeoreferenceImpl.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,21 @@ namespace { LocalHorizontalCoordinateSystem createCoordinateSystem( const DotNet::CesiumForUnity::CesiumGeoreference& georeference) { + double scale = 1.0 / georeference.scale(); + if (georeference.originPlacement() == + DotNet::CesiumForUnity::CesiumGeoreferenceOriginPlacement::TrueOrigin) { + // In True Origin mode, we want a coordinate system that: + // 1. Is at the origin, + // 2. Converts from Y-up to Z-up, and + // 3. Uses the georeference's scale + glm::dmat4 localToEcef( + glm::dvec4(scale, 0.0, 0.0, 0.0), + glm::dvec4(0.0, 0.0, scale, 0.0), + glm::dvec4(0.0, -scale, 0.0, 0.0), + glm::dvec4(0.0, 0.0, 0.0, 1.0)); + return LocalHorizontalCoordinateSystem(localToEcef); + } + if (georeference.originAuthority() == DotNet::CesiumForUnity::CesiumGeoreferenceOriginAuthority:: LongitudeLatitudeHeight) { @@ -35,7 +51,7 @@ LocalHorizontalCoordinateSystem createCoordinateSystem( LocalDirection::East, LocalDirection::Up, LocalDirection::North, - 1.0 / georeference.scale(), + scale, georeference.ellipsoid().NativeImplementation().GetEllipsoid()); } else { return LocalHorizontalCoordinateSystem( @@ -46,7 +62,7 @@ LocalHorizontalCoordinateSystem createCoordinateSystem( LocalDirection::East, LocalDirection::Up, LocalDirection::North, - 1.0 / georeference.scale(), + scale, georeference.ellipsoid().NativeImplementation().GetEllipsoid()); } }