public BoundingBox getWorldBounds(Matrix4 o2w) { BoundingBox bounds = new BoundingBox(); for (int i = 0, i3 = 0; i < n; i++, i3 += 3) bounds.include(particles[i3], particles[i3 + 1], particles[i3 + 2]); bounds.include(bounds.getMinimum().x - r, bounds.getMinimum().y - r, bounds.getMinimum().z - r); bounds.include(bounds.getMaximum().x + r, bounds.getMaximum().y + r, bounds.getMaximum().z + r); return o2w == null ? bounds : o2w.transform(bounds); }
/** * Transforms each corner of the specified axis-aligned bounding box and * returns a new bounding box which incloses the transformed corners. * * @param b original bounding box * @return a new BoundingBox object which encloses the transform version of * b */ public BoundingBox transform(BoundingBox b) { if (b.isEmpty()) { return(new BoundingBox()); } // special case extreme corners BoundingBox rb = new BoundingBox(transformP(b.getMinimum())); rb.include(transformP(b.getMaximum())); // do internal corners for (int i = 1; i < 7; i++) { rb.include(transformP(b.getCorner(i))); } return(rb); }
public bool update(ParameterList pl, SunflowAPI api) { ParameterList.FloatParameter pts = pl.getPointArray("points"); if (pts != null) { BoundingBox bounds = new BoundingBox(); for (int i = 0; i < pts.data.Length; i += 3) bounds.include(pts.data[i], pts.data[i + 1], pts.data[i + 2]); // cube extents minX = bounds.getMinimum().x; minY = bounds.getMinimum().y; minZ = bounds.getMinimum().z; maxX = bounds.getMaximum().x; maxY = bounds.getMaximum().y; maxZ = bounds.getMaximum().z; } return true; }
private int dumpObj(int offset, int vertOffset, int maxN, BoundingBox bounds, StreamWriter file, StreamWriter mtlFile) { if (offset == 0) file.WriteLine(string.Format("mtllib {0}.mtl", dumpPrefix)); int nextOffset = tree[offset]; if ((nextOffset & (3 << 30)) == (3 << 30)) { // leaf int n = tree[offset + 1]; if (n > 0) { // output the current voxel to the file Point3 min = bounds.getMinimum(); Point3 max = bounds.getMaximum(); file.WriteLine(string.Format("o node{0}", offset)); file.WriteLine(string.Format("v {0} {1} {2}", max.x, max.y, min.z)); file.WriteLine(string.Format("v {0} {1} {2}", max.x, min.y, min.z)); file.WriteLine(string.Format("v {0} {1} {2}", min.x, min.y, min.z)); file.WriteLine(string.Format("v {0} {1} {2}", min.x, max.y, min.z)); file.WriteLine(string.Format("v {0} {1} {2}", max.x, max.y, max.z)); file.WriteLine(string.Format("v {0} {1} {2}", max.x, min.y, max.z)); file.WriteLine(string.Format("v {0} {1} {2}", min.x, min.y, max.z)); file.WriteLine(string.Format("v {0} {1} {2}", min.x, max.y, max.z)); int v0 = vertOffset; file.WriteLine(string.Format("usemtl mtl{0}", n)); file.WriteLine("s off"); file.WriteLine(string.Format("f {0} {1} {2} {3}", v0 + 1, v0 + 2, v0 + 3, v0 + 4)); file.WriteLine(string.Format("f {0} {1} {2} {3}", v0 + 5, v0 + 8, v0 + 7, v0 + 6)); file.WriteLine(string.Format("f {0} {1} {2} {3}", v0 + 1, v0 + 5, v0 + 6, v0 + 2)); file.WriteLine(string.Format("f {0} {1} {2} {3}", v0 + 2, v0 + 6, v0 + 7, v0 + 3)); file.WriteLine(string.Format("f {0} {1} {2} {3}", v0 + 3, v0 + 7, v0 + 8, v0 + 4)); file.WriteLine(string.Format("f {0} {1} {2} {3}", v0 + 5, v0 + 1, v0 + 4, v0 + 8)); vertOffset += 8; } return vertOffset; } else { // node, recurse int axis = nextOffset & (3 << 30), v0; float split = ByteUtil.intBitsToFloat(tree[offset + 1]), min, max; nextOffset &= ~(3 << 30); switch (axis) { case 0: max = bounds.getMaximum().x; bounds.getMaximum().x = split; v0 = dumpObj(nextOffset, vertOffset, maxN, bounds, file, mtlFile); // restore and go to other side bounds.getMaximum().x = max; min = bounds.getMinimum().x; bounds.getMinimum().x = split; v0 = dumpObj(nextOffset + 2, v0, maxN, bounds, file, mtlFile); bounds.getMinimum().x = min; break; case 1 << 30: max = bounds.getMaximum().y; bounds.getMaximum().y = split; v0 = dumpObj(nextOffset, vertOffset, maxN, bounds, file, mtlFile); // restore and go to other side bounds.getMaximum().y = max; min = bounds.getMinimum().y; bounds.getMinimum().y = split; v0 = dumpObj(nextOffset + 2, v0, maxN, bounds, file, mtlFile); bounds.getMinimum().y = min; break; case 2 << 30: max = bounds.getMaximum().z; bounds.getMaximum().z = split; v0 = dumpObj(nextOffset, vertOffset, maxN, bounds, file, mtlFile); // restore and go to other side bounds.getMaximum().z = max; min = bounds.getMinimum().z; bounds.getMinimum().z = split; v0 = dumpObj(nextOffset + 2, v0, maxN, bounds, file, mtlFile); // restore and go to other side bounds.getMinimum().z = min; break; default: v0 = vertOffset; break; } return v0; } }
public void build(PrimitiveList primitives) { UI.printDetailed(UI.Module.ACCEL, "KDTree settings"); UI.printDetailed(UI.Module.ACCEL, " * Max Leaf Size: {0}", maxPrims); UI.printDetailed(UI.Module.ACCEL, " * Max Depth: {0}", MAX_DEPTH); UI.printDetailed(UI.Module.ACCEL, " * Traversal cost: {0}", TRAVERSAL_COST); UI.printDetailed(UI.Module.ACCEL, " * Intersect cost: {0}", INTERSECT_COST); UI.printDetailed(UI.Module.ACCEL, " * Empty bonus: {0}", EMPTY_BONUS); UI.printDetailed(UI.Module.ACCEL, " * Dump leaves: {0}", dump ? "enabled" : "disabled"); Timer total = new Timer(); total.start(); primitiveList = primitives; // get the object space bounds bounds = primitives.getWorldBounds(null); int nPrim = primitiveList.getNumPrimitives(), nSplits = 0; BuildTask task = new BuildTask(nPrim); Timer prepare = new Timer(); prepare.start(); for (int i = 0; i < nPrim; i++) { for (int axis = 0; axis < 3; axis++) { float ls = primitiveList.getPrimitiveBound(i, 2 * axis + 0); float rs = primitiveList.getPrimitiveBound(i, 2 * axis + 1); if (ls == rs) { // flat in this dimension task.splits[nSplits] = pack(ls, PLANAR, axis, i); nSplits++; } else { task.splits[nSplits + 0] = pack(ls, OPENED, axis, i); task.splits[nSplits + 1] = pack(rs, CLOSED, axis, i); nSplits += 2; } } } task.n = nSplits; prepare.end(); Timer t = new Timer(); List<int> tempTree = new List<int>(); List<int> tempList = new List<int>(); tempTree.Add(0); tempTree.Add(1); t.start(); // sort it Timer sorting = new Timer(); sorting.start(); radix12(task.splits, task.n); sorting.end(); // build the actual tree BuildStats stats = new BuildStats(); buildTree(bounds.getMinimum().x, bounds.getMaximum().x, bounds.getMinimum().y, bounds.getMaximum().y, bounds.getMinimum().z, bounds.getMaximum().z, task, 1, tempTree, 0, tempList, stats); t.end(); // write out arrays // free some memory task = null; tree = tempTree.ToArray(); tempTree = null; this.primitives = tempList.ToArray(); tempList = null; total.end(); // display some extra info stats.printStats(); UI.printDetailed(UI.Module.ACCEL, " * Node memory: {0}", Memory.SizeOf(tree)); UI.printDetailed(UI.Module.ACCEL, " * Object memory: {0}", Memory.SizeOf(this.primitives)); UI.printDetailed(UI.Module.ACCEL, " * Prepare time: {0}", prepare); UI.printDetailed(UI.Module.ACCEL, " * Sorting time: {0}", sorting); UI.printDetailed(UI.Module.ACCEL, " * Tree creation: {0}", t); UI.printDetailed(UI.Module.ACCEL, " * Build time: {0}", total); if (dump) { try { UI.printInfo(UI.Module.ACCEL, "Dumping mtls to {0}.mtl ...", dumpPrefix); StreamWriter mtlFile = new StreamWriter(dumpPrefix + ".mtl"); int maxN = stats.maxObjects; for (int n = 0; n <= maxN; n++) { float blend = (float)n / (float)maxN; Color nc; if (blend < 0.25) nc = Color.blend(Color.BLUE, Color.GREEN, blend / 0.25f); else if (blend < 0.5) nc = Color.blend(Color.GREEN, Color.YELLOW, (blend - 0.25f) / 0.25f); else if (blend < 0.75) nc = Color.blend(Color.YELLOW, Color.RED, (blend - 0.50f) / 0.25f); else nc = Color.MAGENTA; mtlFile.WriteLine(string.Format("newmtl mtl{0}", n)); float[] rgb = nc.getRGB(); mtlFile.WriteLine("Ka 0.1 0.1 0.1"); mtlFile.WriteLine(string.Format("Kd {0}g {1}g {2}g", rgb[0], rgb[1], rgb[2])); mtlFile.WriteLine("illum 1\n"); } StreamWriter objFile = new StreamWriter(dumpPrefix + ".obj"); UI.printInfo(UI.Module.ACCEL, "Dumping tree to {0}.obj ...", dumpPrefix); dumpObj(0, 0, maxN, new BoundingBox(bounds), objFile, mtlFile); objFile.Close(); mtlFile.Close(); } catch (Exception e) { Console.WriteLine(e); } } }
private void updateGeometry(Point3 c0, Point3 c1) { // figure out cube extents lightBounds = new BoundingBox(c0); lightBounds.include(c1); // cube extents minX = lightBounds.getMinimum().x; minY = lightBounds.getMinimum().y; minZ = lightBounds.getMinimum().z; maxX = lightBounds.getMaximum().x; maxY = lightBounds.getMaximum().y; maxZ = lightBounds.getMaximum().z; // work around epsilon problems for light test lightBounds.enlargeUlps(); // light source geometry lxmin = maxX / 3 + 2 * minX / 3; lxmax = minX / 3 + 2 * maxX / 3; lymin = maxY / 3 + 2 * minY / 3; lymax = minY / 3 + 2 * maxY / 3; area = (lxmax - lxmin) * (lymax - lymin); }
public bool intersects(BoundingBox box) { // this could be optimized BoundingBox b = new BoundingBox(); b.include(new Point3(minX, minY, minZ)); b.include(new Point3(maxX, maxY, maxZ)); if (b.intersects(box)) { // the box is overlapping or enclosed if (!b.contains(new Point3(box.getMinimum().x, box.getMinimum().y, box.getMinimum().z))) return true; if (!b.contains(new Point3(box.getMinimum().x, box.getMinimum().y, box.getMaximum().z))) return true; if (!b.contains(new Point3(box.getMinimum().x, box.getMaximum().y, box.getMinimum().z))) return true; if (!b.contains(new Point3(box.getMinimum().x, box.getMaximum().y, box.getMaximum().z))) return true; if (!b.contains(new Point3(box.getMaximum().x, box.getMinimum().y, box.getMinimum().z))) return true; if (!b.contains(new Point3(box.getMaximum().x, box.getMinimum().y, box.getMaximum().z))) return true; if (!b.contains(new Point3(box.getMaximum().x, box.getMaximum().y, box.getMinimum().z))) return true; if (!b.contains(new Point3(box.getMaximum().x, box.getMaximum().y, box.getMaximum().z))) return true; // all vertices of the box are inside - the surface of the box is // not intersected } return false; }
/** * Transforms each corner of the specified axis-aligned bounding box and * returns a new bounding box which incloses the transformed corners. * * @param b original bounding box * @return a new BoundingBox object which encloses the transform version of * b */ public BoundingBox transform(BoundingBox b) { if (b.isEmpty()) return new BoundingBox(); // special case extreme corners BoundingBox rb = new BoundingBox(transformP(b.getMinimum())); rb.include(transformP(b.getMaximum())); // do internal corners for (int i = 1; i < 7; i++) rb.include(transformP(b.getCorner(i))); return rb; }