// invoked by AnchorRemoved-event private void PlaneAnchorRemoved(ARPlaneAnchor arPlaneAnchor) { string surfId = arPlaneAnchor.identifier; Debug.Log("Plane removed: " + surfId); // remove plane anchor if (planeAnchorDict.ContainsKey(surfId)) { ARPlaneAnchorGameObject arpag = planeAnchorDict[surfId]; if (arpag != null && arpag.gameObject) { GameObject.Destroy(arpag.gameObject); } planeAnchorDict.Remove(surfId); trackedPlanesTimestamp = GetLastFrameTimestamp(); } // remove overlay surface MultiARInterop.MultiARData arData = arManager.GetARData(); if (arData.dictOverlaySurfaces.ContainsKey(surfId)) { OverlaySurfaceUpdater overlaySurface = arData.dictOverlaySurfaces[surfId]; arData.dictOverlaySurfaces.Remove(surfId); Destroy(overlaySurface.gameObject); } }
// looks at the next surface private void LookAtSurface() { if (cameraTransform && alLoadedSurfaces != null && alLoadedSurfaces.Count > 0) { // unselect current surface if (selectedSurface) { MeshRenderer meshRenderer = selectedSurface.gameObject.GetComponent <MeshRenderer>(); if (meshRenderer) { meshRenderer.material = surfaceMaterial; } } for (int i = 0; i < alLoadedSurfaces.Count; i++) { OverlaySurfaceUpdater surface = alLoadedSurfaces[i]; if (selectedSurface == null) { selectedSurface = surface; break; } else if (selectedSurface == surface) { int nextI = (i + 1) % alLoadedSurfaces.Count; selectedSurface = alLoadedSurfaces[nextI]; break; } } // look at the surface and select it if (selectedSurface != null) { Debug.Log("Selected surface: " + selectedSurface.gameObject.name); // reset mouse-look rotation MouseLook mouseLook = cameraTransform.GetComponent <MouseLook>(); if (mouseLook) { mouseLook.ResetRotation(); } // look at the surface cameraTransform.LookAt(selectedSurface.transform); // set selection material MeshRenderer meshRenderer = selectedSurface.gameObject.GetComponent <MeshRenderer>(); if (meshRenderer) { meshRenderer.material = selectedMaterial; } if (sceneInfoText) { sceneInfoText.text = "Look at: " + selectedSurface.gameObject.name; } } } }
// Updates overlay surface mesh. Returns true on success, false if the surface needs to be deleted private bool UpdateOverlaySurface(OverlaySurfaceUpdater overlaySurface, DetectedPlane trackedSurface) { // check for validity if (overlaySurface == null || trackedSurface == null) { return(false); } else if (trackedSurface.SubsumedBy != null) { return(false); } else if (trackedSurface.TrackingState != TrackingState.Tracking) { overlaySurface.SetEnabled(false); return(true); } // enable the surface overlaySurface.SetEnabled(true); // estimate mesh vertices List <Vector3> meshVertices = new List <Vector3>(); // GetBoundaryPolygon returns points in clockwise order. trackedSurface.GetBoundaryPolygon(meshVertices); int verticeLength = meshVertices.Count; // surface position & rotation Vector3 surfacePos = trackedSurface.CenterPose.position; // Vector3.zero; // Quaternion surfaceRot = trackedSurface.CenterPose.rotation; // Quaternion.identity; // // estimate vertices relative to the center Quaternion invRot = Quaternion.Inverse(surfaceRot); for (int v = verticeLength - 1; v >= 0; v--) { meshVertices[v] -= surfacePos; meshVertices[v] = invRot * meshVertices[v]; if (Mathf.Abs(meshVertices[v].y) > 0.1f) { meshVertices.RemoveAt(v); } } // estimate mesh indices List <int> meshIndices = MultiARInterop.GetMeshIndices(meshVertices.Count); // update the surface mesh overlaySurface.UpdateSurfaceMesh(surfacePos, surfaceRot, meshVertices, meshIndices); return(true); }
// invoked by AnchorAdded-event private void PlaneAnchorAdded(ARPlaneAnchor arPlaneAnchor) { Debug.Log("Plane added: " + arPlaneAnchor.identifier); GameObject go = null; // if(arManager.displayTrackedSurfaces) // { // go = UnityARUtility.CreatePlaneInScene(arPlaneAnchor); // go.AddComponent<DontDestroyOnLoad>(); // these GOs persist across scene loads // } ARPlaneAnchorGameObject arpag = new ARPlaneAnchorGameObject(); arpag.planeAnchor = arPlaneAnchor; arpag.gameObject = go; planeAnchorDict.Add(arPlaneAnchor.identifier, arpag); trackedPlanesTimestamp = GetLastFrameTimestamp(); // create overlay surfaces as needed if (arManager.useOverlaySurface != MultiARManager.SurfaceRenderEnum.None) { // estimate the material Material surfaceMat = arManager.GetSurfaceMaterial(); int surfaceLayer = MultiARInterop.GetSurfaceLayer(); MultiARInterop.MultiARData arData = arManager.GetARData(); string surfId = arPlaneAnchor.identifier; if (!arData.dictOverlaySurfaces.ContainsKey(surfId)) { GameObject overlaySurfaceObj = new GameObject(); overlaySurfaceObj.name = "surface-" + surfId; overlaySurfaceObj.layer = surfaceLayer; overlaySurfaceObj.transform.SetParent(arData.surfaceRendererRoot ? arData.surfaceRendererRoot.transform : null); // GameObject overlayCubeObj = GameObject.CreatePrimitive(PrimitiveType.Cube); // overlayCubeObj.name = "surface-cube-" + surfId; // overlayCubeObj.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f); // overlayCubeObj.transform.SetParent(overlaySurfaceObj.transform); OverlaySurfaceUpdater overlaySurface = overlaySurfaceObj.AddComponent <OverlaySurfaceUpdater>(); overlaySurface.SetSurfaceMaterial(surfaceMat); overlaySurface.SetSurfaceCollider(arManager.surfaceCollider, arManager.colliderMaterial); arData.dictOverlaySurfaces.Add(surfId, overlaySurface); } // update the surface mesh UpdateOverlaySurface(arData.dictOverlaySurfaces[surfId], arPlaneAnchor); } }
/// <summary> /// Destroys the existing loaded surfaces. /// </summary> public void DestroyLoadedSurfaces() { if (alLoadedSurfaces.Count > 0) { for (int i = alLoadedSurfaces.Count - 1; i >= 0; i--) { OverlaySurfaceUpdater loadedSurface = alLoadedSurfaces[i]; alLoadedSurfaces.RemoveAt(i); Destroy(loadedSurface.gameObject); } } }
/// <summary> /// Updates existing overlay surfaces with the currently selected material and collider. /// </summary> public void UpdateOverlaySurfaces() { // get current material Material surfaceMat = GetSurfaceMaterial(); foreach (string sKey in arData.dictOverlaySurfaces.Keys) { OverlaySurfaceUpdater surface = arData.dictOverlaySurfaces[sKey]; MeshRenderer meshRenderer = surface.gameObject.GetComponent <MeshRenderer>(); MeshCollider meshCollider = surface.gameObject.GetComponent <MeshCollider>(); // surface renderer if (surfaceMat != null) { if (meshRenderer != null && !meshRenderer.enabled) { meshRenderer.enabled = true; } surface.SetSurfaceMaterial(surfaceMat); } else { if (meshRenderer != null && meshRenderer.enabled) { meshRenderer.enabled = false; } } // surface collider if (surfaceCollider) { if (meshCollider != null && !meshCollider.enabled) { meshCollider.enabled = true; } surface.SetSurfaceCollider(surfaceCollider, colliderMaterial); } else { if (meshCollider != null && meshCollider.enabled) { meshCollider.enabled = false; } } } }
// Updates overlay surface mesh. Returns true on success, false if the surface needs to be deleted private bool UpdateOverlaySurface(OverlaySurfaceUpdater overlaySurface, ARPlaneAnchor arPlaneAnchor) { // check for validity if (overlaySurface == null) { return(false); } // estimate mesh vertices & indices overlaySurface.SetEnabled(true); List <Vector3> meshVertices = new List <Vector3>(); // surface position & rotation Vector3 surfacePos = UnityARMatrixOps.GetPosition(arPlaneAnchor.transform); // Vector3.zero; // Quaternion surfaceRot = UnityARMatrixOps.GetRotation(arPlaneAnchor.transform); // Quaternion.identity; // // add the center offset Vector3 centerPos = arPlaneAnchor.center; centerPos.z = -centerPos.z; centerPos = surfaceRot * centerPos; surfacePos += centerPos; // Vector3 planeHalf = arPlaneAnchor.extent * 0.5f; // meshVertices.Add(new Vector3(-planeHalf.x, planeHalf.y, planeHalf.z)); // meshVertices.Add(new Vector3(planeHalf.x, planeHalf.y, planeHalf.z)); // meshVertices.Add(new Vector3(planeHalf.x, planeHalf.y, -planeHalf.z)); // meshVertices.Add(new Vector3(-planeHalf.x, planeHalf.y, -planeHalf.z)); // // // estimate mesh indices // List<int> meshIndices = MultiARInterop.GetMeshIndices(meshVertices.Count); meshVertices.AddRange(arPlaneAnchor.planeGeometry.vertices); List <int> meshIndices = new List <int>(arPlaneAnchor.planeGeometry.triangleIndices); // update the surface mesh overlaySurface.UpdateSurfaceMesh(surfacePos, surfaceRot, meshVertices, meshIndices); return(true); }
// loads AR scene and the detected surfaces public JsonArScene LoadArScene(string dataFilePath) { if (!File.Exists(dataFilePath)) { return(null); } // load json string sJsonText = File.ReadAllText(dataFilePath); JsonArScene data = JsonUtility.FromJson <JsonArScene>(sJsonText); if (data != null) { if (useSavedHeading) { startHeading = data.startHeading; } Quaternion compStartRot = Quaternion.Euler(0f, -startHeading, 0f); if (data.surfaceSet != null) { // destroy currently loaded surfaces DestroyLoadedSurfaces(); for (int i = 0; i < data.surfaceSet.surfaceCount; i++) { GameObject overlaySurfaceObj = new GameObject(); overlaySurfaceObj.name = "surface-" + i; overlaySurfaceObj.transform.SetParent(transform); OverlaySurfaceUpdater overlaySurface = overlaySurfaceObj.AddComponent <OverlaySurfaceUpdater>(); overlaySurface.SetSurfaceMaterial(surfaceMaterial); overlaySurface.SetSurfaceCollider(true, null); Vector3 surfacePos = data.surfaceSet.surfaces[i].position; surfacePos = compStartRot * surfacePos; Quaternion surfaceRot = Quaternion.Euler(data.surfaceSet.surfaces[i].rotation); surfaceRot = Quaternion.Euler(surfaceRot.eulerAngles + compStartRot.eulerAngles); // List <Vector3> meshVertices = new List <Vector3>(data.surfaceSet.surfaces[i].vertices); List <int> meshIndices = new List <int>(data.surfaceSet.surfaces[i].indices); // update the surface mesh overlaySurface.UpdateSurfaceMesh(surfacePos, surfaceRot, meshVertices, meshIndices); alLoadedSurfaces.Add(overlaySurface); } } if (cameraTransform && data.sceneCam != null) { Vector3 camPos = data.sceneCam.camPos; camPos = compStartRot * camPos; Quaternion camRot = Quaternion.Euler(data.sceneCam.camRot); camRot = Quaternion.Euler(camRot.eulerAngles + compStartRot.eulerAngles); cameraTransform.position = camPos; cameraTransform.rotation = camRot; } if (displaySavedInfos) { if (locationInfoText) { if (data.scenePos != null) { string sMessage = "Lat: " + data.scenePos.lat + ", Lon: " + data.scenePos.lon + ", Alt: " + data.scenePos.alt; sMessage += "\nCompass Head: " + FormatHeading(data.compHeading) + ", Start: " + FormatHeading(data.startHeading); locationInfoText.text = sMessage; } else { locationInfoText.text = "Location service not supported."; } } if (gyroInfoText) { if (data.sceneRot != null) { string sMessage = "Gyro Att: " + data.sceneRot.gyroAtt + ", Rot: " + data.sceneRot.gyroRot; if (data.sceneCam != null) { sMessage += string.Format("\nCamera Pos: {0}, Rot: {1}", data.sceneCam.camPos, data.sceneCam.camRot); } gyroInfoText.text = sMessage; } else { gyroInfoText.text = "Gyroscope not supported."; } } } Debug.Log("AR-Scene (head: " + (int)data.startHeading + ") loaded from: " + dataFilePath); } return(data); }
void Update() { if (!isInitialized) { return; } // check for errors _QuitOnConnectionErrors(); // check for input (touch) CheckForInputAction(); // estimate the tracking state SessionStatus status = Session.Status; if (status.IsError() || status.IsNotInitialized()) { cameraTrackingState = TrackingState.Stopped; return; } else if (status == SessionStatus.Tracking) { cameraTrackingState = TrackingState.Tracking; } else { cameraTrackingState = TrackingState.Paused; } // get frame timestamp and light intensity lastFrameTimestamp = GetCurrentTimestamp(); if (Frame.LightEstimate.State == LightEstimateState.Valid) { // Normalize pixel intensity by middle gray in gamma space. const float middleGray = 0.466f; currentLightIntensity = Frame.LightEstimate.PixelIntensity / middleGray; } // get point cloud, if needed MultiARInterop.MultiARData arData = arManager.GetARData(); if (arManager.usePointCloudData) { if (Frame.PointCloud.PointCount > 0 && Frame.PointCloud.IsUpdatedThisFrame) { // Copy the point cloud points for (int i = 0; i < Frame.PointCloud.PointCount; i++) { PointCloudPoint point = Frame.PointCloud.GetPointAsStruct(i); arData.pointCloudData[i] = new Vector3(point.Position.x, point.Position.y, point.Position.z); } arData.pointCloudLength = Frame.PointCloud.PointCount; arData.pointCloudTimestamp = lastFrameTimestamp; } } // // display the tracked planes if needed // if(arManager.displayTrackedSurfaces && trackedPlanePrefab) // { // // get the new planes // Frame.GetNewPlanes(ref newTrackedPlanes); // // // Iterate over planes found in this frame and instantiate corresponding GameObjects to visualize them. // for (int i = 0; i < newTrackedPlanes.Count; i++) // { // // Instantiate a plane visualization prefab and set it to track the new plane. // GameObject planeObject = Instantiate(trackedPlanePrefab, Vector3.zero, Quaternion.identity); // planeObject.GetComponent<GoogleARCore.HelloAR.TrackedPlaneVisualizer>().SetTrackedPlane(newTrackedPlanes[i]); // // // Apply a random color and grid rotation. // planeObject.GetComponent<Renderer>().material.SetColor("_GridColor", planeColors[Random.Range(0, planeColors.Length - 1)]); // planeObject.GetComponent<Renderer>().material.SetFloat("_UvRotation", Random.Range(0.0f, 360.0f)); // } // } // get all tracked planes Session.GetTrackables <DetectedPlane>(allTrackedPlanes, TrackableQueryFilter.All); // create overlay surfaces as needed if (arManager.useOverlaySurface != MultiARManager.SurfaceRenderEnum.None) { alSurfacesToDelete.Clear(); alSurfacesToDelete.AddRange(arData.dictOverlaySurfaces.Keys); // estimate the material Material surfaceMat = arManager.GetSurfaceMaterial(); int surfaceLayer = MultiARInterop.GetSurfaceLayer(); for (int i = 0; i < allTrackedPlanes.Count; i++) { string surfId = allTrackedPlanes[i].m_TrackableNativeHandle.ToString(); if (!arData.dictOverlaySurfaces.ContainsKey(surfId)) { GameObject overlaySurfaceObj = new GameObject(); overlaySurfaceObj.name = "surface-" + surfId; overlaySurfaceObj.layer = surfaceLayer; overlaySurfaceObj.transform.SetParent(arData.surfaceRendererRoot ? arData.surfaceRendererRoot.transform : null); // GameObject overlayCubeObj = GameObject.CreatePrimitive(PrimitiveType.Cube); // overlayCubeObj.name = "surface-cube-" + surfId; // overlayCubeObj.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f); // overlayCubeObj.transform.SetParent(overlaySurfaceObj.transform); OverlaySurfaceUpdater overlaySurface = overlaySurfaceObj.AddComponent <OverlaySurfaceUpdater>(); overlaySurface.SetSurfaceMaterial(surfaceMat); overlaySurface.SetSurfaceCollider(arManager.surfaceCollider, arManager.colliderMaterial); arData.dictOverlaySurfaces.Add(surfId, overlaySurface); } // update the surface mesh bool bValidSurface = UpdateOverlaySurface(arData.dictOverlaySurfaces[surfId], allTrackedPlanes[i]); if (bValidSurface && alSurfacesToDelete.Contains(surfId)) { alSurfacesToDelete.Remove(surfId); } } // delete not tracked surfaces foreach (string surfId in alSurfacesToDelete) { OverlaySurfaceUpdater overlaySurface = arData.dictOverlaySurfaces[surfId]; arData.dictOverlaySurfaces.Remove(surfId); Destroy(overlaySurface.gameObject); } } // check status of the anchors List <string> alAnchorsToRemove = new List <string>(); foreach (string anchorId in arData.allAnchorsDict.Keys) { List <GameObject> anchoredObjs = arData.allAnchorsDict[anchorId]; foreach (GameObject anchoredObj in anchoredObjs) { Transform parentTrans = anchoredObj.transform.parent; if (parentTrans == null) { if (!alAnchorsToRemove.Contains(anchorId)) { alAnchorsToRemove.Add(anchorId); } anchoredObj.SetActive(false); } else { Anchor anchor = parentTrans.GetComponent <Anchor>(); if (anchor == null || anchor.TrackingState == TrackingState.Stopped) { if (!alAnchorsToRemove.Contains(anchorId)) { alAnchorsToRemove.Add(anchorId); } anchoredObj.transform.parent = null; anchoredObj.SetActive(false); } } } } // remove the stopped anchors from our list foreach (string anchorId in alAnchorsToRemove) { arData.allAnchorsDict.Remove(anchorId); } // clean up alAnchorsToRemove.Clear(); // look for image anchors, if enabled if (arData.imageAnchorsEnabled) { // Get updated augmented images for this frame. Session.GetTrackables <AugmentedImage>(alTrackedAugmentedImages, TrackableQueryFilter.Updated); foreach (var image in alTrackedAugmentedImages) { string sImageName = image.Name; bool wasImageTracked = dictImageAnchors.ContainsKey(sImageName); if (!wasImageTracked && image.TrackingState == TrackingState.Tracking) { // Create an anchor to ensure that ARCore keeps tracking this augmented image. Anchor anchor = image.CreateAnchor(image.CenterPose); anchor.gameObject.name = "ImageAnchor-" + sImageName; DontDestroyOnLoad(anchor.gameObject); alImageAnchorNames.Add(sImageName); dictImageAnchors.Add(sImageName, anchor.gameObject); } else if (wasImageTracked && image.TrackingState == TrackingState.Stopped) { // remove the anchor GameObject anchorObj = dictImageAnchors[sImageName]; alImageAnchorNames.Remove(sImageName); dictImageAnchors.Remove(sImageName); GameObject.Destroy(anchorObj); } } } }
// loads AR scene and the detected surfaces public JsonArScene LoadArScene(string dataFilePath) { if (!File.Exists(dataFilePath)) { return(null); } // load json string sJsonText = File.ReadAllText(dataFilePath); JsonArScene data = JsonUtility.FromJson <JsonArScene>(sJsonText); if (data != null) { Quaternion compStartRot = Quaternion.Euler(0f, -startHeading, 0f); Vector3 camOffset = Vector3.zero; if (applyLocationDistance && locationEnabled && Input.location.status == LocationServiceStatus.Running && data.scenePos != null) { Vector3 locSaved = GeoUtils.LatLong2Meters(data.scenePos.lat, data.scenePos.lon, useLocationAltitude ? data.scenePos.alt : 0f); Vector3 locCamera = GeoUtils.LatLong2Meters(lastLoc.latitude, lastLoc.longitude, useLocationAltitude ? lastLoc.altitude : 0f); camOffset = locSaved - locCamera; camOffset = new Vector3(camOffset.y, camOffset.z, camOffset.x); // x=lon; y=alt; z=lat } if (data.surfaceSet != null) { // destroy currently loaded surfaces DestroyLoadedSurfaces(); for (int i = 0; i < data.surfaceSet.surfaceCount; i++) { GameObject overlaySurfaceObj = new GameObject(); overlaySurfaceObj.name = "surface-" + i; overlaySurfaceObj.transform.SetParent(transform); // GameObject overlayCubeObj = GameObject.CreatePrimitive(PrimitiveType.Cube); // overlayCubeObj.name = "surface-cube-" + i; // overlayCubeObj.transform.localScale = new Vector3(0.1f, 0.2f, 0.3f); // overlayCubeObj.transform.SetParent(overlaySurfaceObj.transform); OverlaySurfaceUpdater overlaySurface = overlaySurfaceObj.AddComponent <OverlaySurfaceUpdater>(); overlaySurface.SetSurfaceMaterial(surfaceMaterial); overlaySurface.SetSurfaceCollider(true, null); Vector3 surfacePos = data.surfaceSet.surfaces[i].position; surfacePos = compStartRot * surfacePos; if (applyLocationDistance) { surfacePos += camOffset; } Quaternion surfaceRot = Quaternion.Euler(data.surfaceSet.surfaces[i].rotation); surfaceRot = Quaternion.Euler(surfaceRot.eulerAngles + compStartRot.eulerAngles); // List <Vector3> meshVertices = new List <Vector3>(data.surfaceSet.surfaces[i].vertices); List <int> meshIndices = new List <int>(data.surfaceSet.surfaces[i].indices); // update the surface mesh overlaySurface.UpdateSurfaceMesh(surfacePos, surfaceRot, meshVertices, meshIndices); // // find the nearest currently tracked surface // MultiARInterop.TrackedSurface[] alTrackedSurf = arManager ? arManager.GetTrackedSurfaces(false) : null; // // MultiARInterop.TrackedSurface nearestSurf; // float nearestDist = float.MaxValue; // bool foundNearestSurf = false; // // if (alTrackedSurf != null && alTrackedSurf.Length > 0) // { // for (int s = 0; s < alTrackedSurf.Length; s++) // { // MultiARInterop.TrackedSurface trackedSurf = alTrackedSurf[s]; // // // } // } alLoadedSurfaces.Add(overlaySurface); } } Debug.Log("AR-Scene (head: " + (int)data.startHeading + ") loaded from: " + dataFilePath); } return(data); }