public OctreeNode(OctreeNodeType _type) { Type = _type; min = Vec3.Zero; size = 0; drawInfo = new OctreeDrawInfo(); children = new OctreeNode[8]; for (var i = 0; i < 8; i++) { children[i] = null; } }
static OctreeNode SimplifyOctree(OctreeNode node, double threshold) { if (node == null) { return(null); } if (node.Type != OctreeNodeType.Node_Internal) { // can't simplify! return(node); } var qef = new QefSolver(); var signs = new int[8] { -1, -1, -1, -1, -1, -1, -1, -1 }; var midsign = -1; var edgeCount = 0; var isCollapsible = true; for (var i = 0; i < 8; i++) { node.children[i] = SimplifyOctree(node.children[i], threshold); if (node.children[i] != null) { var child = node.children[i]; if (child.Type == OctreeNodeType.Node_Internal) { isCollapsible = false; } else { qef.add(child.drawInfo.qef); midsign = (child.drawInfo.corners >> (7 - i)) & 1; signs[i] = (child.drawInfo.corners >> i) & 1; edgeCount++; } } } if (!isCollapsible) { // at least one child is an internal node, can't collapse return(node); } Vec3 qefPosition; qef.solve(out qefPosition, QEF_ERROR, QEF_SWEEPS, QEF_ERROR); var error = qef.getError(); // convert to glm vec3 for ease of use var position = new Vec3(qefPosition.X, qefPosition.Y, qefPosition.Z); // at this point the masspoint will actually be a sum, so divide to make it the average if (error > threshold) { // this collapse breaches the threshold return(node); } if (position.X < node.min.X || position.X > (node.min.X + node.size) || position.Y < node.min.Y || position.Y > (node.min.Y + node.size) || position.Z < node.min.Z || position.Z > (node.min.Z + node.size)) { position = qef.getMassPoint(); } // change the node from an internal node to a 'psuedo leaf' node var drawInfo = new OctreeDrawInfo(); drawInfo.corners = 0; drawInfo.index = -1; for (var i = 0; i < 8; i++) { if (signs[i] == -1) { // Undetermined, use centre sign instead drawInfo.corners |= (midsign << i); } else { drawInfo.corners |= (signs[i] << i); } } drawInfo.averageNormal = Vec3.Zero; for (var i = 0; i < 8; i++) { if (node.children[i] != null) { var child = node.children[i]; if (child.Type == OctreeNodeType.Node_Psuedo || child.Type == OctreeNodeType.Node_Leaf) { drawInfo.averageNormal += child.drawInfo.averageNormal; } } } drawInfo.averageNormal = drawInfo.averageNormal.Normalized; drawInfo.position = position; drawInfo.qef = qef.getData(); for (var i = 0; i < 8; i++) { DestroyOctree(node.children[i]); node.children[i] = null; } node.Type = OctreeNodeType.Node_Psuedo; node.drawInfo = drawInfo; return(node); }