mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 07:47:30 +02:00
Merge pull request #16072 from luiscuenca/improveSphereCollapsing
BUGZ-1156: Improve sphere collapsing mode
This commit is contained in:
commit
4d71891763
2 changed files with 246 additions and 112 deletions
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "MultiSphereShape.h"
|
#include "MultiSphereShape.h"
|
||||||
|
#include "PhysicsLogging.h"
|
||||||
|
|
||||||
void SphereRegion::translate(const glm::vec3& translation) {
|
void SphereRegion::translate(const glm::vec3& translation) {
|
||||||
for (auto &line : _lines) {
|
for (auto &line : _lines) {
|
||||||
|
@ -90,8 +91,8 @@ void SphereRegion::extractSphereRegion(std::vector<std::pair<glm::vec3, glm::vec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CollisionShapeExtractionMode MultiSphereShape::getExtractionModeByName(const QString& name) {
|
MultiSphereShape::ExtractionMode MultiSphereShape::getExtractionModeByJointName(const QString& name) {
|
||||||
CollisionShapeExtractionMode mode = CollisionShapeExtractionMode::Automatic;
|
ExtractionMode mode = ExtractionMode::Automatic;
|
||||||
bool isSim = name.indexOf("SIM") == 0;
|
bool isSim = name.indexOf("SIM") == 0;
|
||||||
bool isFlow = name.indexOf("FLOW") == 0;
|
bool isFlow = name.indexOf("FLOW") == 0;
|
||||||
bool isEye = name.indexOf("EYE") > -1;
|
bool isEye = name.indexOf("EYE") > -1;
|
||||||
|
@ -105,13 +106,13 @@ CollisionShapeExtractionMode MultiSphereShape::getExtractionModeByName(const QSt
|
||||||
|
|
||||||
//bool isFinger =
|
//bool isFinger =
|
||||||
if (isNeck || isLeftFinger || isRightFinger) {
|
if (isNeck || isLeftFinger || isRightFinger) {
|
||||||
mode = CollisionShapeExtractionMode::SpheresY;
|
mode = ExtractionMode::SpheresY;
|
||||||
} else if (isShoulder) {
|
} else if (isShoulder) {
|
||||||
mode = CollisionShapeExtractionMode::SphereCollapse;
|
mode = ExtractionMode::SphereCollapse;
|
||||||
} else if (isRightHand || isLeftHand) {
|
} else if (isRightHand || isLeftHand) {
|
||||||
mode = CollisionShapeExtractionMode::SpheresXY;
|
mode = ExtractionMode::SpheresXY;
|
||||||
} else if (isSim || isFlow || isEye || isToe) {
|
} else if (isSim || isFlow || isEye || isToe) {
|
||||||
mode = CollisionShapeExtractionMode::None;
|
mode = ExtractionMode::None;
|
||||||
}
|
}
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
@ -130,19 +131,33 @@ void MultiSphereShape::filterUniquePoints(const std::vector<btVector3>& kdop, st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MultiSphereShape::computeMultiSphereShape(int jointIndex, const QString& name, const std::vector<btVector3>& kdop, float scale) {
|
bool MultiSphereShape::computeMultiSphereShape(int jointIndex, const QString& jointName, const std::vector<btVector3>& kdop, float scale) {
|
||||||
_scale = scale;
|
_scale = scale;
|
||||||
_jointIndex = jointIndex;
|
_jointIndex = jointIndex;
|
||||||
_name = name;
|
_jointName = jointName;
|
||||||
_mode = getExtractionModeByName(_name);
|
auto mode = getExtractionModeByJointName(_jointName);
|
||||||
if (_mode == CollisionShapeExtractionMode::None || kdop.size() < 4) {
|
KdopData kdopData = getKdopData(kdop);
|
||||||
|
if (kdop.size() < 4 || mode == ExtractionMode::None || !kdopData._isValidShape) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool needRecompute = true;
|
||||||
|
while (needRecompute) {
|
||||||
|
CollapsingMode collapsingMode = computeSpheres(mode, kdopData);
|
||||||
|
needRecompute = collapsingMode != CollapsingMode::None;
|
||||||
|
if (needRecompute) {
|
||||||
|
mode = (CollapsingMode)collapsingMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mode != ExtractionMode::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiSphereShape::KdopData MultiSphereShape::getKdopData(const std::vector<btVector3>& kdop) {
|
||||||
|
KdopData data;
|
||||||
std::vector<glm::vec3> points;
|
std::vector<glm::vec3> points;
|
||||||
filterUniquePoints(kdop, points);
|
filterUniquePoints(kdop, points);
|
||||||
glm::vec3 min = glm::vec3(100.0f, 100.0f, 100.0f);
|
glm::vec3 min = glm::vec3(100.0f, 100.0f, 100.0f);
|
||||||
glm::vec3 max = glm::vec3(-100.0f, -100.0f, -100.0f);
|
glm::vec3 max = glm::vec3(-100.0f, -100.0f, -100.0f);
|
||||||
_midPoint = glm::vec3(0.0f, 0.0f, 0.0f);
|
data._origin = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||||
std::vector<glm::vec3> relPoints;
|
std::vector<glm::vec3> relPoints;
|
||||||
for (size_t i = 0; i < points.size(); i++) {
|
for (size_t i = 0; i < points.size(); i++) {
|
||||||
|
|
||||||
|
@ -154,97 +169,111 @@ bool MultiSphereShape::computeMultiSphereShape(int jointIndex, const QString& na
|
||||||
max.y = points[i].y > max.y ? points[i].y : max.y;
|
max.y = points[i].y > max.y ? points[i].y : max.y;
|
||||||
max.z = points[i].z > max.z ? points[i].z : max.z;
|
max.z = points[i].z > max.z ? points[i].z : max.z;
|
||||||
|
|
||||||
_midPoint += points[i];
|
data._origin += points[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
_midPoint /= (int)points.size();
|
data._origin /= (int)points.size();
|
||||||
glm::vec3 dimensions = max - min;
|
glm::vec3& dimensions = data._dimensions;
|
||||||
|
dimensions = max - min;
|
||||||
if (glm::length(dimensions) == 0.0f) {
|
if (glm::length(dimensions) == 0.0f) {
|
||||||
return false;
|
data._isValidShape = false;
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < points.size(); i++) {
|
for (size_t i = 0; i < points.size(); i++) {
|
||||||
glm::vec3 relPoint = points[i] - _midPoint;
|
glm::vec3 relPoint = points[i] - data._origin;
|
||||||
relPoints.push_back(relPoint);
|
data._relativePoints.push_back(relPoint);
|
||||||
}
|
}
|
||||||
CollisionShapeExtractionMode applyMode = _mode;
|
glm::vec3 corrector;
|
||||||
float xCorrector = dimensions.x > dimensions.y && dimensions.x > dimensions.z ? -1.0f + (dimensions.x / (0.5f * (dimensions.y + dimensions.z))) : 0.0f;
|
|
||||||
float yCorrector = dimensions.y > dimensions.x && dimensions.y > dimensions.z ? -1.0f + (dimensions.y / (0.5f * (dimensions.x + dimensions.z))) : 0.0f;
|
corrector.x = dimensions.x > dimensions.y && dimensions.x > dimensions.z ? -1.0f + (dimensions.x / (0.5f * (dimensions.y + dimensions.z))) : 0.0f;
|
||||||
float zCorrector = dimensions.z > dimensions.x && dimensions.z > dimensions.y ? -1.0f + (dimensions.z / (0.5f * (dimensions.x + dimensions.y))) : 0.0f;
|
corrector.y = dimensions.y > dimensions.x && dimensions.y > dimensions.z ? -1.0f + (dimensions.y / (0.5f * (dimensions.x + dimensions.z))) : 0.0f;
|
||||||
|
corrector.z = dimensions.z > dimensions.x && dimensions.z > dimensions.y ? -1.0f + (dimensions.z / (0.5f * (dimensions.x + dimensions.y))) : 0.0f;
|
||||||
|
|
||||||
float xyDif = glm::abs(dimensions.x - dimensions.y);
|
KdopCoefficient& diff = data._diff;
|
||||||
float xzDif = glm::abs(dimensions.x - dimensions.z);
|
diff.xy = glm::abs(dimensions.x - dimensions.y);
|
||||||
float yzDif = glm::abs(dimensions.y - dimensions.z);
|
diff.xz = glm::abs(dimensions.x - dimensions.z);
|
||||||
|
diff.yz = glm::abs(dimensions.y - dimensions.z);
|
||||||
|
|
||||||
float xyEpsilon = (0.05f + zCorrector) * glm::max(dimensions.x, dimensions.y);
|
KdopCoefficient& epsilon = data._epsilon;
|
||||||
float xzEpsilon = (0.05f + yCorrector) * glm::max(dimensions.x, dimensions.z);
|
epsilon.xy = (0.05f + corrector.z) * glm::max(dimensions.x, dimensions.y);
|
||||||
float yzEpsilon = (0.05f + xCorrector) * glm::max(dimensions.y, dimensions.z);
|
epsilon.xz = (0.05f + corrector.y) * glm::max(dimensions.x, dimensions.z);
|
||||||
|
epsilon.yz = (0.05f + corrector.x) * glm::max(dimensions.y, dimensions.z);
|
||||||
|
|
||||||
if (xyDif < 0.5f * xyEpsilon && xzDif < 0.5f * xzEpsilon && yzDif < 0.5f * yzEpsilon) {
|
return data;
|
||||||
applyMode = CollisionShapeExtractionMode::Sphere;
|
}
|
||||||
} else if (xzDif < xzEpsilon) {
|
|
||||||
applyMode = dimensions.y > dimensions.z ? CollisionShapeExtractionMode::SpheresY : CollisionShapeExtractionMode::SpheresXZ;
|
MultiSphereShape::CollapsingMode MultiSphereShape::computeSpheres(ExtractionMode mode, const KdopData& data) {
|
||||||
} else if (xyDif < xyEpsilon) {
|
_mode = mode;
|
||||||
applyMode = dimensions.z > dimensions.y ? CollisionShapeExtractionMode::SpheresZ : CollisionShapeExtractionMode::SpheresXY;
|
_midPoint = data._origin;
|
||||||
} else if (yzDif < yzEpsilon) {
|
ExtractionMode applyMode = mode;
|
||||||
applyMode = dimensions.x > dimensions.y ? CollisionShapeExtractionMode::SpheresX : CollisionShapeExtractionMode::SpheresYZ;
|
_spheres.clear();
|
||||||
|
auto& diff = data._diff;
|
||||||
|
auto& epsilon = data._epsilon;
|
||||||
|
auto& dimensions = data._dimensions;
|
||||||
|
|
||||||
|
if (_mode == ExtractionMode::Automatic) {
|
||||||
|
if (diff.xy < 0.5f * epsilon.xy && diff.xz < 0.5f * epsilon.xz && diff.yz < 0.5f * epsilon.yz) {
|
||||||
|
applyMode =ExtractionMode::Sphere;
|
||||||
|
} else if (diff.xz < epsilon.xz) {
|
||||||
|
applyMode = dimensions.y > dimensions.z ? ExtractionMode::SpheresY : ExtractionMode::SpheresXZ;
|
||||||
|
} else if (diff.xy < epsilon.xy) {
|
||||||
|
applyMode = dimensions.z > dimensions.y ? ExtractionMode::SpheresZ : ExtractionMode::SpheresXY;
|
||||||
|
} else if (diff.yz < epsilon.yz) {
|
||||||
|
applyMode = dimensions.x > dimensions.y ? ExtractionMode::SpheresX : ExtractionMode::SpheresYZ;
|
||||||
|
} else {
|
||||||
|
applyMode = ExtractionMode::SpheresXYZ;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
applyMode = CollisionShapeExtractionMode::SpheresXYZ;
|
applyMode = _mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_mode != CollisionShapeExtractionMode::Automatic && applyMode != _mode) {
|
|
||||||
bool isModeSphereAxis = (_mode >= CollisionShapeExtractionMode::SpheresX && _mode <= CollisionShapeExtractionMode::SpheresZ);
|
|
||||||
bool isApplyModeComplex = (applyMode >= CollisionShapeExtractionMode::SpheresXY && applyMode <= CollisionShapeExtractionMode::SpheresXYZ);
|
|
||||||
applyMode = (isModeSphereAxis && isApplyModeComplex) ? CollisionShapeExtractionMode::Sphere : _mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<glm::vec3> axes;
|
std::vector<glm::vec3> axes;
|
||||||
glm::vec3 axis, axis1, axis2;
|
glm::vec3 axis, axis1, axis2;
|
||||||
SphereShapeData sphere;
|
SphereData sphere;
|
||||||
switch (applyMode) {
|
switch (applyMode) {
|
||||||
case CollisionShapeExtractionMode::None:
|
case ExtractionMode::None:
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::Automatic:
|
case ExtractionMode::Automatic:
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::Box:
|
case ExtractionMode::Box:
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::Sphere:
|
case ExtractionMode::Sphere:
|
||||||
sphere._radius = 0.5f * (dimensions.x + dimensions.y + dimensions.z) / 3.0f;
|
sphere._radius = 0.5f * (dimensions.x + dimensions.y + dimensions.z) / 3.0f;
|
||||||
sphere._position = glm::vec3(0.0f);
|
sphere._position = glm::vec3(0.0f);
|
||||||
_spheres.push_back(sphere);
|
_spheres.push_back(sphere);
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::SphereCollapse:
|
case ExtractionMode::SphereCollapse:
|
||||||
sphere._radius = 0.5f * glm::min(glm::min(dimensions.x, dimensions.y), dimensions.z);
|
sphere._radius = 0.5f * glm::min(glm::min(dimensions.x, dimensions.y), dimensions.z);
|
||||||
sphere._position = glm::vec3(0.0f);
|
sphere._position = glm::vec3(0.0f);
|
||||||
_spheres.push_back(sphere);
|
_spheres.push_back(sphere);
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::SpheresX:
|
case ExtractionMode::SpheresX:
|
||||||
axis = 0.5f* dimensions.x * Vectors::UNIT_NEG_X;
|
axis = 0.5f* dimensions.x * Vectors::UNIT_NEG_X;
|
||||||
axes = { axis, -axis };
|
axes = { axis, -axis };
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::SpheresY:
|
case ExtractionMode::SpheresY:
|
||||||
axis = 0.5f* dimensions.y * Vectors::UNIT_NEG_Y;
|
axis = 0.5f* dimensions.y * Vectors::UNIT_NEG_Y;
|
||||||
axes = { axis, -axis };
|
axes = { axis, -axis };
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::SpheresZ:
|
case ExtractionMode::SpheresZ:
|
||||||
axis = 0.5f* dimensions.z * Vectors::UNIT_NEG_Z;
|
axis = 0.5f* dimensions.z * Vectors::UNIT_NEG_Z;
|
||||||
axes = { axis, -axis };
|
axes = { axis, -axis };
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::SpheresXY:
|
case ExtractionMode::SpheresXY:
|
||||||
axis1 = glm::vec3(0.5f * dimensions.x, 0.5f * dimensions.y, 0.0f);
|
axis1 = glm::vec3(0.5f * dimensions.x, 0.5f * dimensions.y, 0.0f);
|
||||||
axis2 = glm::vec3(0.5f * dimensions.x, -0.5f * dimensions.y, 0.0f);
|
axis2 = glm::vec3(0.5f * dimensions.x, -0.5f * dimensions.y, 0.0f);
|
||||||
axes = { axis1, axis2, -axis1, -axis2 };
|
axes = { axis1, axis2, -axis1, -axis2 };
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::SpheresYZ:
|
case ExtractionMode::SpheresYZ:
|
||||||
axis1 = glm::vec3(0.0f, 0.5f * dimensions.y, 0.5f * dimensions.z);
|
axis1 = glm::vec3(0.0f, 0.5f * dimensions.y, 0.5f * dimensions.z);
|
||||||
axis2 = glm::vec3(0.0f, 0.5f * dimensions.y, -0.5f * dimensions.z);
|
axis2 = glm::vec3(0.0f, 0.5f * dimensions.y, -0.5f * dimensions.z);
|
||||||
axes = { axis1, axis2, -axis1, -axis2 };
|
axes = { axis1, axis2, -axis1, -axis2 };
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::SpheresXZ:
|
case ExtractionMode::SpheresXZ:
|
||||||
axis1 = glm::vec3(0.5f * dimensions.x, 0.0f, 0.5f * dimensions.z);
|
axis1 = glm::vec3(0.5f * dimensions.x, 0.0f, 0.5f * dimensions.z);
|
||||||
axis2 = glm::vec3(-0.5f * dimensions.x, 0.0f, 0.5f * dimensions.z);
|
axis2 = glm::vec3(-0.5f * dimensions.x, 0.0f, 0.5f * dimensions.z);
|
||||||
axes = { axis1, axis2, -axis1, -axis2 };
|
axes = { axis1, axis2, -axis1, -axis2 };
|
||||||
break;
|
break;
|
||||||
case CollisionShapeExtractionMode::SpheresXYZ:
|
case ExtractionMode::SpheresXYZ:
|
||||||
for (size_t i = 0; i < CORNER_SIGNS.size(); i++) {
|
for (size_t i = 0; i < CORNER_SIGNS.size(); i++) {
|
||||||
axes.push_back(0.5f * (dimensions * CORNER_SIGNS[i]));
|
axes.push_back(0.5f * (dimensions * CORNER_SIGNS[i]));
|
||||||
}
|
}
|
||||||
|
@ -252,24 +281,113 @@ bool MultiSphereShape::computeMultiSphereShape(int jointIndex, const QString& na
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
CollapsingMode collapsingMode = CollapsingMode::None;
|
||||||
if (axes.size() > 0) {
|
if (axes.size() > 0) {
|
||||||
spheresFromAxes(relPoints, axes, _spheres);
|
collapsingMode = spheresFromAxes(data._relativePoints, axes, _spheres);
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < _spheres.size(); i++) {
|
for (size_t i = 0; i < _spheres.size(); i++) {
|
||||||
_spheres[i]._position += _midPoint;
|
_spheres[i]._position += _midPoint;
|
||||||
}
|
}
|
||||||
|
// computing fails if the shape needs to be collapsed
|
||||||
return _mode != CollisionShapeExtractionMode::None;
|
return collapsingMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiSphereShape::spheresFromAxes(const std::vector<glm::vec3>& points, const std::vector<glm::vec3>& axes, std::vector<SphereShapeData>& spheres) {
|
MultiSphereShape::CollapsingMode MultiSphereShape::getNextCollapsingMode(ExtractionMode mode, const std::vector<SphereData>& spheres) {
|
||||||
|
auto collapsingMode = CollapsingMode::None;
|
||||||
|
int collapseCount = 0;
|
||||||
|
glm::vec3 collapseVector;
|
||||||
|
for (size_t i = 0; i < spheres.size() - 1; i++) {
|
||||||
|
for (size_t j = i + 1; j < spheres.size(); j++) {
|
||||||
|
size_t maxRadiusIndex = spheres[i]._radius > spheres[j]._radius ? i : j;
|
||||||
|
auto pairVector = spheres[i]._position - spheres[j]._position;
|
||||||
|
if (glm::length(pairVector) < 0.2f * spheres[maxRadiusIndex]._radius) {
|
||||||
|
collapseCount++;
|
||||||
|
collapseVector += spheres[i]._axis - spheres[j]._axis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collapseCount > 0) {
|
||||||
|
float collapseDistance = glm::length(collapseVector);
|
||||||
|
bool allSpheresCollapse = collapseDistance < EPSILON;
|
||||||
|
if (allSpheresCollapse) {
|
||||||
|
collapsingMode = CollapsingMode::Sphere;
|
||||||
|
} else {
|
||||||
|
collapseVector = glm::normalize(collapseVector);
|
||||||
|
bool alongAxis = collapseVector.x == 1.0f || collapseVector.y == 1.0f || collapseVector.z == 1.0f;
|
||||||
|
bool alongPlane = collapseVector.x == 0.0f || collapseVector.y == 0.0f || collapseVector.z == 0.0f;
|
||||||
|
int halfSphere3DCount = 4;
|
||||||
|
int halfSphere2DCount = 2;
|
||||||
|
bool modeSpheres3D = mode == ExtractionMode::SpheresXYZ;
|
||||||
|
bool modeSpheres2D = mode == ExtractionMode::SpheresXY ||
|
||||||
|
mode == ExtractionMode::SpheresYZ ||
|
||||||
|
mode == ExtractionMode::SpheresXZ;
|
||||||
|
bool modeSpheres1D = mode == ExtractionMode::SpheresX ||
|
||||||
|
mode == ExtractionMode::SpheresY ||
|
||||||
|
mode == ExtractionMode::SpheresZ;
|
||||||
|
// SpheresXYZ will collapse along XY YZ XZ planes or X Y Z axes.
|
||||||
|
// SpheresXY, SpheresYZ and Spheres XZ will collapse only along X Y Z axes.
|
||||||
|
// Other occurences will be collapsed to a single sphere.
|
||||||
|
bool isCollapseValid = (modeSpheres3D && (alongAxis || alongPlane)) ||
|
||||||
|
(modeSpheres2D && (alongAxis));
|
||||||
|
bool collapseToSphere = !isCollapseValid || (modeSpheres3D && collapseCount > halfSphere3DCount) ||
|
||||||
|
(modeSpheres2D && collapseCount > halfSphere2DCount) ||
|
||||||
|
modeSpheres1D;
|
||||||
|
if (collapseToSphere) {
|
||||||
|
collapsingMode = CollapsingMode::Sphere;
|
||||||
|
} else if (modeSpheres3D) {
|
||||||
|
if (alongAxis) {
|
||||||
|
if (collapseVector.x == 1.0f) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresYZ;
|
||||||
|
} else if (collapseVector.y == 1.0f) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresXZ;
|
||||||
|
} else if (collapseVector.z == 1.0f) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresXY;
|
||||||
|
}
|
||||||
|
} else if (alongPlane) {
|
||||||
|
if (collapseVector.x == 0.0f) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresX;
|
||||||
|
} else if (collapseVector.y == 0.0f) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresY;
|
||||||
|
} else if (collapseVector.z == 0.0f) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (modeSpheres2D) {
|
||||||
|
if (collapseVector.x == 1.0f) {
|
||||||
|
if (mode == ExtractionMode::SpheresXY) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresY;
|
||||||
|
} else if (mode == ExtractionMode::SpheresXZ) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresZ;
|
||||||
|
}
|
||||||
|
} else if (collapseVector.y == 1.0f) {
|
||||||
|
if (mode == ExtractionMode::SpheresXY) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresX;
|
||||||
|
} else if (mode == ExtractionMode::SpheresYZ) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresZ;
|
||||||
|
}
|
||||||
|
} else if (collapseVector.z == 1.0f) {
|
||||||
|
if (mode == ExtractionMode::SpheresXZ) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresX;
|
||||||
|
} else if (mode == ExtractionMode::SpheresYZ) {
|
||||||
|
collapsingMode = CollapsingMode::SpheresY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collapsingMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiSphereShape::CollapsingMode MultiSphereShape::spheresFromAxes(const std::vector<glm::vec3>& points,
|
||||||
|
const std::vector<glm::vec3>& axes, std::vector<SphereData>& spheres) {
|
||||||
float maxRadius = 0.0f;
|
float maxRadius = 0.0f;
|
||||||
float maxAverageRadius = 0.0f;
|
float maxAverageRadius = 0.0f;
|
||||||
float minAverageRadius = glm::length(points[0]);
|
float minAverageRadius = glm::length(points[0]);
|
||||||
size_t sphereCount = axes.size();
|
size_t sphereCount = axes.size();
|
||||||
spheres.clear();
|
spheres.clear();
|
||||||
for (size_t j = 0; j < sphereCount; j++) {
|
for (size_t j = 0; j < sphereCount; j++) {
|
||||||
SphereShapeData sphere = SphereShapeData();
|
SphereData sphere = SphereData();
|
||||||
sphere._axis = axes[j];
|
sphere._axis = axes[j];
|
||||||
spheres.push_back(sphere);
|
spheres.push_back(sphere);
|
||||||
}
|
}
|
||||||
|
@ -318,29 +436,11 @@ void MultiSphereShape::spheresFromAxes(const std::vector<glm::vec3>& points, con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Collapse spheres if too close
|
// Collapse spheres if too close
|
||||||
|
CollapsingMode collapsingMode = ExtractionMode::None;
|
||||||
if (sphereCount > 1) {
|
if (sphereCount > 1) {
|
||||||
bool collapsed = false;
|
collapsingMode = getNextCollapsingMode(_mode, spheres);
|
||||||
for (size_t i = 0; i < spheres.size() - 1; i++) {
|
|
||||||
for (size_t j = i + 1; j < spheres.size(); j++) {
|
|
||||||
if (i != j) {
|
|
||||||
size_t maxRadiusIndex = spheres[i]._radius > spheres[j]._radius ? i : j;
|
|
||||||
if (glm::length(spheres[i]._position - spheres[j]._position) < 0.2f * spheres[maxRadiusIndex]._radius) {
|
|
||||||
SphereShapeData newSphere;
|
|
||||||
newSphere._position = _midPoint;
|
|
||||||
newSphere._radius = maxRadius;
|
|
||||||
spheres.clear();
|
|
||||||
spheres.push_back(newSphere);
|
|
||||||
collapsed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (collapsed) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return collapsingMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiSphereShape::connectSpheres(int index1, int index2, bool onlyEdges) {
|
void MultiSphereShape::connectSpheres(int index1, int index2, bool onlyEdges) {
|
||||||
|
|
|
@ -19,28 +19,6 @@
|
||||||
#include "BulletUtil.h"
|
#include "BulletUtil.h"
|
||||||
|
|
||||||
|
|
||||||
enum CollisionShapeExtractionMode {
|
|
||||||
None = 0,
|
|
||||||
Automatic,
|
|
||||||
Box,
|
|
||||||
Sphere,
|
|
||||||
SphereCollapse,
|
|
||||||
SpheresX,
|
|
||||||
SpheresY,
|
|
||||||
SpheresZ,
|
|
||||||
SpheresXY,
|
|
||||||
SpheresYZ,
|
|
||||||
SpheresXZ,
|
|
||||||
SpheresXYZ
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SphereShapeData {
|
|
||||||
SphereShapeData() {}
|
|
||||||
glm::vec3 _position;
|
|
||||||
glm::vec3 _axis;
|
|
||||||
float _radius;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SphereRegion {
|
class SphereRegion {
|
||||||
public:
|
public:
|
||||||
SphereRegion() {}
|
SphereRegion() {}
|
||||||
|
@ -74,23 +52,79 @@ const std::vector<glm::vec3> CORNER_SIGNS = {
|
||||||
|
|
||||||
class MultiSphereShape {
|
class MultiSphereShape {
|
||||||
public:
|
public:
|
||||||
|
enum ExtractionMode {
|
||||||
|
None = 0,
|
||||||
|
Automatic,
|
||||||
|
Box,
|
||||||
|
Sphere,
|
||||||
|
SphereCollapse,
|
||||||
|
SpheresX,
|
||||||
|
SpheresY,
|
||||||
|
SpheresZ,
|
||||||
|
SpheresXY,
|
||||||
|
SpheresYZ,
|
||||||
|
SpheresXZ,
|
||||||
|
SpheresXYZ
|
||||||
|
};
|
||||||
|
|
||||||
|
using CollapsingMode = ExtractionMode;
|
||||||
|
const std::vector<QString> ExtractionModeNames = {
|
||||||
|
"None",
|
||||||
|
"Automatic",
|
||||||
|
"Box",
|
||||||
|
"Sphere",
|
||||||
|
"SphereCollapse",
|
||||||
|
"SpheresX",
|
||||||
|
"SpheresY",
|
||||||
|
"SpheresZ",
|
||||||
|
"SpheresXY",
|
||||||
|
"SpheresYZ",
|
||||||
|
"SpheresXZ",
|
||||||
|
"SpheresXYZ"
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SphereData {
|
||||||
|
glm::vec3 _position;
|
||||||
|
glm::vec3 _axis;
|
||||||
|
float _radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KdopCoefficient {
|
||||||
|
float xy = 0.0f;
|
||||||
|
float yz = 0.0f;
|
||||||
|
float xz = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KdopData {
|
||||||
|
std::vector<glm::vec3> _relativePoints;
|
||||||
|
bool _isValidShape{ true };
|
||||||
|
glm::vec3 _origin;
|
||||||
|
glm::vec3 _dimensions;
|
||||||
|
KdopCoefficient _epsilon;
|
||||||
|
KdopCoefficient _diff;
|
||||||
|
};
|
||||||
|
|
||||||
MultiSphereShape() {};
|
MultiSphereShape() {};
|
||||||
bool computeMultiSphereShape(int jointIndex, const QString& name, const std::vector<btVector3>& points, float scale = 1.0f);
|
bool computeMultiSphereShape(int jointIndex, const QString& name, const std::vector<btVector3>& points, float scale = 1.0f);
|
||||||
void calculateDebugLines();
|
void calculateDebugLines();
|
||||||
const std::vector<SphereShapeData>& getSpheresData() const { return _spheres; }
|
const std::vector<SphereData>& getSpheresData() const { return _spheres; }
|
||||||
const std::vector<std::pair<glm::vec3, glm::vec3>>& getDebugLines() const { return _debugLines; }
|
const std::vector<std::pair<glm::vec3, glm::vec3>>& getDebugLines() const { return _debugLines; }
|
||||||
void setScale(float scale);
|
void setScale(float scale);
|
||||||
AABox& updateBoundingBox(const glm::vec3& position, const glm::quat& rotation);
|
AABox& updateBoundingBox(const glm::vec3& position, const glm::quat& rotation);
|
||||||
const AABox& getBoundingBox() const { return _boundingBox; }
|
const AABox& getBoundingBox() const { return _boundingBox; }
|
||||||
int getJointIndex() const { return _jointIndex; }
|
int getJointIndex() const { return _jointIndex; }
|
||||||
QString getJointName() const { return _name; }
|
QString getJointName() const { return _jointName; }
|
||||||
bool isValid() const { return _spheres.size() > 0; }
|
bool isValid() const { return _spheres.size() > 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CollisionShapeExtractionMode getExtractionModeByName(const QString& name);
|
KdopData getKdopData(const std::vector<btVector3>& kdop);
|
||||||
|
CollapsingMode computeSpheres(ExtractionMode mode, const KdopData& kdopData);
|
||||||
|
ExtractionMode getExtractionModeByJointName(const QString& jointName);
|
||||||
|
CollapsingMode getNextCollapsingMode(ExtractionMode mode, const std::vector<SphereData>& spheres);
|
||||||
|
QString modeToString(CollapsingMode type) { return ExtractionModeNames[(int)type]; }
|
||||||
void filterUniquePoints(const std::vector<btVector3>& kdop, std::vector<glm::vec3>& uniquePoints);
|
void filterUniquePoints(const std::vector<btVector3>& kdop, std::vector<glm::vec3>& uniquePoints);
|
||||||
void spheresFromAxes(const std::vector<glm::vec3>& points, const std::vector<glm::vec3>& axes,
|
CollapsingMode spheresFromAxes(const std::vector<glm::vec3>& points, const std::vector<glm::vec3>& axes,
|
||||||
std::vector<SphereShapeData>& spheres);
|
std::vector<SphereData>& spheres);
|
||||||
|
|
||||||
void calculateSphereLines(std::vector<std::pair<glm::vec3, glm::vec3>>& outLines, const glm::vec3& center, const float& radius,
|
void calculateSphereLines(std::vector<std::pair<glm::vec3, glm::vec3>>& outLines, const glm::vec3& center, const float& radius,
|
||||||
const int& subdivisions = DEFAULT_SPHERE_SUBDIVISIONS, const glm::vec3& direction = Vectors::UNIT_Y,
|
const int& subdivisions = DEFAULT_SPHERE_SUBDIVISIONS, const glm::vec3& direction = Vectors::UNIT_Y,
|
||||||
|
@ -101,10 +135,10 @@ private:
|
||||||
void connectSpheres(int index1, int index2, bool onlyEdges = false);
|
void connectSpheres(int index1, int index2, bool onlyEdges = false);
|
||||||
|
|
||||||
int _jointIndex { -1 };
|
int _jointIndex { -1 };
|
||||||
QString _name;
|
QString _jointName;
|
||||||
std::vector<SphereShapeData> _spheres;
|
std::vector<SphereData> _spheres;
|
||||||
std::vector<std::pair<glm::vec3, glm::vec3>> _debugLines;
|
std::vector<std::pair<glm::vec3, glm::vec3>> _debugLines;
|
||||||
CollisionShapeExtractionMode _mode;
|
ExtractionMode _mode { ExtractionMode::None };
|
||||||
glm::vec3 _midPoint;
|
glm::vec3 _midPoint;
|
||||||
float _scale { 1.0f };
|
float _scale { 1.0f };
|
||||||
AABox _boundingBox;
|
AABox _boundingBox;
|
||||||
|
|
Loading…
Reference in a new issue