// This partition algorithm is inspired by QuickSort; sorting on the // split axis of the node in question. private void PartitionSmallerTriangles(CollisionContent cc, int[] tris, int lo, ref int mid, int hi, BoundingSphere[] tbs, Vector3 d, float r) { int ilo = lo; int ihi = hi; while (lo < hi && lo < ihi && hi > ilo) { // if "lo" and "hi - 1" alias, then one of the first ifs will succeed, and // I'll increment/decrement and break out of the loop! if (Vector3.Dot(tbs[tris[lo]].Center, d) < r) { ++lo; } else if (!(Vector3.Dot(tbs[tris[hi - 1]].Center, d) < r)) { --hi; } else { // I know that "lo" points at a larger tri, and "hi-1" points at a lower tri; so swap them int j = tris[lo]; tris[lo] = tris[hi - 1]; tris[hi - 1] = j; // because of the failure of both of the first two tests, I know that // lo must be lower than hi-1. Debug.Assert(lo < hi - 1); ++lo; --hi; } } // "lo" points at the first "high" value; "hi" points at the last "lo" value Debug.Assert(lo == hi); Debug.Assert(lo == ihi || !(Vector3.Dot(tbs[tris[lo]].Center, d) < r)); mid = lo; }
public override TOutput Process(TInput input, ContentProcessorContext context) { this.context = context; CollisionContent cc = ProcessCollision(input); ModelContent mc = base.Process(input, context); ((Dictionary <string, object>)mc.Tag).Add("Collision", cc); return(mc); }
void GatherLargeTriangles(ref TreeNode tn, CollisionContent cc, int[] tris, ref int lo, int hi, float r, BoundingSphere[] tbs) { for (int i = lo; i < hi; ++i) { if (tbs[tris[i]].Radius >= r) { int j = tris[i]; tris[i] = tris[lo]; tris[lo] = j; ++lo; } } }
public virtual CollisionContent MakeCollisionContent(Gather g) { // todo: I really should find the major modes, and align the AABB to // those by rotating. Then counter-rotate when collision testing. // Oh, well. CollisionContent cc = new CollisionContent(); cc.Bounds = g.Bounds; Vector3 hd = cc.Bounds.HalfDim; Vector3 hc = cc.Bounds.Center; hd.X = Math.Max(hd.X, Math.Max(hd.Y, hd.Z)); hd.Y = hd.X; hd.Z = hd.X; cc.Bounds.Lo = hc - hd; cc.Bounds.Hi = hc + hd; cc.Triangles = g.Triangles.ToArray(); cc.Vertices = g.Vertices.ToArray(); List <TreeNode> TreeNodes = new List <TreeNode>(); int[] ixs = new int[cc.Triangles.Length]; for (int i = 0; i < ixs.Length; ++i) { ixs[i] = i; } BuildNodes(cc, ixs, 0, ixs.Length, TreeNodes, cc.Bounds, g.BoundingSpheres.ToArray()); cc.Nodes = TreeNodes.ToArray(); for (int i = 0; i < ixs.Length; ++i) { cc.Triangles[i] = g.Triangles[ixs[i]]; cc.Triangles[i].CalcColl(cc); } context.Logger.LogImportantMessage("Built CollisionContent with {0} triangles, {1} vertices, {2} cells", cc.Triangles.Length, cc.Vertices.Length, cc.Nodes.Length); return(cc); }
void BuildNodes(CollisionContent cc, int[] tris, int lo, int hi, List <TreeNode> nodes, AABB bounds, BoundingSphere[] tbs) { TreeNode tn = new TreeNode(); tn.TriStart = lo; tn.Expansion = (bounds.Hi - bounds.Lo).Length() * ExpansionFactor; GatherLargeTriangles(ref tn, cc, tris, ref lo, hi, tn.Expansion, tbs); tn.TriEnd = lo; int ix = nodes.Count; nodes.Add(tn); Vector3 lb = bounds.Lo; Vector3 ub = bounds.Hi; Vector3 cb = lb + (ub - lb) * 0.5f; if (hi > lo + 4) { int midX = lo; PartitionSmallerTriangles(cc, tris, lo, ref midX, hi, tbs, Vector3.Right, cb.X); int midXlo = lo; PartitionSmallerTriangles(cc, tris, lo, ref midXlo, midX, tbs, Vector3.Up, cb.Y); int midXhi = midX; PartitionSmallerTriangles(cc, tris, midX, ref midXhi, hi, tbs, Vector3.Up, cb.Y); int midXloYlo = lo; PartitionSmallerTriangles(cc, tris, lo, ref midXloYlo, midXlo, tbs, Vector3.Backward, cb.Z); int midXloYhi = midXlo; PartitionSmallerTriangles(cc, tris, midXlo, ref midXloYhi, midX, tbs, Vector3.Backward, cb.Z); int midXhiYlo = midX; PartitionSmallerTriangles(cc, tris, midX, ref midXhiYlo, midXhi, tbs, Vector3.Backward, cb.Z); int midXhiYhi = midXhi; PartitionSmallerTriangles(cc, tris, midXhi, ref midXhiYhi, hi, tbs, Vector3.Backward, cb.Z); if (lo < midXloYlo) { tn.Child000 = nodes.Count; BuildNodes(cc, tris, lo, midXloYlo, nodes, new AABB(lb, cb), tbs); } if (midXloYlo < midXlo) { tn.Child001 = nodes.Count; BuildNodes(cc, tris, midXloYlo, midXlo, nodes, new AABB(new Vector3(lb.X, lb.Y, cb.Z), new Vector3(cb.X, cb.Y, ub.Z)), tbs); } if (midXlo < midXloYhi) { tn.Child010 = nodes.Count; BuildNodes(cc, tris, midXlo, midXloYhi, nodes, new AABB(new Vector3(lb.X, cb.Y, lb.Z), new Vector3(cb.X, ub.Y, cb.Z)), tbs); } if (midXloYhi < midX) { tn.Child011 = nodes.Count; BuildNodes(cc, tris, midXloYhi, midX, nodes, new AABB(new Vector3(lb.X, cb.Y, cb.Z), new Vector3(cb.X, ub.Y, ub.Z)), tbs); } if (midX < midXhiYlo) { tn.Child100 = nodes.Count; BuildNodes(cc, tris, midX, midXhiYlo, nodes, new AABB(new Vector3(cb.X, lb.Y, lb.Z), new Vector3(ub.X, cb.Y, cb.Z)), tbs); } if (midXhiYlo < midXhi) { tn.Child101 = nodes.Count; BuildNodes(cc, tris, midXhiYlo, midXhi, nodes, new AABB(new Vector3(cb.X, lb.Y, cb.Z), new Vector3(ub.X, cb.Y, ub.Z)), tbs); } if (midXhi < midXhiYhi) { tn.Child110 = nodes.Count; BuildNodes(cc, tris, midXhi, midXhiYhi, nodes, new AABB(new Vector3(cb.X, cb.Y, lb.Z), new Vector3(ub.X, ub.Y, cb.Z)), tbs); } if (midXhiYhi < hi) { tn.Child111 = nodes.Count; BuildNodes(cc, tris, midXhiYhi, hi, nodes, new AABB(new Vector3(cb.X, cb.Y, cb.Z), new Vector3(ub.X, ub.Y, ub.Z)), tbs); } } else { // include them all! tn.TriEnd = hi; } nodes[ix] = tn; }