void ModelContainer::fillContainer(const AABSPTree<SubModel *>::Node& pNode, int &pSubModelPos, int &pTreeNodePos, int &pTrianglePos, Vector3& pLo, Vector3& pHi, Vector3& pFinalLo, Vector3& pFinalHi) { // TreeNode for the SubModel TreeNode treeNode = TreeNode(pNode.valueArray.size(), pSubModelPos); treeNode.setSplitAxis(pNode.splitAxis); treeNode.setSplitLocation(pNode.splitLocation); int currentTreeNodePos = pTreeNodePos++; Vector3 lo = Vector3(inf(),inf(),inf()); Vector3 hi = Vector3(-inf(),-inf(),-inf()); for (int i=0; i<pNode.valueArray.size(); i++) { G3D::_AABSPTree::Handle<SubModel*>* h= pNode.valueArray[i]; SubModel *m = h->value; memcpy(&getTreeNodes()[pTreeNodePos], &m->getTreeNode(0), sizeof(TreeNode) * m->getNNodes()); memcpy(&getTriangles()[pTrianglePos], &m->getTriangle(0), sizeof(TriangleBox) * m->getNTriangles()); SubModel newModel = SubModel(m->getNTriangles(), getTriangles(), pTrianglePos, m->getNNodes(), getTreeNodes(), pTreeNodePos); newModel.setReletiveBounds(m->getReletiveBounds().getLo(), m->getReletiveBounds().getHi()); newModel.setBasePosition(m->getBasePosition()); iSubModel[pSubModelPos++] = newModel; pTreeNodePos += m->getNNodes(); pTrianglePos += m->getNTriangles(); AABox box = m->getAABoxBounds(); lo = lo.min(box.low()); hi = hi.max(box.high()); pFinalLo = pFinalLo.min(lo); pFinalHi = pFinalHi.max(hi); } /* if(pNode.valueArray.size() == 0) { int xxx = 0; // just for the breakpoint } */ // get absolute bounds if(pNode.child[0] != 0) { treeNode.setChildPos(0, pTreeNodePos); fillContainer(*pNode.child[0], pSubModelPos, pTreeNodePos, pTrianglePos, lo, hi,pFinalLo,pFinalHi); } if(pNode.child[1] != 0) { treeNode.setChildPos(1, pTreeNodePos); fillContainer(*pNode.child[1], pSubModelPos, pTreeNodePos, pTrianglePos, lo, hi,pFinalLo,pFinalHi); } pLo = pLo.min(lo); pHi = pHi.max(hi); treeNode.setBounds(lo,hi); setTreeNode(treeNode, currentTreeNodePos); }
Box::Box( const Vector3& min, const Vector3& max) { init(min.min(max), min.max(max)); }
const Vector3 Vector3::clamp(const Vector3& min, const Vector3& max) const { Vector3 vector = *this; vector.min(max); vector.max(min); return vector; }
void fillSubModelArary(const ModelContainer* pModelContainer, const TreeNode *root, Array<SubModel>& array, Vector3& pLo, Vector3& pHi) { Vector3 lo = Vector3(inf(), inf(), inf()); Vector3 hi = Vector3(-inf(), -inf(), -inf()); for(int i=0; i< root->getNValues(); i++) { SubModel sm = pModelContainer->getSubModel(root->getStartPosition() + i); lo = lo.min(sm.getAABoxBounds().low()); hi = hi.max(sm.getAABoxBounds().high()); array.append(sm); } if(root->getChild((TreeNode *) &pModelContainer->getTreeNode(0), 0)) { fillSubModelArary(pModelContainer, root->getChild((TreeNode *)&pModelContainer->getTreeNode(0), 0), array, lo, hi); } if(root->getChild((TreeNode *)&pModelContainer->getTreeNode(0), 1)) { fillSubModelArary(pModelContainer, root->getChild((TreeNode *)&pModelContainer->getTreeNode(0), 1), array, lo, hi); } float dist1 = (hi -lo).magnitude(); AABox b; root->getBounds(b); float dist2 = (b.high() -b.low()).magnitude(); if(dist1 > dist2) { // error int xxx = 0; } }
Welder::Welder( const Array<Vector3>& _oldVertexArray, Array<Vector3>& _newVertexArray, Array<int>& _toNew, Array<int>& _toOld, double _radius) : oldVertexArray(_oldVertexArray), newVertexArray(_newVertexArray), toNew(_toNew), toOld(_toOld), radius(_radius) { // Compute a scale factor that moves the range // of all ordinates to [0, 1] Vector3 minBound = Vector3::inf(); Vector3 maxBound = -minBound; for (int i = 0; i < oldVertexArray.size(); ++i) { minBound = minBound.min(oldVertexArray[i]); maxBound = maxBound.max(oldVertexArray[i]); } offset = minBound; scale = maxBound - minBound; for (int i = 0; i < 3; ++i) { // The model might have zero extent along some axis if (fuzzyEq(scale[i], 0.0)) { scale[i] = 1.0; } else { scale[i] = 1.0 / scale[i]; } } }
void fillSubModelArary (const ModelContainer* pModelContainer, const TreeNode *root, Array<SubModel>& array, Vector3& pLo, Vector3& pHi) { Vector3 lo = Vector3 (inf (), inf (), inf ()); Vector3 hi = Vector3 (-inf (), -inf (), -inf ()); //printf("[VMAP] %i Submodels\n", root->getNValues ()); for (int i = 0; i < root->getNValues (); i++) { SubModel sm = pModelContainer->getSubModel (root->getStartPosition () + i); lo = lo.min (sm.getAABoxBounds ().low ()); hi = hi.max (sm.getAABoxBounds ().high ()); array.append (sm); } if (root->getChild ((TreeNode *) & pModelContainer->getTreeNode (0), 0)) { fillSubModelArary (pModelContainer, root->getChild ((TreeNode *) & pModelContainer->getTreeNode (0), 0), array, lo, hi); } if (root->getChild ((TreeNode *) & pModelContainer->getTreeNode (0), 1)) { fillSubModelArary (pModelContainer, root->getChild ((TreeNode *) & pModelContainer->getTreeNode (0), 1), array, lo, hi); } float dist1 = (hi - lo).magnitude (); AABox b; root->getBounds (b); float dist2 = (b.high () - b.low ()).magnitude (); if (dist1 > dist2) { // error //printf("error in boundingbox size vs. hi-lo size."); // this error seems to happen alot! maybe need to do something against it? int xxx = 0; } }
void MeshBuilder::computeBounds(Vector3& min, Vector3& max) { min = Vector3::inf(); max = -min; int v; for (v = 0; v < triList.size(); ++v) { min = min.min(triList[v]); max = max.max(triList[v]); } }
void Triangle::getBounds(AABox& out) const { Vector3 lo = _vertex[0]; Vector3 hi = lo; for (int i = 1; i < 3; ++i) { lo = lo.min(_vertex[i]); hi = hi.max(_vertex[i]); } out = AABox(lo, hi); }
void SubModel::fillContainer(const AABSPTree<Triangle>::Node& pNode, int &pTreeNodePos, int &pTrianglePos, Vector3& pLo, Vector3& pHi) { TreeNode treeNode = TreeNode(pNode.valueArray.size(), pTrianglePos); treeNode.setSplitAxis(pNode.splitAxis); treeNode.setSplitLocation(pNode.splitLocation); int currentTreeNodePos = pTreeNodePos++; Vector3 lo = Vector3(inf(),inf(),inf()); Vector3 hi = Vector3(-inf(),-inf(),-inf()); for(int i=0;i<pNode.valueArray.size(); i++) { G3D::_AABSPTree::Handle<Triangle>* h= pNode.valueArray[i]; Triangle t = h->value; TriangleBox triangleBox = TriangleBox(t.vertex(0),t.vertex(1), t.vertex(2)); lo = lo.min(triangleBox.getBounds().getLo().getVector3()); hi = hi.max(triangleBox.getBounds().getHi().getVector3()); getTriangles()[pTrianglePos++] = triangleBox; } if(pNode.child[0] != 0) { treeNode.setChildPos(0, pTreeNodePos); fillContainer(*pNode.child[0], pTreeNodePos, pTrianglePos, lo, hi); } if(pNode.child[1] != 0) { treeNode.setChildPos(1, pTreeNodePos); fillContainer(*pNode.child[1], pTreeNodePos, pTrianglePos, lo, hi); } treeNode.setBounds(lo,hi); // get absolute bounds pLo = pLo.min(lo); pHi = pHi.max(hi); getTreeNodes()[currentTreeNodePos] = treeNode; }
void Box::getBounds(class AABox& aabb) const { Vector3 lo = _corner[0]; Vector3 hi = lo; for (int v = 1; v < 8; ++v) { const Vector3& C = _corner[v]; lo = lo.min(C); hi = hi.max(C); } aabb = AABox(lo, hi); }
void MD2Model::Part::load(const std::string& filename, float resize) { resize *= 0.55f; // If models are being reloaded it is dangerous to trust the interpolation cache. interpolatedModel = NULL; alwaysAssertM(FileSystem::exists(filename), std::string("Can't find \"") + filename + "\""); setNormalTable(); // Clear out reset(); BinaryInput b(filename, G3D_LITTLE_ENDIAN); MD2ModelHeader header; header.deserialize(b); debugAssert(header.version == 8); debugAssert(header.numVertices <= 4096); keyFrame.resize(header.numFrames); Array<Vector3> frameMin; frameMin.resize(header.numFrames); Array<Vector3> frameMax; frameMax.resize(header.numFrames); Array<double> frameRad; frameRad.resize(header.numFrames); texCoordScale.x = 1.0f / header.skinWidth; texCoordScale.y = 1.0f / header.skinHeight; Vector3 min = Vector3::inf(); Vector3 max = -Vector3::inf(); double rad = 0; if (header.numVertices < 3) { Log::common()->printf("\n*****************\nWarning: \"%s\" is corrupted and is not being loaded.\n", filename.c_str()); return; } loadTextureFilenames(b, header.numSkins, header.offsetSkins); for (int f = 0; f < keyFrame.size(); ++f) { MD2Frame md2Frame; b.setPosition(header.offsetFrames + f * header.frameSize); md2Frame.deserialize(b); // Read the vertices for the frame keyFrame[f].vertexArray.resize(header.numVertices); keyFrame[f].normalArray.resize(header.numVertices); // Per-pose bounds Vector3 min_1 = Vector3::inf(); Vector3 max_1 = -Vector3::inf(); double rad_1 = 0; // Quake's axes are permuted and scaled double scale[3] = {-.07, .07, -.07}; int permute[3] = {2, 0, 1}; int v, i; for (v = 0; v < header.numVertices; ++v) { Vector3& vertex = keyFrame[f].vertexArray[v]; for (i = 0; i < 3; ++i) { vertex[permute[i]] = (b.readUInt8() * md2Frame.scale[i] + md2Frame.translate[i]) * float(scale[permute[i]]); } vertex *= resize; uint8 normalIndex = b.readUInt8(); debugAssertM(normalIndex < 162, "Illegal canonical normal index in file"); keyFrame[f].normalArray[v] = iClamp(normalIndex, 0, 161); min_1 = min_1.min(vertex); max_1 = max_1.max(vertex); if (vertex.squaredMagnitude() > rad_1) { rad_1 = vertex.squaredMagnitude(); } } frameMin[f] = min_1; frameMax[f] = max_1; frameRad[f] = sqrt(rad_1); min = min.min(min_1); max = max.max(max_1); if (rad_1 > rad) { rad = rad_1; } } // Compute per-animation bounds based on frame bounds for (int a = 0; a < JUMP; ++a) { const int first = animationTable[a].first; const int last = animationTable[a].last; if ((first < header.numFrames) && (last < header.numFrames)) { Vector3 min = frameMin[first]; Vector3 max = frameMax[first]; double rad = frameRad[first]; for (int i = first + 1; i <= last; ++i) { min = min.min(frameMin[i]); max = max.max(frameMax[i]); rad = G3D::max(rad, frameRad[i]); } animationBoundingBox[a] = AABox(min, max); // Sometimes the sphere bounding the box is tighter than the one we calculated. const float boxRadSq = (max-min).squaredMagnitude() * 0.25f; if (boxRadSq >= square(rad)) { animationBoundingSphere[a] = Sphere(Vector3::zero(), (float)rad); } else { animationBoundingSphere[a] = Sphere((max + min) * 0.5f, sqrt(boxRadSq)); } } else { // This animation is not supported by this model animationBoundingBox[a] = AABox(Vector3::zero(), Vector3::zero()); animationBoundingSphere[a] = Sphere(Vector3::zero(), 0); } } animationBoundingBox[JUMP] = animationBoundingBox[JUMP_DOWN]; animationBoundingSphere[JUMP] = animationBoundingSphere[JUMP_DOWN]; boundingBox = AABox(min, max); boundingSphere = Sphere(Vector3::zero(), (float)sqrt(rad)); // Load the texture coords Array<Vector2int16> fileTexCoords; fileTexCoords.resize(header.numTexCoords); b.setPosition(header.offsetTexCoords); for (int t = 0; t < fileTexCoords.size(); ++t) { fileTexCoords[t].x = b.readUInt16(); fileTexCoords[t].y = b.readUInt16(); } // The indices for the texture coords (which don't match the // vertex indices originally). indexArray.resize(header.numTriangles * 3); Array<Vector2int16> index_texCoordArray; index_texCoordArray.resize(indexArray.size()); // Read the triangles, reversing them to get triangle list order b.setPosition(header.offsetTriangles); for (int t = header.numTriangles - 1; t >= 0; --t) { for (int i = 2; i >= 0; --i) { indexArray[t * 3 + i] = b.readUInt16(); } for (int i = 2; i >= 0; --i) { index_texCoordArray[t * 3 + i] = fileTexCoords[b.readUInt16()]; } } computeTexCoords(index_texCoordArray); // Read the primitives { primitiveArray.clear(); b.setPosition(header.offsetGlCommands); int n = b.readInt32(); while (n != 0) { Primitive& primitive = primitiveArray.next(); if (n > 0) { primitive.type = PrimitiveType::TRIANGLE_STRIP; } else { primitive.type = PrimitiveType::TRIANGLE_FAN; n = -n; } primitive.pvertexArray.resize(n); Array<Primitive::PVertex>& pvertex = primitive.pvertexArray; for (int i = 0; i < pvertex.size(); ++i) { pvertex[i].texCoord.x = b.readFloat32(); pvertex[i].texCoord.y = b.readFloat32(); pvertex[i].index = b.readInt32(); } n = b.readInt32(); } } MeshAlg::computeAdjacency(keyFrame[0].vertexArray, indexArray, faceArray, edgeArray, vertexArray); weldedFaceArray = faceArray; weldedEdgeArray = edgeArray; weldedVertexArray = vertexArray; MeshAlg::weldAdjacency(keyFrame[0].vertexArray, weldedFaceArray, weldedEdgeArray, weldedVertexArray); numBoundaryEdges = MeshAlg::countBoundaryEdges(edgeArray); numWeldedBoundaryEdges = MeshAlg::countBoundaryEdges(weldedEdgeArray); shared_ptr<VertexBuffer> indexBuffer = VertexBuffer::create(indexArray.size() * sizeof(int), VertexBuffer::WRITE_ONCE); indexVAR = IndexStream(indexArray, indexBuffer); }
void test( const std::string & meshFile, const uint_t numProcesses, const uint_t numTotalBlocks ) { auto mesh = make_shared<MeshType>(); mesh::readAndBroadcast( meshFile, *mesh); auto aabb = computeAABB( *mesh ); auto domainAABB = aabb.getScaled( typename MeshType::Scalar(3) ); auto triDist = make_shared< mesh::TriangleDistance<MeshType> >( mesh ); auto distanceOctree = make_shared< DistanceOctree< MeshType > >( triDist ); const real_t meshVolume = real_c( computeVolume( *mesh ) ); const real_t blockVolume = meshVolume / real_c( numTotalBlocks ); static const real_t cellsPersBlock = real_t(1000); const real_t cellVolume = blockVolume / cellsPersBlock; const Vector3<real_t> cellSize( std::pow( cellVolume, real_t(1) / real_t(3) ) ); ComplexGeometryStructuredBlockforestCreator bfc( domainAABB, cellSize, makeExcludeMeshInterior( distanceOctree, cellSize.min() ) ); auto wl = mesh::makeMeshWorkloadMemory( distanceOctree, cellSize ); wl.setInsideCellWorkload(0); wl.setOutsideCellWorkload(1); wl.setForceZeroMemoryOnZeroWorkload(true); bfc.setWorkloadMemorySUIDAssignmentFunction( wl ); bfc.setRefinementSelectionFunction( makeRefinementSelection( distanceOctree, 5, cellSize[0], cellSize[0] * real_t(5) ) ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with StaticLevelwiseCurveBalanceWeighted Partitioner" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseCurveBalanceWeighted() ); auto sbf_default = bfc.createSetupBlockForest( Vector3<uint_t>(64,64,64), numProcesses ); //sbf_default->writeVTKOutput("sbf_default"); WALBERLA_LOG_INFO_ON_ROOT( sbf_default->toString() ); return; #ifdef WALBERLA_BUILD_WITH_PARMETIS WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with ParMetis (PART_KWAY, no commweights)" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseParMetis( blockforest::StaticLevelwiseParMetis::PARMETIS_PART_KWAY ) ); auto sbf = bfc.createSetupBlockForest( numTotalBlocks, numProcesses ); //sbf->writeVTKOutput("sbf"); WALBERLA_LOG_INFO_ON_ROOT( sbf->toString() ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with ParMetis (PART_KWAY, commweights)" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseParMetis( commInXDirection, blockforest::StaticLevelwiseParMetis::PARMETIS_PART_KWAY ) ); auto sbf_edge = bfc.createSetupBlockForest( numTotalBlocks, numProcesses ); //sbf_edge->writeVTKOutput("sbf_edge"); WALBERLA_LOG_INFO_ON_ROOT( sbf_edge->toString() ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with ParMetis (PART_GEOM_KWAY, no commweights)" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseParMetis( blockforest::StaticLevelwiseParMetis::PARMETIS_PART_GEOM_KWAY ) ); auto sbf_geom = bfc.createSetupBlockForest( numTotalBlocks, numProcesses ); //sbf_geom->writeVTKOutput("sbf_geom"); WALBERLA_LOG_INFO_ON_ROOT( sbf_geom->toString() ); WALBERLA_LOG_INFO_ON_ROOT( "Creating SBF with ParMetis (PART_GEOM_KWAY, commweights)" ); bfc.setTargetProcessAssignmentFunction( blockforest::StaticLevelwiseParMetis( commInXDirection, blockforest::StaticLevelwiseParMetis::PARMETIS_PART_GEOM_KWAY ) ); auto sbf_geom_edge = bfc.createSetupBlockForest( numTotalBlocks, numProcesses ); //sbf_geom_edge->writeVTKOutput("sbf_geom_edge"); WALBERLA_LOG_INFO_ON_ROOT( sbf_geom_edge->toString() ); #endif }