mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Add fit AABox for avatar and implement multisphere on shapeManager
This commit is contained in:
parent
39dc25ea92
commit
95fca826a5
13 changed files with 120 additions and 39 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue