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

Support custom ellipsoids in Unity #465

Merged
merged 16 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
- Fixed a bug that caused Cesium ion tokens selected on the Tokens panel to fail to save.
- Fixed a bug that caused the "Select Cesium ion Token" panel to show the wrong state when the current token was not from the currently-signed-in Cesium ion account, but the signed-in account had a token named after the current Unity project.

##### Additions :tada:
- Added support for custom non-WGS84 ellipsoids.
- The ellipsoid can be changed by specifying a `CesiumEllipsoid` asset in the new "Ellipsoid Override" property of a `CesiumGeoreference`.
- New `CesiumEllipsoid` assets can be created using the menu option `Assets > Create > Cesium > Ellipsoid`.

### v1.10.1 - 2024-06-03

This release updates [cesium-native](https://github.com/CesiumGS/cesium-native) from v0.35.0 to v0.36.0. See the [changelog](https://github.com/CesiumGS/cesium-native/blob/main/CHANGES.md) for a complete list of changes in cesium-native.
Expand Down
20 changes: 20 additions & 0 deletions Editor/CesiumGeoreferenceEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal CesiumGeoreferenceOriginAuthority originAuthority
}
}

private SerializedProperty _ellipsoidOverride;
private SerializedProperty _latitude;
private SerializedProperty _longitude;
private SerializedProperty _height;
Expand All @@ -35,6 +36,7 @@ private void OnEnable()
{
this._georeference = (CesiumGeoreference)this.target;

this._ellipsoidOverride = this.serializedObject.FindProperty("_ellipsoidOverride");
this._originAuthority =
this.serializedObject.FindProperty("_originAuthority");

Expand All @@ -56,6 +58,8 @@ public override void OnInspectorGUI()
DrawInspectorButtons();
EditorGUILayout.Space(5);

this.DrawEllipsoidOverrideProperty();
EditorGUILayout.Space(5);
this.DrawScaleProperty();
EditorGUILayout.Space(5);
this.DrawOriginAuthorityProperty();
Expand Down Expand Up @@ -104,6 +108,22 @@ private void DrawInspectorButtons()
EditorGUI.EndDisabledGroup();
}

private void DrawEllipsoidOverrideProperty()
{
GUIContent ellipsoidOverrideContent = new GUIContent(
"Ellipsoid Override",
"The ellipsoid definition to use for this tileset. If this is left blank, " +
"the ellipsoid specified by the tileset is used, or WGS84 if the tileset " +
"doesn't list an ellipsoid to use.");
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(this._ellipsoidOverride, ellipsoidOverrideContent);
if(EditorGUI.EndChangeCheck())
{
this.serializedObject.ApplyModifiedProperties();
this._georeference.ReloadEllipsoid();
}
}

