Skip to content

Commit

Permalink
Merge pull request #4 from yamahigashi/develop
Browse files Browse the repository at this point in the history
Added collision mode
  • Loading branch information
yamahigashi authored Aug 5, 2023
2 parents 5f88b10 + e0520ad commit 99b2b47
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 58 deletions.
2 changes: 1 addition & 1 deletion src/intersectionMarkerDrawOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ void IntersectionMarkerDrawOverride::addUIDrawables(
return;
}

drawManager.beginDrawable();
drawManager.beginDrawable(MHWRender::MUIDrawManager::kNonSelectable);
{
// drawManager.setLineWidth(2.0f);
drawManager.setLineStyle(MUIDrawManager::kSolid);
Expand Down
76 changes: 52 additions & 24 deletions src/intersectionMarkerNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ MObject IntersectionMarkerNode::restIntersected;
MObject IntersectionMarkerNode::vertexChecksumA;
MObject IntersectionMarkerNode::vertexChecksumB;
MObject IntersectionMarkerNode::kernelType;
MObject IntersectionMarkerNode::collisionMode;

MObject IntersectionMarkerNode::outputIntersected;
CacheType IntersectionMarkerNode::cache(CACHE_SIZE);
Expand Down Expand Up @@ -129,6 +130,14 @@ MStatus IntersectionMarkerNode::initialize()
status = addAttribute(kernelType);
CHECK_MSTATUS_AND_RETURN_IT(status);

// Initialize Collision mode
collisionMode = eAttr.create(COLLISION_MODE, COLLISION_MODE, 0, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);
eAttr.addField("Kernel to Triangle", 0);
eAttr.addField("Kernel to Kernel", 1);
status = addAttribute(collisionMode);
CHECK_MSTATUS_AND_RETURN_IT(status);

// Initialize Output Intersected
outputIntersected = nAttr.create(OUTPUT_INTERSECTED, OUTPUT_INTERSECTED, MFnNumericData::kBoolean, 0);
nAttr.setStorable(true);
Expand All @@ -151,6 +160,7 @@ MStatus IntersectionMarkerNode::initialize()
CHECK_MSTATUS_AND_RETURN_IT(status);

status = attributeAffects(kernelType, outputIntersected);
status = attributeAffects(collisionMode, outputIntersected);
CHECK_MSTATUS_AND_RETURN_IT(status);

return MS::kSuccess;
Expand Down Expand Up @@ -179,6 +189,9 @@ MStatus IntersectionMarkerNode::preEvaluation(
dirty = dirty || evaluationNode.dirtyPlugExists(kernelType, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);

dirty = dirty || evaluationNode.dirtyPlugExists(collisionMode, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);

if (dirty) {
MHWRender::MRenderer::setGeometryDrawDirty(thisMObject());
}
Expand Down Expand Up @@ -208,7 +221,8 @@ MStatus IntersectionMarkerNode::postEvaluation(
(evaluationNode.dirtyPlugExists(meshB, &status) && status ) ||
(evaluationNode.dirtyPlugExists(offsetMatrixA, &status) && status ) ||
(evaluationNode.dirtyPlugExists(offsetMatrixB, &status) && status ) ||
(evaluationNode.dirtyPlugExists(kernelType, &status) && status )
(evaluationNode.dirtyPlugExists(kernelType, &status) && status ) ||
(evaluationNode.dirtyPlugExists(collisionMode, &status) && status )
) {
MDataBlock block = forceCache();
MDataHandle meshAHandle = block.inputValue(meshA, &status);
Expand Down Expand Up @@ -308,38 +322,52 @@ MStatus IntersectionMarkerNode::compute(const MPlug &plug, MDataBlock &dataBlock

// Build kernel A
std::shared_ptr<SpatialDivisionKernel> kernelA = getActiveKernel();
MBoundingBox bbox = getBoundingBox(meshA);
bbox.transformUsing(offsetA);
status = kernelA->build(meshAObject, bbox, offsetA);
MBoundingBox bboxA = getBoundingBox(meshA);
bboxA.transformUsing(offsetA);
status = kernelA->build(meshAObject, bboxA, offsetA);
CHECK_MSTATUS_AND_RETURN_IT(status);

// check intersections
MDataHandle modeHandle = dataBlock.inputValue(collisionMode, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);
bool mode = modeHandle.asBool();
if (mode == 0) {
// Kernel A vs Mesh B Triangles
// check intersections
status = checkIntersections(meshAObject, meshBObject, kernelA, offsetB);
if(status != MStatus::kSuccess) {
MGlobal::displayError("Failed to get offset data handle");
return status;
}

status = checkIntersections(meshAObject, meshBObject, kernelA, offsetB);
if(status != MStatus::kSuccess) {
MGlobal::displayError("Failed to get offset data handle");
return status;
}
} else if (mode == 1) {
// Kernel A vs Kernel B
//
// Build kernel B
std::shared_ptr<SpatialDivisionKernel> kernelB = getActiveKernel();
MBoundingBox bboxB = getBoundingBox(meshB);
bboxB.transformUsing(offsetB);
status = kernelB->build(meshBObject, bboxB, offsetB);
CHECK_MSTATUS_AND_RETURN_IT(status);

K2KIntersection pairs = kernelA->intersectKernelKernel(*kernelB);
for (auto pair : pairs.first) {
this->intersectedFaceIdsA.insert(pair.faceIndex);
}
for (auto pair : pairs.second) {
this->intersectedFaceIdsB.insert(pair.faceIndex);
}

// Build kernel B
// std::shared_ptr<SpatialDivisionKernel> kernelB = getActiveKernel();
// bbox = getBoundingBox(meshB);
// bbox.transformUsing(offsetB);
// status = kernelB->build(meshBObject, bbox, offsetB.inverse());
// CHECK_MSTATUS_AND_RETURN_IT(status);

// K2KIntersection pairs = kernel->intersectKernelKernel(*kernelB);
// for (auto pair : pairs.first) {
// this->intersectedFaceIdsA.insert(pair.faceIndex);
// }
// for (auto pair : pairs.second) {
// this->intersectedFaceIdsB.insert(pair.faceIndex);
// }
} else {
modeHandle.setClean();
MGlobal::displayError("Invalid collision mode");
return MStatus::kFailure;
}

// -------------------------------------------------------------------------------------------
// Store the result in the cache
CacheResultType res{this->intersectedFaceIdsA, this->intersectedFaceIdsB};
this->cache.put(key, res);
modeHandle.setClean();
}

// Get output data handle
Expand Down
2 changes: 2 additions & 0 deletions src/intersectionMarkerNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#define VERTEX_CHECKSUM_B "vertexChecksumB"

#define KERNEL "kernel"
#define COLLISION_MODE "collisionMode"
#define OUTPUT_INTERSECTED "outputIntersected"
#define OUT_MESH "outMesh"
#define CACHE_SIZE 10000
Expand Down Expand Up @@ -153,6 +154,7 @@ std::shared_ptr<SpatialDivisionKernel> getActiveKernel() const;
static MObject vertexChecksumA;
static MObject vertexChecksumB;
static MObject kernelType;
static MObject collisionMode;

static MObject outputIntersected;

Expand Down
110 changes: 77 additions & 33 deletions src/kernel/OctreeKernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,34 @@ void OctreeKernel::splitNode(OctreeNode* node)

// Move triangles to child nodes
for (const TriangleData& triangle : node->triangles) {
bool inserted = false;
for (int i = 0; i < 8; ++i) {
if (boxContainsAnyVertices(boxes[i], triangle)) {
if (boxContainsAllVertices(boxes[i], triangle)) {
node->children[i]->triangles.push_back(triangle);
inserted = true;
break;
}
}

if (!inserted) {
// most likely the triangle is outside the bounding box
// treat nearest child as the one that contains the center of gravity

MPoint baryCenter = (
triangle.vertices[0] +
triangle.vertices[1] +
triangle.vertices[2]) / 3.0;

int nearestChild = 0;
double minDistance = (boxes[0].center() - baryCenter).length();
for (int i = 1; i < 8; ++i) {
double distance = (boxes[i].center() - baryCenter).length();
if (distance < minDistance) {
minDistance = distance;
nearestChild = i;
}
}
node->children[nearestChild]->triangles.push_back(triangle);
}
}

Expand Down Expand Up @@ -185,54 +209,74 @@ void OctreeKernel::clear(OctreeNode* node)
}


void intersectOctreeNodesRecursive(
OctreeNode* nodeA,
OctreeNode* nodeB,
std::vector<std::pair<OctreeNode*, OctreeNode*>>& intersectedNodes
) {
if (!nodeA->boundingBox.intersects(nodeB->boundingBox)) {
return;
}

if (nodeA->isLeaf() && nodeB->isLeaf()) {
intersectedNodes.push_back(std::make_pair(nodeA, nodeB));
} else {
if (nodeA->isLeaf()) {
for (int i = 0; i < 8; ++i) {
if (nodeB->children[i] != nullptr) {
intersectOctreeNodesRecursive(nodeA, nodeB->children[i], intersectedNodes);
}
}
} else if (nodeB->isLeaf()) {
for (int i = 0; i < 8; ++i) {
if (nodeA->children[i] != nullptr) {
intersectOctreeNodesRecursive(nodeA->children[i], nodeB, intersectedNodes);
}
}
} else {
for (int i = 0; i < 8; ++i) {
for (int j = 0; j < 8; ++j) {
if (nodeA->children[i] != nullptr && nodeB->children[j] != nullptr) {
intersectOctreeNodesRecursive(nodeA->children[i], nodeB->children[j], intersectedNodes);
}
}
}
}
}
}


K2KIntersection OctreeKernel::intersectKernelKernel(
SpatialDivisionKernel& otherKernel
) const {

std::vector<TriangleData> intersectedTriangles;
std::vector<TriangleData> otherIntersectedTriangles;
std::vector<TriangleData> intersectedTrianglesA;
std::vector<TriangleData> intersectedTrianglesB;

OctreeKernel* other = dynamic_cast<OctreeKernel*>(&otherKernel);
if (other == nullptr) {
MGlobal::displayError("Cannot intersect octree with other kernel type!");
return std::make_pair(intersectedTriangles, otherIntersectedTriangles);
return std::make_pair(intersectedTrianglesA, intersectedTrianglesB);
}

std::vector<std::pair<OctreeNode*, OctreeNode*>> intersectedNodes;
intersectOctreeNodesRecursive(this->root, other->root, intersectedNodes);

std::queue<std::pair<OctreeNode*, OctreeNode*>> nodesToCheck;

if (this->root != nullptr && other->root != nullptr) {
nodesToCheck.push(std::make_pair(this->root, other->root));
}

while (!nodesToCheck.empty()) {
std::pair<OctreeNode*, OctreeNode*> currentNodes = nodesToCheck.front();
nodesToCheck.pop();
for (const auto& pair : intersectedNodes) {
OctreeNode* nodeA = pair.first;
OctreeNode* nodeB = pair.second;

if (currentNodes.first->boundingBox.intersects(currentNodes.second->boundingBox)) {
if (currentNodes.first->isLeaf() && currentNodes.second->isLeaf()) {
// If both nodes are leaves and their bounding boxes intersect,
// then all their triangles are considered as intersected triangles
std::copy(
currentNodes.first->triangles.begin(),
currentNodes.first->triangles.end(),
std::back_inserter(intersectedTriangles)
);
std::copy(
currentNodes.second->triangles.begin(),
currentNodes.second->triangles.end(),
std::back_inserter(otherIntersectedTriangles)
);
} else {
// If one of the nodes is not a leaf, then check its children
for (int i = 0; i < 8; ++i) {
if (currentNodes.first->children[i] != nullptr && currentNodes.second->children[i] != nullptr) {
nodesToCheck.push(std::make_pair(currentNodes.first->children[i], currentNodes.second->children[i]));
if (nodeA->isLeaf() && nodeB->isLeaf()) {
for (TriangleData triA : nodeA->triangles) {
for (TriangleData triB : nodeB->triangles) {
if (intersectTriangleTriangle(triA, triB)) {
intersectedTrianglesA.push_back(triA);
intersectedTrianglesB.push_back(triB);
}
}
}
}
}

return std::make_pair(intersectedTriangles, otherIntersectedTriangles);
return std::make_pair(intersectedTrianglesA, intersectedTrianglesB);
}
13 changes: 13 additions & 0 deletions src/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,19 @@ static inline bool boxContainsAnyVertices (
}


static inline bool boxContainsAllVertices (
const MBoundingBox& box,
const TriangleData& triangle
) {
for (const MPoint& vertex : triangle.vertices) {
if (!box.contains(vertex)) {
return false;
}
}
return true;
}


static inline bool intersectBoxTriangle (
const MBoundingBox& box,
const TriangleData& triangle
Expand Down

0 comments on commit 99b2b47

Please sign in to comment.