private void Update() { HoloToolkit.Unity.SpatialMapping.OrientedBoundingBox obb = OBBMeshIntersection.CreateWorldSpaceOBB(GetComponent <BoxCollider>()); List <int> intersecting = OBBMeshIntersection.FindTriangles(obb, m_triangleMesh.vertices, m_triangleMesh.GetTriangles(0), m_triangleXform); GetComponent <Renderer>().material.color = intersecting.Count > 0 ? Color.red : Color.green; }
void Start() { BoxCollider obb = obbParent.GetComponent <BoxCollider>(); Mesh mesh = meshParent.GetComponent <MeshFilter>().sharedMesh; Debug.Log("OBB-Mesh Intersection Result: " + (OBBMeshIntersection.FindTriangles(obb, mesh.vertices, mesh.GetTriangles(0), meshParent.transform).Count > 0)); }
private void CreateBulletHole(Vector3 position, Vector3 normal) { GameObject bulletHole = Instantiate(m_bulletHolePrefab, position, Quaternion.LookRotation(normal)) as GameObject; bulletHole.transform.parent = this.transform; OrientedBoundingBox obb = OBBMeshIntersection.CreateWorldSpaceOBB(bulletHole.GetComponent <BoxCollider>()); SurfacePlaneDeformationManager.Instance.Embed(bulletHole, obb, position, () => { Debug.Log("Embed complete"); }, true); }
private void CreateBulletHole(Vector3 position, Vector3 normal, SurfacePlane plane) { GameObject bulletHole = Instantiate(m_bulletHolePrefab, position, Quaternion.LookRotation(normal)) as GameObject; bulletHole.AddComponent <WorldAnchor>(); // does this do anything? bulletHole.transform.parent = this.transform; OrientedBoundingBox obb = OBBMeshIntersection.CreateWorldSpaceOBB(bulletHole.GetComponent <BoxCollider>()); SurfacePlaneDeformationManager.Instance.Embed(bulletHole, obb, plane); }
// SpatialUnderstanding case public void CreateBulletHole(Vector3 position, Vector3 normal) { GameObject bulletHole = Instantiate(bulletHolePrefab, position + normal * .005f, Quaternion.LookRotation(normal)) as GameObject; bulletHole.transform.parent = this.transform; SurfacePlaneDeformationManager.Instance.Embed(bulletHole, OBBMeshIntersection.CreateWorldSpaceOBB(bulletHole.GetComponent <BoxCollider>()), bulletHole.transform.position); //TODO: logic for objects to self destruct after not being gazed at for long enough? m_bulletHoles.Enqueue(bulletHole); while (m_bulletHoles.Count > maxBulletHoles) { GameObject oldBulletHole = m_bulletHoles.Dequeue(); if (oldBulletHole) // if hasn't destroyed itself already { Destroy(oldBulletHole); } } }
private IEnumerator DeformSurfaceCoroutine() { while (m_requestQueue.Count > 0) { // Dequeue EmbedRequest request = m_requestQueue.Dequeue(); GameObject marginVolume = request.marginVolume; Vector3 marginFrontPlanePoint = request.centerPointOnFrontPlane; Vector3 marginBackPlanePoint = request.centerPointOnBackPlane; GameObject embedded = request.embedded; // Get the OBB that describes the margin volume we want to create BoxCollider obb = marginVolume.GetComponent <BoxCollider>(); /* * Compute a back-plane located directly behind the embedded object. * Triangles that intersect with the embedded object's OBB will be * projected onto this back plane. The projection formula is: * * v' = v - n * (Dot(n, v) + planeToOriginDistance) * * Where n is the normal pointing toward the spatial mesh and * planeToOriginDistance is solved for using the plane equation. * * We assume the OBB's position is located at the front-facing side of the * embedded object rather than in its center. */ Vector3 intoSurface = marginBackPlanePoint - marginFrontPlanePoint; Vector3 intoSurfaceNormal = Vector3.Normalize(intoSurface); float planeToOriginDistance = 0 - Vector3.Dot(intoSurfaceNormal, marginBackPlanePoint); // Ax+By+Cz+D=0, solving for D here // The thickness of the embedded object can easily be obtained from the // desired distance between the margin volume's front and back planes float requiredMargin = Vector3.Magnitude(intoSurface); // Check against each spatial mesh and deform those that intersect the // margin volume foreach (MeshFilter meshFilter in m_spatialMeshFilters) { if (meshFilter == null) { continue; } if (request.HasSufficientMargin(meshFilter, requiredMargin)) { //Debug.Log("Skipping [" + task.plane.GetInstanceID() + "," + meshFilter.GetInstanceID() + "] due to sufficient margin"); continue; } // Detect all triangles that intersect with the margin volume OBB Mesh mesh = meshFilter.sharedMesh; if (mesh == null) { continue; } Vector3[] verts = mesh.vertices; // spatial mesh has vertices and normals, no UVs Vector3[] normals = mesh.normals; List <int> intersectingTriangles = null; IEnumerator f = OBBMeshIntersection.FindTrianglesCoroutine((List <int> result) => { intersectingTriangles = result; }, maxSecondsPerFrame, obb, verts, mesh.GetTriangles(0), meshFilter.transform); while (f.MoveNext()) { yield return(f.Current); } if (intersectingTriangles.Count == 0) { //Debug.Log("No intersecting triangles found in: " + meshFilter.gameObject.name); continue; } // TODO: Use a bit set to keep track of which vertex indices to modify? float t0 = Time.realtimeSinceStartup; List <int> vertIndices = intersectingTriangles; // Modify spatial mesh by pushing vertices inward onto the back plane of // the margin volume foreach (int i in vertIndices) { Vector3 worldVert = meshFilter.transform.TransformPoint(verts[i]); float displacement = Vector3.Dot(intoSurfaceNormal, worldVert) + planeToOriginDistance; worldVert = worldVert - displacement * intoSurfaceNormal; verts[i] = meshFilter.transform.InverseTransformPoint(worldVert); if (Time.realtimeSinceStartup - t0 >= maxSecondsPerFrame) { yield return(null); t0 = Time.realtimeSinceStartup; } } mesh.vertices = verts; // apply changes mesh.RecalculateBounds(); // not needed because deformation should be minor if (Time.realtimeSinceStartup - t0 >= maxSecondsPerFrame) { yield return(null); t0 = Time.realtimeSinceStartup; } // Update margin depth of this plane/spatial mesh pair request.RecordMargin(meshFilter, requiredMargin); //Debug.Log("Finished deforming [" + task.plane.GetInstanceID() + "," + meshFilter.GetInstanceID() + "]"); } // Restore embedded object's shared materials (and its render order) now // that margin exists in the spatial mesh. Clean up temporary objects. // Destroy temporary object embedded.GetComponent <SharedMaterialHelper>().RestoreSharedMaterials(); Object.Destroy(marginVolume.GetComponent <BoxCollider>()); Object.Destroy(marginVolume); } m_working = false; yield break; }
private IEnumerator WorkRoutine() { while (m_work_queue.Count > 0) { // Dequeue and begin processing WorkUnit work = m_work_queue.Dequeue(); BoxCollider obb = work.renderer.gameObject.GetComponent <BoxCollider>(); if (obb == null) { Debug.Log("ERROR: Object " + work.renderer.gameObject.name + " lacks a box collider"); m_working = false; yield break; } // Compute parameters for a projection plane behind embedded object Vector3 displacement_normal; float plane_to_origin_distance; ComputeBackPlaneParameters(out displacement_normal, out plane_to_origin_distance, obb); // Check against each spatial mesh and deform those that intersect int num = 0; foreach (MeshFilter mesh_filter in m_spatialMeshFilters) { Debug.Log("Iterating... " + (num++)); if (mesh_filter == null) { continue; } //TODO: prefetch vertices/normals/uvs and indices because OBBMeshIntersection gets them, too, which is slow /* * Step 3: Detect all triangles that intersect with our object */ Mesh mesh = mesh_filter.sharedMesh; if (mesh == null) { continue; } List <int> intersecting_triangles = new List <int>(); Vector3[] verts = mesh.vertices; // spatial mesh has vertices and normals, no UVs Vector3[] normals = mesh.normals; OBBMeshIntersection.ResultsCallback results = delegate(List <int> intersecting_triangles_found) { intersecting_triangles = intersecting_triangles_found; }; IEnumerator f = OBBMeshIntersection.FindTrianglesCoroutine(results, maxSecondsPerFrame, obb, verts, mesh.GetTriangles(0), mesh_filter.transform); while (f.MoveNext()) { yield return(f.Current); } if (intersecting_triangles.Count == 0) { continue; } float t0 = Time.realtimeSinceStartup; List <int> vert_indices = MakeSetOfVertexIndices(intersecting_triangles); /* * Step 4: Create a new set of vertices and triangles out of the affected * ones to save their state before we alter them in the original mesh. * This "patch" mesh will be drawn after spatial meshes and embedded * objects. * * Step 5: Save the game object along with a mapping of the modified * vertices so we can undo changes later. * * Step 6: Create a new GameObject to hold a mesh with the saved * vertices. Note that the vertices were in spatial mesh local * coordinates, so we copy the spatial mesh transform to position them * correctly in world space. * * Step 7: Reassign render order of saved triangles to a lower priority * than embedded object, so that they are rendered after */ CreatePatchObject(mesh, mesh_filter, intersecting_triangles, verts, normals, vert_indices); if (Time.realtimeSinceStartup - t0 >= maxSecondsPerFrame) { yield return(null); t0 = Time.realtimeSinceStartup; } /* * Step 8: Modify the spatial mesh's vertices by pushing them inward * along axis of normal */ foreach (int i in vert_indices) { Vector3 world_vert = mesh_filter.transform.TransformPoint(verts[i]); float displacement = Vector3.Dot(displacement_normal, world_vert) + plane_to_origin_distance; world_vert = world_vert - displacement * displacement_normal; verts[i] = mesh_filter.transform.InverseTransformPoint(world_vert); } mesh.vertices = verts; // apply changes mesh.RecalculateBounds(); if (Time.realtimeSinceStartup - t0 >= maxSecondsPerFrame) { yield return(null); t0 = Time.realtimeSinceStartup; } if (updateCollider) { MeshCollider collider = mesh_filter.gameObject.GetComponent <MeshCollider>(); if (collider != null) { collider.sharedMesh = null; collider.sharedMesh = mesh; } if (Time.realtimeSinceStartup - t0 >= maxSecondsPerFrame) { yield return(null); t0 = Time.realtimeSinceStartup; } } } /* * Step 9: Reassign render order of embedded object to be just after the * spatial mesh layer but before patches. We */ SharedMaterialHelper helper = work.renderer.gameObject.GetComponent <SharedMaterialHelper>(); if (helper != null) { // Apply clones of the shared material. Only a single clone is ever // instantiated, which is much more efficient than Unity's default // behavior of cloning materials[] for each object! helper.ApplySharedMaterialClones(); } foreach (Material material in work.renderer.materials) { material.renderQueue = material.renderQueue + (spatialMeshRenderQueueValue - highPriorityRenderQueueValue) + 1; } } m_working = false; }