|
|
@ -108,14 +108,19 @@ AABB getOneEightCellAABB(const AABB& fatherAABB, const uvector<int, 3> side, int |
|
|
|
} |
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
bool keepQuadraturePoint(const Scene& scene, const OcTreeNode& ocTreeNode, const uvector3& originPt) |
|
|
|
bool keepQuadraturePoint(const std::vector<tensor3>& tensors, const OcTreeNode& ocTreeNode, const uvector3& point) |
|
|
|
{ |
|
|
|
// 只需要考虑intersect polys,不用考虑fully contained polys
|
|
|
|
const auto& polyIntersectIndices = ocTreeNode.polyIntersectIndices; |
|
|
|
const auto& polyIntersectIndices = ocTreeNode.polyIntersectIndices; |
|
|
|
assert(tensors.size() == polyIntersectIndices.size()); |
|
|
|
if (polyIntersectIndices.size() == 0) { |
|
|
|
assert(ocTreeNode.blobTree.structure.back().inOut != NODE_IN_OUT_UNKNOWN); |
|
|
|
return ocTreeNode.blobTree.structure.back().inOut; |
|
|
|
} |
|
|
|
std::vector<bool> primitiveInOuts(polyIntersectIndices.size()); |
|
|
|
for (int i = 0; i < ocTreeNode.polyIntersectIndices.size(); ++i) { |
|
|
|
// primitiveInOuts[i] = isInsidePowers(scene.polys[polyIntersectIndices[i]].rawPower, originPt);
|
|
|
|
primitiveInOuts[i] = isInsideBernstein(scene.tensors[polyIntersectIndices[i]], originPt); |
|
|
|
primitiveInOuts[i] = isInsideBernstein(tensors[i], point); |
|
|
|
} |
|
|
|
// 这里blobTree是拷贝传参
|
|
|
|
auto blobTree = ocTreeNode.blobTree; |
|
|
@ -188,7 +193,7 @@ void buildOcTreeV1(const Scene& scene, const OcTreeNode& node, std::vector<OcTre |
|
|
|
uvector3 nodeMid = node.aabb.center(); |
|
|
|
for (int i = 0; i < polyIntersectIndices.size(); ++i) { |
|
|
|
const int polyIntersectIndex = polyIntersectIndices[i]; |
|
|
|
const auto& poly = scene.tensors[polyIntersectIndex]; |
|
|
|
const auto& poly = scene.minimalReps[polyIntersectIndex].tensor; |
|
|
|
uvector<int, 3> mark(0, 0, 0); |
|
|
|
for (int faceAxis = 0; faceAxis < 3; ++faceAxis) { |
|
|
|
real centerPlane = nodeMid(faceAxis); |
|
|
@ -296,7 +301,7 @@ void buildOcTreeV0(const Scene& scene, const OcTreeNode& node, std::vector<OcTre |
|
|
|
int bbb = 1; |
|
|
|
} |
|
|
|
const std::vector<int>& polyIntersectIndices = node.polyIntersectIndices; |
|
|
|
if (polyIntersectIndices.size() <= 5) { |
|
|
|
if (polyIntersectIndices.size() <= 3) { |
|
|
|
leaves.emplace_back(node); |
|
|
|
return; |
|
|
|
} |
|
|
@ -326,21 +331,21 @@ void buildOcTreeV0(const Scene& scene, const OcTreeNode& node, std::vector<OcTre |
|
|
|
uvector3 nodeMid = node.aabb.center(); |
|
|
|
for (int i = 0; i < polyIntersectIndices.size(); ++i) { |
|
|
|
const int polyIntersectIndex = polyIntersectIndices[i]; |
|
|
|
const auto& poly = scene.tensors[polyIntersectIndex]; |
|
|
|
const auto& minimalRep = scene.minimalReps[polyIntersectIndex]; |
|
|
|
subIdx = 0; |
|
|
|
for (MultiLoop<3> j(0, 2); ~j; ++j, ++subIdx) { |
|
|
|
// if (!poly.aabb.intersect(subNodes[subIdx].aabb)) {
|
|
|
|
// // out of the subcell
|
|
|
|
// organizer::traverse(subNodes[subIdx].blobTree, polyIntersectIndex, false);
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
if (!minimalRep.aabb.intersect(subNodes[subIdx].aabb)) { |
|
|
|
// out of the subcell
|
|
|
|
organizer::traverse(subNodes[subIdx].blobTree, polyIntersectIndex, false); |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (subIdx == 1) { |
|
|
|
int aaa = 1; |
|
|
|
int bbb = 1; |
|
|
|
} |
|
|
|
tensor3 subcellPoly(nullptr, poly.ext()); |
|
|
|
tensor3 subcellPoly(nullptr, minimalRep.tensor.ext()); |
|
|
|
algoim_spark_alloc(real, subcellPoly); |
|
|
|
bernstein::deCasteljau(poly, subNodes[subIdx].aabb.min, subNodes[subIdx].aabb.max, subcellPoly); |
|
|
|
bernstein::deCasteljau(minimalRep.tensor, subNodes[subIdx].aabb.min, subNodes[subIdx].aabb.max, subcellPoly); |
|
|
|
int sign = bernstein::uniformSign(subcellPoly); |
|
|
|
if (sign == 1) { |
|
|
|
organizer::traverse(subNodes[subIdx].blobTree, polyIntersectIndex, false); |
|
|
@ -458,18 +463,36 @@ void basicTask(const std::vector<std::shared_ptr<PrimitiveDesc>>& primitives, in |
|
|
|
|
|
|
|
BasicTaskRes basicTask(const Scene& scene, const OcTreeNode& node, int q = 10) |
|
|
|
{ |
|
|
|
auto integrand = [](const uvector<real, 3>& x) { return 1.0; }; |
|
|
|
real volume = 0., surf = 0.; |
|
|
|
auto range = node.aabb.size(); |
|
|
|
ImplicitPolyQuadrature<3> ipquad(scene.tensors, node.polyIntersectIndices); |
|
|
|
if (node.polyIntersectIndices.size() == 0) { |
|
|
|
assert(node.blobTree.structure.back().inOut != NODE_IN_OUT_UNKNOWN); |
|
|
|
if (node.blobTree.structure.back().inOut == NODE_IN) { |
|
|
|
return {node.aabb.volume(), 0}; |
|
|
|
} else { |
|
|
|
return {0, 0}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
auto integrand = [](const uvector<real, 3>& x) { return 1.0; }; |
|
|
|
real volume = 0., surf = 0.; |
|
|
|
auto range = node.aabb.size(); |
|
|
|
std::vector<tensor3> phis; // phis using subcell as [0,1]^3
|
|
|
|
std::vector<SparkStack<real>*> phiStacks; |
|
|
|
for (int i = 0; i < node.polyIntersectIndices.size(); i++) { |
|
|
|
const auto& polyWithinScene = scene.minimalReps[node.polyIntersectIndices[i]].tensor; |
|
|
|
phis.emplace_back(tensor3(nullptr, polyWithinScene.ext())); |
|
|
|
phiStacks.emplace_back(algoim_spark_alloc_heap(real, phis.back())); |
|
|
|
bernstein::deCasteljau(polyWithinScene, node.aabb.min, node.aabb.max, phis.back()); |
|
|
|
} |
|
|
|
// ImplicitPolyQuadrature<3> ipquad(scene.minimalReps, node.polyIntersectIndices);
|
|
|
|
ImplicitPolyQuadrature<3> ipquad(phis); |
|
|
|
|
|
|
|
ipquad.integrate(AutoMixed, q, [&](const uvector<real, 3>& x, real w) { |
|
|
|
auto realX = x * range + node.aabb.min; |
|
|
|
if (keepQuadraturePoint(scene, node, realX)) { volume += w * integrand(realX); } |
|
|
|
auto realX = x * range + node.aabb.min; // 这里realX应该是最原始空间下的点?不过因为算体积,所以不影响
|
|
|
|
if (keepQuadraturePoint(phis, node, x)) { volume += w * integrand(realX); } |
|
|
|
}); |
|
|
|
ipquad.integrate_surf(AutoMixed, q, [&](const uvector<real, 3>& x, real w, const uvector<real, 3>& wn) { |
|
|
|
volume += w * integrand(x * range + node.aabb.min); |
|
|
|
}); |
|
|
|
return {volume, surf}; |
|
|
|
|
|
|
|
for (auto& p : phiStacks) delete p; |
|
|
|
return {volume * node.aabb.volume(), surf}; |
|
|
|
} |
|
|
|
|
|
|
|
void quadratureScene(const std::vector<std::shared_ptr<PrimitiveDesc>>& primitives, |
|
|
@ -513,7 +536,7 @@ void quadratureScene(const std::vector<std::shared_ptr<PrimitiveDesc>>& primitiv |
|
|
|
} |
|
|
|
visiblePrimitiveReps[i].aabb.normalize(range, xmin); |
|
|
|
} else if (auto pt = std::dynamic_pointer_cast<CylinderDesc>(primitives[i])) { |
|
|
|
visiblePrimitiveReps[i].tensors = {tensor3(nullptr, 3), tensor3(nullptr, 2), tensor3(nullptr, 2)}; |
|
|
|
visiblePrimitiveReps[i].tensors = {tensor3(nullptr, 3), tensor3(nullptr, 3), tensor3(nullptr, 3)}; |
|
|
|
auto& tensors = visiblePrimitiveReps[i].tensors; |
|
|
|
tensors[0].ext_(pt->alignAxis) = 1; |
|
|
|
algoimSparkAllocHeapVector(tensorStacks, tensors); |
|
|
@ -526,7 +549,7 @@ void quadratureScene(const std::vector<std::shared_ptr<PrimitiveDesc>>& primitiv |
|
|
|
} |
|
|
|
visiblePrimitiveReps[i].aabb.normalize(range, xmin); |
|
|
|
} else if (auto pt = std::dynamic_pointer_cast<ConeDesc>(primitives[i])) { |
|
|
|
visiblePrimitiveReps[i].tensors = {tensor3(nullptr, 3), tensor3(nullptr, 2), tensor3(nullptr, 2)}; |
|
|
|
visiblePrimitiveReps[i].tensors = {tensor3(nullptr, 3), tensor3(nullptr, 3), tensor3(nullptr, 3)}; |
|
|
|
auto& tensors = visiblePrimitiveReps[i].tensors; |
|
|
|
algoimSparkAllocHeapVector(tensorStacks, tensors); |
|
|
|
|
|
|
@ -542,9 +565,9 @@ void quadratureScene(const std::vector<std::shared_ptr<PrimitiveDesc>>& primitiv |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<tensor3> realPrimitives; |
|
|
|
std::vector<MinimalPrimitiveRep> minimalReps; |
|
|
|
/*** merge subtrees to main tree ***/ |
|
|
|
std::vector<int> realLeafIndices; |
|
|
|
std::vector<int> realLeafIndices; |
|
|
|
for (int i = 0; i < visiblePrimitiveReps.size() - 1; ++i) { |
|
|
|
// 必须以自左向右的顺序访问所有叶节点
|
|
|
|
assert(blobTree.primitiveNodeIdx[i] < blobTree.primitiveNodeIdx[i + 1]); |
|
|
@ -574,26 +597,33 @@ void quadratureScene(const std::vector<std::shared_ptr<PrimitiveDesc>>& primitiv |
|
|
|
for (auto primitiveIdx : visiblePrimitiveReps[i].subBlobTree.primitiveNodeIdx) { |
|
|
|
realLeafIndices.push_back(primitiveIdx + originLeafIdx); |
|
|
|
} |
|
|
|
|
|
|
|
realPrimitives.insert(realPrimitives.end(), visiblePrimitiveReps[i].tensors.begin(), |
|
|
|
visiblePrimitiveReps[i].tensors.end()); |
|
|
|
minimalReps.reserve(minimalReps.size() + visiblePrimitiveReps[i].tensors.size()); |
|
|
|
const auto& aabb = visiblePrimitiveReps[i].aabb; |
|
|
|
for (const auto& tensor : visiblePrimitiveReps[i].tensors) { |
|
|
|
minimalReps.emplace_back(MinimalPrimitiveRep{tensor, aabb}); |
|
|
|
} |
|
|
|
} else { |
|
|
|
blobTree.structure[originLeafIdx].isPrimitive = true; |
|
|
|
realLeafIndices.push_back(originLeafIdx); |
|
|
|
realPrimitives.emplace_back(visiblePrimitiveReps[i].tensors[0]); |
|
|
|
minimalReps.emplace_back(MinimalPrimitiveRep{visiblePrimitiveReps[i].tensors[0], visiblePrimitiveReps[i].aabb}); |
|
|
|
} |
|
|
|
} |
|
|
|
blobTree.primitiveNodeIdx = realLeafIndices; |
|
|
|
/*** merge subtrees to main tree ***/ |
|
|
|
Scene scene{realPrimitives, AABB(xmin, xmax)}; |
|
|
|
Scene scene{minimalReps, AABB(xmin, xmax)}; |
|
|
|
OcTreeNode rootNode(0, 1, blobTree); |
|
|
|
for (int i = 0; i < realPrimitives.size(); ++i) { rootNode.polyIntersectIndices.emplace_back(i); } |
|
|
|
for (int i = 0; i < minimalReps.size(); ++i) { rootNode.polyIntersectIndices.emplace_back(i); } |
|
|
|
int cnt = 1; |
|
|
|
buildOcTreeV0(scene, rootNode, leaves, 1, cnt); |
|
|
|
|
|
|
|
basicTask(scene, leaves[14], q); |
|
|
|
|
|
|
|
int i = 0; |
|
|
|
for (const auto& leaf : leaves) { |
|
|
|
auto basicRes = basicTask(scene, leaf, q); |
|
|
|
volume += basicRes.volume * prod(leaf.aabb.max - leaf.aabb.min); |
|
|
|
auto basicRes = basicTask(scene, leaf, q); |
|
|
|
if (std::isinf(basicRes.volume)) { std::cout << "inf volume when solving leaf: " << i << std::endl; } |
|
|
|
volume += basicRes.volume; |
|
|
|
std::cout << "Solved leaves: " << ++i << "/" << leaves.size() << std::endl; |
|
|
|
} |
|
|
|
|
|
|
|
volume *= prod(xmax - xmin); |
|
|
|