private bool IsInsideMesh(Vector3 p, SpatialBinaryTree tree, Dictionary <Vector3, bool> pointInsideMeshCache) { bool isInsideMesh; if (pointInsideMeshCache.TryGetValue(Vector3.one, out isInsideMesh)) { return(isInsideMesh); } var r = new Ray(p, new Vector3(1, 0, 0)); var intersectionCount = tree.GetTris(r).Count(t => t.Intersect(r)); var isInside = intersectionCount % 2 != 0; pointInsideMeshCache[p] = isInside; return(isInside); }
private IEnumerable <Box> CreateMeshIntersectingBoxes(GameObject colliderGo) { var go = colliderGo.transform.parent.gameObject; var colliderLayer = colliderGo.layer; LayerMask colliderLayerMask = 1 << colliderLayer; var bounds = CalculateLocalBounds(go); var mesh = colliderGo.GetComponent <MeshFilter>().sharedMesh; var swTree = Stopwatch.StartNew(); var tree = new SpatialBinaryTree(mesh, spatialTreeLevelDepth); swTree.Stop(); if (outputTimeMeasurements) { Debug.Log("SpatialTree Built in " + swTree.Elapsed); } var boxes = new Box[boxesPerEdge, boxesPerEdge, boxesPerEdge]; var boxColliderPositions = new bool[boxesPerEdge, boxesPerEdge, boxesPerEdge]; var s = bounds.size / boxesPerEdge; var halfExtent = s / 2f; var directionsFromBoxCenterToCorners = new[] { new Vector3(1, 1, 1), new Vector3(1, 1, -1), new Vector3(1, -1, 1), new Vector3(1, -1, -1), new Vector3(-1, 1, 1), new Vector3(-1, 1, -1), new Vector3(-1, -1, 1), new Vector3(-1, -1, -1), }; var pointInsideMeshCache = new Dictionary <Vector3, bool>(); var sw = Stopwatch.StartNew(); var colliders = new Collider[1000]; for (var x = 0; x < boxesPerEdge; x++) { for (var y = 0; y < boxesPerEdge; y++) { for (var z = 0; z < boxesPerEdge; z++) { var center = new Vector3( bounds.center.x - bounds.size.x / 2 + s.x * x + halfExtent.x, bounds.center.y - bounds.size.y / 2 + s.y * y + halfExtent.y, bounds.center.z - bounds.size.z / 2 + s.z * z + halfExtent.z); if (!avoidExceedingMesh) { if (avoidGapsInside) { var isInsideSurface = IsInsideMesh(center, tree, pointInsideMeshCache); boxColliderPositions[x, y, z] = isInsideSurface; } else { var overlapsWithMeshSurface = Physics.OverlapBoxNonAlloc(center, halfExtent, colliders, Quaternion.identity, colliderLayerMask) > 0; boxColliderPositions[x, y, z] = overlapsWithMeshSurface; } continue; } var allCornersInsideMesh = (from d in directionsFromBoxCenterToCorners select new Vector3(center.x + halfExtent.x * d.x, center.y + halfExtent.y * d.y, center.z + halfExtent.z * d.z)) .All(cornerPoint => IsInsideMesh(cornerPoint, tree, pointInsideMeshCache)); boxColliderPositions[x, y, z] = allCornersInsideMesh; } } } sw.Stop(); if (outputTimeMeasurements) { Debug.Log("Boxes analyzed in " + sw.Elapsed); } for (var x = 0; x < boxesPerEdge; x++) { for (var y = 0; y < boxesPerEdge; y++) { for (var z = 0; z < boxesPerEdge; z++) { if (!boxColliderPositions[x, y, z]) { continue; } var center = new Vector3( bounds.center.x - bounds.size.x / 2 + s.x * x + s.x / 2, bounds.center.y - bounds.size.y / 2 + s.y * y + s.y / 2, bounds.center.z - bounds.size.z / 2 + s.z * z + s.z / 2); var b = new Box(boxes, center, s, new Vector3Int(x, y, z)); boxes[x, y, z] = b; yield return(b); } } } }