private void DrawScaleProperty()
{
GUIContent scaleContent = new GUIContent(
Expand Down
5 changes: 3 additions & 2 deletions Runtime/Cesium3DTile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public partial class Cesium3DTile
{
internal double4x4 _transform;
internal IntPtr _pTile;
internal IntPtr _pTileEllipsoid;

internal Cesium3DTile()
{}
Expand All @@ -27,10 +28,10 @@ public Bounds bounds
{
get
{
return Cesium3DTile.getBounds(this._pTile, this._transform);
return Cesium3DTile.getBounds(this._pTile, this._pTileEllipsoid, this._transform);
}
}

private static partial Bounds getBounds(IntPtr pTile, double4x4 ecefToLocalMatrix);
private static partial Bounds getBounds(IntPtr pTile, IntPtr pTileEllipsoid, double4x4 ecefToLocalMatrix);
}
}
4 changes: 2 additions & 2 deletions Runtime/CesiumCameraController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ private void Move(Vector3 movementInput)
if (this._georeference != null)
{
double3 positionECEF = this._globeAnchor.positionGlobeFixed;
double3 upECEF = CesiumWgs84Ellipsoid.GeodeticSurfaceNormal(positionECEF);
double3 upECEF = this._georeference.ellipsoid.GeodeticSurfaceNormal(positionECEF);
double3 upUnity =
this._georeference.TransformEarthCenteredEarthFixedDirectionToUnity(upECEF);

Expand Down Expand Up @@ -801,7 +801,7 @@ private void UpdateClippingPlanes()

if (height >= this._dynamicClippingPlanesMinHeight)
{
farClipPlane = height + (float)(2.0 * CesiumWgs84Ellipsoid.GetMaximumRadius());
farClipPlane = height + (float)(2.0 * this._georeference.ellipsoid.GetMaximumRadius());
farClipPlane = Mathf.Min(farClipPlane, this._maximumFarClipPlane);

float farClipRatio = farClipPlane / this._maximumNearToFarRatio;
Expand Down
2 changes: 1 addition & 1 deletion Runtime/CesiumCartographicPolygon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ internal List<double2> GetCartographicPoints(Matrix4x4 worldToTileset)
float3 worldPosition = knot.Transform(localToWorld).Position;
float3 unityPosition = worldToTileset.MultiplyPoint3x4(worldPosition);
double3 ecefPosition = georeference.TransformUnityPositionToEarthCenteredEarthFixed(unityPosition);
double3 cartographicPosition = CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(ecefPosition);
double3 cartographicPosition = georeference.ellipsoid.LongitudeLatitudeHeightToCenteredFixed(ecefPosition);

cartographicPoints.Add(cartographicPosition.xy);
}
Expand Down
107 changes: 107 additions & 0 deletions Runtime/CesiumEllipsoid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using Reinterop;
using Unity.Mathematics;
using UnityEngine;


namespace CesiumForUnity
{
[ReinteropNativeImplementation("CesiumForUnityNative::CesiumEllipsoidImpl", "CesiumEllipsoidImpl.h")]
[IconAttribute("Packages/com.cesium.unity/Editor/Resources/Cesium-24x24.png")]
[CreateAssetMenu(menuName = "Cesium/Ellipsoid")]
public partial class CesiumEllipsoid : ScriptableObject
{
/// <summary>
/// Obtain a WGS84 ellipsoid.
/// </summary>
public static CesiumEllipsoid WGS84
{
get
{
if (_cachedWgs84 == null)
{
_cachedWgs84 = CreateInstance<CesiumEllipsoid>();
_cachedWgs84.name = "WGS84";
_cachedWgs84.SetRadii(CesiumWgs84Ellipsoid.GetRadii());
}

return _cachedWgs84;
}
}

private static CesiumEllipsoid _cachedWgs84;

[SerializeField]
private double3 _radii = new double3(1.0, 1.0, 1.0);

internal double3 radii
{
get => _radii;
set => _radii = value;
}

/// <summary>
/// Gets the maximum radius of the ellipsoid in any dimension.
/// </summary>
/// <returns>The maximum radius of the ellipsoid.</returns>
public double GetMaximumRadius()
{
return math.cmax(this.GetRadii());
}

/// <summary>
/// Gets the minimum radius of the ellipsoid in any dimension.
/// </summary>
/// <returns>The minimum radius of the ellipsoid.</returns>
public double GetMinimumRadius()
{
return math.cmin(this.GetRadii());
}

/// <summary>
/// Returns the radii of this ellipsoid.
/// </summary>
public partial double3 GetRadii();

/// <summary>
/// Sets the radii of this ellipsoid to the given values.
/// </summary>
/// <param name="newRadii">The new (x, y, z) radii of the ellipsoid.</param>
public partial void SetRadii(double3 newRadii);

/// <summary>
/// Scale the given Ellipsoid-Centered, Ellipsoid-Fixed (ECEF) position along the geodetic surface normal
/// so that it is on the surface of the ellipsoid. If the position is at the center of the
/// ellipsoid, the result will be null.
/// </summary>
/// <param name="ellipsoidCenteredEllipsoidFixed">The ECEF position in meters.</param>
/// <returns>The scaled position, or null if the position is at the center of the ellipsoid.</returns>
public partial double3? ScaleToGeodeticSurface(double3 ellipsoidCenteredEllipsoidFixed);

/// <summary>
/// Computes the normal of the plane tangent to the surface of the ellipsoid at the provided
/// Ellipsoid-Centered, Ellipsoid-Fixed position.
/// </summary>
/// <param name="ellipsoidCenteredEllipsoidFixed">The ECEF position in meters.</param>
/// <returns>The normal at the ECEF position</returns>
public partial double3 GeodeticSurfaceNormal(double3 ellipsoidCenteredEllipsoidFixed);

/// <summary>
/// Convert longitude, latitude, and height to Ellipsoid-Centered, Ellipsoid-Fixed (ECEF) coordinates.
/// </summary>
/// <param name="longitudeLatitudeHeight">
/// The longitude (X) and latitude (Y) are in degrees. The height (Z) is in meters above the ellipsoid,
/// and should not be confused with a geoid, orthometric, or mean sea level height.</param>
/// <returns>The ECEF coordinates in meters.</returns>
public partial double3 LongitudeLatitudeHeightToCenteredFixed(double3 longitudeLatitudeHeight);

/// <summary>
/// Convert Ellipsoid-Centered, Ellipsoid-Fixed (ECEF) coordinates to longitude, latitude, and height.
/// </summary>
/// <param name="ellipsoidCenteredEllipsoidFixed">The ECEF coordinates in meters.</param>
/// <returns>
/// The longitude (X) and latitude (Y) are in degrees. The height (Z) is in meters above the ellipsoid,
/// and should not be confused with a geoid, orthometric, or mean sea level height.
/// </returns>
public partial double3 CenteredFixedToLongitudeLatitudeHeight(double3 ellipsoidCenteredEllipsoidFixed);
}
}
11 changes: 11 additions & 0 deletions Runtime/CesiumEllipsoid.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions Runtime/CesiumFlyToController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,10 @@ private void ComputeFlightPath(
this._destinationRotation = Quaternion.Euler(pitchAtDestination, yawAtDestination, 0.0f);
this._destinationECEF = destinationECEF;

this._flightPath = CesiumSimplePlanarEllipsoidCurve.FromEarthCenteredEarthFixedCoordinates(sourceECEF, destinationECEF);
this._flightPath = CesiumSimplePlanarEllipsoidCurve.FromCenteredFixedCoordinates(
this._georeference.ellipsoid,
sourceECEF,
destinationECEF);
this._flightPathLength = math.length(sourceECEF - destinationECEF);

this._maxHeight = 0.0;
Expand Down Expand Up @@ -483,7 +486,7 @@ public void FlyToLocationLongitudeLatitudeHeight(
bool canInterruptByMoving)
{
double3 destinationECEF =
CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(destination);
this._georeference.ellipsoid.LongitudeLatitudeHeightToCenteredFixed(destination);

this.FlyToLocationEarthCenteredEarthFixed(
destinationECEF,
Expand Down Expand Up @@ -522,7 +525,7 @@ public void FlyToLocationLongitudeLatitudeHeight(
z = destination.z
};
double3 destinationECEF =
CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(
this._georeference.ellipsoid.LongitudeLatitudeHeightToCenteredFixed(
destinationCoordinates);

this.FlyToLocationEarthCenteredEarthFixed(
Expand Down
45 changes: 43 additions & 2 deletions Runtime/CesiumGeoreference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public enum CesiumGeoreferenceOriginAuthority
public partial class CesiumGeoreference : MonoBehaviour
{
#region Fields
[SerializeField]
private CesiumEllipsoid _ellipsoidOverride = null;

[SerializeField]
private CesiumGeoreferenceOriginAuthority _originAuthority = CesiumGeoreferenceOriginAuthority.LongitudeLatitudeHeight;
Expand Down Expand Up @@ -106,6 +108,9 @@ public partial class CesiumGeoreference : MonoBehaviour
[NonSerialized]
private HashSet<CesiumGlobeAnchor> _globeAnchors = new HashSet<CesiumGlobeAnchor>();

[NonSerialized]
private CesiumEllipsoid _ellipsoid = null;

#endregion

/// <summary>
Expand Down Expand Up @@ -254,6 +259,25 @@ public double4x4 ecefToLocalMatrix
}
}

public CesiumEllipsoid ellipsoid
{
get
{
if (this._ellipsoid == null)
{
// Make a copy of the ellipsoid ScriptableObject
this._ellipsoid = ScriptableObject.CreateInstance<CesiumEllipsoid>();
this._ellipsoid.SetRadii((this._ellipsoidOverride ?? CesiumEllipsoid.WGS84).radii);
}

return this._ellipsoid;
}
set
{
this._ellipsoid = value;
}
}

/// <summary>
/// An event raised when the georeference changes.
/// </summary>
Expand Down Expand Up @@ -356,6 +380,23 @@ public void Initialize()
}
}

/// <summary>
/// Called when the ellipsoid override property has changed.
/// </summary>
public void ReloadEllipsoid()
{
// clear cached ellipsoid so it has to be rebuilt
this._ellipsoid = null;
this.UpdateTransformations();
this.UpdateOtherCoordinates();

Cesium3DTileset[] tilesets = GetComponentsInChildren<Cesium3DTileset>();
foreach(var tileset in tilesets)
{
tileset.RecreateTileset();
}
}

private void UpdateTransformations()
{
this._localToEcef = this.ComputeLocalToEarthCenteredEarthFixedTransformation();
Expand Down Expand Up @@ -424,7 +465,7 @@ private void UpdateOtherCoordinates()
if (this._originAuthority == CesiumGeoreferenceOriginAuthority.LongitudeLatitudeHeight)
{
double3 ecef =
CesiumWgs84Ellipsoid.LongitudeLatitudeHeightToEarthCenteredEarthFixed(
this.ellipsoid.LongitudeLatitudeHeightToCenteredFixed(
new double3(this._longitude, this._latitude, this._height));
this._ecefX = ecef.x;
this._ecefY = ecef.y;
Expand All @@ -433,7 +474,7 @@ private void UpdateOtherCoordinates()
else if (this._originAuthority == CesiumGeoreferenceOriginAuthority.EarthCenteredEarthFixed)
{
double3 llh =
CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(
this.ellipsoid.CenteredFixedToLongitudeLatitudeHeight(
new double3(this._ecefX, this._ecefY, this._ecefZ));
this._longitude = llh.x;
this._latitude = llh.y;
Expand Down
Loading
Loading