private void UpdateForDisplayImmediatelyGroundOnly() { long activeSurfaceId = xr.GetActiveSurfaceId(); XRSurface activeSurface = xr.GetSurface(activeSurfaceId); bool activeSurfaceIsValidGround = activeSurface != XRSurface.NO_SURFACE && activeSurface.type == XRSurface.Type.HORIZONTAL_PLANE; if (!activeSurfaceIsValidGround) { return; } Vector3 centerVertex = GetVertexCenter(activeSurface.mesh); if (surfaceFound) { if (centerVertex.y < groundHeightGuess) { groundHeightGuess = centerVertex.y; SetHeight(groundHeightGuess); } } else { if (centerVertex.y < Camera.main.transform.position.y - MIN_GROUND_DISTANCE_FROM_PHONE) { groundHeightGuess = centerVertex.y; SetHeight(groundHeightGuess); onSurfaceAttach.Invoke(); surfaceFound = true; } } }
public override bool Equals(object o) { if (!(o is XRSurface)) { return(false); } XRSurface s = (XRSurface)o; return(id == s.id && type == s.type && rotation == s.rotation && mesh == s.mesh); }
private bool IsValidGroundSurface(XRSurface surface) { if (surface.type != XRSurface.Type.HORIZONTAL_PLANE) { return(false); } Vector3 centerVertex = GetVertexCenter(surface.mesh); // New ground surface must be: // -below a certain cutoff // -lowest surface seen so far (and at least MIN_GROUND_CHANGE_DISTANCE lower) bool surfaceIsGroundHeight = centerVertex.y < Camera.main.transform.position.y - MIN_GROUND_DISTANCE_FROM_PHONE; bool surfaceIsLowestSurface = !surfaceFound || centerMap[surfaceId].y - centerVertex.y > MIN_GROUND_CHANGE_DISTANCE; return(surfaceIsGroundHeight && surfaceIsLowestSurface); }
/** This method doesn't cache its result. */ private Dictionary <long, XRSurface> GetSurfacesFromXRResponse() { var r = GetCurrentReality(); var surfaceSet = r.getXRResponse().getSurfaces().getSet(); var surfaces = surfaceSet.getSurfaces(); var faces = surfaceSet.getFaces(); var vertexList = surfaceSet.getVertices(); var textureCoordsList = surfaceSet.getTextureCoords(); // Boundary vertices are available but not used right now var surfacesToRemove = new HashSet <long>(xrSurfaceMap_.Keys); foreach (var surface in surfaces) { long id = surface.getId().getEventTimeMicros(); surfacesToRemove.Remove(id); var quat = surface.getNormal().getRotation(); // Extract basic info about this mesh. int beginFaceIndex = surface.getFacesBeginIndex(); int endFaceIndex = surface.getFacesEndIndex(); int beginVerticesIndex = surface.getVerticesBeginIndex(); int endVerticesIndex = surface.getVerticesEndIndex(); // Support texture coords when the device has it (e.g. ARKit >1.5) int beginTextureCoordsIndex = 0; bool hasTextureCoords = false; if (surface.getTextureCoordsEndIndex() > 0) { hasTextureCoords = true; beginTextureCoordsIndex = surface.getTextureCoordsBeginIndex(); } // Build the vertex and normal arrays. int nVertices = endVerticesIndex - beginVerticesIndex; Vector3[] vertices = new Vector3[nVertices]; Vector3[] normals = new Vector3[nVertices]; Vector2[] uvs = new Vector2[nVertices]; for (int j = 0; j < nVertices; ++j) { int vertexIndex = beginVerticesIndex + j; vertices[j] = new Vector3( vertexList.get(vertexIndex).getX(), vertexList.get(vertexIndex).getY(), vertexList.get(vertexIndex).getZ()); normals[j] = Vector3.up; float u = vertices[j][0]; float v = vertices[j][2]; if (hasTextureCoords) { int textureIndex = beginTextureCoordsIndex + j; u = textureCoordsList.get(textureIndex).getU(); v = textureCoordsList.get(textureIndex).getV(); } uvs[j] = new Vector2(u, v); } // We can just directly copy over the triangles (they are stored in consecutive sets of three // vertex indices) as long as we offset the vertex indices. int nFaces = endFaceIndex - beginFaceIndex; int[] triangles = new int[nFaces * 3]; for (int j = 0; j < nFaces; ++j) { int v0 = faces.get(j + beginFaceIndex).getV0() - beginVerticesIndex; int v1 = faces.get(j + beginFaceIndex).getV1() - beginVerticesIndex; int v2 = faces.get(j + beginFaceIndex).getV2() - beginVerticesIndex; triangles[3 * j] = v0; triangles[3 * j + 1] = v1; triangles[3 * j + 2] = v2; } var surfaceType = GetSurfaceType(surface.getSurfaceType()); var surfaceRotation = new Quaternion(quat.getX(), quat.getY(), quat.getZ(), quat.getW()); Mesh mesh = null; if (xrSurfaceMap_.ContainsKey(id)) { XRSurface existingSurface = xrSurfaceMap_[id]; mesh = existingSurface.mesh; mesh.Clear(); } else { mesh = new Mesh(); } mesh.vertices = vertices; mesh.normals = normals; mesh.uv = uvs; mesh.triangles = triangles; xrSurfaceMap_[id] = new XRSurface(id, surfaceType, surfaceRotation, mesh); } // Remove surfaces we no longer receive from the map foreach (long surfaceId in surfacesToRemove) { xrSurfaceMap_.Remove(surfaceId); } return(xrSurfaceMap_); }
// Returns true if surface was updated private bool UpdateSurface() { long activeSurfaceId = xr.GetActiveSurfaceId(); XRSurface activeSurface = xr.GetSurface(activeSurfaceId); if (activeSurface.mesh == null) { return(false); } // Update center map height if already in map if (centerMap.ContainsKey(activeSurfaceId)) { Vector3 centerVertex = GetVertexCenter(activeSurface.mesh); Vector3 previousCenter = centerMap[activeSurfaceId]; Vector3 normal = Vector3.Cross( activeSurface.mesh.vertices[0] - activeSurface.mesh.vertices[1], activeSurface.mesh.vertices[0] - activeSurface.mesh.vertices[2] ); normal.Normalize(); Vector3 newCenter = previousCenter + normal * Vector3.Dot(centerVertex - previousCenter, normal); centerMap[activeSurfaceId] = newCenter; } if (surfaceId == activeSurfaceId) { return(false); } if (groundOnly && !IsValidGroundSurface(activeSurface)) { return(false); } if (surfaceFound && lockToFirstSurface) { return(false); } if (!centerMap.ContainsKey(activeSurfaceId)) { centerMap.Add(activeSurfaceId, GetVertexCenter(activeSurface.mesh)); } bool triggerReady = !displayImmediately && !surfaceFound; bool triggerAttach = !surfaceFound; SetHidden(false); transform.position = centerMap[activeSurfaceId]; surfaceId = activeSurfaceId; surfaceFound = true; if (rotatePlaneWithDetectedNormal) { transform.localRotation = originalRotation_; transform.Rotate(activeSurface.rotation.eulerAngles); } if (deformToSurface) { DeformMesh(activeSurface.mesh); } if (triggerReady) { if (onSurfaceReady != null) { onSurfaceReady.Invoke(); } } if (triggerAttach) { if (onSurfaceAttach != null) { onSurfaceAttach.Invoke(); } } else { if (onSurfaceSwitch != null) { onSurfaceSwitch.Invoke(); } } return(true); }