diff --git a/Editor/BuildResources/ARCoreiOSCloudAnchorDependencies.template b/Editor/BuildResources/ARCoreiOSCloudAnchorDependencies.template index 17b3f4b..b9a6402 100644 --- a/Editor/BuildResources/ARCoreiOSCloudAnchorDependencies.template +++ b/Editor/BuildResources/ARCoreiOSCloudAnchorDependencies.template @@ -1,6 +1,6 @@ - + diff --git a/Editor/BuildResources/ARCoreiOSDependencies.template b/Editor/BuildResources/ARCoreiOSDependencies.template index 8b8ff8c..da17e6b 100644 --- a/Editor/BuildResources/ARCoreiOSDependencies.template +++ b/Editor/BuildResources/ARCoreiOSDependencies.template @@ -1,6 +1,6 @@ - + diff --git a/Editor/BuildResources/ARCoreiOSGeospatialDependencies.template b/Editor/BuildResources/ARCoreiOSGeospatialDependencies.template index a0e2908..60e999a 100644 --- a/Editor/BuildResources/ARCoreiOSGeospatialDependencies.template +++ b/Editor/BuildResources/ARCoreiOSGeospatialDependencies.template @@ -1,6 +1,6 @@ - + diff --git a/Editor/GeospatialEditor.meta b/Editor/GeospatialCreator.meta similarity index 100% rename from Editor/GeospatialEditor.meta rename to Editor/GeospatialCreator.meta diff --git a/Editor/GeospatialEditor/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef b/Editor/GeospatialCreator/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef similarity index 97% rename from Editor/GeospatialEditor/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef rename to Editor/GeospatialCreator/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef index 4381e26..a2f82e7 100644 --- a/Editor/GeospatialEditor/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef +++ b/Editor/GeospatialCreator/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef @@ -5,7 +5,6 @@ "Google.XR.ARCoreExtensions.GeospatialCreator", "Google.XR.ARCoreExtensions.Editor", "Unity.Mathematics", - "CesiumEditor", "CesiumRuntime" ], "includePlatforms": [ @@ -31,4 +30,3 @@ ], "noEngineReferences": false } - diff --git a/Editor/GeospatialEditor/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef.meta b/Editor/GeospatialCreator/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef.meta similarity index 100% rename from Editor/GeospatialEditor/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef.meta rename to Editor/GeospatialCreator/Google.XR.ARCoreExtensions.GeospatialCreator.Editor.asmdef.meta diff --git a/Editor/GeospatialEditor/Scripts.meta b/Editor/GeospatialCreator/Scripts.meta similarity index 100% rename from Editor/GeospatialEditor/Scripts.meta rename to Editor/GeospatialCreator/Scripts.meta diff --git a/Editor/GeospatialEditor/Scripts/Internal.meta b/Editor/GeospatialCreator/Scripts/Internal.meta similarity index 100% rename from Editor/GeospatialEditor/Scripts/Internal.meta rename to Editor/GeospatialCreator/Scripts/Internal.meta diff --git a/Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs b/Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs similarity index 72% rename from Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs rename to Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs index 8ceab55..78deebc 100644 --- a/Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs +++ b/Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs @@ -18,8 +18,6 @@ // //----------------------------------------------------------------------- -#if UNITY_2021_3_OR_NEWER - namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal { using System; @@ -28,7 +26,7 @@ namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal using UnityEngine; [CustomEditor(typeof(ARGeospatialCreatorAnchor))] - public class ARGeospatialCreatorAnchorEditor : Editor + internal class ARGeospatialCreatorAnchorEditor : Editor { private SerializedProperty _altitudeType; private SerializedProperty _latitude; @@ -40,11 +38,7 @@ public override void OnInspectorGUI() { serializedObject.Update(); - EditorGUI.BeginDisabledGroup(false); - var anchor = serializedObject.targetObject as ARGeospatialCreatorAnchor; - bool hasChanged = false; - GUIStyle titleStyle = new GUIStyle(EditorStyles.boldLabel); titleStyle.fontSize = 20; GUILayout.Label("Geospatial Creator Anchor", titleStyle); @@ -63,40 +57,35 @@ public override void OnInspectorGUI() if (anchor.AltType == ARGeospatialCreatorAnchor.AltitudeType.Terrain || anchor.AltType == ARGeospatialCreatorAnchor.AltitudeType.Rooftop) { - _altitudeOffset.doubleValue = EditorGUILayout.DoubleField( - "Altitude Offset", _altitudeOffset.doubleValue); + _altitudeOffset.doubleValue = EditorGUILayout.DoubleField( + "Altitude Offset", + _altitudeOffset.doubleValue); } _altitude.doubleValue = EditorGUILayout.DoubleField("WGS84 Altitude", _altitude.doubleValue); if (anchor.AltType == ARGeospatialCreatorAnchor.AltitudeType.Terrain) { - EditorGUILayout.HelpBox("WGS84 Altitude is only used in the editor to display altitude of the anchored object. At runtime Altitude Offset is used to position the anchor relative to the terrain.", MessageType.Info, wide:true); + EditorGUILayout.HelpBox("WGS84 Altitude is only used in the editor to " + + "display altitude of the anchored object. At runtime Altitude Offset is " + + "used to position the anchor relative to the terrain.", + MessageType.Info, + wide: true); } else if (anchor.AltType == ARGeospatialCreatorAnchor.AltitudeType.Rooftop) { - EditorGUILayout.HelpBox("WGS84 Altitude is only used in the editor to display altitude of the anchored object. At runtime Altitude Offset is used to position the anchor relative to rooftops.", MessageType.Info, wide:true); + EditorGUILayout.HelpBox("WGS84 Altitude is only used in the editor to " + + "display altitude of the anchored object. At runtime Altitude Offset is " + + "used to position the anchor relative to rooftops.", + MessageType.Info, + wide: true); } } - hasChanged = EditorGUI.EndChangeCheck(); - if (hasChanged) + if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); - anchor.SetUnityPosition(); - } - - EditorGUI.EndDisabledGroup(); - - using (new EditorGUI.DisabledScope(true)) - { - EditorGUILayout.PropertyField(serializedObject.FindProperty("ECEF")); - EditorGUILayout.PropertyField(serializedObject.FindProperty("EUN")); - EditorGUILayout.PropertyField(serializedObject.FindProperty("EUS")); } - - // Apply changes to the serializedProperty - always do this at the end of OnInspectorGUI. - serializedObject.ApplyModifiedProperties(); } private void OnEnable() @@ -111,4 +100,3 @@ private void OnEnable() } } -#endif // UNITY_X_OR_LATER diff --git a/Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs.meta similarity index 100% rename from Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs.meta rename to Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorAnchorEditor.cs.meta diff --git a/Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs b/Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs new file mode 100644 index 0000000..40d2977 --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs @@ -0,0 +1,217 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal +{ + using System; +#if ARCORE_INTERNAL_USE_CESIUM + using CesiumForUnity; +#endif + using Google.XR.ARCoreExtensions.Editor.Internal; + using Google.XR.ARCoreExtensions.GeospatialCreator.Internal; + using UnityEditor; + using UnityEngine; + + [CustomEditor(typeof(ARGeospatialCreatorOrigin))] + internal class ARGeospatialCreatorOriginEditor : Editor + { + /// Helper that extracts the API key from a Google Map Tiles API URL. + /// A URL containing a "key=" parameter. + /// The key extracted from the "key" parameter. + public static string ApiKeyFromTilesetUrl(string url) + { + char[] delimeters = { '&', '?' }; + foreach (string urlPart in url.Split(delimeters)) + { + if (urlPart.StartsWith("key=")) + { + return urlPart.Substring(4); + } + } + + return string.Empty; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + var origin = serializedObject.targetObject as ARGeospatialCreatorOrigin; + + GUIStyle titleStyle = new GUIStyle(EditorStyles.boldLabel); + titleStyle.fontSize = 20; + GUILayout.Label("Geospatial Creator Origin", titleStyle); + + if (HasGeoreference(origin)) + { + // Always draw the CesiumGeoreference-specific GUI, since we only support Cesium + // references currently. + GUIForCesiumGeoreference(origin); + } + else + { + GUIForMissingReference(origin); + } + + serializedObject.ApplyModifiedProperties(); + } + + // Helper that returns the URL for the tiles API for the given key + private static string TilesApiUrl(string apiKey) + { + return String.Format( + "https://tile.googleapis.com/v1/3dtiles/root.json?key={0}", + apiKey); + } + + private bool HasGeoreference(ARGeospatialCreatorOrigin origin) + { +#if ARCORE_INTERNAL_USE_CESIUM + return (origin.gameObject.GetComponent() != null); +#else + return false; +#endif + } + + // Draw the GUI when there's no Georeference attached to the target Origin. + private void GUIForMissingReference(ARGeospatialCreatorOrigin origin) + { + GUILayout.BeginVertical(); + EditorGUILayout.Space(); + GUILayout.BeginHorizontal(); + + GUIContent addGeoreferenceContent = new GUIContent( + "Add Cesium Georeference Component", + "Add a CesiumGeoreference to locate Geospatial Anchors in the Unity scene."); + if (GUILayout.Button(addGeoreferenceContent)) + { + // Only Cesium anchors are supported so far; this method will throw an exception + // if the Cesium dependency is unavailable. + AddGeoreference(origin); + } + + GUILayout.EndHorizontal(); + GUILayout.EndVertical(); + } + + private void GUIForCesiumGeoreference(ARGeospatialCreatorOrigin origin) + { + EditorGUILayout.BeginVertical(); + EditorGUILayout.Space(); + GUIContent openQuickstartContent = new GUIContent( + "Open Geospatial Creator Quickstart", + "Open the Quickstart webpage for Geospatial Creator in a browser."); + if (GUILayout.Button(openQuickstartContent)) + { + Application.OpenURL(GeospatialCreatorHelper.QuickstartUrl); + } + + // We don't persist the API Key directly in this component. Instead, it is always read + // from and written to the tiles child. + string oldApiKey = Get3DTilesApiKey(origin); + string newApiKey = EditorGUILayout.DelayedTextField( + "Google Map Tiles API Key", + oldApiKey); + if (String.IsNullOrEmpty(newApiKey)) + { + EditorGUILayout.HelpBox( + "An API key is required to use Google Map Tiles. Follow the Quickstart " + + "Guide for additional instructions.", + MessageType.Warning); + } + + if (newApiKey != oldApiKey) + { + Set3DTileApiKey(origin, newApiKey); + } + + EditorGUILayout.EndVertical(); + } + + private void AddGeoreference(ARGeospatialCreatorOrigin origin) + { + // Only Cesium anchors are supported so far +#if !ARCORE_INTERNAL_USE_CESIUM + throw new Exception("Cesium dependency is missing."); +#else // need to use #else block to avoid unreachable code failures + + CesiumGeoreference georeference = + origin.gameObject.AddComponent(typeof(CesiumGeoreference)) as CesiumGeoreference; + + GameObject tilesetObject = new GameObject("Cesium3DTileset"); + tilesetObject.transform.SetParent(georeference.gameObject.transform); + + // Since this is an AR app, it is likely using the camera instead of a scene + // so default to the tiles only being visible in the Editor. Developers can + // manually change the tag in the Inspector, if desired. + Cesium3DTileset tileset = + tilesetObject.AddComponent(typeof(Cesium3DTileset)) as Cesium3DTileset; + tileset.name = tilesetObject.name; + tileset.tilesetSource = CesiumDataSource.FromUrl; + tileset.showCreditsOnScreen = true; + tileset.createPhysicsMeshes = false; + + georeference.tag = "EditorOnly"; + tilesetObject.tag = "EditorOnly"; + Undo.RegisterCreatedObjectUndo(georeference, "Create Cesium Georeference"); +#endif + } + + private string Get3DTilesApiKey(ARGeospatialCreatorOrigin origin) + { +#if !ARCORE_INTERNAL_USE_CESIUM + throw new Exception("Cannot get Map Tiles API key; Cesium dependency is missing."); +#else // need to use #else block to avoid unreachable code failures + Cesium3DTileset tileset = + origin.gameObject.GetComponentInChildren(typeof(Cesium3DTileset)) + as Cesium3DTileset; + if (tileset == null) + { + return ""; + } + return ApiKeyFromTilesetUrl(tileset.url); +#endif + } + + private void Set3DTileApiKey(ARGeospatialCreatorOrigin origin, string key) + { +#if !ARCORE_INTERNAL_USE_CESIUM + throw new Exception("Cannot set Map Tiles API key; Cesium dependency is missing."); +#else // need to use #else block to avoid unreachable code failures + Cesium3DTileset tileset = + origin.gameObject.GetComponentInChildren(typeof(Cesium3DTileset)) + as Cesium3DTileset; + if (tileset == null) + { + Debug.LogError( + "Attempted to set Map Tiles API key on a missing Cesium3DTileset component."); + return; + } + String url = String.IsNullOrEmpty(key) ? "" : TilesApiUrl(key); + if (url != tileset.url) + { + Undo.RecordObject(tileset, "Update Map Tiles API key"); + tileset.url = url; + EditorUtility.SetDirty(tileset); + } +#endif + } + } +} + diff --git a/Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs.meta similarity index 100% rename from Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs.meta rename to Editor/GeospatialCreator/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs.meta diff --git a/Editor/GeospatialCreator/Scripts/Internal/GeoMath.cs b/Editor/GeospatialCreator/Scripts/Internal/GeoMath.cs new file mode 100644 index 0000000..5ac516b --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/GeoMath.cs @@ -0,0 +1,170 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal +{ + using System; + + using Google.XR.ARCoreExtensions.GeospatialCreator.Internal; +#if ARCORE_INTERNAL_USE_UNITY_MATH + using Unity.Mathematics; +#endif + using UnityEngine; + + // :TODO: b/277365140 Automated testing + internal static class GeoMath + { + public static double3 EarthCenteredEarthFixedToLongitudeLatitudeHeight(double3 ecef) + { +#if ARCORE_INTERNAL_USE_CESIUM && ARCORE_INTERNAL_USE_UNITY_MATH + return CesiumForUnity.CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight(ecef); +#else + throw new Exception("Missing dependencies: Cesium 1.0.0+"); +#endif + } + + /// + /// Conversion between geodetic and earth-centered, earth-fixed (ECEF) coordinates + /// https://en.wikipedia.org/wiki/Geographic_coordinate_conversion. + /// + /// Vector in earth centered, earth fixed coordinates. + /// The GeoCoordinate that corresponds to the ecef location. + public static GeoCoordinate ECEFToGeoCoordinate(double3 ecef) + { + var A = 6378137.0; // equatorial radius in meters + var B = 6356752.314245179; // Polar radius in meters + var p = Math.Sqrt(ecef.x * ecef.x + ecef.y * ecef.y); // Temporary value + var q = Math.Atan2((ecef.z * A), (p * B)); // Temporary value + + // special case of north/south pole + var epsilon = 1e-10; + if (p < epsilon) + { + var lng = 0.0; + var zSign = (ecef.z < 0) ? -1 : 1; + var lat = (Math.PI / 2.0) * zSign; + var alt = Math.Sqrt(ecef.z * ecef.z) - B; + return new GeoCoordinate(lat * 180.0 / Math.PI, lng * 180.0 / Math.PI, alt); + } + + var longitude = Math.Atan2(ecef.y, ecef.x); + var latitude = Math.Atan2( + (ecef.z + ((A * A - B * B) / B) * Math.Pow(Math.Sin(q), 3.0)), + (p - ((A * A - B * B) / A) * Math.Pow(Math.Cos(q), 3.0))); + + var N = + A + / Math.Sqrt( + 1.0 - (1.0 - (B * B) / (A * A)) * Math.Sin(latitude) * Math.Sin(latitude)); + var altitude = Math.Sqrt(ecef.x * ecef.x + ecef.y * ecef.y) / Math.Cos(latitude) - N; + + return new GeoCoordinate( + latitude * 180.0 / Math.PI, + longitude * 180.0 / Math.PI, + altitude); + } + + public static double3 GeoCoordinateToECEF(GeoCoordinate coor) + { + double3 ret = new double3(); + + // a and b are from from WGS84 + // https://en.wikipedia.org/wiki/World_Geodetic_System + var a = 6378137.0; // equatorial radius in meters + var b = 6356752.314245179; // Polar radius in meters + var rlong = Math.PI * coor.Longitude / 180.0; + var rlat = Math.PI * coor.Latitude / 180.0; + var coslong = Math.Cos(rlong); + var sinlong = Math.Sin(rlong); + var coslat = Math.Cos(rlat); + var sinlat = Math.Sin(rlat); + var a2 = a * a; + var b2 = b * b; + var f = 1 - (b / a); + var e2 = 1 - (b2 / a2); + var n_2 = a2 / Math.Sqrt((a2 * (coslat * coslat)) + ((b2) * (sinlat * sinlat))); + var n = a / Math.Sqrt(1 - (e2 * sinlat * sinlat)); + var x = (n + coor.Altitude) * coslat * coslong; + var y = (n + coor.Altitude) * coslat * sinlong; + var neg1f2 = (1 - f) * (1 - f); + var neg1e2 = 1 - e2; + var z = (neg1f2 * n + coor.Altitude) * sinlat; + var z_2 = (neg1e2 * n + coor.Altitude) * sinlat; + + // x y z are in meters + ret.x = x; + ret.y = y; + ret.z = z; + return ret; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1300:LinesMustBe100CharactersOrShorter", + Justification = "URL length > 100")] + public static double4x4 CalculateEcefToEnuTransform(GeoCoordinate originPoint) + { + // :TODO b/277370107: This could be optimized by only changing the position if the + // object or origin has moved + double3 PositionInECEF = GeoCoordinateToECEF(originPoint); + + // Rotate from y up to z up and flip X. References: + // https://github.com/CesiumGS/3d-tiles/tree/main/specification#transforms + // https://stackoverflow.com/questions/1263072/changing-a-matrix-from-right-handed-to-left-handed-coordinate-system + // https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#From_ECEF_to_ENU + MatrixStack matrixStack = new MatrixStack(); + matrixStack.PushMatrix(); + + double latSin, latCos; + math.sincos(originPoint.Latitude / 180 * Math.PI, out latSin, out latCos); + double lngSin, lngCos; + math.sincos(originPoint.Longitude / 180 * Math.PI, out lngSin, out lngCos); + double4x4 ECEFToENURot = new double4x4( + -lngSin, + lngCos, + 0.0, + 0.0, + -latSin * lngCos, + -latSin * lngSin, + latCos, + 0.0, + latCos * lngCos, + latCos * lngSin, + latSin, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0); + + matrixStack.MultMatrix( + MatrixStack.Translate( + new double3(-PositionInECEF.x, -PositionInECEF.y, -PositionInECEF.z))); + matrixStack.MultMatrix(ECEFToENURot); + return matrixStack.GetMatrix(); + } + + public static double4x4 CalculateEnuToEcefTransform(GeoCoordinate originPoint) + { + return math.inverse(CalculateEcefToEnuTransform(originPoint)); + } + } +} + diff --git a/Runtime/Scripts/GeospatialEditorRuntime/GeoTilesReference.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/GeoMath.cs.meta similarity index 83% rename from Runtime/Scripts/GeospatialEditorRuntime/GeoTilesReference.cs.meta rename to Editor/GeospatialCreator/Scripts/Internal/GeoMath.cs.meta index 0b9748b..80abfa8 100644 --- a/Runtime/Scripts/GeospatialEditorRuntime/GeoTilesReference.cs.meta +++ b/Editor/GeospatialCreator/Scripts/Internal/GeoMath.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 13e8804fcdd36a64f94b00922ea3e23e +guid: fde23e3ba86434b2d94a4956bbe0ef37 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Editor/GeospatialCreator/Scripts/Internal/GeospatialAnchorUpdater.cs b/Editor/GeospatialCreator/Scripts/Internal/GeospatialAnchorUpdater.cs new file mode 100644 index 0000000..699a2ba --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/GeospatialAnchorUpdater.cs @@ -0,0 +1,165 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +#if ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal +{ + using System; + using System.Collections.Generic; + using Google.XR.ARCoreExtensions.GeospatialCreator.Internal; +#if ARCORE_INTERNAL_USE_UNITY_MATH + using Unity.Mathematics; +#endif + using UnityEditor; + using UnityEngine; + + /// + /// Handles Editor Updates for ARGeospatialCreatorAnchor objects. Specifically, it updates the + /// anchor's lat/lon/alt properties whenever the transform is updated, and vice versa. This + /// class is used instead of implementing ARGeospatialCreatorAnchor's Update() method to avoid + /// requiring the Cesium dependency in the GeospatialCreator's runtime assembly references. + /// + [InitializeOnLoad] + internal class GeospatialAnchorUpdater + { + private static GeospatialObjectTracker tracker; + + private ARGeospatialCreatorAnchor _anchor; + + private bool shouldPosition = true; + + private Vector3 _previousPosition = Vector3.zero; + private Quaternion _previousRotation = Quaternion.identity; + private Vector3 _previousScale = Vector3.one; + private GeoCoordinate _previousCoor = new GeoCoordinate(Mathf.Infinity, Mathf.Infinity, 0); + + // Use a static initializer, plus the InitializeOnLoad attribute, to ensure objects in the + // scene are always being tracked. + static GeospatialAnchorUpdater() + { + Func actionFactory = anchor => + (new GeospatialAnchorUpdater(anchor)).EditorUpdate; + + var tracker = new GeospatialObjectTracker(actionFactory); + tracker.StartTracking(); + } + + // :TODO b/278071434: Make the Origin a property of the anchor instead of finding it. This + // implementation is inefficient to do on each Editor Update, but will be replaced soon. + private static GeoCoordinate FindOriginPoint() + { + ARGeospatialCreatorOrigin[] origins = + GameObject.FindObjectsOfType(); + if (origins.Length == 0) + { + Debug.LogError("No valid ARGeospatialCreatorOrigin found in scene"); + return null; + } + if (origins.Length > 1) + { + Debug.LogWarning("Multiple ARGeospatialCreatorOrigin objects found in scene."); + } + return origins[0].OriginPoint; + } + + public GeospatialAnchorUpdater(ARGeospatialCreatorAnchor anchor) + { + _anchor = anchor; + } + + private void EditorUpdate() + { + if (_previousPosition != _anchor.transform.position || + _previousRotation != _anchor.transform.rotation || + _previousScale != _anchor.transform.localScale) + { + // Update lat/lon/alt to match the changed game coordinates + UpdateGeospatialCoordinate(); + } + else if (_previousCoor.Latitude != _anchor.Latitude || + _previousCoor.Longitude != _anchor.Longitude || + _previousCoor.Altitude != _anchor.Altitude) + { + // update the game coordinates to match the changed lat/lon/alt + UpdateUnityPosition(); + } else + { + return; + } + + _previousPosition = _anchor.transform.position; + _previousRotation = _anchor.transform.rotation; + _previousScale = _anchor.transform.localScale; + _previousCoor = new GeoCoordinate( + _anchor.Latitude, + _anchor.Longitude, + _anchor.Altitude); + } + + // :TODO: b/277365140 Automated testing for these two methods + private void UpdateGeospatialCoordinate() + { + GeoCoordinate originPoint = FindOriginPoint(); + if (originPoint == null) + { + // An error message was already printed (if needed) in FindOriginPoint() + return; + } + + double4x4 ENUToECEF = GeoMath.CalculateEnuToEcefTransform(originPoint); + double3 EUN = new double3( + _anchor.transform.position.x, + _anchor.transform.position.y, + _anchor.transform.position.z); + double3 ENU = new double3(EUN.x, EUN.z, EUN.y); + double3 ECEF = MatrixStack.MultPoint(ENUToECEF, ENU); + double3 llh = GeoMath.EarthCenteredEarthFixedToLongitudeLatitudeHeight(ECEF); + + _anchor.Longitude = llh.x; + _anchor.Latitude = llh.y; + _anchor.Altitude = llh.z; + } + + private void UpdateUnityPosition() + { + GeoCoordinate originPoint = FindOriginPoint(); + if (originPoint == null) + { + // An error message was already printed (if needed) in FindOriginPoint() + return; + } + + double4x4 ECEFToENU = GeoMath.CalculateEcefToEnuTransform(originPoint); + GeoCoordinate coor = new GeoCoordinate( + _anchor.Latitude, + _anchor.Longitude, + _anchor.Altitude); + double3 localInECEF = GeoMath.GeoCoordinateToECEF(coor); + double3 ENU = MatrixStack.MultPoint(ECEFToENU, localInECEF); + // Unity is EUN not ENU so swap z and y + Vector3 EUN = new Vector3((float)ENU.x, (float)ENU.z, (float)ENU.y); + + _anchor.transform.position = EUN; + } + } +} + +#endif // ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED diff --git a/Editor/GeospatialCreator/Scripts/Internal/GeospatialAnchorUpdater.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/GeospatialAnchorUpdater.cs.meta new file mode 100644 index 0000000..5d14339 --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/GeospatialAnchorUpdater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73a1b80b3bf1d4e508dde8ca7d23c5c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/GeospatialEditor/Scripts/Internal/MenuUtils.cs b/Editor/GeospatialCreator/Scripts/Internal/GeospatialCreatorMenuUtils.cs similarity index 88% rename from Editor/GeospatialEditor/Scripts/Internal/MenuUtils.cs rename to Editor/GeospatialCreator/Scripts/Internal/GeospatialCreatorMenuUtils.cs index 204a358..6027e25 100644 --- a/Editor/GeospatialEditor/Scripts/Internal/MenuUtils.cs +++ b/Editor/GeospatialCreator/Scripts/Internal/GeospatialCreatorMenuUtils.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // // Copyright 2023 Google LLC // @@ -18,7 +18,6 @@ // //----------------------------------------------------------------------- -#if UNITY_2021_3_OR_NEWER namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal { @@ -27,7 +26,7 @@ namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal using UnityEditor; using UnityEngine; - internal static class MenuUtils + internal static class GeospatialCreatorMenuUtils { private static int _createdAnchorCount = 1; @@ -39,8 +38,8 @@ private static void CreateOrigin(MenuCommand menuCommand) GameObject origin = CreateObject( menuCommand, "AR Geospatial Creator Origin", - typeof(ARGeospatialCreatorOrigin) - ); + typeof(ARGeospatialCreatorOrigin)); + origin.tag = "EditorOnly"; } #if ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED @@ -51,16 +50,14 @@ private static void CreateAnchor(MenuCommand menuCommand) CreateObject( menuCommand, $"AR Geospatial Creator Anchor {_createdAnchorCount}", - typeof(ARGeospatialCreatorAnchor) - ); + typeof(ARGeospatialCreatorAnchor)); _createdAnchorCount++; } private static GameObject CreateObject( MenuCommand menuCommand, string name, - params Type[] types - ) + params Type[] types) { GameObject gameObject = ObjectFactory.CreateGameObject(name, types); GameObjectUtility.EnsureUniqueNameForSibling(gameObject); @@ -75,4 +72,3 @@ params Type[] types } } -#endif // UNITY_X_OR_NEWER diff --git a/Editor/GeospatialEditor/Scripts/Internal/MenuUtils.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/GeospatialCreatorMenuUtils.cs.meta similarity index 100% rename from Editor/GeospatialEditor/Scripts/Internal/MenuUtils.cs.meta rename to Editor/GeospatialCreator/Scripts/Internal/GeospatialCreatorMenuUtils.cs.meta diff --git a/Editor/GeospatialCreator/Scripts/Internal/GeospatialObjectTracker.cs b/Editor/GeospatialCreator/Scripts/Internal/GeospatialObjectTracker.cs new file mode 100644 index 0000000..a5fe57e --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/GeospatialObjectTracker.cs @@ -0,0 +1,134 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +#if ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal +{ + using System; + using System.Collections.Generic; + + using Google.XR.ARCoreExtensions.GeospatialCreator.Internal; + using UnityEditor; + using UnityEngine; + + /// + /// Class to track specific ARGeospatialCreatorObject objects in the scene, so they can be + /// assigned Editor-only Update() behaviors. + /// + /// + /// This is useful if the Editor-only behaviors rely on assemblies that we do not want included + /// in the runtime. If there's no special dependencies required, the object's Update() method + /// can be implemented with "#if UNITY_EDITOR ... #endif" guards instead. + /// + internal class GeospatialObjectTracker where T : ARGeospatialCreatorObject + { + private Func _updateActionFactory; + private Dictionary _trackedObjects; + private bool _isTracking; + + /// + /// Create a GeospatialObjectTracker that will assign an Editor-specific Update behavior + /// to all objects of type T in a scene. + /// + /// + /// The factory function that returns an Update action for a given object of type T. The + /// Action returned by the function will be invoked whenever the Editor calls the Update + /// method on the given object. + /// + public GeospatialObjectTracker(Func updateActionFactory) + { + _trackedObjects = new Dictionary(); + _updateActionFactory = updateActionFactory; + _isTracking = false; + } + + ~GeospatialObjectTracker() + { + if (_isTracking) + { + StopTracking(); + } + } + + public void StartTracking() + { + if (_isTracking) + { + StopTracking(); + } + + UpdateTrackedObjects(); + EditorApplication.hierarchyChanged += UpdateTrackedObjects; + _isTracking = true; + } + + public void StopTracking() + { + EditorApplication.hierarchyChanged -= UpdateTrackedObjects; + _isTracking = false; + foreach (KeyValuePair entry in _trackedObjects) + { + entry.Key.OnEditorUpdate -= entry.Value; + } + + _trackedObjects.Clear(); + } + + /// + /// Handles EditorApplication.Update() events to check if GameObjects of type T have been + /// added to or removed from the scene. For new objects, a a new update Action is created + /// and added to that object's OnEditorUpdate delegates. For removed objects, any + /// previously-assigned delegate is removed. + /// + private void UpdateTrackedObjects() + { + HashSet currentObjects = new HashSet(GameObject.FindObjectsOfType()); + if (currentObjects.SetEquals(_trackedObjects.Keys)) + { + // no added or removed objects, so there's nothing to do + return; + } + + HashSet newObjects = new HashSet(currentObjects); + newObjects.ExceptWith(_trackedObjects.Keys); + HashSet removedObjects = new HashSet(_trackedObjects.Keys); + removedObjects.ExceptWith(currentObjects); + + foreach (T obj in newObjects) + { + Action updateAction = _updateActionFactory(obj); + obj.OnEditorUpdate += updateAction; + _trackedObjects.Add(obj, updateAction); + } + + foreach (T obj in removedObjects) + { + Action updateAction; + if (_trackedObjects.TryGetValue(obj, out updateAction)) + { + obj.OnEditorUpdate -= updateAction; + _trackedObjects.Remove(obj); + } + } + } + } +} +#endif // ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED diff --git a/Editor/GeospatialCreator/Scripts/Internal/GeospatialObjectTracker.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/GeospatialObjectTracker.cs.meta new file mode 100644 index 0000000..fa77fd7 --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/GeospatialObjectTracker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3fb76f3276a8c41fab7fd9315b23e406 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/GeospatialCreator/Scripts/Internal/GeospatialOriginUpdater.cs b/Editor/GeospatialCreator/Scripts/Internal/GeospatialOriginUpdater.cs new file mode 100644 index 0000000..a964ee5 --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/GeospatialOriginUpdater.cs @@ -0,0 +1,80 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +#if ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal +{ + using System; + using System.Collections.Generic; + using Google.XR.ARCoreExtensions.GeospatialCreator.Internal; + using UnityEditor; + using UnityEngine; + + /// + /// Handles Editor Updates for ARGeospatialCreatorOrigin objects. Specifically, it ensures + /// the Origin's GeoCoordinate point is in sync with the CesiumGeoreference location. This + /// class is used instead of implementing ARGeospatialCreatorOrigin's Update() method to + /// avoid requiring the Cesium dependency in the GeospatialCreator's runtime assembly + /// references. + /// + [InitializeOnLoad] + internal class GeospatialOriginUpdater + { + private static GeospatialObjectTracker tracker; + + private ARGeospatialCreatorOrigin _origin; + + // Use a static initializer, plus the InitializeOnLoad attribute, to ensure objects in the + // scene are always being tracked. + static GeospatialOriginUpdater() + { + Func actionFactory = origin => + (new GeospatialOriginUpdater(origin)).EditorUpdate; + + var tracker = new GeospatialObjectTracker(actionFactory); + tracker.StartTracking(); + } + + public GeospatialOriginUpdater(ARGeospatialCreatorOrigin origin) + { + _origin = origin; + } + + private void EditorUpdate() + { +#if ARCORE_INTERNAL_USE_CESIUM + // :TODO b/276777888: Handle invalid case where there's multiple origin points. + // A missing CesiumGeoreference is not an error, for example if the + // ARGeospatialCreatorOrigin was recently created. + CesiumForUnity.CesiumGeoreference geoRef = + _origin.gameObject.GetComponent(); + if (geoRef != null) + { + _origin.OriginPoint = + new GeoCoordinate(geoRef.latitude, geoRef.longitude, geoRef.height); + } +#endif + } + } +} + +#endif // ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED + diff --git a/Editor/GeospatialCreator/Scripts/Internal/GeospatialOriginUpdater.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/GeospatialOriginUpdater.cs.meta new file mode 100644 index 0000000..a9eab3f --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/GeospatialOriginUpdater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd2a0229f46d74f6dbc2b9e7de8e395c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/GeospatialCreator/Scripts/Internal/MatrixStack.cs b/Editor/GeospatialCreator/Scripts/Internal/MatrixStack.cs new file mode 100644 index 0000000..c77826f --- /dev/null +++ b/Editor/GeospatialCreator/Scripts/Internal/MatrixStack.cs @@ -0,0 +1,328 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal +{ + using System; + using System.Collections.Generic; +#if ARCORE_INTERNAL_USE_UNITY_MATH + using Unity.Mathematics; +#endif + using UnityEngine; + + internal class MatrixStack + { + private List _stack = new List(); + + public MatrixStack() + { + _stack.Add(double4x4.identity); + } + + public static Quaternion GetRotation(double4x4 m) + { + Vector3 forward; + forward.x = (float)m.c2.x; + forward.y = (float)m.c2.y; + forward.z = (float)m.c2.z; + + Vector3 upwards; + upwards.x = (float)m.c1.x; + upwards.y = (float)m.c1.y; + upwards.z = (float)m.c1.z; + + return Quaternion.LookRotation(forward, upwards); + } + + public static double3 MultPoint(double4x4 mat, double3 a) + { + double4 v = new double4(a[0], a[1], a[2], 1.0); + double4 ret = math.mul(mat, v); + return new double3(ret[0], ret[1], ret[2]); + } + + public static double4x4 YupToZupTest() + { + return new double4x4( + -1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0); + } + + public static double4x4 YupToZup() + { + return new double4x4( + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0); + } + + public static double4x4 RotateX(double angle) + { + // {{1, 0, 0}, {0, c_0, -s_0}, {0, s_0, c_0}} + double s, + c; + math.sincos(angle, out s, out c); + return new double4x4( + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + c, + -s, + 0.0, + 0.0, + s, + c, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0); + } + + /// Returns a double4x4 matrix that rotates around the y-axis by a given number of radians. + /// The clockwise rotation angle when looking along the y-axis towards the origin in radians. + /// The double4x4 rotation matrix that rotates around the y-axis. + public static double4x4 RotateY(double angle) + { + // {{c_1, 0, s_1}, {0, 1, 0}, {-s_1, 0, c_1}} + double s, + c; + math.sincos(angle, out s, out c); + return new double4x4( + c, + 0.0, + s, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + -s, + 0.0, + c, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0); + } + + /// Returns a double4x4 matrix that rotates around the z-axis by a given number of radians. + /// The clockwise rotation angle when looking along the z-axis towards the origin in radians. + /// The double4x4 rotation matrix that rotates around the z-axis. + public static double4x4 RotateZ(double angle) + { + // {{c_2, -s_2, 0}, {s_2, c_2, 0}, {0, 0, 1}} + double s, + c; + math.sincos(angle, out s, out c); + return new double4x4( + c, + -s, + 0.0, + 0.0, + s, + c, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0); + } + + /// Returns a double4x4 scale matrix given 3 axis scales. + /// The uniform scaling factor. + /// The double4x4 matrix that represents a uniform scale. + public static double4x4 Scale(double3 s) + { + return new double4x4( + s.x, + 0.0, + 0.0, + 0.0, + 0.0, + s.y, + 0.0, + 0.0, + 0.0, + 0.0, + s.z, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0); + } + + /// Returns a double4x4 translation matrix given a double3 translation vector. + /// The translation vector. + /// The double4x4 translation matrix. + public static double4x4 Translate(double3 vector) + { + return new double4x4( + new double4(1.0, 0.0, 0.0, 0.0), + new double4(0.0, 1.0, 0.0, 0.0), + new double4(0.0, 0.0, 1.0, 0.0), + new double4(vector.x, vector.y, vector.z, 1.0)); + } + + public void PushMatrix() + { + _stack.Add(_stack[_stack.Count - 1]); + } + + public void PushIdentityMatrix() + { + _stack.Add(double4x4.identity); + } + + public void PopMatrix() + { + Debug.Assert(_stack.Count >= 2); + _stack.RemoveAt(_stack.Count - 1); + } + + public double4x4 GetMatrix() + { + Debug.Assert(_stack.Count >= 1); + return _stack[_stack.Count - 1]; + } + + public Quaternion GetRotation() + { + double4x4 m = _stack[_stack.Count - 1]; + + Vector3 forward; + forward.x = (float)m.c2.x; + forward.y = (float)m.c2.y; + forward.z = (float)m.c2.z; + + Vector3 upwards; + upwards.x = (float)m.c1.x; + upwards.y = (float)m.c1.y; + upwards.z = (float)m.c1.z; + + return Quaternion.LookRotation(forward, upwards); + } + + public void Transpose() + { + Debug.Assert(_stack.Count >= 1); + _stack[_stack.Count - 1] = math.transpose(_stack[_stack.Count - 1]); + } + + // Pre multiply + public void PreMultMatrix(double4x4 m) + { + Debug.Assert(_stack.Count >= 1); + _stack[_stack.Count - 1] = math.mul(_stack[_stack.Count - 1], m); + } + + // Post multiply + public void MultMatrix(double4x4 m) + { + Debug.Assert(_stack.Count >= 1); + _stack[_stack.Count - 1] = math.mul(m, _stack[_stack.Count - 1]); + } + + public void MultMatrix(List a) + { + Debug.Assert(_stack.Count >= 1); + Debug.Assert(a.Count >= 16); + + // load column-major order + double4x4 m = new double4x4( + a[0], + a[4], + a[8], + a[12], + a[1], + a[5], + a[9], + a[13], + a[2], + a[6], + a[10], + a[14], + a[3], + a[7], + a[11], + a[15]); + _stack[_stack.Count - 1] = math.mul(_stack[_stack.Count - 1], m); + } + + public double4 MultPoints(List a) + { + Debug.Assert(_stack.Count >= 1); + Debug.Assert(a.Count >= 4); + double4 v = new double4(a[0], a[1], a[2], 1.0); + return math.mul(_stack[_stack.Count - 1], v); + } + + public double3 MultPoint(double3 a) + { + Debug.Assert(_stack.Count >= 1); + double4 v = new double4(a[0], a[1], a[2], 1.0); + double4 ret = math.mul(_stack[_stack.Count - 1], v); + return new double3(ret[0], ret[1], ret[2]); + } + + public double4 MultPoint(double4 v) + { + Debug.Assert(_stack.Count >= 1); + return math.mul(_stack[_stack.Count - 1], v); + } + } +} + diff --git a/Runtime/Scripts/GeospatialEditorRuntime/GeoMath.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/MatrixStack.cs.meta similarity index 100% rename from Runtime/Scripts/GeospatialEditorRuntime/GeoMath.cs.meta rename to Editor/GeospatialCreator/Scripts/Internal/MatrixStack.cs.meta diff --git a/Runtime/Scripts/GeospatialEditorRuntime/UnityMathematicsStub.cs b/Editor/GeospatialCreator/Scripts/Internal/UnityMathematicsStub.cs similarity index 61% rename from Runtime/Scripts/GeospatialEditorRuntime/UnityMathematicsStub.cs rename to Editor/GeospatialCreator/Scripts/Internal/UnityMathematicsStub.cs index 098b3e8..623169b 100644 --- a/Runtime/Scripts/GeospatialEditorRuntime/UnityMathematicsStub.cs +++ b/Editor/GeospatialCreator/Scripts/Internal/UnityMathematicsStub.cs @@ -18,62 +18,24 @@ // //----------------------------------------------------------------------- -#if UNITY_2021_3_OR_NEWER - #if !ARCORE_INTERNAL_USE_UNITY_MATH -namespace Google.XR.ARCoreExtensions.GeospatialCreator.Internal -{ - /// Stub that allows our Math-dependent code to compile when the real Unity math - /// dependency is not present. This gives us control over the error message without requiring - /// ifdefs everywhere we use the math library. - public static class math - { - public static void throwDependencyException() - { - throw new System.Exception("Unity.Mathematics 1.2.0+ not available."); - } - - public static void sincos(double x, out double s, out double c) - { - s = 0; - c = 0; - throwDependencyException(); - } - - public static double4 mul(double4x4 m1, double4 v) - { - throwDependencyException(); - return new double4(0); - } - - public static double4x4 mul(double4x4 m1, double4x4 m2) - { - throwDependencyException(); - return new double4x4(0); - } - - public static void sincos(double3 x, out double3 s, out double3 c) - { - s = new double3(0); - c = new double3(0); - throwDependencyException(); - } +[module: System.Diagnostics.CodeAnalysis.SuppressMessage( + "StyleCop.CSharp.DocumentationRules", + "SA1649:FileHeaderFileNameDocumentationMustMatchTypeName", + Justification = "Must match names in Unity.Mathematics")] - public static double4x4 transpose(double4x4 m) - { - throwDependencyException(); - return new double4x4(0); - } - - public static double4x4 inverse(double4x4 m) - { - throwDependencyException(); - return new double4x4(0); - } - } - - public struct double3 +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1107:PublicFieldsMustBeUpperCamelCase", + Justification = "Must match names in Unity.Mathematics")] + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1111:StructsMustBeUpperCamelCase", + Justification = "Must match names in Unity.Mathematics")] + internal struct double3 { public double x, y, @@ -87,8 +49,9 @@ public double3(double v) math.throwDependencyException(); } - public double3(double x, double y, double z) - : this(0.0d) { } + public double3(double x, double y, double z) : this(0.0d) + { + } public double this[int i] { @@ -97,11 +60,23 @@ public double this[int i] math.throwDependencyException(); return 0.0d; } - set { math.throwDependencyException(); } + + set + { + math.throwDependencyException(); + } } } - public struct double4 + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1107:PublicFieldsMustBeUpperCamelCase", + Justification = "Must match names in Unity.Mathematics")] + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1111:StructsMustBeUpperCamelCase", + Justification = "Must match names in Unity.Mathematics")] + internal struct double4 { public double x, y, @@ -117,8 +92,9 @@ public double4(double v) math.throwDependencyException(); } - public double4(double x, double y, double z, double w) - : this(0d) { } + public double4(double x, double y, double z, double w) : this(0d) + { + } public double this[int i] { @@ -127,12 +103,26 @@ public double this[int i] math.throwDependencyException(); return 0.0d; } - set { math.throwDependencyException(); } + + set + { + math.throwDependencyException(); + } } } - public struct double4x4 + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1107:PublicFieldsMustBeUpperCamelCase", + Justification = "Must match names in Unity.Mathematics")] + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1111:StructsMustBeUpperCamelCase", + Justification = "Must match names in Unity.Mathematics")] + internal struct double4x4 { + public static readonly double4x4 identity = new double4x4(0.0d); + public double4 c0, c1, c2, @@ -147,8 +137,9 @@ public double4x4(double v) math.throwDependencyException(); } - public double4x4(double4 c0, double4 c1, double4 c2, double4 c3) - : this(0.0d) { } + public double4x4(double4 c0, double4 c1, double4 c2, double4 c3) : this(0.0d) + { + } public double4x4( double m00, @@ -166,13 +157,68 @@ public double4x4( double m30, double m31, double m32, - double m33 - ) - : this() { } + double m33) + : this() + { + } + } - public static readonly double4x4 identity = new double4x4(0.0d); + /// Stub that allows our Math-dependent code to compile when the real Unity math + /// dependency is not present. This gives us control over the error message without requiring + /// ifdefs everywhere we use the math library. + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1110:ClassesMustBeUpperCamelCase", + Justification = "Must match names in Unity.Mathematics")] + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1113:MethodsMustBeUpperCamelCase", + Justification = "Must match names in Unity.Mathematics")] + internal static class math + { + public static void throwDependencyException() + { + throw new System.Exception("Unity.Mathematics 1.2.0+ not available."); + } + + public static void sincos(double x, out double s, out double c) + { + s = 0; + c = 0; + throwDependencyException(); + } + + public static double4 mul(double4x4 m1, double4 v) + { + throwDependencyException(); + return new double4(0); + } + + public static double4x4 mul(double4x4 m1, double4x4 m2) + { + throwDependencyException(); + return new double4x4(0); + } + + public static void sincos(double3 x, out double3 s, out double3 c) + { + s = new double3(0); + c = new double3(0); + throwDependencyException(); + } + + public static double4x4 transpose(double4x4 m) + { + throwDependencyException(); + return new double4x4(0); + } + + public static double4x4 inverse(double4x4 m) + { + throwDependencyException(); + return new double4x4(0); + } } } #endif // !ARCORE_INTERNAL_USE_UNITY_MATH -#endif // UNITY_X_OR_NEWER diff --git a/Runtime/Scripts/GeospatialEditorRuntime/UnityMathematicsStub.cs.meta b/Editor/GeospatialCreator/Scripts/Internal/UnityMathematicsStub.cs.meta similarity index 100% rename from Runtime/Scripts/GeospatialEditorRuntime/UnityMathematicsStub.cs.meta rename to Editor/GeospatialCreator/Scripts/Internal/UnityMathematicsStub.cs.meta diff --git a/Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs b/Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs deleted file mode 100644 index 61883a5..0000000 --- a/Editor/GeospatialEditor/Scripts/Internal/ARGeospatialCreatorOriginEditor.cs +++ /dev/null @@ -1,115 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -#if UNITY_2021_3_OR_NEWER - -namespace Google.XR.ARCoreExtensions.GeospatialCreator.Editor.Internal -{ - using System; - using Google.XR.ARCoreExtensions.Editor.Internal; - using Google.XR.ARCoreExtensions.GeospatialCreator.Internal; - using UnityEditor; - using UnityEngine; - - [CustomEditor(typeof(ARGeospatialCreatorOrigin))] - public class ARGeospatialCreatorOriginEditor : Editor - { - public override void OnInspectorGUI() - { - serializedObject.Update(); - var origin = serializedObject.targetObject as ARGeospatialCreatorOrigin; - - GUIStyle titleStyle = new GUIStyle(EditorStyles.boldLabel); - titleStyle.fontSize = 20; - GUILayout.Label("Geospatial Creator Origin", titleStyle); - - if (origin.HasGeoreference()) - { - // Always draw the CesiumGeoreference-specific GUI, since we only support Cesium - // references currently. - GUIForCesiumGeoreference(origin); - } - else - { - GUIForMissingReference(origin); - } - } - - // Draw the GUI when there's no Georeference attached to the target Origin. - private void GUIForMissingReference(ARGeospatialCreatorOrigin origin) - { - GUILayout.BeginVertical(); - EditorGUILayout.PrefixLabel(""); // vertical whitespace for readability. - GUILayout.BeginHorizontal(); - - GUIContent addGeoreferenceContent = new GUIContent( - "Add Cesium Georeference Component", - "Add a CesiumGeoreference to locate Geospatial Anchors in the Unity scene." - ); - if (GUILayout.Button(addGeoreferenceContent)) - { - AddGeoreference(origin); - } - GUILayout.EndHorizontal(); - GUILayout.EndVertical(); - } - - private void AddGeoreference(ARGeospatialCreatorOrigin origin) - { - // Only Cesium anchors are supported so far; the underlying origin object - // will throw an exception if the Cesium dependency is unavailable. - origin.AddNewGeoreferenceComponent(); - } - - private void GUIForCesiumGeoreference(ARGeospatialCreatorOrigin origin) - { - EditorGUILayout.BeginVertical(); - EditorGUILayout.PrefixLabel(""); // vertical whitespace for readability. - GUIContent openQuickstartContent = new GUIContent( - "Open Geospatial Creator Quickstart", - "Open the Quickstart webpage for Geospatial Creator in a browser."); - if (GUILayout.Button(openQuickstartContent)) - { - Application.OpenURL(GeospatialEditorHelper.QuickstartUrl); - } - - // We don't persist the API Key directly in this component. Instead, it is always read from - // and written to the tiles child. - string oldApiKey = origin.Get3DTilesApiKey(); - string newApiKey = EditorGUILayout.DelayedTextField( - "Google Map Tiles API Key", - oldApiKey); - if (String.IsNullOrEmpty(newApiKey)) - { - EditorGUILayout.HelpBox( - "An API key is required to use Google Map Tiles. Follow the Quickstart " - + "Guide for additional instructions.", - MessageType.Warning); - } - if (newApiKey != oldApiKey) - { - origin.Set3DTileApiKey(newApiKey); - } - - EditorGUILayout.EndVertical(); - } - } -} -#endif // UNITY_X_OR_LATER diff --git a/Editor/Scripts/Internal/ARCoreExtensionsProjectSettingsProvider.cs b/Editor/Scripts/Internal/ARCoreExtensionsProjectSettingsProvider.cs index add5db8..4354e08 100644 --- a/Editor/Scripts/Internal/ARCoreExtensionsProjectSettingsProvider.cs +++ b/Editor/Scripts/Internal/ARCoreExtensionsProjectSettingsProvider.cs @@ -54,7 +54,7 @@ public override void OnGUI(string searchContext) IOSSupportHelper.UpdateIOSScriptingDefineSymbols( ARCoreExtensionsProjectSettings.Instance); - GeospatialEditorHelper.OnToggle( + GeospatialCreatorHelper.OnToggle( ARCoreExtensionsProjectSettings.Instance.GeospatialEditorEnabled); ARCoreExtensionsProjectSettings.Instance.Save(); } diff --git a/Editor/Scripts/Internal/GeospatialCreatorEnabledWizard.cs b/Editor/Scripts/Internal/GeospatialCreatorEnabledWizard.cs index 117ecf8..b15c9e2 100644 --- a/Editor/Scripts/Internal/GeospatialCreatorEnabledWizard.cs +++ b/Editor/Scripts/Internal/GeospatialCreatorEnabledWizard.cs @@ -18,8 +18,6 @@ // //----------------------------------------------------------------------- -#if UNITY_2021_3_OR_NEWER - namespace Google.XR.ARCoreExtensions.Editor.Internal { using System; @@ -31,69 +29,45 @@ namespace Google.XR.ARCoreExtensions.Editor.Internal using UnityEngine; using UnityEngine.UIElements; - public class GeospatialCreatorEnabledWizard : EditorWindow + internal class GeospatialCreatorEnabledWizard : EditorWindow { - private static readonly string cesiumId = "com.cesium.unity"; - private static readonly Version cesiumMinVersion = new Version("1.0.0"); - - private static readonly string unityMathId = "com.unity.mathematics"; - private static readonly Version unityMathMinVersion = new Version("1.2.0"); + private const string _cesiumId = "com.cesium.unity"; + private const string _unityMathId = "com.unity.mathematics"; - private static readonly Vector2 wizardWindowSize = new Vector2(350, 400); + private static readonly Version _cesiumMinVersion = new Version("1.1.0"); + private static readonly Version _unityMathMinVersion = new Version("1.2.0"); + private static readonly Vector2 _wizardWindowSize = new Vector2(350, 400); - private static GeospatialCreatorEnabledWizard instance; + private static GeospatialCreatorEnabledWizard _instance; private ListRequest _listInstalledPackagesRequest = null; private bool _isMissingCesium = true; private bool _isMissingUnityMath = true; - private static class WizardStyles - { - public static readonly GUIStyle BodyLabel; - public static readonly GUIStyle BoldBodyLabel; - public static readonly GUIStyle TitleLabel; - - static WizardStyles() - { - BodyLabel = new GUIStyle(EditorStyles.largeLabel); - BodyLabel.wordWrap = true; - - BoldBodyLabel = new GUIStyle(BodyLabel); - BoldBodyLabel.fontStyle = FontStyle.Bold; - - TitleLabel = new GUIStyle(EditorStyles.boldLabel); - TitleLabel.fontSize = 20; - TitleLabel.alignment = TextAnchor.MiddleCenter; - } - } - public static GeospatialCreatorEnabledWizard ShowWizard() { - if (instance == null) + if (_instance == null) { - instance = + _instance = ScriptableObject.CreateInstance(typeof(GeospatialCreatorEnabledWizard)) as GeospatialCreatorEnabledWizard; - instance.ShowUtility(); + _instance.ShowUtility(); - instance.titleContent = new GUIContent("Geospatial Creator"); - instance.minSize = wizardWindowSize; - instance.maxSize = instance.minSize; + _instance.titleContent = new GUIContent("Geospatial Creator"); + _instance.minSize = _wizardWindowSize; + _instance.maxSize = _instance.minSize; } else { - instance.ShowUtility(); + _instance.ShowUtility(); } - return instance; - } - private static bool MeetsVersionRequirement(Version toCheck, Version minVersion) { - return (toCheck.CompareTo(minVersion) >= 0); + return _instance; } public void OnDestroy() { - instance = null; + _instance = null; } public void OnFocus() @@ -118,9 +92,15 @@ public void OnGUI() { FinishGUI(); } + GUILayout.EndVertical(); } + private static bool MeetsVersionRequirement(Version toCheck, Version minVersion) + { + return (toCheck.CompareTo(minVersion) >= 0); + } + // Draw the GUI elements for the title, fixed product summary, and Quickstart button private void HeaderGUI() { @@ -135,8 +115,9 @@ private void HeaderGUI() "Open the Quickstart webpage for Geospatial Creator in a browser."); if (GUILayout.Button(openQuickstartContent)) { - Application.OpenURL(GeospatialEditorHelper.QuickstartUrl); + Application.OpenURL(GeospatialCreatorHelper.QuickstartUrl); } + EditorGUILayout.Space(); } @@ -168,6 +149,7 @@ private void FooterGUI( { action(); } + GUI.enabled = prevEnabled; GUILayout.EndHorizontal(); } @@ -190,13 +172,18 @@ private void IsMissingDependenciesGUI() if (_isMissingCesium) { dependenciesText.Append( - String.Format("\n • {0} {1}+", cesiumId, cesiumMinVersion.ToString())); + String.Format("\n • {0} {1}+", _cesiumId, _cesiumMinVersion.ToString())); } + if (_isMissingUnityMath) { dependenciesText.Append( - String.Format("\n • {0} {1}+", unityMathId, unityMathMinVersion.ToString())); + String.Format( + "\n • {0} {1}+", + _unityMathId, + _unityMathMinVersion.ToString())); } + dependenciesText.Append("\n\nSee the Quickstart Guide for more information."); HeaderGUI(); @@ -220,11 +207,12 @@ private void FinishGUI() FooterGUI(false, true, finishButtonText, () => { - GeospatialEditorHelper.ConfigureScriptingSymbols(true); - ARCoreExtensionsProjectSettings.Instance.GeospatialEditorEnabled = true; - ARCoreExtensionsProjectSettings.Instance.Save(); - // :TODO (b/277333333): Consider waiting for scripts to reload before closing - Close(); + GeospatialCreatorHelper.ConfigureScriptingSymbols(true); + ARCoreExtensionsProjectSettings.Instance.GeospatialEditorEnabled = true; + ARCoreExtensionsProjectSettings.Instance.Save(); + + // :TODO (b/277333333): Consider waiting for scripts to reload before closing + Close(); }); } @@ -252,28 +240,51 @@ private void ListPackagesRequestProgress() { return; } + foreach (var package in _listInstalledPackagesRequest.Result) { - if (package.name == cesiumId) + if (package.name == _cesiumId) { _isMissingCesium = - !MeetsVersionRequirement(new Version(package.version), cesiumMinVersion); + !MeetsVersionRequirement(new Version(package.version), _cesiumMinVersion); } - else if (package.name == unityMathId) + else if (package.name == _unityMathId) { _isMissingUnityMath = - !MeetsVersionRequirement(new Version(package.version), unityMathMinVersion); + !MeetsVersionRequirement( + new Version(package.version), _unityMathMinVersion); } + if (!_isMissingCesium && !_isMissingUnityMath) { break; } } + EditorApplication.update -= ListPackagesRequestProgress; _listInstalledPackagesRequest = null; Repaint(); } + + private static class WizardStyles + { + public static readonly GUIStyle BodyLabel; + public static readonly GUIStyle BoldBodyLabel; + public static readonly GUIStyle TitleLabel; + + static WizardStyles() + { + BodyLabel = new GUIStyle(EditorStyles.largeLabel); + BodyLabel.wordWrap = true; + + BoldBodyLabel = new GUIStyle(BodyLabel); + BoldBodyLabel.fontStyle = FontStyle.Bold; + + TitleLabel = new GUIStyle(EditorStyles.boldLabel); + TitleLabel.fontSize = 20; + TitleLabel.alignment = TextAnchor.MiddleCenter; + } + } } } -#endif // UNITY_X_OR_LATER diff --git a/Editor/Scripts/Internal/GeospatialEditorHelper.cs b/Editor/Scripts/Internal/GeospatialCreatorHelper.cs similarity index 97% rename from Editor/Scripts/Internal/GeospatialEditorHelper.cs rename to Editor/Scripts/Internal/GeospatialCreatorHelper.cs index c26e513..6ffd2a1 100644 --- a/Editor/Scripts/Internal/GeospatialEditorHelper.cs +++ b/Editor/Scripts/Internal/GeospatialCreatorHelper.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// +// // // Copyright 2023 Google LLC // @@ -18,7 +18,6 @@ // //----------------------------------------------------------------------- - namespace Google.XR.ARCoreExtensions.Editor.Internal { using System; @@ -32,9 +31,9 @@ namespace Google.XR.ARCoreExtensions.Editor.Internal /// /// The functions defined here can be invoked directly from other parts of ARCore /// Extensions, which is why this class is in the Google.XR.ARCoreExtensions.Editor namespace - /// and ASMDEF. If this code was in the GeospatialEditor assembly, we'd need to modify the + /// and ASMDEF. If this code was in the GeospatialCreator assembly, we'd need to modify the /// ARCoreExtensions ASMDEF to include additional assemblies. - public static class GeospatialEditorHelper + public static class GeospatialCreatorHelper { /// URL for the Geospatial Creator quickstart page. public static readonly string QuickstartUrl = diff --git a/Editor/Scripts/Internal/GeospatialEditorHelper.cs.meta b/Editor/Scripts/Internal/GeospatialCreatorHelper.cs.meta similarity index 100% rename from Editor/Scripts/Internal/GeospatialEditorHelper.cs.meta rename to Editor/Scripts/Internal/GeospatialCreatorHelper.cs.meta diff --git a/Runtime/Scripts/GeospatialEditorRuntime.meta b/Runtime/GeospatialCreatorRuntime.meta similarity index 100% rename from Runtime/Scripts/GeospatialEditorRuntime.meta rename to Runtime/GeospatialCreatorRuntime.meta diff --git a/Runtime/Scripts/GeospatialEditorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef b/Runtime/GeospatialCreatorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef similarity index 53% rename from Runtime/Scripts/GeospatialEditorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef rename to Runtime/GeospatialCreatorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef index 4f068de..8b235a8 100644 --- a/Runtime/Scripts/GeospatialEditorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef +++ b/Runtime/GeospatialCreatorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef @@ -6,9 +6,7 @@ "Unity.XR.ARCore", "Unity.XR.ARSubsystems", "Unity.XR.ARFoundation", - "Unity.XR.CoreUtils", - "CesiumRuntime", - "Unity.Mathematics" + "Unity.XR.CoreUtils" ], "includePlatforms": [], "excludePlatforms": [], @@ -17,18 +15,6 @@ "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], - "versionDefines": [ - { - "name": "com.cesium.unity", - "expression": "1.0.0", - "define": "ARCORE_INTERNAL_USE_CESIUM" - }, - { - "name": "com.unity.mathematics", - "expression": "1.2.0", - "define": "ARCORE_INTERNAL_USE_UNITY_MATH" - } - ], + "versionDefines": [], "noEngineReferences": false } - diff --git a/Runtime/Scripts/GeospatialEditorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef.meta b/Runtime/GeospatialCreatorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef.meta similarity index 100% rename from Runtime/Scripts/GeospatialEditorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef.meta rename to Runtime/GeospatialCreatorRuntime/Google.XR.ARCoreExtensions.GeospatialCreator.asmdef.meta diff --git a/Runtime/GeospatialCreatorRuntime/Scripts.meta b/Runtime/GeospatialCreatorRuntime/Scripts.meta new file mode 100644 index 0000000..accd681 --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e45781be5b6c34dee8d4e8572c643fab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/GeospatialCreatorRuntime/Scripts/AssemblyInfo.cs b/Runtime/GeospatialCreatorRuntime/Scripts/AssemblyInfo.cs new file mode 100644 index 0000000..38754fe --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts/AssemblyInfo.cs @@ -0,0 +1,23 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo( + "Google.XR.ARCoreExtensions.GeospatialCreator.Editor")] + diff --git a/Runtime/GeospatialCreatorRuntime/Scripts/AssemblyInfo.cs.meta b/Runtime/GeospatialCreatorRuntime/Scripts/AssemblyInfo.cs.meta new file mode 100644 index 0000000..04dbb14 --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6dbe9cc6f034e4fa289ce13354c71d76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/GeospatialCreatorRuntime/Scripts/Internal.meta b/Runtime/GeospatialCreatorRuntime/Scripts/Internal.meta new file mode 100644 index 0000000..57d1077 --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts/Internal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ca481bcbdb6bd4aa9a4d5a0ae4592e81 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorAnchor.cs b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorAnchor.cs similarity index 56% rename from Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorAnchor.cs rename to Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorAnchor.cs index 53c75b1..6dbf155 100644 --- a/Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorAnchor.cs +++ b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorAnchor.cs @@ -17,234 +17,139 @@ // // //----------------------------------------------------------------------- -#if UNITY_2021_3_OR_NEWER namespace Google.XR.ARCoreExtensions.GeospatialCreator.Internal { using System; using System.Collections; + using Google.XR.ARCoreExtensions; using Google.XR.ARCoreExtensions.Internal; -#if ARCORE_INTERNAL_USE_UNITY_MATH - using Unity.Mathematics; -#endif using UnityEngine; using UnityEngine.XR.ARFoundation; using UnityEngine.XR.ARSubsystems; + /// + /// A representation of a Geospatial Anchor that was created using the Geospatial Creator tool. + /// This object is responsible for creating a proper ARGeospatialAnchor at runtime at the + /// latitude, longitude, and altitude specified. + /// [AddComponentMenu("XR/AR Geospatial Creator Anchor")] [ExecuteInEditMode] - public class ARGeospatialCreatorAnchor : MonoBehaviour + public class ARGeospatialCreatorAnchor : ARGeospatialCreatorObject { + /// Gets or sets the AltitudeType used for resolution of this anchor. + public AltitudeType AltType = AltitudeType.ManualAltitude; + + [SerializeField] + private double _latitude; + + [SerializeField] + private double _longitude; + + [SerializeField] + private double _altitude; + + [SerializeField] + private double _altitudeOffset; + +#if !UNITY_EDITOR + private AnchorResolutionState _anchorResolution = AnchorResolutionState.NotStarted; +#endif + + /// + /// Determines how the Altitude and AlttudeOffset fields are interpreted. + /// public enum AltitudeType { + /// + /// Altitude specifies the altitude of the anchor in meters for WGS84. AltitudeOffset + /// is not used. + /// ManualAltitude, + + /// + /// AltitudeOffset specifies the relative altitude above/below the terrain, in meters. + /// Altitude is used only in the Editor for visualizing the anchor in the scene view. + /// Terrain, - Rooftop, - }; + + /// + /// AltitudeOffset specifies the relative altitude above/below the rooftop, in meters. + /// Altitude is used only in the Editor for visualizing the anchor in the scene view. + /// + Rooftop + } #if !UNITY_EDITOR - private enum AnchorResolutionState { + private enum AnchorResolutionState + { NotStarted, InProgress, Complete - }; -#endif - -#if UNITY_EDITOR - public GeoTilesReference GeoReference; - - public double3 ECEF; - public double3 EUN; - public double3 EUS; - - public bool shouldPosition = true; + } #endif - public AltitudeType AltType = AltitudeType.ManualAltitude; - + /// Gets or sets the latitude of this anchor. public double Latitude { get => this._latitude; set { this._latitude = value; } } + /// Gets or sets the longitude of this anchor. public double Longitude { get => this._longitude; set { this._longitude = value; } } + /// + /// Gets or sets the altitude. When AltType is ManualAltitude, this value is the altitude + /// of the anchor, in meters according to WGS84. When AltType is Terrain or Rooftop, this + /// value is ONLY used in Editor mode, to determine the altitude at which to render the + /// anchor in the Editor's Scene View. If AltType is Terrain or Rooftop, this value is + /// ignored in the Player. + /// public double Altitude { get => this._altitude; set { this._altitude = value; } } + /// + /// Gets or sets the altitude offset of the anchor, in meters relative to the resolved + /// terrain or rooftop. This value is ignored when AltType is ManualAltitude. + /// public double AltitudeOffset { get => this._altitudeOffset; set { this._altitudeOffset = value; } } - [SerializeField] - private double _latitude; - - [SerializeField] - private double _longitude; - - [SerializeField] - private double _altitude; - - [SerializeField] - private double _altitudeOffset; - #if !UNITY_EDITOR - private AnchorResolutionState _anchorResolution = AnchorResolutionState.NotStarted; -#endif - -#if UNITY_EDITOR - [SerializeField] - private double _geoRefLatitude; - - [SerializeField] - private double _geoRefLongitude; - - [SerializeField] - private double _geoRefHeight; - - private double4x4 ENUToECEF; - private double4x4 ECEFToENU; - private Vector3 _oldPosition = Vector3.zero; - private Quaternion _oldRotation = Quaternion.identity; - private Vector3 _oldScale = Vector3.one; - - public void SetUnityPosition() - { - shouldPosition = false; - CalculateRealWorldPosition(); - GeoCoor coor = new GeoCoor(Latitude, Longitude, Altitude); - double3 localInECEF = GeoCoor.GeoCoorToECEF(coor); - double3 ENU = MatrixStack.MultPoint(ECEFToENU, localInECEF); - // Unity is EUN not ENU so swap z and y - Vector3 EUN = new Vector3((float)ENU.x, (float)ENU.z, (float)ENU.y); - transform.position = EUN; - } - - private void CalculateRealWorldPosition() - { - GeoCoor coor; - GeoTilesReferencePoint refPoint = GeoReference.GetTilesReferencePoint(this.gameObject); - if (refPoint != null) - { - coor = new GeoCoor(refPoint.Latitude, refPoint.Longitude, refPoint.Height); - } - else - { - coor = new GeoCoor(_geoRefLatitude, _geoRefLongitude, _geoRefHeight); - } - - // :TODO b/277370107: This could be optimized by only changing the position if the - // object or origin has moved - double3 PositionInECEF = GeoCoor.GeoCoorToECEF(coor); - - // Rotate from y up to z up and flip X. References: - // https://github.com/CesiumGS/3d-tiles/tree/main/specification#transforms - // https://stackoverflow.com/questions/1263072/changing-a-matrix-from-right-handed-to-left-handed-coordinate-system - // https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#From_ECEF_to_ENU - MatrixStack _matrixStack = new MatrixStack(); - _matrixStack.PushMatrix(); - - double latSin, latCos; - math.sincos(coor.Latitude / 180 * Math.PI, out latSin, out latCos); - double lngSin, lngCos; - math.sincos(coor.Longitude / 180 * Math.PI, out lngSin, out lngCos); - double4x4 ECEFToENURot = new double4x4( - -lngSin, - lngCos, - 0.0, - 0.0, - -latSin * lngCos, - -latSin * lngSin, - latCos, - 0.0, - latCos * lngCos, - latCos * lngSin, - latSin, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0); - - _matrixStack.MultMatrix( - MatrixStack.Translate( - new double3(-PositionInECEF.x, -PositionInECEF.y, -PositionInECEF.z))); - _matrixStack.MultMatrix(ECEFToENURot); - ECEFToENU = _matrixStack.GetMatrix(); - ENUToECEF = math.inverse(ECEFToENU); - - if (refPoint != null) - { - _geoRefLatitude = refPoint.Latitude; - _geoRefLongitude = refPoint.Longitude; - _geoRefHeight = refPoint.Height; - } - } - private void Update() { - if (Application.isPlaying) + // Create the geospatial anchor in Player mode only + if (!Application.isPlaying) { return; } - CalculateRealWorldPosition(); - EUN = new double3(transform.position.x, transform.position.y, transform.position.z); - double3 ENU = new double3(EUN.x, EUN.z, EUN.y); - EUS = new double3(EUN.x, EUN.y, -EUN.z); - ECEF = MatrixStack.MultPoint(ENUToECEF, ENU); - - double3 llh = CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight( - ECEF - ); - if (_oldPosition != transform.position) - { - shouldPosition = true; - _oldPosition = transform.position; - } - if (_oldRotation != transform.rotation) - { - shouldPosition = true; - _oldRotation = transform.rotation; - } - if (_oldScale != transform.localScale) - { - shouldPosition = true; - _oldScale = transform.localScale; - } - - if (shouldPosition) + // Only attempt to create the geospatial anchor once + if (_anchorResolution == AnchorResolutionState.NotStarted) { - _longitude = llh.x; - _latitude = llh.y; - _altitude = llh.z; + AddGeoAnchorAtRuntime(); } } - private void OnEnable() - { - GeoReference = new GeoTilesReference(this.gameObject); - CalculateRealWorldPosition(); - } - - private void OnDisable() - { - GeoReference = null; - } -#else // !UNITY_EDITOR + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "UnityRules.UnityStyleRules", + "US1300:LinesMustBe100CharactersOrShorter", + Justification = "Unity issue URL length > 100")] private void AddGeoAnchorAtRuntime() { IntPtr sessionHandle = ARCoreExtensions._instance.currentARCoreSessionHandle; + // During boot this will return false a few times. if (sessionHandle == IntPtr.Zero) { @@ -255,7 +160,7 @@ private void AddGeoAnchorAtRuntime() // https://developers.google.com/ar/develop/unity-arf/geospatial/geospatial-anchors#place_a_geospatial_anchor_in_the_real_world if (EarthApi.GetEarthTrackingState(sessionHandle) != TrackingState.Tracking) { - Debug.Log("Waiting for AR Session to become stable (earthTrackingState != TrackingState.Tracking)"); + Debug.Log("Waiting for AR Session to become stable."); return; } @@ -293,8 +198,8 @@ private void FinishAnchor(ARGeospatialAnchor resolvedAnchor) { if (resolvedAnchor == null) { + // If we failed once, resolution is likley to keep failing. Don't retry endlessly. Debug.LogError("Failed to make Geospatial Anchor for " + name); - // If we failed once, resolution is likley to keep failing, so don't retry endlessly _anchorResolution = AnchorResolutionState.Complete; return; } @@ -314,14 +219,13 @@ private void FinishAnchor(ARGeospatialAnchor resolvedAnchor) private void ResolveManualAltitudeAnchor(ARAnchorManager anchorManager) { ARGeospatialAnchor anchor = anchorManager.AddAnchor( - Latitude, Longitude, Altitude, transform.rotation); + Latitude, Longitude, Altitude, transform.rotation); FinishAnchor(anchor); } private IEnumerator ResolveTerrainAnchor(ARAnchorManager anchorManager) { ARGeospatialAnchor anchor = null; - ResolveAnchorOnTerrainPromise promise = anchorManager.ResolveAnchorOnTerrainAsync( Latitude, Longitude, AltitudeOffset, transform.rotation); @@ -332,6 +236,7 @@ private IEnumerator ResolveTerrainAnchor(ARAnchorManager anchorManager) { anchor = result.Anchor; } + FinishAnchor(anchor); yield break; } @@ -339,7 +244,6 @@ private IEnumerator ResolveTerrainAnchor(ARAnchorManager anchorManager) private IEnumerator ResolveRooftopAnchor(ARAnchorManager anchorManager) { ARGeospatialAnchor anchor = null; - ResolveAnchorOnRooftopPromise promise = anchorManager.ResolveAnchorOnRooftopAsync( Latitude, Longitude, AltitudeOffset, transform.rotation); @@ -350,25 +254,11 @@ private IEnumerator ResolveRooftopAnchor(ARAnchorManager anchorManager) { anchor = result.Anchor; } + FinishAnchor(anchor); yield break; } - - private void Update() - { - // Only create the geospatial anchor in Player mode - if (!Application.isPlaying) - { - return; - } - - // Only attempt to create the geospatial anchor once - if (_anchorResolution == AnchorResolutionState.NotStarted) - { - AddGeoAnchorAtRuntime(); - } - } -#endif // UNITY_EDITOR +#endif // !UNITY_EDITOR } } -#endif // UNITY_X_OR_NEWER + diff --git a/Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorAnchor.cs.meta b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorAnchor.cs.meta similarity index 100% rename from Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorAnchor.cs.meta rename to Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorAnchor.cs.meta diff --git a/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorObject.cs b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorObject.cs new file mode 100644 index 0000000..d1417dc --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorObject.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Internal +{ + using System; +#if UNITY_EDITOR + using UnityEditor; +#endif + using UnityEngine; + + /// + /// Base class for Geospatial Creator objects. Useful for managing Editor-specific updates. + /// + [ExecuteInEditMode] + public abstract class ARGeospatialCreatorObject : MonoBehaviour + { +#if UNITY_EDITOR +#if ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED + internal Action OnEditorUpdate; + + internal virtual void Update() + { + OnEditorUpdate?.Invoke(); + } +#endif // ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED +#endif // UNITY_EDITOR + } +} + diff --git a/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorObject.cs.meta b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorObject.cs.meta new file mode 100644 index 0000000..b92755d --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3d62d9bd225f47648d60fba514f98e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorOrigin.cs b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorOrigin.cs new file mode 100644 index 0000000..16a01da --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorOrigin.cs @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Internal +{ + using System; + + using Google.XR.ARCoreExtensions.Internal; +#if UNITY_EDITOR + using UnityEditor; +#endif + using UnityEngine; + + /// + /// Provides a Geospatial Creator Origin that has both a lat/lon and gamespace coordinates. This is + /// the reference point used by AR Anchors made in the Geospatial Creator to resolve their + /// location in gamespace. + /// +#if ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED + [AddComponentMenu("XR/Geospatial Creator/AR Geospatial Creator Origin")] +#endif + public class ARGeospatialCreatorOrigin : ARGeospatialCreatorObject + { +#if UNITY_EDITOR + // Updated in the Editor assembly from the GeospatialOriginUpdater. Can be null if there's + // no origin specified. + internal GeoCoordinate OriginPoint; +#endif + } +} + diff --git a/Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorOrigin.cs.meta b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorOrigin.cs.meta similarity index 100% rename from Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorOrigin.cs.meta rename to Runtime/GeospatialCreatorRuntime/Scripts/Internal/ARGeospatialCreatorOrigin.cs.meta diff --git a/Runtime/GeospatialCreatorRuntime/Scripts/Internal/GeoCoordinate.cs b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/GeoCoordinate.cs new file mode 100644 index 0000000..d41fc1a --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/GeoCoordinate.cs @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------- +// +// +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +//----------------------------------------------------------------------- + +namespace Google.XR.ARCoreExtensions.GeospatialCreator.Internal +{ + using System; + using System.Collections.Generic; + using UnityEngine; + + /// Immutable class representing a specific lat/lon/altitude. + internal sealed class GeoCoordinate + { + private double _latitude; + private double _longitude; + private double _altitude; + + public GeoCoordinate(double latitude, double longitude, double altitude) + { + _latitude = latitude; + _longitude = longitude; + _altitude = altitude; + } + + public double Latitude + { + get { return _latitude; } + } + + public double Longitude + { + get { return _longitude; } + } + + public double Altitude + { + get { return _altitude; } + } + } +} + diff --git a/Runtime/GeospatialCreatorRuntime/Scripts/Internal/GeoCoordinate.cs.meta b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/GeoCoordinate.cs.meta new file mode 100644 index 0000000..a6ef359 --- /dev/null +++ b/Runtime/GeospatialCreatorRuntime/Scripts/Internal/GeoCoordinate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0820e4284ede6469585a7c45da681d69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Plugins/ARPresto.aar b/Runtime/Plugins/ARPresto.aar index 378092c..dcea0c1 100644 Binary files a/Runtime/Plugins/ARPresto.aar and b/Runtime/Plugins/ARPresto.aar differ diff --git a/Runtime/Plugins/arcore_client.aar b/Runtime/Plugins/arcore_client.aar index 95aa06d..5508061 100644 Binary files a/Runtime/Plugins/arcore_client.aar and b/Runtime/Plugins/arcore_client.aar differ diff --git a/Runtime/Scripts/ARSemanticManager.cs b/Runtime/Scripts/ARSemanticManager.cs index 0b73463..d875cb9 100644 --- a/Runtime/Scripts/ARSemanticManager.cs +++ b/Runtime/Scripts/ARSemanticManager.cs @@ -64,7 +64,7 @@ public FeatureSupported IsSemanticModeSupported(SemanticMode mode) /// Attempts to get a texture representing the semantic image for the current frame. /// The texture format is . Each pixel in the /// image is an 8-bit unsigned integer representing a semantic class label. - /// is the list of possible pixel labels. See the is the list of possible pixel labels. See the Scene /// Semantics Developer Guide for more information. /// @@ -153,7 +153,7 @@ public bool TryGetSemanticTexture(ref Texture2D texture) /// to query for support for Scene Semantics. /// /// The size of the semantic confidence image is the same size as the image - /// obtained by . + /// obtained by . /// /// Scene Semantics is currently not supported on the iOS platform. Calling this /// on an iOS device will return false. diff --git a/Runtime/Scripts/ARStreetscapeGeometry.cs b/Runtime/Scripts/ARStreetscapeGeometry.cs index 349af9e..8008586 100644 --- a/Runtime/Scripts/ARStreetscapeGeometry.cs +++ b/Runtime/Scripts/ARStreetscapeGeometry.cs @@ -17,6 +17,7 @@ // // //----------------------------------------------------------------------- + namespace Google.XR.ARCoreExtensions { using System; diff --git a/Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorOrigin.cs b/Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorOrigin.cs deleted file mode 100644 index a29c87b..0000000 --- a/Runtime/Scripts/GeospatialEditorRuntime/ARGeospatialCreatorOrigin.cs +++ /dev/null @@ -1,146 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- -#if UNITY_2021_3_OR_NEWER - -namespace Google.XR.ARCoreExtensions.GeospatialCreator.Internal -{ - using System; -#if ARCORE_INTERNAL_USE_CESIUM - using CesiumForUnity; -#endif - using Google.XR.ARCoreExtensions.Internal; -#if UNITY_EDITOR - using UnityEditor; -#endif - using UnityEngine; - - /// - /// Provides a Geospatial Creator Origin that has both a lat/lon and gamespace coordinates. This is - /// the reference point used by AR Anchors made in the Geospatial Creator to resolve their - /// location in gamespace. - /// -#if ARCORE_INTERNAL_GEOSPATIAL_CREATOR_ENABLED - [AddComponentMenu("XR/Geospatial Creator/AR Geospatial Creator Origin")] -#endif - [ExecuteInEditMode] - public class ARGeospatialCreatorOrigin : MonoBehaviour - { - // Helper that extracts the API key from a Google Map Tiles API call URL - public static string ApiKeyFromTilesetUrl(string url) - { - char[] delimeters = { '&', '?' }; - foreach (string urlPart in url.Split(delimeters)) - { - if (urlPart.StartsWith("key=")) - { - return urlPart.Substring(4); - } - } - return ""; - } - - // Returns the URL for the tiles API for the given key - private static string TilesApiUrl(string apiKey) { - return String.Format("https://tile.googleapis.com/v1/3dtiles/root?key={0}", apiKey); - } - - public bool HasGeoreference() - { -#if ARCORE_INTERNAL_USE_CESIUM - return (gameObject.GetComponent(typeof(CesiumGeoreference)) != null); -#endif - return false; - } - - public void AddNewGeoreferenceComponent() - { - if (HasGeoreference()) - { - throw new Exception( - "Geospatial Creator georeference already exists, could not create another."); - } - -#if !ARCORE_INTERNAL_USE_CESIUM - throw new Exception("Cesium dependency is missing."); -#else // need to use #else block to avoid unreachable code failures - - CesiumGeoreference georeference = - gameObject.AddComponent(typeof(CesiumGeoreference)) as CesiumGeoreference; - - GameObject tilesetObject = new GameObject("Cesium3DTileset"); - tilesetObject.transform.SetParent(georeference.gameObject.transform); - - // Since this is an AR app, it is likely using the camera instead of a scene - // so default to the tiles only being visible in the Editor. Developers can - // manually change the tag in the Inspector, if desired. - Cesium3DTileset tileset = - tilesetObject.AddComponent(typeof(Cesium3DTileset)) as Cesium3DTileset; - tileset.name = tilesetObject.name; - tileset.tilesetSource = CesiumDataSource.FromUrl; - tileset.showCreditsOnScreen = true; - tileset.createPhysicsMeshes = false; -#if UNITY_EDITOR - tilesetObject.tag = "EditorOnly"; - Undo.RegisterCreatedObjectUndo(georeference, "Create Cesium Georeference"); -#endif -#endif - } - - public string Get3DTilesApiKey() - { -#if !ARCORE_INTERNAL_USE_CESIUM - throw new Exception("Cannot get Map Tiles API key; Cesium dependency is missing."); -#else // need to use #else block to avoid unreachable code failures - Cesium3DTileset tileset = - gameObject.GetComponentInChildren(typeof(Cesium3DTileset)) as Cesium3DTileset; - if (tileset == null) - { - return ""; - } - return ApiKeyFromTilesetUrl(tileset.url); -#endif - } - - public void Set3DTileApiKey(string key) - { -#if !ARCORE_INTERNAL_USE_CESIUM - throw new Exception("Cannot set Map Tiles API key; Cesium dependency is missing."); -#else // need to use #else block to avoid unreachable code failures - Cesium3DTileset tileset = - gameObject.GetComponentInChildren(typeof(Cesium3DTileset)) as Cesium3DTileset; - if (tileset == null) - { - Debug.LogError( - "Attempted to set Map Tiles API key on a missing Cesium3DTileset component."); - return; - } - String url = String.IsNullOrEmpty(key) ? "" : TilesApiUrl(key); - if (url != tileset.url) - { - Debug.Log("Setting new URL for Map Tiles API: " + url); - tileset.url = url; - } -#endif - } - - } -} - -#endif // UNITY_X_OR_NEWER diff --git a/Runtime/Scripts/GeospatialEditorRuntime/GeoMath.cs b/Runtime/Scripts/GeospatialEditorRuntime/GeoMath.cs deleted file mode 100644 index adf2fcd..0000000 --- a/Runtime/Scripts/GeospatialEditorRuntime/GeoMath.cs +++ /dev/null @@ -1,630 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -#if UNITY_2021_3_OR_NEWER - -namespace Google.XR.ARCoreExtensions.GeospatialCreator.Internal -{ - using System; - using System.Collections.Generic; -#if ARCORE_INTERNAL_USE_UNITY_MATH - using Unity.Mathematics; -#endif - using UnityEngine; - - public class GeoCoor - { - public double Latitude; - public double Longitude; - public double Height; - - public GeoCoor(double _Latitude, double _Longitude, double _Height) - { - Latitude = _Latitude; - Longitude = _Longitude; - Height = _Height; - } - - public static GeoCoor ECEFToGeoCoor(double3 ecef) - { - var A = 6378137.0; // equatorial radius in meters - var B = 6356752.314245179; // Polar radius in meters - var p = Math.Sqrt(ecef.x * ecef.x + ecef.y * ecef.y); // Temporary value - var q = Math.Atan2((ecef.z * A), (p * B)); // Temporary value - - // special case of north/south pole - var epsilon = 1e-10; - if (p < epsilon) - { - var lng = 0.0; - var lat = (Math.PI / 2.0) * sgn(ecef.z); - var alt = Math.Sqrt(ecef.z * ecef.z) - B; - return new GeoCoor(lat * 180.0 / Math.PI, lng * 180.0 / Math.PI, alt); - } - - var longitude = Math.Atan2(ecef.y, ecef.x); - var latitude = Math.Atan2( - (ecef.z + ((A * A - B * B) / B) * Math.Pow(Math.Sin(q), 3.0)), - (p - ((A * A - B * B) / A) * Math.Pow(Math.Cos(q), 3.0)) - ); - - var N = - A - / Math.Sqrt( - 1.0 - (1.0 - (B * B) / (A * A)) * Math.Sin(latitude) * Math.Sin(latitude) - ); - var altitude = Math.Sqrt(ecef.x * ecef.x + ecef.y * ecef.y) / Math.Cos(latitude) - N; - - return new GeoCoor(latitude * 180.0 / Math.PI, longitude * 180.0 / Math.PI, altitude); - } - - // conversion between geodetic and earth-centered, earth-fixed (ECEF) coordinates - // https://en.wikipedia.org/wiki/Geographic_coordinate_conversion - public static double3 GeoCoorToECEF(GeoCoor Coor) - { - double3 ret = new double3(); - // a and b are from from WGS84 - // https://en.wikipedia.org/wiki/World_Geodetic_System - var a = 6378137.0; // equatorial radius in meters - var b = 6356752.314245179; // Polar radius in meters - var rlong = Math.PI * Coor.Longitude / 180.0; - var rlat = Math.PI * Coor.Latitude / 180.0; - var coslong = Math.Cos(rlong); - var sinlong = Math.Sin(rlong); - var coslat = Math.Cos(rlat); - var sinlat = Math.Sin(rlat); - var a2 = a * a; - var b2 = b * b; - var f = 1 - (b / a); - var e2 = 1 - (b2 / a2); - var n_2 = a2 / Math.Sqrt((a2 * (coslat * coslat)) + ((b2) * (sinlat * sinlat))); - var n = a / Math.Sqrt(1 - (e2 * sinlat * sinlat)); - // Debug.Log($"Hello: {n} {n_2}"); - var x = (n + Coor.Height) * coslat * coslong; - var y = (n + Coor.Height) * coslat * sinlong; - var neg1f2 = (1 - f) * (1 - f); - var neg1e2 = 1 - e2; - var z = (neg1f2 * n + Coor.Height) * sinlat; - var z_2 = (neg1e2 * n + Coor.Height) * sinlat; - // Debug.Log($"Hello: {z} {z_2}"); - - // tests - var iszero = (x / coslong) - (y / sinlong); - // Debug.Log($"Hello: {iszero}"); - - // x y z are in meters - // save things in the structure - ret.x = x; - ret.y = y; - ret.z = z; - return ret; - } - - private static int sgn(double val) - { - return val < 0 ? -1 : 1; - } - } - - public class LoadingPoint - { - public double3 PositionInECEF; - public double3 PositionInUnityWorldSpace; - public double3 PositionInGLTFSpace; - public double Radius; - public GeoCoor LatLongGeoCoor; - public double4x4 bbToEUNPos; - public double4x4 bbToEUNRot; - public double4x4 meshEUNPos; - - public LoadingPoint(GeoCoor coor, double radius) - { - LatLongGeoCoor = coor; - PositionInECEF = GeoCoor.GeoCoorToECEF(coor); - PositionInUnityWorldSpace = new double3( - -PositionInECEF.y, - PositionInECEF.z, - PositionInECEF.x - ); - PositionInGLTFSpace = new double3( - -PositionInECEF.x, - PositionInECEF.z, - -PositionInECEF.y - ); - Radius = radius; - - // Rotate from y up to z up and flip X. References: - // https://github.com/CesiumGS/3d-tiles/tree/main/specification#transforms - // https://stackoverflow.com/questions/1263072/changing-a-matrix-from-right-handed-to-left-handed-coordinate-system - // https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#From_ECEF_to_ENU - MatrixStack _matrixStack = new MatrixStack(); - _matrixStack.PushMatrix(); - - double latSin, - latCos; - math.sincos(LatLongGeoCoor.Latitude / 180 * Math.PI, out latSin, out latCos); - double lngSin, - lngCos; - math.sincos(LatLongGeoCoor.Longitude / 180 * Math.PI, out lngSin, out lngCos); - double4x4 ECEFToENU = new double4x4( - -lngSin, - lngCos, - 0.0, - 0.0, - -latSin * lngCos, - -latSin * lngSin, - latCos, - 0.0, - latCos * lngCos, - latCos * lngSin, - latSin, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - double4x4 ENUToECEF = math.inverse(ECEFToENU); - - double4x4 ECEFToESU = new double4x4( - -lngSin, - -lngCos, - 0.0, - 0.0, - -latSin * lngCos, - latSin * lngSin, - latCos, - 0.0, - latCos * lngCos, - -latCos * lngSin, - latSin, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - double4x4 ESUToECEF = math.inverse(ECEFToENU); - - // https://stackoverflow.com/questions/1263072/changing-a-matrix-from-right-handed-to-left-handed-coordinate-system - double4x4 GLTFToENU = new double4x4( - -1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - -1.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - double4x4 ENUToGLTF = math.inverse(GLTFToENU); - double4x4 GLTFToECEF = GLTFToENU; - double4x4 ECEFToGLTF = ENUToGLTF; - - double4x4 WUSToEUN = new double4x4( - -1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - -1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - double4x4 EUNToWUS = math.inverse(WUSToEUN); - - double4x4 ENUToEUN = new double4x4( - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - double4x4 EUNToENU = math.inverse(ENUToEUN); - - // WUS Mesh space after ENUToGLTF - // W = +x - // E = -x - // Up = +Y - // Dn = -Y - // N = -z - // S = +z - - // ENU Current BB space - // W = -x - // E = +x - // N = +y - // S = -y - // Up = +z - // Dn = -z - - // Unity EUN - // E = +x - // W = -x - // Up = +y - // Dn = -y - // N = +z - // S = -z - - _matrixStack.MultMatrix( - MatrixStack.Translate( - new double3(-PositionInECEF.x, -PositionInECEF.y, -PositionInECEF.z) - ) - ); - _matrixStack.MultMatrix(ECEFToENU); - _matrixStack.MultMatrix(ENUToEUN); - bbToEUNPos = _matrixStack.GetMatrix(); - _matrixStack.PopMatrix(); - - _matrixStack.PushMatrix(); - _matrixStack.MultMatrix(ECEFToENU); - _matrixStack.MultMatrix(ENUToEUN); - bbToEUNRot = _matrixStack.GetMatrix(); - _matrixStack.PopMatrix(); - - _matrixStack.PushMatrix(); - _matrixStack.MultMatrix(GLTFToECEF); - _matrixStack.MultMatrix( - MatrixStack.Translate( - new double3(-PositionInECEF.x, -PositionInECEF.y, -PositionInECEF.z) - ) - ); - _matrixStack.MultMatrix(ECEFToENU); - _matrixStack.MultMatrix(ENUToGLTF); - _matrixStack.MultMatrix(WUSToEUN); - meshEUNPos = _matrixStack.GetMatrix(); - _matrixStack.PopMatrix(); - } - } - - public class MatrixStack - { - private List Stack = new List(); - - public MatrixStack() - { - Stack.Add(double4x4.identity); - } - - public void PushMatrix() - { - Stack.Add(Stack[Stack.Count - 1]); - } - - public void PushIdentityMatrix() - { - Stack.Add(double4x4.identity); - } - - public void PopMatrix() - { - Debug.Assert(Stack.Count >= 2); - Stack.RemoveAt(Stack.Count - 1); - } - - public double4x4 GetMatrix() - { - Debug.Assert(Stack.Count >= 1); - return Stack[Stack.Count - 1]; - } - - public static Quaternion GetRotation(double4x4 m) - { - Vector3 forward; - forward.x = (float)m.c2.x; - forward.y = (float)m.c2.y; - forward.z = (float)m.c2.z; - - Vector3 upwards; - upwards.x = (float)m.c1.x; - upwards.y = (float)m.c1.y; - upwards.z = (float)m.c1.z; - - return Quaternion.LookRotation(forward, upwards); - } - - public Quaternion GetRotation() - { - double4x4 m = Stack[Stack.Count - 1]; - - Vector3 forward; - forward.x = (float)m.c2.x; - forward.y = (float)m.c2.y; - forward.z = (float)m.c2.z; - - Vector3 upwards; - upwards.x = (float)m.c1.x; - upwards.y = (float)m.c1.y; - upwards.z = (float)m.c1.z; - - return Quaternion.LookRotation(forward, upwards); - } - - public void Transpose() - { - Debug.Assert(Stack.Count >= 1); - Stack[Stack.Count - 1] = math.transpose(Stack[Stack.Count - 1]); - } - - // Pre multiply - public void PreMultMatrix(double4x4 m) - { - Debug.Assert(Stack.Count >= 1); - Stack[Stack.Count - 1] = math.mul(Stack[Stack.Count - 1], m); - } - - // Post multiply - public void MultMatrix(double4x4 m) - { - Debug.Assert(Stack.Count >= 1); - Stack[Stack.Count - 1] = math.mul(m, Stack[Stack.Count - 1]); - } - - public void MultMatrix(List a) - { - Debug.Assert(Stack.Count >= 1); - Debug.Assert(a.Count >= 16); - // load column-major order - double4x4 m = new double4x4( - a[0], - a[4], - a[8], - a[12], - a[1], - a[5], - a[9], - a[13], - a[2], - a[6], - a[10], - a[14], - a[3], - a[7], - a[11], - a[15] - ); - Stack[Stack.Count - 1] = math.mul(Stack[Stack.Count - 1], m); - } - - public double4 MultPoints(List a) - { - Debug.Assert(Stack.Count >= 1); - Debug.Assert(a.Count >= 4); - double4 v = new double4(a[0], a[1], a[2], 1.0); - return math.mul(Stack[Stack.Count - 1], v); - } - - public static double3 MultPoint(double4x4 mat, double3 a) - { - double4 v = new double4(a[0], a[1], a[2], 1.0); - double4 ret = math.mul(mat, v); - return new double3(ret[0], ret[1], ret[2]); - } - - public double3 MultPoint(double3 a) - { - Debug.Assert(Stack.Count >= 1); - double4 v = new double4(a[0], a[1], a[2], 1.0); - double4 ret = math.mul(Stack[Stack.Count - 1], v); - return new double3(ret[0], ret[1], ret[2]); - } - - public double4 MultPoint(double4 v) - { - Debug.Assert(Stack.Count >= 1); - return math.mul(Stack[Stack.Count - 1], v); - } - - public static double4x4 YupToZupTest() - { - return new double4x4( - -1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - -1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - } - - public static double4x4 YupToZup() - { - return new double4x4( - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - -1.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - } - - public static double4x4 RotateX(double angle) - { - // {{1, 0, 0}, {0, c_0, -s_0}, {0, s_0, c_0}} - double s, - c; - math.sincos(angle, out s, out c); - return new double4x4( - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - c, - -s, - 0.0, - 0.0, - s, - c, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - } - - /// Returns a double4x4 matrix that rotates around the y-axis by a given number of radians. - /// The clockwise rotation angle when looking along the y-axis towards the origin in radians. - /// The double4x4 rotation matrix that rotates around the y-axis. - public static double4x4 RotateY(double angle) - { - // {{c_1, 0, s_1}, {0, 1, 0}, {-s_1, 0, c_1}} - double s, - c; - math.sincos(angle, out s, out c); - return new double4x4( - c, - 0.0, - s, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - -s, - 0.0, - c, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - } - - /// Returns a double4x4 matrix that rotates around the z-axis by a given number of radians. - /// The clockwise rotation angle when looking along the z-axis towards the origin in radians. - /// The double4x4 rotation matrix that rotates around the z-axis. - public static double4x4 RotateZ(double angle) - { - // {{c_2, -s_2, 0}, {s_2, c_2, 0}, {0, 0, 1}} - double s, - c; - math.sincos(angle, out s, out c); - return new double4x4( - c, - -s, - 0.0, - 0.0, - s, - c, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - } - - /// Returns a double4x4 scale matrix given 3 axis scales. - /// The uniform scaling factor. - /// The double4x4 matrix that represents a uniform scale. - public static double4x4 Scale(double3 s) - { - return new double4x4( - s.x, - 0.0, - 0.0, - 0.0, - 0.0, - s.y, - 0.0, - 0.0, - 0.0, - 0.0, - s.z, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - } - - /// Returns a double4x4 translation matrix given a double3 translation vector. - /// The translation vector. - /// The double4x4 translation matrix. - public static double4x4 Translate(double3 vector) - { - return new double4x4( - new double4(1.0, 0.0, 0.0, 0.0), - new double4(0.0, 1.0, 0.0, 0.0), - new double4(0.0, 0.0, 1.0, 0.0), - new double4(vector.x, vector.y, vector.z, 1.0) - ); - } - } -} - -#endif // UNITY_X_OR_NEWER diff --git a/Runtime/Scripts/GeospatialEditorRuntime/GeoTilesReference.cs b/Runtime/Scripts/GeospatialEditorRuntime/GeoTilesReference.cs deleted file mode 100644 index 453ef61..0000000 --- a/Runtime/Scripts/GeospatialEditorRuntime/GeoTilesReference.cs +++ /dev/null @@ -1,169 +0,0 @@ -//----------------------------------------------------------------------- -// -// -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// -//----------------------------------------------------------------------- - -#if UNITY_2021_3_OR_NEWER - -namespace Google.XR.ARCoreExtensions.GeospatialCreator.Internal -{ - using System; -#if ARCORE_INTERNAL_USE_CESIUM - using CesiumForUnity; -#endif -#if ARCORE_INTERNAL_USE_UNITY_MATH - using Unity.Mathematics; -#endif - using UnityEngine; - - public class GeoTilesReferencePoint - { - public double Latitude; - public double Longitude; - public double Height; - - public GeoTilesReferencePoint() - { - Latitude = 0; - Longitude = 0; - Height = 0; - } - - public GeoTilesReferencePoint(double latitude, double longitude, double height) - { - Latitude = latitude; - Longitude = longitude; - Height = height; - } - } - - public class GeoTilesReference - { -#if ARCORE_INTERNAL_USE_CESIUM - private CesiumGeoreference geoReference = null; -#endif - - public GeoTilesReference(GameObject gameObject) - { -#if ARCORE_INTERNAL_USE_CESIUM - geoReference = GetReference(gameObject); -#endif - } - - public GeoTilesReferencePoint GetTilesReferencePoint(GameObject gameObject) - { -#if ARCORE_INTERNAL_USE_CESIUM - if (geoReference == null) - { - geoReference = GetReference(gameObject); - if (geoReference == null) - { - // higher level code can use cached values if they have one. - return null; - } - } - GeoTilesReferencePoint RefPoint = new GeoTilesReferencePoint( - geoReference.latitude, - geoReference.longitude, - geoReference.height - ); - return RefPoint; -#else - throw new Exception("Missing dependency: Cesium 1.0.0+ not available."); -#endif - } - - public void SetGameLayer(GameObject gameObject, int _layer) - { -#if ARCORE_INTERNAL_USE_CESIUM - if (geoReference == null) - { - geoReference = GetReference(gameObject); - if (geoReference == null) - { - return; - } - } - SetGameLayerRecursive(geoReference.gameObject, _layer); -#endif - } - -#if ARCORE_INTERNAL_USE_CESIUM - private void SetGameLayerRecursive(GameObject _go, int _layer) - { - _go.layer = _layer; - foreach (Transform child in _go.transform) - { - child.gameObject.layer = _layer; - - Transform _HasChildren = child.GetComponentInChildren(); - if (_HasChildren != null) - SetGameLayerRecursive(child.gameObject, _layer); - } - } - - private CesiumGeoreference GetReference(GameObject gameObject) - { - // First check parent, then global, then error out. - // :TODO b/276777888 & b/268498440 to make this more flexible - CesiumGeoreference geoRef = gameObject.GetComponentInParent(); - if (geoRef == null) - { - geoRef = FindFirstGeoreference(); - } - if (geoRef == null) - { - throw new InvalidOperationException( - "Can't find CesiumGeoreference used to calculate latitude and longitude"); - } - return geoRef; - } - - private CesiumGeoreference FindFirstGeoreference() - { - CesiumForUnity.CesiumGeoreference[] georeferences = - UnityEngine.Object.FindObjectsOfType(true); - for (int i = 0; i < georeferences.Length; i++) - { - CesiumGeoreference georeference = georeferences[i]; - if (georeference != null) - { - return georeference; - } - } - return null; - } -#endif - } - - public class CesiumWgs84Ellipsoid - { - public static double3 EarthCenteredEarthFixedToLongitudeLatitudeHeight(double3 ecef) - { -#if ARCORE_INTERNAL_USE_CESIUM && ARCORE_INTERNAL_USE_UNITY_MATH - return CesiumForUnity.CesiumWgs84Ellipsoid.EarthCenteredEarthFixedToLongitudeLatitudeHeight( - ecef - ); -#else - throw new Exception("Missing dependencies: Cesium 1.0.0+ and/or com.unity.mathematics 1.2.0+ not available."); -#endif - } - } -} - -#endif // UNITY_X_OR_NEWER diff --git a/Runtime/Scripts/GeospatialPose.cs b/Runtime/Scripts/GeospatialPose.cs index f9f8596..33c8a37 100644 --- a/Runtime/Scripts/GeospatialPose.cs +++ b/Runtime/Scripts/GeospatialPose.cs @@ -41,7 +41,7 @@ namespace Google.XR.ARCoreExtensions /// up away from gravity, and Z+ points north. /// /// - /// Accuracy of the latitude, longitude, altitude, and heading are available as numeric + /// Accuracy of the latitude, longitude, altitude, and orientation are available as numeric /// confidence intervals where a large value (large interval) means low confidence and small /// value (small interval) means high confidence. /// @@ -99,6 +99,7 @@ public struct GeospatialPose /// i.e. perpendicular to the ground, heading is analoguous to roll, and when the device is /// upright in the device's default orientation mode, heading is analogous to yaw. [Obsolete("This field has been deprecated. Please use EunRotation instead.")] + /// public double Heading; @@ -121,6 +122,7 @@ public struct GeospatialPose /// heading accuracy when the device is held upright in the default orientation mode. [Obsolete( "This field has been deprecated. Please use OrientationYawAccuracy instead.")] + /// public double HeadingAccuracy; diff --git a/Runtime/Scripts/HostCloudAnchorPromise.cs b/Runtime/Scripts/HostCloudAnchorPromise.cs index 2ad33e2..3c6c0c1 100644 --- a/Runtime/Scripts/HostCloudAnchorPromise.cs +++ b/Runtime/Scripts/HostCloudAnchorPromise.cs @@ -46,9 +46,10 @@ internal HostCloudAnchorPromise() } /// - /// Constructs a specific promise with the associated handle. It polls the - /// result in the Update event every frame until the result gets resolved. The promise - /// result is accessible via , and can be cancelled by + /// Constructs a specific promise with the associated handle. The + /// must be polled in a coroutine until it returns + /// or . When done, the promise result is + /// accessible via . The promise can be cancelled by /// . /// /// The future handle associated with this promise. @@ -75,6 +76,7 @@ internal HostCloudAnchorPromise(IntPtr futureHandle) // Set defaults. _state = PromiseState.Pending; _result = new HostCloudAnchorResult(); + _onPromiseDone += AssignResult; } #if UNITY_ANDROID @@ -82,35 +84,19 @@ internal HostCloudAnchorPromise(IntPtr futureHandle) #endif } - /// - /// Gets the associated with this - /// promise or the default values of and - /// null if the promise was cancelled. - /// - public override HostCloudAnchorResult Result + private void AssignResult() { - get - { - IntPtr sessionHandle = GetSessionHandle(); - - if (_future != IntPtr.Zero && sessionHandle != IntPtr.Zero && - _result.CloudAnchorState == CloudAnchorState.None && - this.State == PromiseState.Done) - { - CloudAnchorState cloudAnchorState = FutureApi.GetHostCloudAnchorState( - sessionHandle, _future); - string cloudAnchorId = null; - - if (cloudAnchorState == CloudAnchorState.Success) - { - cloudAnchorId = FutureApi.GetCloudAnchorId(sessionHandle, _future); - } - - _result = new HostCloudAnchorResult(cloudAnchorState, cloudAnchorId); - } + IntPtr sessionHandle = GetSessionHandle(); + CloudAnchorState cloudAnchorState = FutureApi.GetHostCloudAnchorState( + sessionHandle, _future); + string cloudAnchorId = null; - return _result; + if (cloudAnchorState == CloudAnchorState.Success) + { + cloudAnchorId = FutureApi.GetCloudAnchorId(sessionHandle, _future); } + + _result = new HostCloudAnchorResult(cloudAnchorState, cloudAnchorId); } } } diff --git a/Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs b/Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs index ac45409..36270be 100644 --- a/Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs +++ b/Runtime/Scripts/Internal/ARCoreExtensionsProjectSettings.cs @@ -131,11 +131,13 @@ public class ARCoreExtensionsProjectSettings public bool GeospatialEnabled; /// - /// Indicates if ARCore Geospatial Editor features should be available in the Unity Editor. + /// Indicates if ARCore Geospatial Creator features should be available in the Unity Editor. /// When this is checked, the scripting symbol will be defined which enables the features. /// + /// We use the original "GeospatialEditor" feature name for the field here to retain + /// backwards compatibility. [DisplayName("Geospatial Creator")] - [DynamicHelp("GetGeospatialEditorHelpInfo")] + [DynamicHelp("GetGeospatialCreatorHelpInfo")] public bool GeospatialEditorEnabled; private const string _projectSettingsPath = @@ -446,7 +448,7 @@ public HelpAttribute GetGeospatialHelpInfo() /// . /// /// Help info for . - public HelpAttribute GetGeospatialEditorHelpInfo() + public HelpAttribute GetGeospatialCreatorHelpInfo() { #if !UNITY_2021_3_OR_NEWER if (GeospatialEditorEnabled) diff --git a/Runtime/Scripts/Internal/InterruptiblePromise.cs b/Runtime/Scripts/Internal/InterruptiblePromise.cs index d98973e..3c202ef 100644 --- a/Runtime/Scripts/Internal/InterruptiblePromise.cs +++ b/Runtime/Scripts/Internal/InterruptiblePromise.cs @@ -45,6 +45,11 @@ public abstract class InterruptiblePromise : CustomYieldInstruction /// protected IntPtr _future; + /// + /// Invoked when the promise successfully completes, so the subclass can assign the result. + /// + protected Action _onPromiseDone; + /// /// Releases the underlying native handle. /// @@ -76,12 +81,7 @@ public PromiseState State { get { - var sessionHandle = GetSessionHandle(); - if (_future != IntPtr.Zero && sessionHandle != IntPtr.Zero) - { - _state = FutureApi.GetState(sessionHandle, _future); - } - + CheckState(); return _state; } } @@ -89,7 +89,14 @@ public PromiseState State /// /// Gets the result, if the operation is done. /// - public abstract T Result { get; } + public virtual T Result + { + get + { + CheckState(); + return _result; + } + } /// /// Cancels execution of this promise if it's still pending. @@ -112,5 +119,29 @@ protected IntPtr GetSessionHandle() return ARPrestoApi.GetSessionHandle(); #endif } + + /// + /// Update the state field based on the current status of future. If it has transitioned + /// from Pending to Done, invoke the PromiseDone action to set the result. + /// + private void CheckState() + { + if (_state != PromiseState.Pending) + { + return; + } + + var sessionHandle = GetSessionHandle(); + if (_future != IntPtr.Zero && sessionHandle != IntPtr.Zero) + { + _state = FutureApi.GetState(sessionHandle, _future); + if (_state == PromiseState.Done && _onPromiseDone != null) + { + // Guaranteed to be called at most once, since future calls to "get" will + // return immediately when _state == Done + _onPromiseDone(); + } + } + } } } diff --git a/Runtime/Scripts/Internal/Types/ApiStreetscapeGeometryMode.cs b/Runtime/Scripts/Internal/Types/ApiStreetscapeGeometryMode.cs index fcb0646..e0f52db 100644 --- a/Runtime/Scripts/Internal/Types/ApiStreetscapeGeometryMode.cs +++ b/Runtime/Scripts/Internal/Types/ApiStreetscapeGeometryMode.cs @@ -17,6 +17,7 @@ // // //----------------------------------------------------------------------- + namespace Google.XR.ARCoreExtensions.Internal { internal enum ApiStreetscapeGeometryMode diff --git a/Runtime/Scripts/Internal/Wrappers/MeshApi.cs b/Runtime/Scripts/Internal/Wrappers/MeshApi.cs index 394e6c2..5c3e370 100644 --- a/Runtime/Scripts/Internal/Wrappers/MeshApi.cs +++ b/Runtime/Scripts/Internal/Wrappers/MeshApi.cs @@ -17,6 +17,7 @@ // // //----------------------------------------------------------------------- + namespace Google.XR.ARCoreExtensions.Internal { using System; diff --git a/Runtime/Scripts/Internal/Wrappers/StreetscapeGeometryApi.cs b/Runtime/Scripts/Internal/Wrappers/StreetscapeGeometryApi.cs index d24d3e7..7b9d8fc 100644 --- a/Runtime/Scripts/Internal/Wrappers/StreetscapeGeometryApi.cs +++ b/Runtime/Scripts/Internal/Wrappers/StreetscapeGeometryApi.cs @@ -17,6 +17,7 @@ // // //----------------------------------------------------------------------- + namespace Google.XR.ARCoreExtensions.Internal { using System; diff --git a/Runtime/Scripts/ResolveAnchorOnRooftopPromise.cs b/Runtime/Scripts/ResolveAnchorOnRooftopPromise.cs index bc183f1..f093df6 100644 --- a/Runtime/Scripts/ResolveAnchorOnRooftopPromise.cs +++ b/Runtime/Scripts/ResolveAnchorOnRooftopPromise.cs @@ -47,9 +47,10 @@ internal ResolveAnchorOnRooftopPromise() } /// - /// Constructs a specific promise with the associated handle. It polls the - /// result in the Update event every frame until the result gets resolved. The promise - /// result is accessible via , and can be cancelled by + /// Constructs a specific promise with the associated handle. The + /// must be polled in a coroutine until it returns + /// or . When done, the promise result is + /// accessible via . The promise can be cancelled by /// . /// /// The future handle associated with this promise. @@ -76,6 +77,7 @@ internal ResolveAnchorOnRooftopPromise(IntPtr futureHandle) // Set defaults. _state = PromiseState.Pending; _result = new ResolveAnchorOnRooftopResult(); + _onPromiseDone += AssignResult; } #if UNITY_ANDROID @@ -83,53 +85,35 @@ internal ResolveAnchorOnRooftopPromise(IntPtr futureHandle) #endif } - /// - /// Gets the associated with this - /// promise or the default values of and - /// null if the promise was cancelled. - /// - public override ResolveAnchorOnRooftopResult Result + private void AssignResult() { - get + IntPtr sessionHandle = GetSessionHandle(); + RooftopAnchorState rooftopAnchorState = FutureApi.GetRooftopAnchorState( + sessionHandle, _future); + + ARGeospatialAnchor anchor = null; + if (rooftopAnchorState == RooftopAnchorState.Success) { - IntPtr sessionHandle = GetSessionHandle(); + IntPtr anchorHandle = FutureApi.GetRooftopAnchorHandle(sessionHandle, _future); - if (_future != IntPtr.Zero && sessionHandle != IntPtr.Zero && - _result.RooftopAnchorState == RooftopAnchorState.None && - this.State == PromiseState.Done) + if (anchorHandle != IntPtr.Zero) { - RooftopAnchorState rooftopAnchorState = FutureApi.GetRooftopAnchorState( - sessionHandle, _future); - - ARGeospatialAnchor anchor = null; - if (rooftopAnchorState == RooftopAnchorState.Success) + // Create the GameObject that is the Geospatial Rooftop anchor. + anchor = new GameObject(_rooftopAnchorName).AddComponent(); + if (anchor) { - IntPtr anchorHandle = FutureApi.GetRooftopAnchorHandle(sessionHandle, - _future); + anchor.SetAnchorHandle(anchorHandle); - if (anchorHandle != IntPtr.Zero) - { - // Create the GameObject that is the Geospatial Rooftop anchor. - anchor = new GameObject(_rooftopAnchorName) - .AddComponent(); - if (anchor) - { - anchor.SetAnchorHandle(anchorHandle); - - // Parent the new Geospatial Rooftop anchor to the session origin. - anchor.transform.SetParent( - ARCoreExtensions._instance.SessionOrigin.trackablesParent, - false); - anchor.Update(); - } - } + // Parent the new Geospatial Rooftop anchor to the session origin. + anchor.transform.SetParent( + ARCoreExtensions._instance.SessionOrigin.trackablesParent, + false); + anchor.Update(); } - - _result = new ResolveAnchorOnRooftopResult(rooftopAnchorState, anchor); } - - return _result; } + + _result = new ResolveAnchorOnRooftopResult(rooftopAnchorState, anchor); } } } diff --git a/Runtime/Scripts/ResolveAnchorOnTerrainPromise.cs b/Runtime/Scripts/ResolveAnchorOnTerrainPromise.cs index a54736b..4766930 100644 --- a/Runtime/Scripts/ResolveAnchorOnTerrainPromise.cs +++ b/Runtime/Scripts/ResolveAnchorOnTerrainPromise.cs @@ -48,9 +48,10 @@ internal ResolveAnchorOnTerrainPromise() } /// - /// Constructs a specific promise with the associated handle. It polls the - /// result in the Update event every frame until the result gets resolved. The promise - /// result is accessible via , and can be cancelled by + /// Constructs a specific promise with the associated handle. The + /// must be polled in a coroutine until it returns + /// or . When done, the promise result is + /// accessible via . The promise can be cancelled by /// . /// /// The future handle associated with this promise. @@ -77,6 +78,7 @@ internal ResolveAnchorOnTerrainPromise(IntPtr futureHandle) // Set defaults. _state = PromiseState.Pending; _result = new ResolveAnchorOnTerrainResult(); + _onPromiseDone += AssignResult; } #if UNITY_ANDROID @@ -84,53 +86,35 @@ internal ResolveAnchorOnTerrainPromise(IntPtr futureHandle) #endif } - /// - /// Gets the associated with this - /// promise or the default values of and - /// null if the promise was cancelled. - /// - public override ResolveAnchorOnTerrainResult Result + private void AssignResult() { - get + IntPtr sessionHandle = GetSessionHandle(); + TerrainAnchorState terrainAnchorState = FutureApi.GetTerrainAnchorState( + sessionHandle, _future); + + ARGeospatialAnchor anchor = null; + if (terrainAnchorState == TerrainAnchorState.Success) { - IntPtr sessionHandle = GetSessionHandle(); + IntPtr anchorHandle = FutureApi.GetTerrainAnchorHandle(sessionHandle, _future); - if (_future != IntPtr.Zero && sessionHandle != IntPtr.Zero && - _result.TerrainAnchorState == TerrainAnchorState.None && - this.State == PromiseState.Done) + if (anchorHandle != IntPtr.Zero) { - TerrainAnchorState terrainAnchorState = FutureApi.GetTerrainAnchorState( - sessionHandle, _future); - - ARGeospatialAnchor anchor = null; - if (terrainAnchorState == TerrainAnchorState.Success) + // Create the GameObject that is the Geospatial Terrain anchor. + anchor = new GameObject(_terrainAnchorName).AddComponent(); + if (anchor) { - IntPtr anchorHandle = FutureApi.GetTerrainAnchorHandle(sessionHandle, - _future); + anchor.SetAnchorHandle(anchorHandle); - if (anchorHandle != IntPtr.Zero) - { - // Create the GameObject that is the Geospatial Terrain anchor. - anchor = new GameObject(_terrainAnchorName) - .AddComponent(); - if (anchor) - { - anchor.SetAnchorHandle(anchorHandle); - - // Parent the new Geospatial Terrain anchor to the session origin. - anchor.transform.SetParent( - ARCoreExtensions._instance.SessionOrigin.trackablesParent, - false); - anchor.Update(); - } - } + // Parent the new Geospatial Terrain anchor to the session origin. + anchor.transform.SetParent( + ARCoreExtensions._instance.SessionOrigin.trackablesParent, + false); + anchor.Update(); } - - _result = new ResolveAnchorOnTerrainResult(terrainAnchorState, anchor); } - - return _result; } + + _result = new ResolveAnchorOnTerrainResult(terrainAnchorState, anchor); } } } diff --git a/Runtime/Scripts/ResolveCloudAnchorPromise.cs b/Runtime/Scripts/ResolveCloudAnchorPromise.cs index 4750302..bd546d6 100644 --- a/Runtime/Scripts/ResolveCloudAnchorPromise.cs +++ b/Runtime/Scripts/ResolveCloudAnchorPromise.cs @@ -48,9 +48,10 @@ internal ResolveCloudAnchorPromise() } /// - /// Constructs a specific promise with the associated handle. It polls the - /// result in the Update event every frame until the result gets resolved. The promise - /// result is accessible via , and can be cancelled by + /// Constructs a specific promise with the associated handle. The + /// must be polled in a coroutine until it returns + /// or . When done, the promise result is + /// accessible via . The promise can be cancelled by /// . /// /// The future handle associated with this promise. @@ -77,6 +78,7 @@ internal ResolveCloudAnchorPromise(IntPtr futureHandle) // Set defaults. _state = PromiseState.Pending; _result = new ResolveCloudAnchorResult(); + _onPromiseDone += AssignResult; } #if UNITY_ANDROID @@ -84,52 +86,35 @@ internal ResolveCloudAnchorPromise(IntPtr futureHandle) #endif } - /// - /// Gets the associated with this - /// promise or the default values of and - /// null if the promise was cancelled. - /// - public override ResolveCloudAnchorResult Result + private void AssignResult() { - get + IntPtr sessionHandle = GetSessionHandle(); + CloudAnchorState cloudAnchorState = FutureApi.GetResolveCloudAnchorState( + sessionHandle, _future); + + ARCloudAnchor anchor = null; + if (cloudAnchorState == CloudAnchorState.Success) { - IntPtr sessionHandle = GetSessionHandle(); + IntPtr anchorHandle = FutureApi.GetCloudAnchorHandle(sessionHandle, _future); - if (_future != IntPtr.Zero && sessionHandle != IntPtr.Zero && - _result.CloudAnchorState == CloudAnchorState.None && - this.State == PromiseState.Done) + if (anchorHandle != IntPtr.Zero) { - CloudAnchorState cloudAnchorState = FutureApi.GetResolveCloudAnchorState( - sessionHandle, _future); - - ARCloudAnchor anchor = null; - if (cloudAnchorState == CloudAnchorState.Success) + // Create the GameObject that is the cloud anchor. + anchor = new GameObject(_cloudAnchorName).AddComponent(); + if (anchor) { - IntPtr anchorHandle = FutureApi.GetCloudAnchorHandle(sessionHandle, - _future); + anchor.SetAnchorHandle(anchorHandle); - if (anchorHandle != IntPtr.Zero) - { - // Create the GameObject that is the cloud anchor. - anchor = new GameObject(_cloudAnchorName).AddComponent(); - if (anchor) - { - anchor.SetAnchorHandle(anchorHandle); - - // Parent the new cloud anchor to the session origin. - anchor.transform.SetParent( - ARCoreExtensions._instance.SessionOrigin.trackablesParent, - false); - anchor.Update(); - } - } + // Parent the new cloud anchor to the session origin. + anchor.transform.SetParent( + ARCoreExtensions._instance.SessionOrigin.trackablesParent, + false); + anchor.Update(); } - - _result = new ResolveCloudAnchorResult(cloudAnchorState, anchor); } - - return _result; } + + _result = new ResolveCloudAnchorResult(cloudAnchorState, anchor); } } } diff --git a/Runtime/Scripts/StreetscapeGeometryMode.cs b/Runtime/Scripts/StreetscapeGeometryMode.cs index 55ce441..1e17c75 100644 --- a/Runtime/Scripts/StreetscapeGeometryMode.cs +++ b/Runtime/Scripts/StreetscapeGeometryMode.cs @@ -17,6 +17,7 @@ // // //----------------------------------------------------------------------- + namespace Google.XR.ARCoreExtensions { /// diff --git a/Runtime/Scripts/StreetscapeGeometryType.cs b/Runtime/Scripts/StreetscapeGeometryType.cs index e096503..349104a 100644 --- a/Runtime/Scripts/StreetscapeGeometryType.cs +++ b/Runtime/Scripts/StreetscapeGeometryType.cs @@ -17,6 +17,7 @@ // // //----------------------------------------------------------------------- + namespace Google.XR.ARCoreExtensions { using System.Collections; diff --git a/Runtime/Scripts/VersionInfo.cs b/Runtime/Scripts/VersionInfo.cs index dc2592e..2151ee2 100644 --- a/Runtime/Scripts/VersionInfo.cs +++ b/Runtime/Scripts/VersionInfo.cs @@ -28,6 +28,6 @@ public class VersionInfo /// /// The current ARCore Extensions package version. /// - public static readonly string Version = "1.37.0"; + public static readonly string Version = "1.38.0"; } } diff --git a/Runtime/Scripts/VpsAvailabilityPromise.cs b/Runtime/Scripts/VpsAvailabilityPromise.cs index d977a78..0a98676 100644 --- a/Runtime/Scripts/VpsAvailabilityPromise.cs +++ b/Runtime/Scripts/VpsAvailabilityPromise.cs @@ -58,24 +58,15 @@ internal VpsAvailabilityPromise(IntPtr future) _state = PromiseState.Done; _result = VpsAvailability.ErrorInternal; } + else + { + _onPromiseDone = AssignResult; + } } - /// - /// Gets the associated with this promise or the - /// default value if the promise was cancelled. - /// - public override VpsAvailability Result + private void AssignResult() { - get - { - var sessionHandle = GetSessionHandle(); - if (_future != IntPtr.Zero && sessionHandle != IntPtr.Zero) - { - _result = FutureApi.GetVpsAvailabilityResult(sessionHandle, _future); - } - - return _result; - } + _result = FutureApi.GetVpsAvailabilityResult(GetSessionHandle(), _future); } } } diff --git a/Samples~/Geospatial/Materials/TransparentMat_building_blue.mat b/Samples~/Geospatial/Materials/TransparentMat_building_blue.mat index 07dd7a9..e1944e9 100644 --- a/Samples~/Geospatial/Materials/TransparentMat_building_blue.mat +++ b/Samples~/Geospatial/Materials/TransparentMat_building_blue.mat @@ -9,12 +9,13 @@ Material: m_PrefabAsset: {fileID: 0} m_Name: TransparentMat_building_blue m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: _EMISSION + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _EMISSION m_LightmapFlags: 2 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 - m_CustomRenderQueue: -1 - stringTagMap: {} + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent disabledShaderPasses: [] m_SavedProperties: serializedVersion: 3 @@ -59,19 +60,19 @@ Material: - _BumpScale: 1 - _Cutoff: 0.5 - _DetailNormalMapScale: 1 - - _DstBlend: 0 + - _DstBlend: 10 - _GlossMapScale: 1 - _Glossiness: 0.5 - _GlossyReflections: 1 - _Metallic: 0 - - _Mode: 0 + - _Mode: 3 - _OcclusionStrength: 1 - _Parallax: 0.02 - _SmoothnessTextureChannel: 0 - _SpecularHighlights: 1 - _SrcBlend: 1 - _UVSec: 0 - - _ZWrite: 1 + - _ZWrite: 0 m_Colors: - _Color: {r: 0, g: 0.8638129, b: 1, a: 0.34901962} - _EmissionColor: {r: 0, g: 0.60784316, b: 1, a: 1} diff --git a/Samples~/Geospatial/Scripts/GeospatialController.cs b/Samples~/Geospatial/Scripts/GeospatialController.cs index e072e73..b0f7806 100644 --- a/Samples~/Geospatial/Scripts/GeospatialController.cs +++ b/Samples~/Geospatial/Scripts/GeospatialController.cs @@ -201,13 +201,6 @@ public class GeospatialController : MonoBehaviour /// private const string _localizationSuccessMessage = "Localization completed."; - /// - /// Help message shown when resolving takes too long. - /// - private const string _resolvingTimeoutMessage = - "Still resolving the terrain anchor.\n" + - "Please make sure you're in an area that has VPS coverage."; - /// /// The timeout period waiting for localization to be completed. /// @@ -258,14 +251,14 @@ public class GeospatialController : MonoBehaviour private bool _showAnchorSettingsPanel = false; /// - /// Determines if streetscape geometry is rendered in the scene. + /// Represents the current anchor type of the anchor being placed in the scene. /// - private bool _streetscapeGeometryVisibility = false; + private AnchorType _anchorType = AnchorType.Geospatial; /// - /// Represents the current anchor type of the anchor being placed in the scene. + /// Determines if streetscape geometry is rendered in the scene. /// - private AnchorType _anchorType = AnchorType.Geospatial; + private bool _streetscapeGeometryVisibility = false; /// /// Determines which building material will be used for the current building mesh. @@ -282,18 +275,19 @@ public class GeospatialController : MonoBehaviour /// /// ARStreetscapeGeometries added in the last Unity Update. /// - List _addedStreetscapeGeometrys = new List(); + List _addedStreetscapeGeometries = + new List(); /// /// ARStreetscapeGeometries updated in the last Unity Update. /// - List _updatedStreetscapeGeometrys = + List _updatedStreetscapeGeometries = new List(); /// /// ARStreetscapeGeometries removed in the last Unity Update. /// - List _removedStreetscapeGeometrys = + List _removedStreetscapeGeometries = new List(); /// @@ -506,6 +500,12 @@ public void OnEnable() "GeospatialController Inspector to render StreetscapeGeometry."); return; } + + // get access to ARstreetscapeGeometries in ARStreetscapeGeometryManager + if (StreetscapeGeometryManager) + { + StreetscapeGeometryManager.StreetscapeGeometriesChanged += GetStreetscapeGeometry; + } } /// @@ -527,6 +527,12 @@ public void OnDisable() _anchorObjects.Clear(); SaveGeospatialAnchorHistory(); + + if (StreetscapeGeometryManager) + { + StreetscapeGeometryManager.StreetscapeGeometriesChanged -= + GetStreetscapeGeometry; + } } /// @@ -660,7 +666,6 @@ public void Update() SnackBarText.text = _localizationSuccessMessage; foreach (var go in _anchorObjects) { - go.SetActive(true); } @@ -670,29 +675,14 @@ public void Update() { if (_streetscapeGeometryVisibility) { - // get access to ARstreetscapeGeometries in ARStreetscapeGeometryManager - if (StreetscapeGeometryManager) - { - StreetscapeGeometryManager.StreetscapeGeometriesChanged - += (ARStreetscapeGeometrysChangedEventArgs) => - { - _addedStreetscapeGeometrys = - ARStreetscapeGeometrysChangedEventArgs.Added; - _updatedStreetscapeGeometrys = - ARStreetscapeGeometrysChangedEventArgs.Updated; - _removedStreetscapeGeometrys = - ARStreetscapeGeometrysChangedEventArgs.Removed; - }; - } - foreach ( - ARStreetscapeGeometry streetscapegeometry in _addedStreetscapeGeometrys) + ARStreetscapeGeometry streetscapegeometry in _addedStreetscapeGeometries) { InstantiateRenderObject(streetscapegeometry); } foreach ( - ARStreetscapeGeometry streetscapegeometry in _updatedStreetscapeGeometrys) + ARStreetscapeGeometry streetscapegeometry in _updatedStreetscapeGeometries) { // This second call to instantiate is required if geometry is toggled on // or off after the app has started. @@ -701,7 +691,7 @@ public void Update() } foreach ( - ARStreetscapeGeometry streetscapegeometry in _removedStreetscapeGeometrys) + ARStreetscapeGeometry streetscapegeometry in _removedStreetscapeGeometries) { DestroyRenderObject(streetscapegeometry); } @@ -760,6 +750,20 @@ public void Update() } } + /// + /// Connects the ARStreetscapeGeometry to the specified lists for access. + /// + /// The + /// containing the + /// ARStreetscapeGeometry. + /// + private void GetStreetscapeGeometry(ARStreetscapeGeometriesChangedEventArgs eventArgs) + { + _addedStreetscapeGeometries = eventArgs.Added; + _updatedStreetscapeGeometries = eventArgs.Updated; + _removedStreetscapeGeometries = eventArgs.Removed; + } + /// /// Sets up a render object for this ARStreetscapeGeometry. /// @@ -811,7 +815,7 @@ private void InstantiateRenderObject(ARStreetscapeGeometry streetscapegeometry) } /// - /// Updates the render object transform based on this streetscapegeometrys pose. + /// Updates the render object transform based on this StreetscapeGeometries pose. /// It must be called every frame to update the mesh. /// /// The @@ -872,17 +876,7 @@ private void SetAnchorPanelState(bool state) private IEnumerator CheckRooftopPromise(ResolveAnchorOnRooftopPromise promise, GeospatialAnchorHistory history) { - var retry = 0; - while (promise.State == PromiseState.Pending) - { - if (retry == 100) - { - SnackBarText.text = _resolvingTimeoutMessage; - } - - yield return new WaitForSeconds(0.1f); - retry = Math.Min(retry + 1, 100); - } + yield return promise; var result = promise.Result; if (result.RooftopAnchorState == RooftopAnchorState.Success && @@ -916,17 +910,7 @@ private IEnumerator CheckRooftopPromise(ResolveAnchorOnRooftopPromise promise, private IEnumerator CheckTerrainPromise(ResolveAnchorOnTerrainPromise promise, GeospatialAnchorHistory history) { - var retry = 0; - while (promise.State == PromiseState.Pending) - { - if (retry == 100) - { - SnackBarText.text = _resolvingTimeoutMessage; - } - - yield return new WaitForSeconds(0.1f); - retry = Math.Min(retry + 1, 100); - } + yield return promise; var result = promise.Result; if (result.TerrainAnchorState == TerrainAnchorState.Success && @@ -1067,6 +1051,7 @@ private Quaternion CreateRotation(GeospatialAnchorHistory history) eunRotation = Quaternion.AngleAxis(180f - (float)history.Heading, Vector3.up); } + return eunRotation; } @@ -1084,8 +1069,8 @@ private Quaternion CreateRotation(GeospatialAnchorHistory history) 0, eunRotation); StartCoroutine(CheckRooftopPromise(rooftopPromise, history)); - return null; + case AnchorType.Terrain: ResolveAnchorOnTerrainPromise terrainPromise = AnchorManager.ResolveAnchorOnTerrainAsync( @@ -1093,8 +1078,8 @@ private Quaternion CreateRotation(GeospatialAnchorHistory history) 0, eunRotation); StartCoroutine(CheckTerrainPromise(terrainPromise, history)); - return null; + case AnchorType.Geospatial: ARStreetscapeGeometry streetscapegeometry = StreetscapeGeometryManager.GetStreetscapeGeometry(trackableId); @@ -1157,6 +1142,7 @@ private ARGeospatialAnchor PlaceGeospatialAnchor( anchor.gameObject.SetActive(!terrain); anchorGO.transform.parent = anchor.gameObject.transform; _anchorObjects.Add(anchor.gameObject); + SnackBarText.text = GetDisplayStringForAnchorPlacedSuccess(); } else { diff --git a/Samples~/PersistentCloudAnchors/Scripts/ARViewManager.cs b/Samples~/PersistentCloudAnchors/Scripts/ARViewManager.cs index 8cb0c38..b9bb366 100644 --- a/Samples~/PersistentCloudAnchors/Scripts/ARViewManager.cs +++ b/Samples~/PersistentCloudAnchors/Scripts/ARViewManager.cs @@ -355,7 +355,6 @@ public void OnDisable() } _resolveResults.Clear(); - UpdatePlaneVisibility(false); } diff --git a/package.json b/package.json index 973db07..abad7f7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.google.ar.core.arfoundation.extensions", "displayName": "ARCore Extensions", - "version": "1.37.0", + "version": "1.38.0", "unity": "2019.4", "description": "Google ARCore Extensions for AR Foundation. This package provides access to ARCore features not covered by AR Foundation's cross platform API.", "author":