mirror of
https://github.com/overte-org/overte.git
synced 2025-08-05 01:30:18 +02:00
Merge branch 'multi-hull-collisions' of github.com:sethalves/hifi into vhacd-knobs
This commit is contained in:
commit
0d4b0ad11e
11 changed files with 184 additions and 21 deletions
|
@ -266,6 +266,26 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
|||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking);
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||
ModelEntityItem::setCollisionModelURL(url);
|
||||
if (_model) {
|
||||
_model->setCollisionModelURL(QUrl(url));
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::hasCollisionModel() const {
|
||||
if (_model) {
|
||||
return ! _model->getCollisionURL().isEmpty();
|
||||
} else {
|
||||
return !_collisionModelURL.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
const QString& RenderableModelEntityItem::getCollisionModelURL() const {
|
||||
assert (!_model || _collisionModelURL == _model->getCollisionURL().toString());
|
||||
return _collisionModelURL;
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::isReadyToComputeShape() {
|
||||
|
||||
if (!_model) {
|
||||
|
@ -294,13 +314,64 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
||||
const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry();
|
||||
|
||||
AABox aaBox;
|
||||
_points.clear();
|
||||
unsigned int i = 0;
|
||||
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
||||
_points << mesh.vertices;
|
||||
|
||||
foreach (const FBXMeshPart &meshPart, mesh.parts) {
|
||||
QVector<glm::vec3> pointsInPart;
|
||||
unsigned int triangleCount = meshPart.triangleIndices.size() / 3;
|
||||
assert((unsigned int)meshPart.triangleIndices.size() == triangleCount*3);
|
||||
for (unsigned int j = 0; j < triangleCount; j++) {
|
||||
unsigned int p0Index = meshPart.triangleIndices[j*3];
|
||||
unsigned int p1Index = meshPart.triangleIndices[j*3+1];
|
||||
unsigned int p2Index = meshPart.triangleIndices[j*3+2];
|
||||
|
||||
assert(p0Index < (unsigned int)mesh.vertices.size());
|
||||
assert(p1Index < (unsigned int)mesh.vertices.size());
|
||||
assert(p2Index < (unsigned int)mesh.vertices.size());
|
||||
|
||||
glm::vec3 p0 = mesh.vertices[p0Index];
|
||||
glm::vec3 p1 = mesh.vertices[p1Index];
|
||||
glm::vec3 p2 = mesh.vertices[p2Index];
|
||||
|
||||
aaBox += p0;
|
||||
aaBox += p1;
|
||||
aaBox += p2;
|
||||
|
||||
if (!pointsInPart.contains(p0)) {
|
||||
pointsInPart << p0;
|
||||
}
|
||||
if (!pointsInPart.contains(p1)) {
|
||||
pointsInPart << p1;
|
||||
}
|
||||
if (!pointsInPart.contains(p2)) {
|
||||
pointsInPart << p2;
|
||||
}
|
||||
}
|
||||
|
||||
QVector<glm::vec3> newMeshPoints;
|
||||
_points << newMeshPoints;
|
||||
_points[i++] << pointsInPart;
|
||||
}
|
||||
}
|
||||
|
||||
info.setParams(getShapeType(), 0.5f * getDimensions(), _collisionModelURL);
|
||||
info.setConvexHull(_points);
|
||||
// make sure we aren't about to divide by zero
|
||||
glm::vec3 aaBoxDim = aaBox.getDimensions();
|
||||
aaBoxDim = glm::clamp(aaBoxDim, glm::vec3(FLT_EPSILON), aaBoxDim);
|
||||
|
||||
glm::vec3 scale = _dimensions / aaBoxDim;
|
||||
|
||||
// multiply each point by scale before handing the point-set off to the physics engine
|
||||
for (int i = 0; i < _points.size(); i++) {
|
||||
for (int j = 0; j < _points[i].size(); j++) {
|
||||
_points[i][j] *= scale;
|
||||
}
|
||||
}
|
||||
|
||||
info.setParams(getShapeType(), _dimensions, _collisionModelURL);
|
||||
info.setConvexHulls(_points);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,7 +379,9 @@ ShapeType RenderableModelEntityItem::getShapeType() const {
|
|||
// XXX make hull an option in edit.js ?
|
||||
if (!_model || _model->getCollisionURL().isEmpty()) {
|
||||
return _shapeType;
|
||||
} else {
|
||||
} else if (_points.size() == 1) {
|
||||
return SHAPE_TYPE_CONVEX_HULL;
|
||||
} else {
|
||||
return SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@ public:
|
|||
|
||||
bool needsToCallUpdate() const;
|
||||
|
||||
virtual void setCollisionModelURL(const QString& url);
|
||||
virtual bool hasCollisionModel() const;
|
||||
virtual const QString& getCollisionModelURL() const;
|
||||
|
||||
bool isReadyToComputeShape();
|
||||
void computeShapeInfo(ShapeInfo& info);
|
||||
ShapeType getShapeType() const;
|
||||
|
@ -66,7 +70,7 @@ private:
|
|||
QString _currentTextures;
|
||||
QStringList _originalTextures;
|
||||
bool _originalTexturesRead;
|
||||
QVector<glm::vec3> _points;
|
||||
QVector<QVector<glm::vec3>> _points;
|
||||
};
|
||||
|
||||
#endif // hifi_RenderableModelEntityItem_h
|
||||
|
|
|
@ -95,7 +95,6 @@ public:
|
|||
|
||||
void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = false);
|
||||
void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = false);
|
||||
void removeEntityFromSimulation(EntityItem* entity);
|
||||
|
||||
/// \param position point of query in world-frame (meters)
|
||||
/// \param targetRadius radius of query (meters)
|
||||
|
|
|
@ -281,6 +281,13 @@ void ModelEntityItem::updateShapeType(ShapeType type) {
|
|||
}
|
||||
}
|
||||
|
||||
void ModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||
if (_collisionModelURL != url) {
|
||||
_collisionModelURL = url;
|
||||
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelEntityItem::setAnimationURL(const QString& url) {
|
||||
_dirtyFlags |= EntityItem::DIRTY_UPDATEABLE;
|
||||
_animationURL = url;
|
||||
|
|
|
@ -57,13 +57,13 @@ public:
|
|||
const rgbColor& getColor() const { return _color; }
|
||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||
bool hasModel() const { return !_modelURL.isEmpty(); }
|
||||
bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); }
|
||||
virtual bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); }
|
||||
|
||||
static const QString DEFAULT_MODEL_URL;
|
||||
const QString& getModelURL() const { return _modelURL; }
|
||||
|
||||
static const QString DEFAULT_COLLISION_MODEL_URL;
|
||||
const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
||||
virtual const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
||||
|
||||
bool hasAnimation() const { return !_animationURL.isEmpty(); }
|
||||
static const QString DEFAULT_ANIMATION_URL;
|
||||
|
@ -78,7 +78,7 @@ public:
|
|||
|
||||
// model related properties
|
||||
void setModelURL(const QString& url) { _modelURL = url; }
|
||||
void setCollisionModelURL(const QString& url) { _collisionModelURL = url; }
|
||||
virtual void setCollisionModelURL(const QString& url);
|
||||
void setAnimationURL(const QString& url);
|
||||
static const float DEFAULT_ANIMATION_FRAME_INDEX;
|
||||
void setAnimationFrameIndex(float value);
|
||||
|
|
|
@ -169,7 +169,9 @@ void EntityMotionState::updateObjectVelocities() {
|
|||
}
|
||||
|
||||
void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||
_entity->computeShapeInfo(shapeInfo);
|
||||
if (_entity->isReadyToComputeShape()) {
|
||||
_entity->computeShapeInfo(shapeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const {
|
||||
|
|
|
@ -29,6 +29,9 @@ int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) {
|
|||
case SHAPE_TYPE_CONVEX_HULL:
|
||||
bulletShapeType = CONVEX_HULL_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
bulletShapeType = COMPOUND_SHAPE_PROXYTYPE;
|
||||
break;
|
||||
}
|
||||
return bulletShapeType;
|
||||
}
|
||||
|
@ -48,6 +51,9 @@ int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) {
|
|||
case CONVEX_HULL_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_CONVEX_HULL;
|
||||
break;
|
||||
case COMPOUND_SHAPE_PROXYTYPE:
|
||||
shapeInfoType = SHAPE_TYPE_COMPOUND;
|
||||
break;
|
||||
}
|
||||
return shapeInfoType;
|
||||
}
|
||||
|
@ -70,12 +76,34 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf
|
|||
const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(shape);
|
||||
const int numPoints = convexHullShape->getNumPoints();
|
||||
const btVector3* btPoints = convexHullShape->getUnscaledPoints();
|
||||
QVector<glm::vec3> points;
|
||||
QVector<QVector<glm::vec3>> points;
|
||||
QVector<glm::vec3> childPoints;
|
||||
for (int i = 0; i < numPoints; i++) {
|
||||
glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ());
|
||||
points << point;
|
||||
childPoints << point;
|
||||
}
|
||||
info.setConvexHull(points);
|
||||
points << childPoints;
|
||||
info.setConvexHulls(points);
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND: {
|
||||
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape);
|
||||
const int numChildShapes = compoundShape->getNumChildShapes();
|
||||
QVector<QVector<glm::vec3>> points;
|
||||
for (int i = 0; i < numChildShapes; i ++) {
|
||||
const btCollisionShape* childShape = compoundShape->getChildShape(i);
|
||||
const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(childShape);
|
||||
const int numPoints = convexHullShape->getNumPoints();
|
||||
const btVector3* btPoints = convexHullShape->getUnscaledPoints();
|
||||
|
||||
QVector<glm::vec3> childPoints;
|
||||
for (int j = 0; j < numPoints; j++) {
|
||||
glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ());
|
||||
childPoints << point;
|
||||
}
|
||||
points << childPoints;
|
||||
}
|
||||
info.setConvexHulls(points);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
|
@ -109,13 +137,29 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
|||
break;
|
||||
case SHAPE_TYPE_CONVEX_HULL: {
|
||||
shape = new btConvexHullShape();
|
||||
const QVector<glm::vec3>& points = info.getPoints();
|
||||
foreach (glm::vec3 point, points) {
|
||||
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||
foreach (glm::vec3 point, points[0]) {
|
||||
btVector3 btPoint(point[0], point[1], point[2]);
|
||||
static_cast<btConvexHullShape*>(shape)->addPoint(btPoint);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND: {
|
||||
shape = new btCompoundShape();
|
||||
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||
|
||||
foreach (QVector<glm::vec3> hullPoints, info.getPoints()) {
|
||||
auto hull = new btConvexHullShape();
|
||||
foreach (glm::vec3 point, hullPoints) {
|
||||
btVector3 btPoint(point[0], point[1], point[2]);
|
||||
hull->addPoint(btPoint);
|
||||
}
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
static_cast<btCompoundShape*>(shape)->addChildShape (trans, hull);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
// translates between ShapeInfo and btShape
|
||||
|
||||
namespace ShapeInfoUtil {
|
||||
|
||||
// XXX is collectInfoFromShape no longer strictly needed?
|
||||
void collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info);
|
||||
|
||||
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
||||
|
|
|
@ -100,6 +100,18 @@ void ShapeManager::collectGarbage() {
|
|||
DoubleHashKey& key = _pendingGarbage[i];
|
||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||
if (shapeRef && shapeRef->refCount == 0) {
|
||||
// if the shape we're about to delete is compound, delete the children first.
|
||||
auto shapeType = ShapeInfoUtil::fromBulletShapeType(shapeRef->shape->getShapeType());
|
||||
if (shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shapeRef->shape);
|
||||
const int numChildShapes = compoundShape->getNumChildShapes();
|
||||
QVector<QVector<glm::vec3>> points;
|
||||
for (int i = 0; i < numChildShapes; i ++) {
|
||||
const btCollisionShape* childShape = compoundShape->getChildShape(i);
|
||||
delete childShape;
|
||||
}
|
||||
}
|
||||
|
||||
delete shapeRef->shape;
|
||||
_shapeMap.remove(key);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ void ShapeInfo::clear() {
|
|||
|
||||
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) {
|
||||
_type = type;
|
||||
_points.clear();
|
||||
switch(type) {
|
||||
case SHAPE_TYPE_NONE:
|
||||
_halfExtents = glm::vec3(0.0f);
|
||||
|
@ -37,6 +38,12 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
|||
break;
|
||||
}
|
||||
case SHAPE_TYPE_CONVEX_HULL:
|
||||
_url = QUrl(url);
|
||||
// halfExtents aren't used by convex-hull or compound convex-hull except as part of
|
||||
// the generation of the key for the ShapeManager.
|
||||
_halfExtents = halfExtents;
|
||||
break;
|
||||
case SHAPE_TYPE_COMPOUND:
|
||||
_url = QUrl(url);
|
||||
_halfExtents = halfExtents;
|
||||
break;
|
||||
|
@ -47,31 +54,44 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
|||
}
|
||||
|
||||
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_BOX;
|
||||
_halfExtents = halfExtents;
|
||||
_points.clear();
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setSphere(float radius) {
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_SPHERE;
|
||||
_halfExtents = glm::vec3(radius, radius, radius);
|
||||
_points.clear();
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) {
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_ELLIPSOID;
|
||||
_halfExtents = halfExtents;
|
||||
_points.clear();
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setConvexHull(const QVector<glm::vec3>& points) {
|
||||
_type = SHAPE_TYPE_CONVEX_HULL;
|
||||
void ShapeInfo::setConvexHulls(const QVector<QVector<glm::vec3>>& points) {
|
||||
if (points.size() == 1) {
|
||||
_type = SHAPE_TYPE_CONVEX_HULL;
|
||||
} else {
|
||||
_type = SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
_points = points;
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
|
||||
_url = "";
|
||||
_type = SHAPE_TYPE_CAPSULE_Y;
|
||||
_halfExtents = glm::vec3(radius, halfHeight, radius);
|
||||
_points.clear();
|
||||
_doubleHashKey.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -44,14 +44,14 @@ public:
|
|||
void setBox(const glm::vec3& halfExtents);
|
||||
void setSphere(float radius);
|
||||
void setEllipsoid(const glm::vec3& halfExtents);
|
||||
void setConvexHull(const QVector<glm::vec3>& points);
|
||||
void setConvexHulls(const QVector<QVector<glm::vec3>>& points);
|
||||
void setCapsuleY(float radius, float halfHeight);
|
||||
|
||||
const int getType() const { return _type; }
|
||||
|
||||
const glm::vec3& getHalfExtents() const { return _halfExtents; }
|
||||
|
||||
const QVector<glm::vec3>& getPoints() const { return _points; }
|
||||
const QVector<QVector<glm::vec3>>& getPoints() const { return _points; }
|
||||
|
||||
void clearPoints () { _points.clear(); }
|
||||
void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; }
|
||||
|
@ -64,8 +64,8 @@ protected:
|
|||
ShapeType _type = SHAPE_TYPE_NONE;
|
||||
glm::vec3 _halfExtents = glm::vec3(0.0f);
|
||||
DoubleHashKey _doubleHashKey;
|
||||
QVector<glm::vec3> _points; // points for convex collision hull
|
||||
QUrl _url; // url for model of convex collision hull
|
||||
QVector<QVector<glm::vec3>> _points; // points for convex collision hulls
|
||||
QUrl _url; // url for model of convex collision hulls
|
||||
};
|
||||
|
||||
#endif // hifi_ShapeInfo_h
|
||||
|
|
Loading…
Reference in a new issue