void BvhTree::BuildNode(BvhNode *node, const std::list<Geom*> &a_geoms, int &outGeomPos) { const int numGeoms = a_geoms.size(); // make aabb from spheres // XXX suboptimal for static objects, as they have fixed rotation so // we can use a precise rotated aabb rather than worst case XXX Aabb aabb; aabb.min = vector3d(FLT_MAX, FLT_MAX, FLT_MAX); aabb.max = vector3d(-FLT_MAX, -FLT_MAX, -FLT_MAX); for (std::list<Geom*>::const_iterator i = a_geoms.begin(); i != a_geoms.end(); ++i) { vector3d p = (*i)->GetPosition(); double rad = (*i)->GetGeomTree()->GetRadius(); aabb.Update(p + vector3d(rad,rad,rad)); aabb.Update(p - vector3d(rad,rad,rad)); } // divide by longest axis int axis; const vector3d axislen = aabb.max - aabb.min; if ((axislen.x > axislen.y) && (axislen.x > axislen.z)) axis = 0; else if (axislen.y > axislen.z) axis = 1; else axis = 2; const double pivot = 0.5*(aabb.max[axis] + aabb.min[axis]); std::list<Geom*> side[2]; for (std::list<Geom*>::const_iterator i = a_geoms.begin(); i != a_geoms.end(); ++i) { if ((*i)->GetPosition()[axis] < pivot) { side[0].push_back(*i); } else { side[1].push_back(*i); } } node->numGeoms = numGeoms; node->aabb = aabb; // side 1 has all nodes. just make a f*****g child if ((side[0].size() == 0) || (side[1].size() == 0)) { node->geomStart = &m_geoms[outGeomPos]; // copy geoms to the stinking flat array for (std::list<Geom*>::const_iterator i = a_geoms.begin(); i != a_geoms.end(); ++i) { m_geoms[outGeomPos++] = *i; } } else { // recurse! node->geomStart = 0; node->kids[0] = AllocNode(); node->kids[1] = AllocNode(); BuildNode(node->kids[0], side[0], outGeomPos); BuildNode(node->kids[1], side[1], outGeomPos); } }
void LightTree::build(const Assembly& assembly_) { assembly = &assembly_; // Populate the build nodes for (size_t i = 0; i < assembly->instances.size(); ++i) { const auto& instance = assembly->instances[i]; // Shorthand // If it's an object if (instance.type == Instance::OBJECT) { const Object* obj = assembly->objects[instance.data_index].get(); // Shorthand if (obj->total_emitted_color().energy() > 0.0f) { build_nodes.push_back(BuildNode()); build_nodes.back().instance_index = i; build_nodes.back().bbox = assembly->instance_bounds_at(0.5f, i); build_nodes.back().center = build_nodes.back().bbox.center(); const Vec3 scale = assembly->instance_xform_at(0.5f, i).get_inv_scale(); const float surface_scale = ((scale[0]*scale[1]) + (scale[0]*scale[2]) + (scale[1]*scale[2])) * 0.33333333f; build_nodes.back().energy = obj->total_emitted_color().energy() / surface_scale; ++total_lights; } } // If it's an assembly else if (instance.type == Instance::ASSEMBLY) { const Assembly* asmb = assembly->assemblies[instance.data_index].get(); // Shorthand const auto count = asmb->light_accel.light_count(); const float energy = asmb->light_accel.total_emitted_color().energy(); if (count > 0 && energy > 0.0f) { build_nodes.push_back(BuildNode()); build_nodes.back().instance_index = i; if (instance.transform_count > 0) { auto xstart = assembly->xforms.cbegin() + instance.transform_index; auto xend = xstart + instance.transform_count; build_nodes.back().bbox = lerp_seq(0.5f, asmb->light_accel.bounds()).inverse_transformed(lerp_seq(0.5f, xstart, xend)); } else { build_nodes.back().bbox = lerp_seq(0.5f, asmb->light_accel.bounds()); } build_nodes.back().center = build_nodes.back().bbox.center(); const Vec3 scale = assembly->instance_xform_at(0.5f, i).get_inv_scale(); const float surface_scale = ((scale[0]*scale[1]) + (scale[0]*scale[2]) + (scale[1]*scale[2])) * 0.33333333f; build_nodes.back().energy = energy / surface_scale; total_lights += count; } } } if (build_nodes.size() > 0) { recursive_build(build_nodes.begin(), build_nodes.end()); bounds_ = nodes[0].bounds; total_energy = nodes[0].energy; } else { bounds_.clear(); bounds_.emplace_back(BBox()); } }
//---------------------------------------------------------------------------- PX2::Movable *SceneBuilder::BuildGeometry (INode *maxNode, PX2::Node *relatParent, bool hasSkin) { // 建立并且链接几何图形物体到场景 // maxNode: // Max场景中节点的指针 // relatParent: // 当前新节点要绑定到的父亲节点 // 如果Max“几何图形”节点没有孩子节点,直接在relatParent下添加几何图形。 // 如果Max“几何图形”节点有孩子节点,会新建一个Node节点,将孩子几何图形节 // 点添加到这个新建的Node节点下。 PX2::Movable *child = 0; PX2::Node *link = 0; int numMaxChildren = maxNode->NumberOfChildren(); for (int i=0; i<numMaxChildren; i++) { ObjectState objectState = maxNode->GetChildNode(i) ->EvalWorldState(mTimeStart); if (objectState.obj->SuperClassID() == GEOMOBJECT_CLASS_ID || objectState.obj->SuperClassID() == HELPER_CLASS_ID) { link = BuildNode(maxNode, relatParent); break; } } if (link == 0) { if (mSettings->IncludeMeshes && !maxNode->IsHidden()) { child = BuildMesh(maxNode, relatParent, hasSkin); } else { child = BuildNode(maxNode, relatParent); } return child; } else { if (mSettings->IncludeMeshes && !maxNode->IsHidden()) { child = BuildMesh(maxNode, link, hasSkin); } else { child = BuildNode(maxNode, link); } return link; } }
void KdTreeBuilder::BuildNode(const BoundingBox_f& nodeBounds, const int32_t* nodeTriangles, int32_t nodeTrianglesCount, int depth, int32_t* triangles0, int32_t* triangles1) { if (nodes.size() >= KdTree::Node::maxNodesCount) RuntimeError("maximum number of KdTree nodes has been reached: " + std::to_string(KdTree::Node::maxNodesCount)); // check if leaf node should be created if (nodeTrianglesCount <= buildParams.leafTrianglesLimit || depth == 0) { CreateLeaf(nodeTriangles, nodeTrianglesCount); buildStats.NewLeaf(nodeTrianglesCount, buildParams.maxDepth - depth); return; } // select split position auto split = SelectSplit(nodeBounds, nodeTriangles, nodeTrianglesCount); if (split.edge == -1) { CreateLeaf(nodeTriangles, nodeTrianglesCount); buildStats.NewLeaf(nodeTrianglesCount, buildParams.maxDepth - depth); return; } float splitPosition = edgesBuffer[split.edge].positionOnAxis; // classify triangles with respect to split int32_t n0 = 0; for (int32_t i = 0; i < split.edge; i++) { if (edgesBuffer[i].IsStart()) triangles0[n0++] = edgesBuffer[i].GetTriangleIndex(); } int32_t n1 = 0; for (int32_t i = split.edge + 1; i < 2 * nodeTrianglesCount; i++) { if (edgesBuffer[i].IsEnd()) triangles1[n1++] = edgesBuffer[i].GetTriangleIndex(); } // add interior node and recursively create children nodes auto thisNodeIndex = static_cast<int32_t>(nodes.size()); nodes.push_back(KdTree::Node()); BoundingBox_f bounds0 = nodeBounds; bounds0.maxPoint[split.axis] = splitPosition; BuildNode(bounds0, triangles0, n0, depth - 1, triangles0, triangles1 + n1); auto aboveChild = static_cast<int32_t>(nodes.size()); nodes[thisNodeIndex].InitInteriorNode(split.axis, aboveChild, splitPosition); BoundingBox_f bounds1 = nodeBounds; bounds1.minPoint[split.axis] = splitPosition; BuildNode(bounds1, triangles1, n1, depth - 1, triangles0, triangles1); }
/* * Recursively builds the BVH starting at the given node with the given * first and last primitive indices (in bag). */ size_t BVH4::recursive_build(size_t parent, size_t first_prim, size_t last_prim) { // Allocate the node const size_t me = build_nodes.size(); build_nodes.push_back(BuildNode()); build_nodes[me].flags = 0; build_nodes[me].parent_index = parent; if (first_prim == last_prim) { // Leaf node build_nodes[me].flags |= IS_LEAF; build_nodes[me].data = prim_bag[first_prim].data; // Copy bounding boxes build_nodes[me].bbox_index = build_bboxes.size(); build_nodes[me].ts = prim_bag[first_prim].data->bounds().size(); for (size_t i = 0; i < build_nodes[me].ts; i++) build_bboxes.push_back(prim_bag[first_prim].data->bounds()[i]); } else { // Not a leaf node // Create child nodes uint32_t split_index = split_primitives(first_prim, last_prim); const size_t child1i = recursive_build(me, first_prim, split_index); const size_t child2i = recursive_build(me, split_index+1, last_prim); build_nodes[me].child_index = child2i; // Calculate bounds build_nodes[me].bbox_index = build_bboxes.size(); // If both children have same number of time samples if (build_nodes[child1i].ts == build_nodes[child2i].ts) { build_nodes[me].ts = build_nodes[child1i].ts; // Copy merged bounding boxes for (size_t i = 0; i < build_nodes[me].ts; i++) { build_bboxes.push_back(build_bboxes[build_nodes[child1i].bbox_index+i]); build_bboxes.back().merge_with(build_bboxes[build_nodes[child2i].bbox_index+i]); } } // If children have different number of time samples else { build_nodes[me].ts = 1; // Merge children's bboxes to get our bbox build_bboxes.push_back(build_bboxes[build_nodes[child1i].bbox_index]); for (size_t i = 1; i < build_nodes[child1i].ts; i++) build_bboxes.back().merge_with(build_bboxes[build_nodes[child1i].bbox_index+i]); for (size_t i = 0; i < build_nodes[child2i].ts; i++) build_bboxes.back().merge_with(build_bboxes[build_nodes[child2i].bbox_index+i]); } } return me; }
void kDOPTree::BuildTree( Vector<Trianglef>& pTriangleSoup, Vector<Vector3f>& pVertices ) { // Keep a copy of the vertices and triangles. mVertices.resize( pVertices.size() ); for( UInt32 i = 0; i < pVertices.size(); i++ ) mVertices[i] = pVertices[i]; mTriangles.resize( pTriangleSoup.size() ); for( UInt32 i = 0; i < pTriangleSoup.size(); i++ ) { mTriangles[i].mIndices[0] = pTriangleSoup[i].mIndices[0]; mTriangles[i].mIndices[1] = pTriangleSoup[i].mIndices[1]; mTriangles[i].mIndices[2] = pTriangleSoup[i].mIndices[2]; } mTrianglesCentroids.resize( pTriangleSoup.size() ); // Find each triangle center. for( UInt32 i = 0; i < pTriangleSoup.size(); i++ ) { mTrianglesCentroids[i] = mVertices[mTriangles[i].mIndices[0]]; mTrianglesCentroids[i] += mVertices[mTriangles[i].mIndices[1]]; mTrianglesCentroids[i] += mVertices[mTriangles[i].mIndices[2]]; mTrianglesCentroids[i] *= (1.0f / 3.0f); } mNumNodes = 1; mNumLeaves = 0; mMaxDepth = 0; mDepth = 0; // Create the root node. kDOPNode* root = GD_NEW(kDOPNode, this, "Engine::Collision::kDOPTree"); mNodes.push_back( root ); // Insert the triangles indices in the root node list. root->mTriangleIndices.resize( pTriangleSoup.size() ); for( UInt32 i = 0; i < pTriangleSoup.size(); i++ ) { root->mTriangleIndices[i] = i; } // Recursively build kDOP tree. BuildNode( root ); // No need to store centroids. mTrianglesCentroids.clear(); /* #ifdef GD_DEBUG // // Report memory usage UInt32 memUsage = 0; memUsage += (mNodes.size() * 4) + (mNodes.size() * sizeof(kDOPNode)); memUsage += mVertices.size() * sizeof(mVertices[0]); memUsage += mTriangles.size() * sizeof(mTriangles[0]); printf( "kDOPTree mem usage = %08d bytes", memUsage ); #endif */ }
KdTree KdTreeBuilder::BuildTree() { const auto trianglesCount = mesh.GetTrianglesCount(); // initialize bounding boxes triangleBounds.resize(trianglesCount); BoundingBox_f meshBounds; for (auto i = 0; i < trianglesCount; i++) { triangleBounds[i] = mesh.GetTriangleBounds(i); meshBounds = BoundingBox_f::Union(meshBounds, triangleBounds[i]); } // initialize working memory edgesBuffer.resize(2 * trianglesCount); trianglesBuffer.resize(trianglesCount * (buildParams.maxDepth + 1)); // fill triangle indices for root node for (auto i = 0; i < trianglesCount; i++) trianglesBuffer[i] = i; // recursively build all nodes BuildNode(meshBounds, trianglesBuffer.data(), trianglesCount, buildParams.maxDepth, trianglesBuffer.data(), trianglesBuffer.data() + trianglesCount); buildStats.FinalizeStats(); return KdTree(std::move(nodes), std::move(triangleIndices), mesh); }
void kDOPTree::BuildNode( kDOPTree::kDOPNode* pNode ) { mDepth++; if( mDepth > mMaxDepth ) mMaxDepth = mDepth; FindBoundingBox( pNode ); // Test if we're creating a leaf or a node. if( pNode->mTriangleIndices.size() > 5 ) { mNumNodes++; Float axisMean; Axis splitAxis = SelectSplitAxis( pNode->mTriangleIndices, axisMean ); // Add two nodes. kDOPNode* leftNode = GD_NEW(kDOPNode, this, "Engine::Collision::kDOPTree"); kDOPNode* rightNode = GD_NEW(kDOPNode, this, "Engine::Collision::kDOPTree"); pNode->mChildsIndex = mNodes.size(); mNodes.push_back( leftNode ); mNodes.push_back( rightNode ); // Split triangles into two list. SplitTriangles( pNode, splitAxis, axisMean ); // No need to store this in nodes. pNode->mTriangleIndices.clear(); // Recursively call build tree. BuildNode( leftNode ); BuildNode( rightNode ); } else { // No work to do for leaves! mNumLeaves++; } mDepth--; }
BVHTree::BVHTree(int numObjs, const objPtr_t *objPtrs, const Aabb *objAabbs) { std::vector<int> activeObjIdxs(numObjs); for (int i=0; i<numObjs; i++) activeObjIdxs[i] = i; m_objPtrAlloc = new objPtr_t[numObjs]; m_objPtrAllocPos = 0; m_objPtrAllocMax = numObjs; m_bvhNodes = new BVHNode[numObjs*2 + 1]; m_nodeAllocPos = 0; m_nodeAllocMax = numObjs*2 + 1; m_root = AllocNode(); BuildNode(m_root, objPtrs, objAabbs, activeObjIdxs); }
int ESceneAIMapTool::AddNode(const Fvector& pos, bool bIgnoreConstraints, bool bAutoLink, int sz) { Fvector Pos = pos; if (1==sz){ SAINode* N = BuildNode(Pos,Pos,bIgnoreConstraints,true); if (N){ N->flags.set (SAINode::flSelected,TRUE); if (bAutoLink) UpdateLinks(N,bIgnoreConstraints); return 1; }else{ ELog.Msg (mtError,"Can't create node."); return 0; } }else{ return BuildNodes (Pos,sz,bIgnoreConstraints); } }
BvhTree::BvhTree(const std::list<Geom*> &geoms) { m_geoms = 0; m_nodesAlloc = 0; int numGeoms = geoms.size(); if (numGeoms == 0) { m_root = 0; return; } m_geoms = new Geom*[numGeoms]; int geomPos = 0; m_nodesAllocPos = 0; m_nodesAllocMax = numGeoms*2; m_nodesAlloc = new BvhNode[m_nodesAllocMax]; m_root = AllocNode(); BuildNode(m_root, geoms, geomPos); assert(geomPos == numGeoms); }
//---------------------------------------------------------------------------- bool SceneBuilder::Traverse(INode *maxNode, PX2::Node *relatParent) { // movbale对应maxNode的父节点 bool isHasSkin = false; // Modifier if (mSettings->IncludeModifiers) { ModifierInfo *modInfo = new0 ModifierInfo; CollectModifiers(maxNode, modInfo->Modifiers); if (modInfo->Modifiers.empty()) { delete0(modInfo); } else { modInfo->Node = maxNode; mModifierList.push_back(modInfo); for (int i=0; i<(int)modInfo->Modifiers.size(); i++) { Modifier *modifier = modInfo->Modifiers[i]; Class_ID id = modifier->ClassID(); if (id == SKIN_CLASSID || id == Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B)) { isHasSkin = true; } } } } // Node const char *nodeName = maxNode->GetName(); if(stricmp(nodeName, "PHYSICSDATA") == 0) { } else if(stricmp(nodeName, "PORTALDATA") == 0) { } PX2::Movable *child = 0; ObjectState objectState = maxNode->EvalWorldState(mTimeStart); bool supported = true; // Object if (objectState.obj) { switch (objectState.obj->SuperClassID()) { case GEOMOBJECT_CLASS_ID: if (IsNodeRenderable(maxNode, objectState.obj)) child = BuildGeometry(maxNode, relatParent, isHasSkin); else child = BuildNode(maxNode, relatParent); break; case CAMERA_CLASS_ID: // ToDo break; case LIGHT_CLASS_ID: if (mSettings->IncludeLights && !maxNode->IsHidden()) { BuildLight(maxNode, relatParent); } break; case HELPER_CLASS_ID: //supported = false; child = BuildNode(maxNode, relatParent); break; default: assertion(false, "Some object type not supportted."); supported = false; break; } } // Keyframe if (child) { if (mSettings->IncludeKeyFrames) BuildKeyFrameController(maxNode, child); else BuildFrameController(maxNode, child); } // Child int numChildren = maxNode->NumberOfChildren(); if (numChildren == 0) return true; PX2::Node *childNode = 0; childNode = PX2::DynamicCast<PX2::Node>(child); if (childNode == 0) return true; for (int i=0; i<numChildren; i++) { if (!Traverse(maxNode->GetChildNode(i), childNode) || mMax->GetCancel()) return false; } return true; }
void ESceneAIMapTool::BuildNodes(bool bFromSelectedOnly) { // begin m_Nodes.reserve (1024*1024); // Initialize hash // hash_Initialize (); R_ASSERT(!m_Nodes.empty()); // Estimate nodes Fvector Pos,LevelSize; m_AIBBox.getsize (LevelSize); float estimated_nodes = (LevelSize.x/m_Params.fPatchSize)*(LevelSize.z/m_Params.fPatchSize); SPBItem* pb = UI->ProgressStart(1, "Building nodes..."); // General cycle for (int k=0; k<(int)m_Nodes.size(); k++){ SAINode* N = m_Nodes[k]; if (bFromSelectedOnly && !N->flags.is(SAINode::flSelected)) continue; // left if (0==N->n1){ Pos.set (N->Pos); Pos.x -= m_Params.fPatchSize; N->n1 = BuildNode(N->Pos,Pos,false); } // fwd if (0==N->n2){ Pos.set (N->Pos); Pos.z += m_Params.fPatchSize; N->n2 = BuildNode(N->Pos,Pos,false); } // right if (0==N->n3){ Pos.set (N->Pos); Pos.x += m_Params.fPatchSize; N->n3 = BuildNode(N->Pos,Pos,false); } // back if (0==N->n4){ Pos.set (N->Pos); Pos.z -= m_Params.fPatchSize; N->n4 = BuildNode(N->Pos,Pos,false); } if (bFromSelectedOnly){ // select neighbour nodes if (N->n1) N->n1->flags.set(SAINode::flSelected,TRUE); if (N->n2) N->n2->flags.set(SAINode::flSelected,TRUE); if (N->n3) N->n3->flags.set(SAINode::flSelected,TRUE); if (N->n4) N->n4->flags.set(SAINode::flSelected,TRUE); } if (k%512==0) { float p1 = float(k)/float(m_Nodes.size()); float p2 = float(m_Nodes.size())/estimated_nodes; float p = 0.1f*p1+0.9f*p2; clamp (p,0.f,1.f); pb->Update(p); // check need abort && redraw if (k%32768==0) UI->RedrawScene(true); if (UI->NeedAbort()) break; } } UI->ProgressEnd(pb); }
//---------------------------------------------------------------------------- PX2::Movable *SceneBuilder::BuildMesh(INode *maxNode, PX2::Node *relatParentOrEqualNode) { // 将Max的三角形网格数据转换到一个或者更多的等价的Phoenix2三角形网格。 // // maxNode: // Max场景图中的Mesh节点。 // relatParentOrEqualNode: // 在Phoenix2场景图系统中最新创建的父亲节点。 // 返回在Phoenix2场景中指向新的孩子节点的指针,这个指针直接指向TriMesh物体; // 或者是一个“link”节点,“link”的多个孩子TriMesh代表Max中的多个孩子mesh。 bool needDel = false; TriObject *triObject = GetTriObject(maxNode, &needDel); if (!triObject) { return 0; } Mesh *maxMesh = &triObject->GetMesh(); Mtl *mtl = maxNode->GetMtl(); int mtlIndex = mMtls.GetIndex(mtl); // 判断这个Max的几何图形节点是否有“子几何图形节点”,如果有子几何图形节点 // isEqualNode为真,反之为假。 // 如果名称相等,就不是relatParentOrEqualNode了,而是equalNode PX2::Movable *link = 0; bool isEqualNode = (relatParentOrEqualNode->GetName().length()>0 && strcmp(maxNode->GetName(), relatParentOrEqualNode->GetName().c_str()) == 0); // maxName char *maxName = maxNode->GetName(); // 如果只需要一个Phoenix的Mesh表示Max的Mesh,直接将Phoenix的Mesh链接到 // Phoenix的场景图中;否则,创建一个"link"节点,将按照材质分割的子Mesh // 放在"link"下。 int i; std::vector<UniMaterialMesh*> uMeshs; SplitGeometry(maxMesh, mtlIndex, uMeshs); if ((int)uMeshs.size() > 1) { if (!isEqualNode) { link = BuildNode(maxNode, relatParentOrEqualNode); } else { link = relatParentOrEqualNode; } assertion(link->IsDerived(PX2::Node::TYPE), "link must be a Node."); for (i=0; i<(int)uMeshs.size(); i++) { PX2::TriMesh *triMesh = uMeshs[i]->ToTriMesh(); if (triMesh) { char meshNumber[6]; sprintf_s(meshNumber, 6, "_%d", i+1); size_t size = strlen(maxName) + strlen(meshNumber) + 1; char *tdName = new1<char>((int)size); strcpy_s(tdName, size, maxName); strcat_s(tdName, size, meshNumber); triMesh->SetName(tdName); delete1(tdName); ((PX2::Node*)link)->AttachChild(triMesh); } } } else if ((int)uMeshs.size() == 1) { PX2::TriMesh *triMesh = uMeshs[0]->ToTriMesh(); if (triMesh) { if (!isEqualNode) { triMesh->SetName(maxName); triMesh->LocalTransform = GetLocalTransform(maxNode, mTimeStart); } else { size_t size = strlen(maxName) + 3; char *tdName = new1<char>((int)size); strcpy_s(tdName, size, maxName); strcat_s(tdName, size, "_1"); triMesh->SetName(tdName); delete1(tdName); } assertion(relatParentOrEqualNode->IsDerived(PX2::Node::TYPE), "relatParentOrEqualNode must be a Node."); relatParentOrEqualNode->AttachChild(triMesh); link = triMesh; } } for (i=0; i<(int)uMeshs.size(); i++) { delete0(uMeshs[i]); } if (needDel) { delete0(triObject); } return link; }
CTreeNode* CTreeBuilder::AddNode(CTreeNode* pParentNode, NodeDetails enNodedetails) { if (enNodedetails.type == STARTTAG || enNodedetails.type ==VALUE ) { CTreeNode* temp = BuildNode(enNodedetails); CTreeNode*p = NULL; temp->SetParent(pParentNode); if(temp->GetParent()== NULL) { if(this->m_RootNode == NULL) { this->m_RootNode = temp; } else { p = this->m_RootNode; while(p && p->GetSibling()) p = p->GetSibling(); p->SetSibling(temp); } } else { if (pParentNode!=NULL) { if(pParentNode->GetDepth()== temp->GetDepth()) /* sibling */ { p = pParentNode->GetSibling(); while(p && p->GetSibling()) p = p->GetSibling(); if(p) p->SetSibling(temp); else pParentNode->SetSibling(temp); } else { p = pParentNode->GetChild(); while(p && p->GetSibling()) p = p->GetSibling(); if(p) p->SetSibling(temp); else pParentNode->SetChild(temp); } } } if (enNodedetails.type != 2) { pParentNode = temp; } else { pParentNode = temp->GetParent(); } } if (enNodedetails.type == 1) { if ( pParentNode->GetParent()!= NULL) { pParentNode = pParentNode->GetParent(); } } return pParentNode; }
void BVHTree::BuildNode(BVHNode *node, const objPtr_t *objPtrs, const Aabb *objAabbs, std::vector<objPtr_t> &activeObjIdx) { const int numTris = activeObjIdx.size(); if (numTris <= 0) Error("BuildNode called with no elements in activeObjIndex."); if (numTris == 1) { MakeLeaf(node, objPtrs, activeObjIdx); return; } std::vector<int> splitSides(numTris); Aabb aabb; aabb.min = vector3d(FLT_MAX, FLT_MAX, FLT_MAX); aabb.max = vector3d(-FLT_MAX, -FLT_MAX, -FLT_MAX); for (int i=0; i<numTris; i++) { int idx = activeObjIdx[i]; aabb.Update(objAabbs[idx].min); aabb.Update(objAabbs[idx].max); } node->numTris = numTris; node->aabb = aabb; Aabb splitBox = aabb; double splitPos; int splitAxis; int s1count, s2count; int attempt = 0; for (;;) { splitAxis = 0; vector3d boxSize = splitBox.max - splitBox.min; if (boxSize[1] > boxSize[0]) splitAxis = 1; if ((boxSize[2] > boxSize[1]) && (boxSize[2] > boxSize[0])) splitAxis = 2; // split pos in middle of splitBox splitPos = 0.5f * (splitBox.min[splitAxis] + splitBox.max[splitAxis]); s1count = 0, s2count = 0; for (int i=0; i<numTris; i++) { int idx = activeObjIdx[i]; double mid = 0.5 * (objAabbs[idx].min[splitAxis] + objAabbs[idx].max[splitAxis]); if (mid < splitPos) { splitSides[i] = 0; s1count++; } else { splitSides[i] = 1; s2count++; } } if (s1count == numTris) { if (attempt < MAX_SPLITPOS_RETRIES) { // try splitting at average point splitBox.max[splitAxis] = splitPos; attempt++; continue; } else { MakeLeaf(node, objPtrs, activeObjIdx); return; } } else if (s2count == numTris) { if (attempt < MAX_SPLITPOS_RETRIES) { // try splitting at average point splitBox.min[splitAxis] = splitPos; attempt++; continue; } else { MakeLeaf(node, objPtrs, activeObjIdx); return; } } break; } std::vector<int> side[2]; for (int i=0; i<numTris; i++) { side[splitSides[i]].push_back(activeObjIdx[i]); } // recurse! node->triIndicesStart = 0; node->kids[0] = AllocNode(); node->kids[1] = AllocNode(); BuildNode(node->kids[0], objPtrs, objAabbs, side[0]); BuildNode(node->kids[1], objPtrs, objAabbs, side[1]); }
void xrBuildNodes() { // begin XRC.box_options (CDB::OPT_FULL_TEST); XRC.ray_options (CDB::OPT_CULL | CDB::OPT_ONLYNEAREST); g_nodes.reserve (1024*1024); // Initialize hash hash_Initialize (); for (u32 em=0; em<Emitters.size(); em++) { // Align emitter Fvector Pos = Emitters[em]; SnapXZ (Pos); Pos.y +=1; Fvector Dir; Dir.set(0,-1,0); XRC.ray_query (&Level,Pos,Dir,3); if (XRC.r_count()==0) { Msg ("Can't align emitter"); abort (); } else { CDB::RESULT& R = *XRC.r_begin(); Pos.y = Pos.y - R.range; } // Build first node int oldcount = g_nodes.size(); int start = BuildNode (Pos,Pos); if (start==InvalidNode) continue; if (start<oldcount) continue; // Estimate nodes Fvector LevelSize; LevelBB.getsize (LevelSize); u32 estimated_nodes = iFloor(LevelSize.x/g_params.fPatchSize)*iFloor(LevelSize.z/g_params.fPatchSize); // General cycle for (u32 i=0; i<g_nodes.size(); i++) { // left if (g_nodes[i].n1==UnkonnectedNode) { Pos.set (g_nodes[i].Pos); Pos.x -= g_params.fPatchSize; int id = BuildNode(g_nodes[i].Pos,Pos); g_nodes[i].n1 = id; } // fwd if (g_nodes[i].n2==UnkonnectedNode) { Pos.set (g_nodes[i].Pos); Pos.z += g_params.fPatchSize; int id = BuildNode(g_nodes[i].Pos,Pos); g_nodes[i].n2 = id; } // right if (g_nodes[i].n3==UnkonnectedNode) { Pos.set (g_nodes[i].Pos); Pos.x += g_params.fPatchSize; int id = BuildNode(g_nodes[i].Pos,Pos); g_nodes[i].n3 = id; } // back if (g_nodes[i].n4==UnkonnectedNode) { Pos.set (g_nodes[i].Pos); Pos.z -= g_params.fPatchSize; int id = BuildNode(g_nodes[i].Pos,Pos); g_nodes[i].n4 = id; } if (i%512==0) { Status("%d / %d nodes created.",g_nodes.size()-i,g_nodes.size()); float p1 = float(i)/float(g_nodes.size()); float p2 = float(g_nodes.size())/estimated_nodes; float p = 0.1f*p1+0.9f*p2; clamp (p,0.f,1.f); Progress(p); } } } Msg("Freeing memory..."); hash_Destroy (); }
int ESceneAIMapTool::BuildNodes(const Fvector& pos, int sz, bool bIC) { // Align emitter Fvector Pos = pos; SnapXZ (Pos,m_Params.fPatchSize); Pos.y += 1; Fvector Dir; Dir.set(0,-1,0); int cnt = 0; if (m_CFModel) cnt=Scene->RayQuery(PQ,Pos,Dir,3,CDB::OPT_ONLYNEAREST|CDB::OPT_CULL,m_CFModel); else cnt=Scene->RayQuery(PQ,Pos,Dir,3,CDB::OPT_ONLYNEAREST|CDB::OPT_CULL,GetSnapList()); if (0==cnt) { ELog.Msg (mtInformation,"Can't align position."); return 0; } else { Pos.y = Pos.y - PQ.r_begin()->range; } // Build first node int oldcount = m_Nodes.size(); SAINode* start = BuildNode(Pos,Pos,bIC); if (!start) return 0; // Estimate nodes float estimated_nodes = (2*sz-1)*(2*sz-1); SPBItem* pb = 0; if (estimated_nodes>1024) pb = UI->ProgressStart(1, "Building nodes..."); float radius = sz*m_Params.fPatchSize-EPS_L; // General cycle for (int k=0; k<(int)m_Nodes.size(); k++){ SAINode* N = m_Nodes[k]; // left if (0==N->n1){ Pos.set (N->Pos); Pos.x -= m_Params.fPatchSize; if (Pos.distance_to(start->Pos)<=radius) N->n1 = BuildNode(N->Pos,Pos,bIC); } // fwd if (0==N->n2){ Pos.set (N->Pos); Pos.z += m_Params.fPatchSize; if (Pos.distance_to(start->Pos)<=radius) N->n2 = BuildNode(N->Pos,Pos,bIC); } // right if (0==N->n3){ Pos.set (N->Pos); Pos.x += m_Params.fPatchSize; if (Pos.distance_to(start->Pos)<=radius) N->n3 = BuildNode(N->Pos,Pos,bIC); } // back if (0==N->n4){ Pos.set (N->Pos); Pos.z -= m_Params.fPatchSize; if (Pos.distance_to(start->Pos)<=radius) N->n4 = BuildNode(N->Pos,Pos,bIC); } if (estimated_nodes>1024){ if (k%128==0) { float p1 = float(k)/float(m_Nodes.size()); float p2 = float(m_Nodes.size())/estimated_nodes; float p = 0.1f*p1+0.9f*p2; clamp (p,0.f,1.f); pb->Update(p); // check need abort && redraw if (UI->NeedAbort()) break; } } } if (estimated_nodes>1024) UI->ProgressEnd(pb); return oldcount-m_Nodes.size(); }