void BSPDeriveConvex(BSPNode & node, WingMesh cnvx) { if (cnvx.edges.size() && cnvx.verts.size()) { assert(cnvx.verts.size()); assert(cnvx.edges.size()); assert(cnvx.faces.size()); } node.convex = std::move(cnvx); if(node.isleaf) return; // if we are "editing" a bsp then the current plane may become coplanar to one of its parents (boundary of convex) or outside of the current volume (outside the convex) WingMesh cu; WingMesh co; if(node.convex.verts.size()) // non empty { int f = node.convex.SplitTest(node.plane()); if(f==SPLIT) { cu = WingMeshCrop(node.convex, node.plane()); co = WingMeshCrop(node.convex, -node.plane()); } else if(f==OVER) { co = node.convex; } else if(f==UNDER) { cu = node.convex; } else { assert(0); // hunh? the 3d convex has 0 volume } } // Under SubTree assert(node.under); BSPDeriveConvex(*node.under,cu); // Over SubTree assert(node.over); BSPDeriveConvex(*node.over ,co); }
float PlaneCost(const std::vector<Face> &inputfaces,const float4 &split,const WingMesh &space,int onbrep) { count[COPLANAR] = 0; count[UNDER] = 0; count[OVER] = 0; count[SPLIT] = 0; for(unsigned int i=0;i<inputfaces.size();i++) { count[FaceSplitTest(inputfaces[i],split,FUZZYWIDTH)]++; } if (space.verts.size() == 0) { // The following formula isn't that great. // Better to use volume as well eh. return (float)(abs(count[OVER]-count[UNDER]) + count[SPLIT] - count[COPLANAR]); } float volumeover =(float)1.0; float volumeunder=(float)1.0; float volumetotal=WingMeshVolume(space); WingMesh spaceunder= WingMeshCrop(space,float4( split.xyz(), split.w)); WingMesh spaceover = WingMeshCrop(space,float4(-split.xyz(),-split.w)); if(usevolcalc==1) { volumeunder = WingMeshVolume(spaceunder); volumeover = WingMeshVolume(spaceover ); } else if (usevolcalc==2) { volumeunder = sumbboxdim(spaceunder); volumeover = sumbboxdim(spaceover ); } assert(volumeover/volumetotal>=-0.01); assert(volumeunder/volumetotal>=-0.01); if(fabs((volumeover+volumeunder-volumetotal)/volumetotal)>0.01) { // ok our volume equations are starting to break down here // lets hope that we dont have too many polys to deal with at this point. volumetotal=volumeover+volumeunder; } if(solidbias && onbrep && count[OVER]==0 && count[SPLIT]==0) { return volumeunder; } return volumeover *powf(count[OVER] +1.5f*count[SPLIT],0.9f) + volumeunder*powf(count[UNDER]+1.5f*count[SPLIT],0.9f); }
void BSPPartition(std::unique_ptr<BSPNode> n, const float4 &p, std::unique_ptr<BSPNode> & nodeunder, std::unique_ptr<BSPNode> & nodeover) { nodeunder=NULL; nodeover =NULL; if(!n) { return; } // assert(n->cell); int flag; //flag = SplitTest(n->cell,p); //assert(flag==SplitTest(*n->convex,p)); flag = n->convex.SplitTest(p); if(flag == UNDER) { nodeunder = move(n); return; } if(flag==OVER) { nodeover = move(n); return; } assert(flag==SPLIT); // Polyhedron *cellover = PolyhedronDup(n->cell); // Polyhedron *cellunder = PolyhedronDup(n->cell); // cellunder->Crop(p); // cellover->Crop(Plane(-p.normal,-p.dist)); nodeunder.reset(new BSPNode(n->xyz(), n->w)); nodeover.reset(new BSPNode(n->xyz(),n->w)); nodeunder->isleaf = n->isleaf; nodeover->isleaf = n->isleaf; // nodeunder->cell= cellunder; // nodeover->cell = cellover; nodeunder->convex = WingMeshCrop(n->convex,p); nodeover->convex = WingMeshCrop(n->convex, float4(-p.xyz(), -p.w)); if(n->isleaf==UNDER) { int i; BSPNode fake(p.xyz(), p.w); fake.under=move(nodeunder); fake.over=move(nodeover); i=n->brep.size(); while(i--){ FaceEmbed(&fake, std::move(n->brep[i])); } n->brep.clear(); nodeunder = move(fake.under); nodeover = move(fake.over); } BSPPartition(move(n->under), p, nodeunder->under, nodeover->under); BSPPartition(move(n->over), p, nodeunder->over, nodeover->over ); if(n->isleaf) { assert(nodeunder->isleaf); assert(nodeover->isleaf); return; } assert(nodeunder->over || nodeunder->under); assert(nodeover->over || nodeover->under); n.reset(); if(!nodeunder->under) { // assert(SplitTest(nodeunder->cell,*nodeunder)==OVER); nodeunder = move(nodeunder->over); } else if(!nodeunder->over) { // assert(SplitTest(nodeunder->cell,*nodeunder)==UNDER); nodeunder = move(nodeunder->under); } assert(nodeunder); assert(nodeunder->isleaf || (nodeunder->under && nodeunder->over)); if(!nodeover->under) { // assert(SplitTest(nodeover->cell,*nodeover)==OVER); nodeover = move(nodeover->over); } else if(!nodeover->over) { // assert(SplitTest(nodeover->cell,*nodeover)==UNDER); nodeover = move(nodeover->under); } assert(nodeover); assert(nodeover->isleaf || (nodeover->under && nodeover->over)); if(!nodeunder->isleaf && nodeunder->over->isleaf && nodeunder->over->isleaf==nodeunder->under->isleaf) { nodeunder->isleaf = nodeunder->over->isleaf; // pick one of the children int i; i=nodeunder->under->brep.size(); while(i--){ nodeunder->brep.push_back(nodeunder->under->brep[i]); } nodeunder->under->brep.clear(); i=nodeunder->over->brep.size(); while(i--){ nodeunder->brep.push_back(nodeunder->over->brep[i]); } nodeunder->over->brep.clear(); nodeunder->under.reset(); nodeunder->over.reset(); } // wtf: if(!nodeover->isleaf && nodeover->over->isleaf==nodeover->under->isleaf) { if(!nodeover->isleaf && nodeover->over->isleaf && nodeover->over->isleaf==nodeover->under->isleaf) { nodeover->isleaf = nodeover->over->isleaf; // pick one of the children int i; i=nodeover->under->brep.size(); while(i--){ nodeover->brep.push_back(nodeover->under->brep[i]); } nodeover->under->brep.clear(); i=nodeover->over->brep.size(); while(i--){ nodeover->brep.push_back(nodeover->over->brep[i]); } nodeover->over->brep.clear(); nodeover->under.reset(); nodeover->over.reset(); } /* if(fusenodes) { if(0==nodeunder->isleaf) { if(nodeunder->over->isleaf==UNDER) { DeriveCells(nodeunder->under,nodeunder->cell); nodeunder = nodeunder->under; // memleak } else if(nodeunder->under->isleaf==OVER) { DeriveCells(nodeunder->over,nodeunder->cell); nodeunder = nodeunder->over; // memleak } } assert(nodeunder); if(0==nodeover->isleaf) { if(nodeover->over->isleaf==UNDER) { DeriveCells(nodeover->under,nodeover->cell); nodeover = nodeover->under; // memleak } else if(nodeover->under->isleaf==OVER) { DeriveCells(nodeover->over,nodeover->cell); nodeover = nodeover->over; // memleak } } assert(nodeover); } */ }
std::unique_ptr<BSPNode> BSPCompile(std::vector<Face> && inputfaces,WingMesh space,int side) { if (inputfaces.size() == 0) { std::unique_ptr<BSPNode> node(new BSPNode); node->convex = space; node->isleaf=side; return node; } std::vector<Face> over; std::vector<Face> under; std::vector<Face> coplanar; ReorderFaceArray(inputfaces); // select partitioning plane float minval=FLT_MAX; float4 split(float3(0,0,0),0); // if (inputfaces.size()>1 && inputfaces.size() <= allowhull) // { // int j; // std::vector<float3> verts; // for(i=0;i<inputfaces.size();i++) // for(j=0;j<inputfaces[i]->vertex.size();j++) // AddUnique(verts, inputfaces[i]->vertex[j]); // // // std::vector<int3> tris=calchull(verts.data(), verts.size(), 50); // passing in array members might not be the best thing here!! // // for(i=0;i<tris.size();i++) // { // float4 p(TriNormal(verts[tris[i][0]],verts[tris[i][1]],verts[tris[i][2]]),0); // if(p.xyz()==float3(0,0,0))continue; // p.w = -dot(verts[tris[i][0]],p.xyz()); // float3 c = (verts[tris[i][0]]+verts[tris[i][1]]+verts[tris[i][2]]) /3.0f + p.xyz() * 0.001f; // if(solidbias && !currentbsp) continue; // if(solidbias && HitCheck(currentbsp,1,c,c,&c)) continue; // if(WingMeshSplitTest(space,p)!= SPLIT) continue; // float val = PlaneCost(inputfaces,p,space,1)*1.01f; // if(val<minval) // { // minval=val; // split = p; // } // } // } if(!solidbias || split.xyz()==float3(0,0,0)) { for (unsigned int i = 0; i<inputfaces.size() && (int)i<facetestlimit; i++) { float val=PlaneCost(inputfaces, inputfaces[i].plane(), space, 1); if(val<minval) { minval=val; split = inputfaces[i].plane(); } } assert(split.xyz() != float3(0,0,0)); PlaneCost(inputfaces,split,space,1); if (allowaxial && inputfaces.size() > 8) { // consider some other planes: for (unsigned int i = 0; i<inputfaces.size() && (int)i<facetestlimit; i++) { for(unsigned int j=0;j<inputfaces[i].vertex.size();j++ ) { float val; if(allowaxial & (1<<0)) { val = PlaneCost(inputfaces,float4(float3(1,0,0),-inputfaces[i].vertex[j].x),space,0); if(val<minval && (count[OVER]*count[UNDER]>0 || count[SPLIT]>0)) { minval=val; split.xyz() = float3(1, 0, 0); split.w = -inputfaces[i].vertex[j].x; } } if(allowaxial & (1<<1)) { val = PlaneCost(inputfaces,float4(float3(0,1,0),-inputfaces[i].vertex[j].y),space,0); if(val<minval && (count[OVER]*count[UNDER]>0 || count[SPLIT]>0)) { minval=val; split.xyz() = float3(0, 1, 0); split.w = -inputfaces[i].vertex[j].y; } } if(allowaxial & (1<<2)) { val = PlaneCost(inputfaces,float4(float3(0,0,1),-inputfaces[i].vertex[j].z),space,0); if(val<minval && (count[OVER]*count[UNDER]>0 || count[SPLIT]>0)) { minval=val; split.xyz() = float3(0, 0, 1); split.w = -inputfaces[i].vertex[j].z; } } } } } } // Divide the faces std::unique_ptr<BSPNode> node(new BSPNode); node->plane() = split; node->convex = space; DividePolys(float4(split.xyz(), split.w), std::move(inputfaces), under, over, coplanar); for(unsigned int i=0;i<over.size();i++) { for(unsigned int j=0;j<over[i].vertex.size();j++) { assert(dot(node->xyz(),over[i].vertex[j])+node->w >= -FUZZYWIDTH); } } for(unsigned int i=0;i<under.size();i++) { for(unsigned int j=0;j<under[i].vertex.size();j++) { assert(dot(node->xyz(),under[i].vertex[j])+node->w <= FUZZYWIDTH); } } node->under = BSPCompile(std::move(under), WingMeshCrop(space, split), UNDER); node->over = BSPCompile(std::move(over), WingMeshCrop(space, -split), OVER); return node; }