Add fit AABox for avatar and implement multisphere on shapeManager

This commit is contained in:
luiscuenca 2019-01-09 17:49:19 -07:00
parent 39dc25ea92
commit 95fca826a5
13 changed files with 120 additions and 39 deletions

View file

@ -59,7 +59,6 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const {
const btCollisionShape* AvatarMotionState::computeNewShape() {
ShapeInfo shapeInfo;
_avatar->computeShapeInfo(shapeInfo);
qDebug() << "Creating new Capsule Shape";
return getShapeManager()->getShape(shapeInfo);
}

View file

@ -36,9 +36,6 @@ bool DetailedMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngin
DetailedMotionState::~DetailedMotionState() {
assert(_avatar);
_avatar = nullptr;
if (_shape) {
delete _shape;
}
}
// virtual
@ -163,4 +160,3 @@ void DetailedMotionState::setRigidBody(btRigidBody* body) {
void DetailedMotionState::setShape(const btCollisionShape* shape) {
ObjectMotionState::setShape(shape);
}

View file

@ -423,6 +423,16 @@ void MyAvatar::clearIKJointLimitHistory() {
_skeletonModel->getRig().clearIKJointLimitHistory();
}
QVariantMap MyAvatar::getBoundingBox() {
QVariantMap bbox;
auto avatarBBox = getFitBounds();
auto center = avatarBBox.calcCenter();
auto dimensions = avatarBBox.getDimensions();
bbox["center"] = vec3toVariant(center);
bbox["dimensions"] = vec3toVariant(dimensions);
return bbox;
}
void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
assert(QThread::currentThread() == thread());

View file

@ -311,6 +311,8 @@ public:
*/
Q_INVOKABLE void clearIKJointLimitHistory(); // thread-safe
Q_INVOKABLE QVariantMap getBoundingBox();
void update(float deltaTime);
virtual void postUpdate(float deltaTime, const render::ScenePointer& scene) override;
void preDisplaySide(const RenderArgs* renderArgs);

View file

@ -108,25 +108,15 @@ int OtherAvatar::parseDataFromBuffer(const QByteArray& buffer) {
int32_t bytesRead = Avatar::parseDataFromBuffer(buffer);
if (_moving && _motionState) {
_motionState->addDirtyFlags(Simulation::DIRTY_POSITION);
for (auto mState : _detailedMotionStates) {
if (mState) {
mState->addDirtyFlags(Simulation::DIRTY_POSITION);
}
}
}
return bytesRead;
}
btCollisionShape* OtherAvatar::createDetailedCollisionShapeForJoint(int jointIndex) {
if (jointIndex > -1 && jointIndex < _multiSphereShapes.size()) {
auto& data = _multiSphereShapes[jointIndex].getSpheresData();
std::vector<btVector3> positions;
std::vector<btScalar> radiuses;
for (auto& sphere : data) {
positions.push_back(glmToBullet(sphere._position));
radiuses.push_back(sphere._radius);
}
btCollisionShape* shape = new btMultiSphereShape(positions.data(), radiuses.data(), (int)positions.size());
ShapeInfo shapeInfo;
computeDetailedShapeInfo(shapeInfo, jointIndex);
if (shapeInfo.getType() != SHAPE_TYPE_NONE) {
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
return shape;
}
return nullptr;

View file

@ -956,6 +956,7 @@ void Avatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
}
fixupModelsInScene(scene);
updateFitBoundingBox();
}
void Avatar::render(RenderArgs* renderArgs) {
@ -1670,7 +1671,7 @@ void Avatar::rigReset() {
void Avatar::computeMultiSphereShapes() {
const Rig& rig = getSkeletonModel()->getRig();
auto scale = extractScale(rig.getGeometryToRigTransform());
glm::vec3 scale = extractScale(rig.getGeometryToRigTransform());
const HFMModel& geometry = getSkeletonModel()->getHFMModel();
int jointCount = rig.getJointStateCount();
_multiSphereShapes.clear();
@ -1688,13 +1689,28 @@ void Avatar::computeMultiSphereShapes() {
}
auto jointName = rig.nameOfJoint(i).toUpper();
MultiSphereShape multiSphereShape;
if (multiSphereShape.computeMultiSphereShape(jointName, btPoints, getSensorToWorldScale())) {
if (multiSphereShape.computeMultiSphereShape(jointName, btPoints)) {
multiSphereShape.calculateDebugLines();
}
multiSphereShape.setScale(getTargetScale());
; }
_multiSphereShapes.push_back(multiSphereShape);
}
}
void Avatar::updateFitBoundingBox() {
_fitBoundingBox = AABox();
if (getJointCount() == _multiSphereShapes.size()) {
for (int i = 0; i < getJointCount(); i++) {
auto &shape = _multiSphereShapes[i];
glm::vec3 jointPosition;
glm::quat jointRotation;
_skeletonModel->getJointPositionInWorldFrame(i, jointPosition);
_skeletonModel->getJointRotationInWorldFrame(i, jointRotation);
_fitBoundingBox += shape.updateBoundingBox(jointPosition, jointRotation);
}
}
}
// create new model, can return an instance of a SoftAttachmentModel rather then Model
static std::shared_ptr<Model> allocateAttachmentModel(bool isSoft, const Rig& rigOverride, bool isCauterized) {
if (isSoft) {
@ -1874,6 +1890,19 @@ void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
shapeInfo.setOffset(offset);
}
void Avatar::computeDetailedShapeInfo(ShapeInfo& shapeInfo, int jointIndex) {
if (jointIndex > -1 && jointIndex < _multiSphereShapes.size()) {
auto& data = _multiSphereShapes[jointIndex].getSpheresData();
std::vector<glm::vec3> positions;
std::vector<btScalar> radiuses;
for (auto& sphere : data) {
positions.push_back(sphere._position);
radiuses.push_back(sphere._radius);
}
shapeInfo.setMultiSphere(positions, radiuses);
}
}
void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) {
ShapeInfo shapeInfo;
computeShapeInfo(shapeInfo);

View file

@ -319,6 +319,7 @@ public:
virtual void rebuildCollisionShape() = 0;
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
virtual void computeDetailedShapeInfo(ShapeInfo& shapeInfo, int jointIndex);
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
float computeMass();
/**jsdoc
@ -397,6 +398,7 @@ public:
float getBoundingRadius() const;
AABox getRenderBounds() const; // THis call is accessible from rendering thread only to report the bounding box of the avatar during the frame.
AABox getFitBounds() const { return _fitBoundingBox; }
void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene);
@ -440,6 +442,8 @@ public:
void accumulateGrabPositions(std::map<QUuid, GrabLocationAccumulator>& grabAccumulators);
const std::vector<MultiSphereShape>& getMultiSphereShapes() const { return _multiSphereShapes; }
signals:
void targetScaleChanged(float targetScale);
@ -508,7 +512,7 @@ protected:
QString _empty{};
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
void computeMultiSphereShapes();
const std::vector<MultiSphereShape>& getMultiSphereShapes() const { return _multiSphereShapes; }
void updateFitBoundingBox();
SkeletonModelPointer _skeletonModel;
@ -633,6 +637,7 @@ protected:
const QVector<int>& blendedMeshSizes, const render::ItemIDs& subItemIDs);
std::vector<MultiSphereShape> _multiSphereShapes;
AABox _fitBoundingBox;
AvatarGrabMap _avatarGrabs;
};

View file

@ -524,4 +524,17 @@ void MultiSphereShape::setScale(float scale) {
}
_scale = scale;
}
}
AABox& MultiSphereShape::updateBoundingBox(const glm::vec3& position, const glm::quat& rotation) {
_boundingBox = AABox();
auto spheres = getSpheresData();
for (size_t i = 0; i < spheres.size(); i++) {
auto sphere = spheres[i];
auto worldPosition = position + rotation * sphere._position;
glm::vec3 corner = worldPosition - glm::vec3(sphere._radius);
glm::vec3 dimensions = glm::vec3(2.0f * sphere._radius);
_boundingBox += AABox(corner, dimensions);
}
return _boundingBox;
}

View file

@ -15,6 +15,7 @@
#include <stdint.h>
#include <btBulletDynamicsCommon.h>
#include <GLMHelpers.h>
#include <AABox.h>
#include "BulletUtil.h"
@ -78,6 +79,7 @@ public:
const std::vector<SphereShapeData>& getSpheresData() const { return _spheres; }
const std::vector<std::pair<glm::vec3, glm::vec3>>& getDebugLines() const { return _debugLines; }
void setScale(float scale);
AABox& updateBoundingBox(const glm::vec3& position, const glm::quat& rotation);
private:
CollisionShapeExtractionMode getExtractionModeByName(const QString& name);
@ -97,6 +99,7 @@ private:
CollisionShapeExtractionMode _mode;
glm::vec3 _midPoint;
float _scale { 1.0f };
AABox _boundingBox;
};
#endif // hifi_MultiSphereShape_h

View file

@ -195,11 +195,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) {
void ObjectMotionState::setShape(const btCollisionShape* shape) {
if (_shape != shape) {
if (_shape) {
if (_type == MOTIONSTATE_TYPE_DETAILED) {
delete _shape;
} else {
getShapeManager()->releaseShape(_shape);
}
getShapeManager()->releaseShape(_shape);
}
_shape = shape;
if (_body && _type != MOTIONSTATE_TYPE_DETAILED) {
@ -313,12 +309,8 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine*
if (_shape == newShape) {
// the shape didn't actually change, so we clear the DIRTY_SHAPE flag
flags &= ~Simulation::DIRTY_SHAPE;
if (_type == MOTIONSTATE_TYPE_DETAILED) {
delete _shape;
} else {
// and clear the reference we just created
getShapeManager()->releaseShape(_shape);
}
// and clear the reference we just created
getShapeManager()->releaseShape(_shape);
} else {
_body->setCollisionShape(const_cast<btCollisionShape*>(newShape));
setShape(newShape);

View file

@ -284,6 +284,17 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
shape = new btSphereShape(radius);
}
break;
case SHAPE_TYPE_MULTISPHERE: {
std::vector<btVector3> positions;
std::vector<float> radiuses;
auto sphereCollection = info.getSphereCollection();
for (auto &sphereData : sphereCollection) {
positions.push_back(glmToBullet(sphereData.first));
radiuses.push_back(sphereData.second);
}
shape = new btMultiSphereShape(positions.data(), radiuses.data(), (int)positions.size());
}
break;
case SHAPE_TYPE_ELLIPSOID: {
glm::vec3 halfExtents = info.getHalfExtents();
float radius = halfExtents.x;

View file

@ -38,6 +38,7 @@
* sub-meshes.</td></tr>
* <tr><td><code>"static-mesh"</code></td><td>The exact shape of the model.</td></tr>
* <tr><td><code>"plane"</code></td><td>A plane.</td></tr>
* <tr><td><code>"multisphere"</code></td><td>A convex hull generated from a set of spheres.</td></tr>
* </tbody>
* </table>
* @typedef {string} ShapeType
@ -59,7 +60,9 @@ const char* shapeTypeNames[] = {
"simple-hull",
"simple-compound",
"static-mesh",
"ellipsoid"
"ellipsoid",
"circle",
"multisphere"
};
static const size_t SHAPETYPE_NAME_COUNT = (sizeof(shapeTypeNames) / sizeof((shapeTypeNames)[0]));
@ -90,6 +93,7 @@ void ShapeInfo::clear() {
_url.clear();
_pointCollection.clear();
_triangleIndices.clear();
_sphereCollection.clear();
_halfExtents = glm::vec3(0.0f);
_offset = glm::vec3(0.0f);
_hashKey.clear();
@ -106,6 +110,7 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
break;
case SHAPE_TYPE_BOX:
case SHAPE_TYPE_HULL:
case SHAPE_TYPE_MULTISPHERE:
break;
case SHAPE_TYPE_SPHERE: {
float radius = glm::length(halfExtents) / SQUARE_ROOT_OF_3;
@ -144,6 +149,17 @@ void ShapeInfo::setSphere(float radius) {
_hashKey.clear();
}
void ShapeInfo::setMultiSphere(const std::vector<glm::vec3>& centers, const std::vector<float>& radiuses) {
_url = "";
_type = SHAPE_TYPE_MULTISPHERE;
assert(centers.size() == radiuses.size() && centers.size() > 0);
for (size_t i = 0; i < centers.size(); i++) {
SphereData sphere = SphereData(centers[i], radiuses[i]);
_sphereCollection.push_back(sphere);
}
_hashKey.clear();
}
void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) {
_pointCollection = pointCollection;
_hashKey.clear();
@ -170,6 +186,7 @@ uint32_t ShapeInfo::getNumSubShapes() const {
case SHAPE_TYPE_COMPOUND:
case SHAPE_TYPE_SIMPLE_COMPOUND:
return _pointCollection.size();
case SHAPE_TYPE_MULTISPHERE:
case SHAPE_TYPE_SIMPLE_HULL:
case SHAPE_TYPE_STATIC_MESH:
assert(_pointCollection.size() == 1);
@ -257,7 +274,12 @@ const HashKey& ShapeInfo::getHash() const {
// The key is not yet cached therefore we must compute it.
_hashKey.hashUint64((uint64_t)_type);
if (_type != SHAPE_TYPE_SIMPLE_HULL) {
if (_type == SHAPE_TYPE_MULTISPHERE) {
for (auto &sphereData : _sphereCollection) {
_hashKey.hashVec3(sphereData.first);
_hashKey.hashFloat(sphereData.second);
}
} else if (_type != SHAPE_TYPE_SIMPLE_HULL) {
_hashKey.hashVec3(_halfExtents);
_hashKey.hashVec3(_offset);
} else {
@ -283,9 +305,12 @@ const HashKey& ShapeInfo::getHash() const {
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) {
uint64_t numHulls = (uint64_t)_pointCollection.size();
_hashKey.hashUint64(numHulls);
} else if (_type == SHAPE_TYPE_MULTISPHERE) {
uint64_t numSpheres = (uint64_t)_sphereCollection.size();
_hashKey.hashUint64(numSpheres);
} else if (_type == SHAPE_TYPE_SIMPLE_HULL) {
_hashKey.hashUint64(1);
}
}
}
return _hashKey;
}

View file

@ -47,7 +47,8 @@ enum ShapeType {
SHAPE_TYPE_SIMPLE_COMPOUND,
SHAPE_TYPE_STATIC_MESH,
SHAPE_TYPE_ELLIPSOID,
SHAPE_TYPE_CIRCLE
SHAPE_TYPE_CIRCLE,
SHAPE_TYPE_MULTISPHERE
};
class ShapeInfo {
@ -57,6 +58,8 @@ public:
using PointList = QVector<glm::vec3>;
using PointCollection = QVector<PointList>;
using TriangleIndices = QVector<int32_t>;
using SphereData = QPair<glm::vec3, float>;
using SphereCollection = QVector<SphereData>;
static QString getNameForShapeType(ShapeType type);
static ShapeType getShapeTypeForName(QString string);
@ -68,7 +71,8 @@ public:
void setSphere(float radius);
void setPointCollection(const PointCollection& pointCollection);
void setCapsuleY(float radius, float cylinderHalfHeight);
void setOffset(const glm::vec3& offset);
void setMultiSphere(const std::vector<glm::vec3>& centers, const std::vector<float>& radiuses);
void setOffset(const glm::vec3& offset);
ShapeType getType() const { return _type; }
@ -78,6 +82,7 @@ public:
PointCollection& getPointCollection() { return _pointCollection; }
const PointCollection& getPointCollection() const { return _pointCollection; }
const SphereCollection& getSphereCollection() const { return _sphereCollection; }
TriangleIndices& getTriangleIndices() { return _triangleIndices; }
const TriangleIndices& getTriangleIndices() const { return _triangleIndices; }
@ -92,6 +97,7 @@ protected:
void setHalfExtents(const glm::vec3& halfExtents);
QUrl _url; // url for model of convex collision hulls
SphereCollection _sphereCollection;
PointCollection _pointCollection;
TriangleIndices _triangleIndices;
glm::vec3 _halfExtents = glm::vec3(0.0f);