private void RenderBounds(AxisAlignedBoundingBox aabb) { RGBA_Bytes color = RGBA_Bytes.Red; // the bottom RenderLine(transform.Peek(), aabb.GetBottomCorner(0), aabb.GetBottomCorner(1), color); RenderLine(transform.Peek(), aabb.GetBottomCorner(1), aabb.GetBottomCorner(2), color); RenderLine(transform.Peek(), aabb.GetBottomCorner(2), aabb.GetBottomCorner(3), color); RenderLine(transform.Peek(), aabb.GetBottomCorner(3), aabb.GetBottomCorner(0), color); // the top RenderLine(transform.Peek(), aabb.GetTopCorner(0), aabb.GetTopCorner(1), color); RenderLine(transform.Peek(), aabb.GetTopCorner(1), aabb.GetTopCorner(2), color); RenderLine(transform.Peek(), aabb.GetTopCorner(2), aabb.GetTopCorner(3), color); RenderLine(transform.Peek(), aabb.GetTopCorner(3), aabb.GetTopCorner(0), color); // the sides RenderLine(transform.Peek(), new Vector3(aabb.minXYZ.x, aabb.minXYZ.y, aabb.minXYZ.z), new Vector3(aabb.minXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.z), color); RenderLine(transform.Peek(), new Vector3(aabb.maxXYZ.x, aabb.minXYZ.y, aabb.minXYZ.z), new Vector3(aabb.maxXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.z), color); RenderLine(transform.Peek(), new Vector3(aabb.minXYZ.x, aabb.maxXYZ.y, aabb.minXYZ.z), new Vector3(aabb.minXYZ.x, aabb.maxXYZ.y, aabb.maxXYZ.z), color); RenderLine(transform.Peek(), new Vector3(aabb.maxXYZ.x, aabb.maxXYZ.y, aabb.minXYZ.z), new Vector3(aabb.maxXYZ.x, aabb.maxXYZ.y, aabb.maxXYZ.z), color); }
public override bool CheckIfBundleHitsAabb(AxisAlignedBoundingBox aabbToCheck) { if (frustumForRays.GetIntersect(aabbToCheck) == FrustumIntersection.Outside) { return false; } return true; }
public bool GetContained(List<IPrimitive> results, AxisAlignedBoundingBox subRegion) { bool foundItem = false; foreach (IPrimitive item in items) { foundItem |= item.GetContained(results, subRegion); } return foundItem; }
public bool GetContained(List<IPrimitive> results, AxisAlignedBoundingBox subRegion) { AxisAlignedBoundingBox bounds = GetAxisAlignedBoundingBox(); if (bounds.Contains(subRegion)) { results.Add(this); return true; } return false; }
public AxisAlignedBoundingBox GetAxisAlignedBoundingBox() { if (cachedAABB.minXYZ.x == double.NegativeInfinity) { cachedAABB = items[0].GetAxisAlignedBoundingBox(); for (int i = 1; i < items.Count; i++) { cachedAABB += items[i].GetAxisAlignedBoundingBox(); } } return cachedAABB; }
private void CalculateIntersectCostsAndSaveToFile() { int numInterations = 5000000; AxisAlignedBoundingBox referenceCostObject = new AxisAlignedBoundingBox(new Vector3(-.5, -.5, -.5), new Vector3(.5, .5, .5)); Stopwatch timer = new Stopwatch(); Vector3 accumulation = new Vector3(); timer.Start(); for (int i = 0; i < numInterations; i++) { accumulation += GetRandomIntersectingRay().directionNormal; } long notIntersectStuff = timer.ElapsedMilliseconds; timer.Restart(); for (int i = 0; i < numInterations; i++) { GetRandomIntersectingRay().Intersection(referenceCostObject); } long referenceMiliseconds = timer.ElapsedMilliseconds; SolidMaterial material = new SolidMaterial(RGBA_Floats.Black, 0, 0, 1); long sphereMiliseconds = CalculateIntersectCostsForItem(new SphereShape(new Vector3(), .5, material), numInterations); long cylinderMiliseconds = CalculateIntersectCostsForItem(new CylinderShape(.5, 1, material), numInterations); long boxMiliseconds = CalculateIntersectCostsForItem(new BoxShape(new Vector3(-.5, -.5, -.5), new Vector3(.5, .5, .5), material), numInterations); long planeMiliseconds = CalculateIntersectCostsForItem(new PlaneShape(new Vector3(0, 0, 1), 0, material), numInterations); BaseShape triangleTest = new TriangleShape(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 0), material); long triangleMiliseconds = CalculateIntersectCostsForItem(triangleTest, numInterations); System.IO.File.WriteAllText("Cost Of Primitive.txt", "Cost of Primitives" + "\r\n" + numInterations.ToString("N0") + " intersections per primitive." + "\r\nTest Overhead: " + notIntersectStuff.ToString() + GetStringForFile("AABB", referenceMiliseconds, notIntersectStuff) + GetStringForFile("Sphere", sphereMiliseconds, notIntersectStuff) + GetStringForFile("Cylider", cylinderMiliseconds, notIntersectStuff) + GetStringForFile("Box", boxMiliseconds, notIntersectStuff) + GetStringForFile("Plane", planeMiliseconds, notIntersectStuff) + GetStringForFile("Triangle", triangleMiliseconds, notIntersectStuff) ); }
public void SplitOnAllEdgeIntersections(CsgAcceleratedMesh meshWidthEdges) { foreach (var meshEdge in meshWidthEdges.mesh.MeshEdges) { // Check the mesh edge bounds agains all polygons. If there is an intersection // subdivide the mesh edge and if the face that is hit. If hit face on an edge only split the edge. Vector3 end0 = meshEdge.VertexOnEnd[0].Position; Vector3 end1 = meshEdge.VertexOnEnd[1].Position; AxisAlignedBoundingBox edgeBounds = new AxisAlignedBoundingBox(Vector3.ComponentMin(end0, end1), Vector3.ComponentMax(end0, end1)); foreach (Face face in GetFacesTouching(edgeBounds)) { Vector3 intersectionPosition; // intersect the face with the edge switch (face.Intersection(end0, end1, out intersectionPosition)) { case FaceHelper.IntersectionType.Vertex: break; case FaceHelper.IntersectionType.MeshEdge: { SplitMeshEdgeIfRequired(meshEdge, intersectionPosition); // split the face at intersectionPosition SplitMeshEdgeAtPosition(face, intersectionPosition); } break; case FaceHelper.IntersectionType.Face: { SplitMeshEdgeIfRequired(meshEdge, intersectionPosition); // split the face at intersectionPosition SplitFaceAtPosition(face, intersectionPosition); } break; } } } }
private double GetAlignToOffset(Aabb anchorBounds, int axis, Align alignTo) { switch (alignTo) { case Align.None: return(0); case Align.Min: return(anchorBounds.MinXYZ[axis]); case Align.Center: return(anchorBounds.Center[axis]); case Align.Max: return(anchorBounds.MaxXYZ[axis]); case Align.Origin: return(Vector3Ex.Transform(Vector3.Zero, SelectedObject.WorldMatrix())[axis]); default: throw new NotImplementedException(); } }
public static PolygonMesh.Mesh CreateBox(AxisAlignedBoundingBox aabb) { PolygonMesh.Mesh cube = new PolygonMesh.Mesh(); Vertex[] verts = new Vertex[8]; //verts[0] = cube.CreateVertex(new Vector3(-1, -1, 1)); //verts[1] = cube.CreateVertex(new Vector3(1, -1, 1)); //verts[2] = cube.CreateVertex(new Vector3(1, 1, 1)); //verts[3] = cube.CreateVertex(new Vector3(-1, 1, 1)); //verts[4] = cube.CreateVertex(new Vector3(-1, -1, -1)); //verts[5] = cube.CreateVertex(new Vector3(1, -1, -1)); //verts[6] = cube.CreateVertex(new Vector3(1, 1, -1)); //verts[7] = cube.CreateVertex(new Vector3(-1, 1, -1)); verts[0] = cube.CreateVertex(new Vector3(aabb.minXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.z)); verts[1] = cube.CreateVertex(new Vector3(aabb.maxXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.z)); verts[2] = cube.CreateVertex(new Vector3(aabb.maxXYZ.x, aabb.maxXYZ.y, aabb.maxXYZ.z)); verts[3] = cube.CreateVertex(new Vector3(aabb.minXYZ.x, aabb.maxXYZ.y, aabb.maxXYZ.z)); verts[4] = cube.CreateVertex(new Vector3(aabb.minXYZ.x, aabb.minXYZ.y, aabb.minXYZ.z)); verts[5] = cube.CreateVertex(new Vector3(aabb.maxXYZ.x, aabb.minXYZ.y, aabb.minXYZ.z)); verts[6] = cube.CreateVertex(new Vector3(aabb.maxXYZ.x, aabb.maxXYZ.y, aabb.minXYZ.z)); verts[7] = cube.CreateVertex(new Vector3(aabb.minXYZ.x, aabb.maxXYZ.y, aabb.minXYZ.z)); // front cube.CreateFace(new Vertex[] { verts[0], verts[1], verts[2], verts[3] }); // left cube.CreateFace(new Vertex[] { verts[4], verts[0], verts[3], verts[7] }); // right cube.CreateFace(new Vertex[] { verts[1], verts[5], verts[6], verts[2] }); // back cube.CreateFace(new Vertex[] { verts[4], verts[7], verts[6], verts[5] }); // top cube.CreateFace(new Vertex[] { verts[3], verts[2], verts[6], verts[7] }); // bottom cube.CreateFace(new Vertex[] { verts[4], verts[5], verts[1], verts[0] }); return cube; }
public bool GetContained(List<IPrimitive> results, AxisAlignedBoundingBox subRegion) { throw new NotImplementedException(); }
public BvhTreeItemData(T item, AxisAlignedBoundingBox bounds) { this.Item = item; Aabb = bounds; }
public AxisAlignedBoundingBox GetAxisAlignedBoundingBox(Matrix4X4 transform) { if (fastAABBTransform == transform && fastAABBCache != null) { return fastAABBCache; } else { Vector3 minXYZ = new Vector3(double.MaxValue, double.MaxValue, double.MaxValue); Vector3 maxXYZ = new Vector3(double.MinValue, double.MinValue, double.MinValue); foreach (Vertex vertex in vertices) { Vector3 position = Vector3.Transform(vertex.Position, transform); minXYZ.x = Math.Min(minXYZ.x, position.x); minXYZ.y = Math.Min(minXYZ.y, position.y); minXYZ.z = Math.Min(minXYZ.z, position.z); maxXYZ.x = Math.Max(maxXYZ.x, position.x); maxXYZ.y = Math.Max(maxXYZ.y, position.y); maxXYZ.z = Math.Max(maxXYZ.z, position.z); } fastAABBTransform = transform; fastAABBCache = new AxisAlignedBoundingBox(minXYZ, maxXYZ); } return fastAABBCache; }
public FrustumIntersection GetIntersect(AxisAlignedBoundingBox boundingBox) { FrustumIntersection returnValue = FrustumIntersection.Inside; Vector3 vmin, vmax; for (int i = 0; i < plane.Length; ++i) { // X axis if (plane[i].planeNormal.x > 0) { vmin.x = boundingBox.minXYZ.x; vmax.x = boundingBox.maxXYZ.x; } else { vmin.x = boundingBox.maxXYZ.x; vmax.x = boundingBox.minXYZ.x; } // Y axis if (plane[i].planeNormal.y > 0) { vmin.y = boundingBox.minXYZ.y; vmax.y = boundingBox.maxXYZ.y; } else { vmin.y = boundingBox.maxXYZ.y; vmax.y = boundingBox.minXYZ.y; } // Z axis if (plane[i].planeNormal.z > 0) { vmin.z = boundingBox.minXYZ.z; vmax.z = boundingBox.maxXYZ.z; } else { vmin.z = boundingBox.maxXYZ.z; vmax.z = boundingBox.minXYZ.z; } if (Vector3.Dot(plane[i].planeNormal, vmin) - plane[i].distanceToPlaneFromOrigin > 0) { if (Vector3.Dot(plane[i].planeNormal, vmax) - plane[i].distanceToPlaneFromOrigin >= 0) { return FrustumIntersection.Outside; } } if (Vector3.Dot(plane[i].planeNormal, vmax) - plane[i].distanceToPlaneFromOrigin >= 0) { returnValue = FrustumIntersection.Intersect; } } return returnValue; }
public abstract bool CheckIfBundleHitsAabb(AxisAlignedBoundingBox aabbToCheck);
public void SearchBounds(AxisAlignedBoundingBox bounds) { QueryResults.Clear(); root.SearchBounds(bounds, QueryResults); }
public double GetIntersectCost() { return(AxisAlignedBoundingBox.GetIntersectCost()); }
private IEnumerable<Face> GetFacesTouching(AxisAlignedBoundingBox edgeBounds) { // TODO: make this only get the right faces foreach(var face in mesh.Faces) { yield return face; } }
internal Branch(AxisAlignedBoundingBox bounds) { this.Bounds = bounds; }
public BoundingVolumeHierarchy(IPrimitive nodeA, IPrimitive nodeB, int splitingPlane) { this.splitingPlane = splitingPlane; this.nodeA = nodeA; this.nodeB = nodeB; this.Aabb = nodeA.GetAxisAlignedBoundingBox() + nodeB.GetAxisAlignedBoundingBox(); // we can cache this because it is not allowed to change. }
/// <summary> /// Find all values touching in the specified area. /// </summary> /// <returns>True if any values were found.</returns> /// <param name="x">X position to search.</param> /// <param name="y">Y position to search.</param> /// <param name="xSize">xSize of the search area.</param> /// <param name="ySize">ySize of the search area.</param> /// <param name="values">A list to populate with the results. If null, this function will create the list for you.</param> public void SearchBounds(double x, double y, double z, double xSize, double ySize, double zSize) { var bounds = new AxisAlignedBoundingBox(x, y, z, x + xSize, y + ySize, z + zSize); SearchBounds(bounds); }
public bool Equals(AxisAlignedBoundingBox bounds, double equalityTolerance = 0) { return(this.minXYZ.Equals(bounds.minXYZ, equalityTolerance) && this.maxXYZ.Equals(bounds.maxXYZ, equalityTolerance)); }
public static AxisAlignedBoundingBox Intersection(AxisAlignedBoundingBox boundsA, AxisAlignedBoundingBox boundsB) { Vector3 minXYZ = new Vector3( Math.Max(boundsA.minXYZ.X, boundsB.minXYZ.X), Math.Max(boundsA.minXYZ.Y, boundsB.minXYZ.Y), Math.Max(boundsA.minXYZ.Z, boundsB.minXYZ.Z)); Vector3 maxXYZ = new Vector3( Math.Max(minXYZ.X, Math.Min(boundsA.maxXYZ.X, boundsB.maxXYZ.X)), Math.Max(minXYZ.Y, Math.Min(boundsA.maxXYZ.Y, boundsB.maxXYZ.Y)), Math.Max(minXYZ.Z, Math.Min(boundsA.maxXYZ.Z, boundsB.maxXYZ.Z))); return(new AxisAlignedBoundingBox(minXYZ, maxXYZ)); }
public bool Intersection(AxisAlignedBoundingBox bounds) { Ray ray = this; // we calculate distance to the intersection with the x planes of the box double minDistFound = (bounds[(int)ray.sign[0]].x - ray.origin.x) * ray.oneOverDirection.x; double maxDistFound = (bounds[1 - (int)ray.sign[0]].x - ray.origin.x) * ray.oneOverDirection.x; // now find the distance to the y planes of the box double minDistToY = (bounds[(int)ray.sign[1]].y - ray.origin.y) * ray.oneOverDirection.y; double maxDistToY = (bounds[1 - (int)ray.sign[1]].y - ray.origin.y) * ray.oneOverDirection.y; if ((minDistFound > maxDistToY) || (minDistToY > maxDistFound)) { return false; } if (minDistToY > minDistFound) { minDistFound = minDistToY; } if (maxDistToY < maxDistFound) { maxDistFound = maxDistToY; } // and finaly the z planes double minDistToZ = (bounds[(int)ray.sign[2]].z - ray.origin.z) * ray.oneOverDirection.z; double maxDistToZ = (bounds[1 - (int)ray.sign[2]].z - ray.origin.z) * ray.oneOverDirection.z; if ((minDistFound > maxDistToZ) || (minDistToZ > maxDistFound)) { return false; } if (minDistToZ > minDistFound) { minDistFound = minDistToZ; } if (maxDistToZ < maxDistFound) { maxDistFound = maxDistToZ; } bool withinDistanceToConsider = (minDistFound < ray.maxDistanceToConsider) && (maxDistFound > ray.minDistanceToConsider); return withinDistanceToConsider; }
public static AxisAlignedBoundingBox Intersection(AxisAlignedBoundingBox boundsA, AxisAlignedBoundingBox boundsB) { Vector3 minXYZ = Vector3.Zero; minXYZ.x = Math.Max(boundsA.minXYZ.x, boundsB.minXYZ.x); minXYZ.y = Math.Max(boundsA.minXYZ.y, boundsB.minXYZ.y); minXYZ.z = Math.Max(boundsA.minXYZ.z, boundsB.minXYZ.z); Vector3 maxXYZ = Vector3.Zero; maxXYZ.x = Math.Max(minXYZ.x, Math.Min(boundsA.maxXYZ.x, boundsB.maxXYZ.x)); maxXYZ.y = Math.Max(minXYZ.y, Math.Min(boundsA.maxXYZ.y, boundsB.maxXYZ.y)); maxXYZ.z = Math.Max(minXYZ.z, Math.Min(boundsA.maxXYZ.z, boundsB.maxXYZ.z)); return(new AxisAlignedBoundingBox(minXYZ, maxXYZ)); }
public static Matrix4X4 ApplyAtCenter(AxisAlignedBoundingBox boundsToApplyTo, Matrix4X4 currentTransform, Matrix4X4 transformToApply) { return ApplyAtPosition(currentTransform, transformToApply, boundsToApplyTo.Center); }
public bool GetContained(List<IPrimitive> results, AxisAlignedBoundingBox subRegion) { AxisAlignedBoundingBox bounds = GetAxisAlignedBoundingBox(); if (bounds.Contains(subRegion)) { bool resultA = this.nodeA.GetContained(results, subRegion); bool resultB = this.nodeB.GetContained(results, subRegion); return resultA | resultB; } return false; }
/// <summary> /// Creates a new Octree. /// </summary> /// <param name="splitCount">How many leaves a branch can hold before it splits into sub-branches.</param> /// <param name="region">The region that your Octree occupies, all inserted bounds should fit into this.</param> public Octree(int splitCount, AxisAlignedBoundingBox region) { this.splitCount = splitCount; root = CreateBranch(this, null, region); }
public static AxisAlignedBoundingBox Intersection(AxisAlignedBoundingBox boundsA, AxisAlignedBoundingBox boundsB) { Vector3 minXYZ = Vector3.Zero; minXYZ.x = Math.Max(boundsA.minXYZ.x, boundsB.minXYZ.x); minXYZ.y = Math.Max(boundsA.minXYZ.y, boundsB.minXYZ.y); minXYZ.z = Math.Max(boundsA.minXYZ.z, boundsB.minXYZ.z); Vector3 maxXYZ = Vector3.Zero; maxXYZ.x = Math.Max(minXYZ.x, Math.Min(boundsA.maxXYZ.x, boundsB.maxXYZ.x)); maxXYZ.y = Math.Max(minXYZ.y, Math.Min(boundsA.maxXYZ.y, boundsB.maxXYZ.y)); maxXYZ.z = Math.Max(minXYZ.z, Math.Min(boundsA.maxXYZ.z, boundsB.maxXYZ.z)); return new AxisAlignedBoundingBox(minXYZ, maxXYZ); }
public bool Contains(AxisAlignedBoundingBox bounds) { if (this.minXYZ.x <= bounds.minXYZ.x && this.maxXYZ.x >= bounds.maxXYZ.x && this.minXYZ.y <= bounds.minXYZ.y && this.maxXYZ.y >= bounds.maxXYZ.y && this.minXYZ.z <= bounds.minXYZ.z && this.maxXYZ.z >= bounds.maxXYZ.z) { return true; } return false; }
public void SetMeshAfterLoad(List<MeshGroup> loadedMeshGroups, CenterPartAfterLoad centerPart, Vector2 bedCenter) { MeshGroups.Clear(); if (loadedMeshGroups == null) { partProcessingInfo.centeredInfoText.Text = string.Format("Sorry! No 3D view available\nfor this file."); } else { CreateGlDataForMeshes(loadedMeshGroups); AxisAlignedBoundingBox bounds = new AxisAlignedBoundingBox(Vector3.Zero, Vector3.Zero); bool first = true; foreach (MeshGroup meshGroup in loadedMeshGroups) { if (first) { bounds = meshGroup.GetAxisAlignedBoundingBox(); first = false; } else { bounds = AxisAlignedBoundingBox.Union(bounds, meshGroup.GetAxisAlignedBoundingBox()); } } foreach (MeshGroup meshGroup in loadedMeshGroups) { // make sure the mesh is centered about the origin so rotations will come from a reasonable place ScaleRotateTranslate centering = ScaleRotateTranslate.Identity(); centering.SetCenteringForMeshGroup(meshGroup); meshTransforms.Add(centering); MeshGroups.Add(meshGroup); } if (centerPart == CenterPartAfterLoad.DO) { // make sure the entire load is centered and on the bed Vector3 boundsCenter = (bounds.maxXYZ + bounds.minXYZ) / 2; for (int i = 0; i < MeshGroups.Count; i++) { ScaleRotateTranslate moved = meshTransforms[i]; moved.translation *= Matrix4X4.CreateTranslation(-boundsCenter + new Vector3(0, 0, bounds.ZSize / 2) + new Vector3(bedCenter)); meshTransforms[i] = moved; } } trackballTumbleWidget.TrackBallController = new TrackBallController(); trackballTumbleWidget.OnBoundsChanged(null); trackballTumbleWidget.TrackBallController.Scale = .03; trackballTumbleWidget.TrackBallController.Translate(-new Vector3(BedCenter)); trackballTumbleWidget.TrackBallController.Rotate(Quaternion.FromEulerAngles(new Vector3(0, 0, MathHelper.Tau / 16))); trackballTumbleWidget.TrackBallController.Rotate(Quaternion.FromEulerAngles(new Vector3(-MathHelper.Tau * .19, 0, 0))); } }
AxisAlignedBoundingBox GetAxisAlignedBoundingBox(List<MeshGroup> meshGroups) { AxisAlignedBoundingBox totalMeshBounds = new AxisAlignedBoundingBox(Vector3.NegativeInfinity, Vector3.NegativeInfinity); bool first = true; foreach (MeshGroup meshGroup in meshGroups) { AxisAlignedBoundingBox meshBounds = meshGroup.GetAxisAlignedBoundingBox(); if (first) { totalMeshBounds = meshBounds; first = false; } else { totalMeshBounds = AxisAlignedBoundingBox.Union(totalMeshBounds, meshBounds); } } return totalMeshBounds; }
public static AxisAlignedBoundingBox operator +(AxisAlignedBoundingBox A, AxisAlignedBoundingBox B) { #if true return Union(A, B); #else Vector3 calcMinXYZ = new Vector3(); calcMinXYZ.x = Math.Min(A.minXYZ.x, B.minXYZ.x); calcMinXYZ.y = Math.Min(A.minXYZ.y, B.minXYZ.y); calcMinXYZ.z = Math.Min(A.minXYZ.z, B.minXYZ.z); Vector3 calcMaxXYZ = new Vector3(); calcMaxXYZ.x = Math.Max(A.maxXYZ.x, B.maxXYZ.x); calcMaxXYZ.y = Math.Max(A.maxXYZ.y, B.maxXYZ.y); calcMaxXYZ.z = Math.Max(A.maxXYZ.z, B.maxXYZ.z); AxisAlignedBoundingBox combinedBounds = new AxisAlignedBoundingBox(calcMinXYZ, calcMaxXYZ); return combinedBounds; #endif }
/// <summary> /// Insert a new leaf node into the Octree. /// </summary> /// <param name="value">The leaf value.</param> /// <param name="x">X position of the leaf.</param> /// <param name="y">Y position of the leaf.</param> /// <param name="xSize">xSize of the leaf.</param> /// <param name="ySize">ySize of the leaf.</param> public void Insert(T value, double x, double y, double z, double xSize, double ySize, double zSize) { var bounds = new AxisAlignedBoundingBox(x, y, z, x + xSize, y + ySize, z + zSize); Insert(value, bounds); }
public static AxisAlignedBoundingBox Union(AxisAlignedBoundingBox bounds, Vector3 vertex) { Vector3 minXYZ = Vector3.Zero; minXYZ.x = Math.Min(bounds.minXYZ.x, vertex.x); minXYZ.y = Math.Min(bounds.minXYZ.y, vertex.y); minXYZ.z = Math.Min(bounds.minXYZ.z, vertex.z); Vector3 maxXYZ = Vector3.Zero; maxXYZ.x = Math.Max(bounds.maxXYZ.x, vertex.x); maxXYZ.y = Math.Max(bounds.maxXYZ.y, vertex.y); maxXYZ.z = Math.Max(bounds.maxXYZ.z, vertex.z); return new AxisAlignedBoundingBox(minXYZ, maxXYZ); }
private static BvhTree <T> CreateNewHierachy(List <BvhTreeItemData <T> > itemsToAdd, int maxRecursion, int recursionDepth, SortingAccelerator accelerator) { if (accelerator == null) { accelerator = new SortingAccelerator(); } int numItems = itemsToAdd.Count; if (numItems == 0) { return(null); } if (numItems == 1) { return(new BvhTree <T>(itemsToAdd)); } int bestAxis = -1; int bestIndexToSplitOn = -1; var axisSorter = new AxisSorter(0); if (recursionDepth < maxRecursion) { if (numItems > 5000) { bestAxis = accelerator.NextAxis; bestIndexToSplitOn = numItems / 2; } else { double totalIntersectCost = 0; int skipInterval = 1; for (int i = 0; i < numItems; i += skipInterval) { var item = itemsToAdd[i]; if (item.Item is IIntersectable intersectable) { totalIntersectCost += intersectable.GetIntersectCost(); } else { totalIntersectCost += AxisAlignedBoundingBox.GetIntersectCost(); } } // get the bounding box of all the items we are going to consider. AxisAlignedBoundingBox OverallBox = itemsToAdd[0].Aabb; for (int i = skipInterval; i < numItems; i += skipInterval) { OverallBox += itemsToAdd[i].Aabb; } double areaOfTotalBounds = OverallBox.GetSurfaceArea(); double bestCost = totalIntersectCost; Vector3 totalDeviationOnAxis = new Vector3(); double[] surfaceArreaOfItem = new double[numItems - 1]; double[] rightBoundsAtItem = new double[numItems - 1]; for (int axis = 0; axis < 3; axis++) { double intersectCostOnLeft = 0; axisSorter.WhichAxis = axis; itemsToAdd.Sort(axisSorter); // Get all left bounds AxisAlignedBoundingBox currentLeftBounds = itemsToAdd[0].Aabb; surfaceArreaOfItem[0] = currentLeftBounds.GetSurfaceArea(); for (int itemIndex = 1; itemIndex < numItems - 1; itemIndex += skipInterval) { currentLeftBounds += itemsToAdd[itemIndex].Aabb; surfaceArreaOfItem[itemIndex] = currentLeftBounds.GetSurfaceArea(); totalDeviationOnAxis[axis] += Math.Abs(itemsToAdd[itemIndex].Center[axis] - itemsToAdd[itemIndex - 1].Center[axis]); } // Get all right bounds if (numItems > 1) { AxisAlignedBoundingBox currentRightBounds = itemsToAdd[numItems - 1].Aabb; rightBoundsAtItem[numItems - 2] = currentRightBounds.GetSurfaceArea(); for (int itemIndex = numItems - 1; itemIndex > 1; itemIndex -= skipInterval) { currentRightBounds += itemsToAdd[itemIndex - 1].Aabb; rightBoundsAtItem[itemIndex - 2] = currentRightBounds.GetSurfaceArea(); } } // Sweep from left for (int itemIndex = 0; itemIndex < numItems - 1; itemIndex += skipInterval) { double thisCost = 0; { // Evaluate Surface Cost Equation double costOfTwoAABB = 2 * AxisAlignedBoundingBox.GetIntersectCost(); // the cost of the two children AABB tests // do the left cost if (itemsToAdd[itemIndex].Item is IIntersectable intersectable) { intersectCostOnLeft += intersectable.GetIntersectCost(); } else { intersectCostOnLeft += AxisAlignedBoundingBox.GetIntersectCost(); } double leftCost = (surfaceArreaOfItem[itemIndex] / areaOfTotalBounds) * intersectCostOnLeft; // do the right cost double intersectCostOnRight = totalIntersectCost - intersectCostOnLeft; double rightCost = (rightBoundsAtItem[itemIndex] / areaOfTotalBounds) * intersectCostOnRight; thisCost = costOfTwoAABB + leftCost + rightCost; } if (thisCost < bestCost + .000000001) // if it is less within some tiny error { if (thisCost > bestCost - .000000001) { // they are the same within the error if (axis > 0 && bestAxis != axis) // we have changed axis since last best and we need to decide if this is better than the last axis best { if (totalDeviationOnAxis[axis] > totalDeviationOnAxis[axis - 1]) { // this new axis is better and we'll switch to it. Otherwise don't switch. bestCost = thisCost; bestIndexToSplitOn = itemIndex; bestAxis = axis; } } } else // this is just better { bestCost = thisCost; bestIndexToSplitOn = itemIndex; bestAxis = axis; } } } } } } if (bestAxis == -1) { // No better partition found return(new BvhTree <T>(itemsToAdd)); } else { axisSorter.WhichAxis = bestAxis; itemsToAdd.Sort(axisSorter); var leftItems = new List <BvhTreeItemData <T> >(bestIndexToSplitOn + 1); var rightItems = new List <BvhTreeItemData <T> >(numItems - bestIndexToSplitOn + 1); for (int i = 0; i <= bestIndexToSplitOn; i++) { leftItems.Add(itemsToAdd[i]); } for (int i = bestIndexToSplitOn + 1; i < numItems; i++) { rightItems.Add(itemsToAdd[i]); } var leftGroup = CreateNewHierachy(leftItems, maxRecursion, recursionDepth + 1, accelerator); var rightGroup = CreateNewHierachy(rightItems, maxRecursion, recursionDepth + 1, accelerator); var newBVHNode = new BvhTree <T>(leftGroup, rightGroup, bestAxis); return(newBVHNode); } }
public static void CenterMeshesXY(List<Mesh> meshesList, List<ScaleRotateTranslate> meshTransforms) { bool first = true; AxisAlignedBoundingBox totalBounds = new AxisAlignedBoundingBox(new Vector3(), new Vector3()); for(int index= 0; index<meshesList.Count; index++) { if(first) { totalBounds = meshesList[index].GetAxisAlignedBoundingBox(meshTransforms[index].TotalTransform); first = false; } else { AxisAlignedBoundingBox bounds = meshesList[index].GetAxisAlignedBoundingBox(meshTransforms[index].TotalTransform); totalBounds = AxisAlignedBoundingBox.Union(totalBounds, bounds); } } Vector3 boundsCenter = (totalBounds.maxXYZ + totalBounds.minXYZ) / 2; boundsCenter.z = 0; for (int index = 0; index < meshesList.Count; index++) { ScaleRotateTranslate moved = meshTransforms[index]; moved.translation *= Matrix4X4.CreateTranslation(-boundsCenter); meshTransforms[index] = moved; } }
public void FrustumIntersetAABBTests() { { Frustum frustum = new Frustum( new Plane(new Vector3(1, 0, 0), 20), new Plane(new Vector3(-1, 0, 0), 20), new Plane(new Vector3(0, 1, 0), 20), new Plane(new Vector3(0, -1, 0), 20), new Plane(new Vector3(0, 0, 1), 20), new Plane(new Vector3(0, 0, -1), 20)); // outside to left { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-30, -10, -10), new Vector3(-25, 10, 10)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Outside); } // intersect { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-25, 0, -10), new Vector3(-15, 10, 10)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Intersect); } // inside { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-5, -5, -5), new Vector3(5, 5, 5)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Inside); } } { Frustum frustum = new Frustum( new Plane(new Vector3(-1, -1, 0), 0), new Plane(new Vector3(1, -1, 0), 0), new Plane(new Vector3(0, -1, -1), 0), new Plane(new Vector3(0, -1, 1), 0), new Plane(new Vector3(0, -1, 0), 0), new Plane(new Vector3(0, 1, 0), 10000)); // outside to left { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-110, 0, -10), new Vector3(-100, 10, 10)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Outside); } // intersect with origin (front) { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-10, -10, -10), new Vector3(10, 10, 10)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Intersect); } // inside { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-5, 100, -5), new Vector3(5, 110, 5)); FrustumIntersection intersection = frustum.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Inside); } } { // looking down -z Frustum frustum5PlaneNegZ = new Frustum( new Vector3(-1, 0, 1), new Vector3(-1, 0, 1), new Vector3(0, 1, 1), new Vector3(0, -1, 1), new Vector3(0, 0, -1), 10000); // outside to left { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-110, 0, -10), new Vector3(-100, 10, 10)); FrustumIntersection intersection = frustum5PlaneNegZ.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Outside); } // intersect with origin (front) { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-10, -10, -10), new Vector3(10, 10, 10)); FrustumIntersection intersection = frustum5PlaneNegZ.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Intersect); } // inside { AxisAlignedBoundingBox aabb = new AxisAlignedBoundingBox(new Vector3(-5, -5, -110), new Vector3(5, 5, -100)); FrustumIntersection intersection = frustum5PlaneNegZ.GetIntersect(aabb); Assert.IsTrue(intersection == FrustumIntersection.Inside); } } }
private RectangleDouble GetScreenBounds(AxisAlignedBoundingBox meshBounds) { RectangleDouble screenBounds = RectangleDouble.ZeroIntersection; screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.minXYZ.x, meshBounds.minXYZ.y, meshBounds.minXYZ.z))); screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.maxXYZ.x, meshBounds.minXYZ.y, meshBounds.minXYZ.z))); screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.maxXYZ.x, meshBounds.maxXYZ.y, meshBounds.minXYZ.z))); screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.minXYZ.x, meshBounds.maxXYZ.y, meshBounds.minXYZ.z))); screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.minXYZ.x, meshBounds.minXYZ.y, meshBounds.maxXYZ.z))); screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.maxXYZ.x, meshBounds.minXYZ.y, meshBounds.maxXYZ.z))); screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.maxXYZ.x, meshBounds.maxXYZ.y, meshBounds.maxXYZ.z))); screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.minXYZ.x, meshBounds.maxXYZ.y, meshBounds.maxXYZ.z))); return screenBounds; }
private static bool CheckPosition(int meshGroupToMoveIndex, List<MeshGroup> allMeshGroups, List<ScaleRotateTranslate> meshTransforms, MeshGroup meshGroupToMove, AxisAlignedBoundingBox meshToMoveBounds, int yStep, int xStep, ref Matrix4X4 transform) { double xStepAmount = 5; double yStepAmount = 5; Matrix4X4 positionTransform = Matrix4X4.CreateTranslation(xStep * xStepAmount, yStep * yStepAmount, 0); Vector3 newPosition = Vector3.Transform(Vector3.Zero, positionTransform); transform = Matrix4X4.CreateTranslation(newPosition); AxisAlignedBoundingBox testBounds = meshToMoveBounds.NewTransformed(transform); bool foundHit = false; for (int i = 0; i < meshGroupToMoveIndex; i++) { MeshGroup meshToTest = allMeshGroups[i]; if (meshToTest != meshGroupToMove) { AxisAlignedBoundingBox existingMeshBounds = GetAxisAlignedBoundingBox(meshToTest, meshTransforms[i].TotalTransform); AxisAlignedBoundingBox intersection = AxisAlignedBoundingBox.Intersection(testBounds, existingMeshBounds); if (intersection.XSize > 0 && intersection.YSize > 0) { foundHit = true; break; } } } if (!foundHit) { return true; } return false; }