void calcMaxBoundingSphere(Sphere& _sphere, const void* _vertices, uint32_t _numVertices, uint32_t _stride) { Aabb aabb; calcAabb(aabb, _vertices, _numVertices, _stride); float center[3]; center[0] = (aabb.m_min[0] + aabb.m_max[0]) * 0.5f; center[1] = (aabb.m_min[1] + aabb.m_max[1]) * 0.5f; center[2] = (aabb.m_min[2] + aabb.m_max[2]) * 0.5f; float maxDistSq = 0.0f; uint8_t* vertex = (uint8_t*)_vertices; for (uint32_t ii = 0; ii < _numVertices; ++ii) { float* position = (float*)vertex; vertex += _stride; float xx = position[0] - center[0]; float yy = position[1] - center[1]; float zz = position[2] - center[2]; float distSq = xx*xx + yy*yy + zz*zz; maxDistSq = bx::fmax(distSq, maxDistSq); } bx::vec3Move(_sphere.m_center, center); _sphere.m_radius = sqrtf(maxDistSq); }
void writeBounds(bx::WriterI* _writer, const void* _vertices, uint32_t _numVertices, uint32_t _stride) { Sphere maxSphere; calcMaxBoundingSphere(maxSphere, _vertices, _numVertices, _stride); Sphere minSphere; calcMinBoundingSphere(minSphere, _vertices, _numVertices, _stride); if (minSphere.m_radius > maxSphere.m_radius) { bx::write(_writer, maxSphere); } else { bx::write(_writer, minSphere); } Aabb aabb; calcAabb(aabb, _vertices, _numVertices, _stride); bx::write(_writer, aabb); Obb obb; calcObb(obb, _vertices, _numVertices, _stride, s_obbSteps); bx::write(_writer, obb); }
void calcObb(Obb& _obb, const void* _vertices, uint32_t _numVertices, uint32_t _stride, uint32_t _steps) { Aabb aabb; calcAabb(aabb, _vertices, _numVertices, _stride); float minArea = calcAreaAabb(aabb); Obb best; aabbToObb(best, aabb); float angleStep = float(bx::piHalf/_steps); float ax = 0.0f; float mtx[16]; for (uint32_t ii = 0; ii < _steps; ++ii) { float ay = 0.0f; for (uint32_t jj = 0; jj < _steps; ++jj) { float az = 0.0f; for (uint32_t kk = 0; kk < _steps; ++kk) { bx::mtxRotateXYZ(mtx, ax, ay, az); float mtxT[16]; bx::mtxTranspose(mtxT, mtx); calcAabb(aabb, mtxT, _vertices, _numVertices, _stride); float area = calcAreaAabb(aabb); if (area < minArea) { minArea = area; aabbTransformToObb(best, aabb, mtx); } az += angleStep; } ay += angleStep; } ax += angleStep; } memcpy(&_obb, &best, sizeof(Obb) ); }
//============================================================================== OctreeNode* Octree::placeInternal(const Aabb& aabb, U depth, OctreeNode& node) { if(depth >= maxDepth) { return &node; } for(U i = 0; i < 2; ++i) { for(U j = 0; j < 2; ++j) { for(U k = 0; k < 2; ++k) { U id = i * 4 + j * 2 + k; // Get the node's AABB. If there is no node then calculate the // AABB Aabb childAabb; Bool child = node.children[id] != nullptr; if(child) { // There is a child childAabb = node.children[id]->aabb; } else { // Calculate calcAabb(i, j, k, node.aabb, childAabb); } // If aabb its completely inside the target => go deeper if(aabb.getMax() <= childAabb.getMax() && aabb.getMin() >= childAabb.getMin()) { if(!child) { #if ANKI_CFG_OCTREE_THREAD_SAFE node.mtx.lock(); // Check again now that the mutex is locked volatile Bool checkAgain = node.children[id] == nullptr; if(checkAgain) #endif { SceneAllocator<U8> alloc = sector->getSectorGroup().getSceneGraph(). getAllocator(); // Create new node if needed OctreeNode* newNode = ANKI_NEW(OctreeNode, alloc, childAabb, &node, alloc); node.addChild(id, newNode); } #if ANKI_CFG_OCTREE_THREAD_SAFE node.mtx.unlock(); #endif } ANKI_ASSERT(node.children[id]); return placeInternal(aabb, depth + 1, *node.children[id]); } } // k } // j } // i return &node; }