From 46c91052c9edae7be647480c07f36ae1bad189ed Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 14:29:03 -0700 Subject: [PATCH 1/5] split SkeletonModel and Ragdoll classes apart --- interface/src/avatar/MyAvatar.cpp | 11 +- interface/src/avatar/SkeletonModel.cpp | 200 +++++++---------------- interface/src/avatar/SkeletonModel.h | 19 +-- interface/src/avatar/SkeletonRagdoll.cpp | 148 +++++++++++++++++ interface/src/avatar/SkeletonRagdoll.h | 42 +++++ interface/src/renderer/Model.h | 3 + libraries/shared/src/Ragdoll.h | 2 +- 7 files changed, 263 insertions(+), 162 deletions(-) create mode 100644 interface/src/avatar/SkeletonRagdoll.cpp create mode 100644 interface/src/avatar/SkeletonRagdoll.h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c9d19d4bcc..ac44e1884e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -83,10 +83,11 @@ MyAvatar::MyAvatar() : for (int i = 0; i < MAX_DRIVE_KEYS; i++) { _driveKeys[i] = 0.0f; } - _skeletonModel.setEnableShapes(true); - // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type. _physicsSimulation.setEntity(&_skeletonModel); - _physicsSimulation.setRagdoll(&_skeletonModel); + + _skeletonModel.setEnableShapes(true); + Ragdoll* ragdoll = _skeletonModel.buildRagdoll(); + _physicsSimulation.setRagdoll(ragdoll); } MyAvatar::~MyAvatar() { @@ -1604,10 +1605,10 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { if (simulation != &(_physicsSimulation)) { skeleton->setEnableShapes(true); _physicsSimulation.addEntity(skeleton); - _physicsSimulation.addRagdoll(skeleton); + _physicsSimulation.addRagdoll(skeleton->getRagdoll()); } } else if (simulation == &(_physicsSimulation)) { - _physicsSimulation.removeRagdoll(skeleton); + _physicsSimulation.removeRagdoll(skeleton->getRagdoll()); _physicsSimulation.removeEntity(skeleton); skeleton->setEnableShapes(false); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 29c4e2cc52..90145f0af8 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -23,13 +23,21 @@ #include "Menu.h" #include "MuscleConstraint.h" #include "SkeletonModel.h" +#include "SkeletonRagdoll.h" SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : Model(parent), - Ragdoll(), _owningAvatar(owningAvatar), _boundingShape(), - _boundingShapeLocalOffset(0.0f) { + _boundingShapeLocalOffset(0.0f), + _ragdoll(NULL) { +} + +SkeletonModel::~SkeletonModel() { + if (_ragdoll) { + delete _ragdoll; + _ragdoll = NULL; + } } void SkeletonModel::setJointStates(QVector states) { @@ -155,9 +163,6 @@ void SkeletonModel::getBodyShapes(QVector& shapes) const { void SkeletonModel::renderIKConstraints() { renderJointConstraints(getRightHandJointIndex()); renderJointConstraints(getLeftHandJointIndex()); - //if (isActive() && _owningAvatar->isMyAvatar()) { - // renderRagdoll(); - //} } class IndexValue { @@ -489,21 +494,25 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco } void SkeletonModel::renderRagdoll() { + if (!_ragdoll) { + return; + } + const QVector& points = _ragdoll->getRagdollPoints(); const int BALL_SUBDIVISIONS = 6; glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); - int numPoints = _ragdollPoints.size(); + int numPoints = points.size(); float alpha = 0.3f; float radius1 = 0.008f; float radius2 = 0.01f; - glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); + glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); for (int i = 0; i < numPoints; ++i) { glPushMatrix(); // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative - glm::vec3 position = _ragdollPoints[i]._position - simulationTranslation; + glm::vec3 position = points[i]._position - simulationTranslation; glTranslatef(position.x, position.y, position.z); // draw each point as a yellow hexagon with black border glColor4f(0.0f, 0.0f, 0.0f, alpha); @@ -517,109 +526,18 @@ void SkeletonModel::renderRagdoll() { glEnable(GL_LIGHTING); } -// virtual -void SkeletonModel::initRagdollPoints() { - clearRagdollConstraintsAndPoints(); - _muscleConstraints.clear(); - - initRagdollTransform(); - // one point for each joint - int numStates = _jointStates.size(); - _ragdollPoints.fill(VerletPoint(), numStates); - for (int i = 0; i < numStates; ++i) { - const JointState& state = _jointStates.at(i); - // _ragdollPoints start in model-frame - _ragdollPoints[i].initPosition(state.getPosition()); - } -} - -void SkeletonModel::buildRagdollConstraints() { - // NOTE: the length of DistanceConstraints is computed and locked in at this time - // so make sure the ragdoll positions are in a normal configuration before here. - const int numPoints = _ragdollPoints.size(); - assert(numPoints == _jointStates.size()); - - float minBone = FLT_MAX; - float maxBone = -FLT_MAX; - QMultiMap families; - for (int i = 0; i < numPoints; ++i) { - const JointState& state = _jointStates.at(i); - int parentIndex = state.getParentIndex(); - if (parentIndex == -1) { - FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); - _fixedConstraints.push_back(anchor); - } else { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); - bone->setDistance(state.getDistanceToParent()); - _boneConstraints.push_back(bone); - families.insert(parentIndex, i); - } - float boneLength = glm::length(state.getPositionInParentFrame()); - if (boneLength > maxBone) { - maxBone = boneLength; - } else if (boneLength < minBone) { - minBone = boneLength; - } - } - // Joints that have multiple children effectively have rigid constraints between the children - // in the parent frame, so we add DistanceConstraints between children in the same family. - QMultiMap::iterator itr = families.begin(); - while (itr != families.end()) { - QList children = families.values(itr.key()); - int numChildren = children.size(); - if (numChildren > 1) { - for (int i = 1; i < numChildren; ++i) { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); - _boneConstraints.push_back(bone); - } - if (numChildren > 2) { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); - _boneConstraints.push_back(bone); - } - } - ++itr; - } - - float MAX_STRENGTH = 0.6f; - float MIN_STRENGTH = 0.05f; - // each joint gets a MuscleConstraint to its parent - for (int i = 1; i < numPoints; ++i) { - const JointState& state = _jointStates.at(i); - int p = state.getParentIndex(); - if (p == -1) { - continue; - } - MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i])); - _muscleConstraints.push_back(constraint); - - // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: - // long = weak and short = strong. - constraint->setIndices(p, i); - float boneLength = glm::length(state.getPositionInParentFrame()); - - float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone); - if (!families.contains(i)) { - // Although muscles only pull on the children not parents, nevertheless those joints that have - // parents AND children are more stable than joints at the end such as fingers. For such joints we - // bestow maximum strength which helps reduce wiggle. - strength = MAX_MUSCLE_STRENGTH; - } - constraint->setStrength(strength); - } - -} - void SkeletonModel::updateVisibleJointStates() { - if (_showTrueJointTransforms) { + if (_showTrueJointTransforms || !_ragdoll) { // no need to update visible transforms return; } + const QVector& ragdollPoints = _ragdoll->getRagdollPoints(); QVector points; points.reserve(_jointStates.size()); glm::quat invRotation = glm::inverse(_rotation); for (int i = 0; i < _jointStates.size(); i++) { JointState& state = _jointStates[i]; - points.push_back(_ragdollPoints[i]._position); + points.push_back(ragdollPoints[i]._position); // get the parent state (this is the state that we want to rotate) int parentIndex = state.getParentIndex(); @@ -653,15 +571,14 @@ void SkeletonModel::updateVisibleJointStates() { } } -// virtual -void SkeletonModel::stepRagdollForward(float deltaTime) { - setRagdollTransform(_translation, _rotation); - Ragdoll::stepRagdollForward(deltaTime); - updateMuscles(); - int numConstraints = _muscleConstraints.size(); - for (int i = 0; i < numConstraints; ++i) { - _muscleConstraints[i]->enforce(); +SkeletonRagdoll* SkeletonModel::buildRagdoll() { + if (!_ragdoll) { + _ragdoll = new SkeletonRagdoll(this); + if (_enableShapes) { + buildShapes(); + } } + return _ragdoll; } float DENSITY_OF_WATER = 1000.0f; // kg/m^3 @@ -679,8 +596,13 @@ void SkeletonModel::buildShapes() { return; } - initRagdollPoints(); - float massScale = getMassScale(); + if (!_ragdoll) { + _ragdoll = new SkeletonRagdoll(this); + } + _ragdoll->initRagdollPoints(); + QVector& points = _ragdoll->getRagdollPoints(); + + float massScale = _ragdoll->getMassScale(); float uniformScale = extractUniformScale(_scale); const int numStates = _jointStates.size(); @@ -700,14 +622,14 @@ void SkeletonModel::buildShapes() { Shape* shape = NULL; int parentIndex = joint.parentIndex; if (type == Shape::SPHERE_SHAPE) { - shape = new VerletSphereShape(radius, &(_ragdollPoints[i])); + shape = new VerletSphereShape(radius, &(points[i])); shape->setEntity(this); - _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); + points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); } else if (type == Shape::CAPSULE_SHAPE) { assert(parentIndex != -1); - shape = new VerletCapsuleShape(radius, &(_ragdollPoints[parentIndex]), &(_ragdollPoints[i])); + shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i])); shape->setEntity(this); - _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); + points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); } if (parentIndex != -1) { // always disable collisions between joint and its parent @@ -717,7 +639,7 @@ void SkeletonModel::buildShapes() { } else { // give the base joint a very large mass since it doesn't actually move // in the local-frame simulation (it defines the origin) - _ragdollPoints[i].setMass(VERY_BIG_MASS); + points[i].setMass(VERY_BIG_MASS); } _shapes.push_back(shape); } @@ -729,17 +651,11 @@ void SkeletonModel::buildShapes() { // joints that are currently colliding. disableCurrentSelfCollisions(); - buildRagdollConstraints(); + _ragdoll->buildRagdollConstraints(); // ... then move shapes back to current joint positions - if (_ragdollPoints.size() == numStates) { - int numStates = _jointStates.size(); - for (int i = 0; i < numStates; ++i) { - // ragdollPoints start in model-frame - _ragdollPoints[i].initPosition(_jointStates.at(i).getPosition()); - } - } - enforceRagdollConstraints(); + _ragdoll->slamPointPositions(); + _ragdoll->enforceRagdollConstraints(); } void SkeletonModel::moveShapesTowardJoints(float deltaTime) { @@ -747,8 +663,9 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { // unravel a skelton that has become tangled in its constraints. So let's keep this // around for a while just in case. const int numStates = _jointStates.size(); - assert(_jointStates.size() == _ragdollPoints.size()); - if (_ragdollPoints.size() != numStates) { + QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + assert(_jointStates.size() == ragdollPoints.size()); + if (ragdollPoints.size() != numStates) { return; } @@ -757,32 +674,22 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f); float oneMinusFraction = 1.0f - fraction; - glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); + glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); for (int i = 0; i < numStates; ++i) { // ragdollPoints are in simulation-frame but jointStates are in model-frame - _ragdollPoints[i].initPosition(oneMinusFraction * _ragdollPoints[i]._position + + ragdollPoints[i].initPosition(oneMinusFraction * ragdollPoints[i]._position + fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition()))); } } -void SkeletonModel::updateMuscles() { - int numConstraints = _muscleConstraints.size(); - for (int i = 0; i < numConstraints; ++i) { - MuscleConstraint* constraint = _muscleConstraints[i]; - int j = constraint->getParentIndex(); - int k = constraint->getChildIndex(); - assert(j != -1 && k != -1); - // ragdollPoints are in simulation-frame but jointStates are in model-frame - constraint->setChildOffset(_rotation * (_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition())); - } -} - void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { // compute default joint transforms int numStates = _jointStates.size(); QVector transforms; transforms.fill(glm::mat4(), numStates); + QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + // compute the default transforms and slam the ragdoll positions accordingly // (which puts the shapes where we want them) for (int i = 0; i < numStates; i++) { @@ -791,7 +698,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { int parentIndex = joint.parentIndex; if (parentIndex == -1) { transforms[i] = _jointStates[i].getTransform(); - _ragdollPoints[i].initPosition(extractTranslation(transforms[i])); + ragdollPoints[i].initPosition(extractTranslation(transforms[i])); continue; } @@ -799,7 +706,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; // setting the ragdollPoints here slams the VerletShapes into their default positions - _ragdollPoints[i].initPosition(extractTranslation(transforms[i])); + ragdollPoints[i].initPosition(extractTranslation(transforms[i])); } // compute bounding box that encloses all shapes @@ -918,9 +825,12 @@ const int BALL_SUBDIVISIONS = 10; // virtual void SkeletonModel::renderJointCollisionShapes(float alpha) { + if (!_ragdoll) { + return; + } glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); - glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); + glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); for (int i = 0; i < _shapes.size(); i++) { Shape* shape = _shapes[i]; if (!shape) { diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 55fedbcb6b..b0d6ed7325 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -15,18 +15,20 @@ #include "renderer/Model.h" #include -#include +#include "SkeletonRagdoll.h" class Avatar; class MuscleConstraint; +class SkeletonRagdoll; /// A skeleton loaded from a model. -class SkeletonModel : public Model, public Ragdoll { +class SkeletonModel : public Model { Q_OBJECT public: SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL); + ~SkeletonModel(); void setJointStates(QVector states); @@ -96,12 +98,11 @@ public: bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; virtual void updateVisibleJointStates(); - - // virtual overrride from Ragdoll - virtual void stepRagdollForward(float deltaTime); + SkeletonRagdoll* buildRagdoll(); + SkeletonRagdoll* getRagdoll() { return _ragdoll; } + void moveShapesTowardJoints(float fraction); - void updateMuscles(); void computeBoundingShape(const FBXGeometry& geometry); void renderBoundingCollisionShapes(float alpha); @@ -115,10 +116,6 @@ public: protected: - // virtual overrrides from Ragdoll - void initRagdollPoints(); - void buildRagdollConstraints(); - void buildShapes(); /// \param jointIndex index of joint in model @@ -147,7 +144,7 @@ private: CapsuleShape _boundingShape; glm::vec3 _boundingShapeLocalOffset; - QVector _muscleConstraints; + SkeletonRagdoll* _ragdoll; }; #endif // hifi_SkeletonModel_h diff --git a/interface/src/avatar/SkeletonRagdoll.cpp b/interface/src/avatar/SkeletonRagdoll.cpp new file mode 100644 index 0000000000..b63197bd2c --- /dev/null +++ b/interface/src/avatar/SkeletonRagdoll.cpp @@ -0,0 +1,148 @@ +// +// SkeletonRagdoll.cpp +// interface/src/avatar +// +// Created by Andrew Meadows 2014.08.14 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include + +#include "SkeletonRagdoll.h" +#include "MuscleConstraint.h" +#include "../renderer/Model.h" + +SkeletonRagdoll::SkeletonRagdoll(Model* model) : Ragdoll(), _model(model) { + assert(_model); +} + +SkeletonRagdoll::~SkeletonRagdoll() { +} + +// virtual +void SkeletonRagdoll::stepRagdollForward(float deltaTime) { + setRagdollTransform(_model->getTranslation(), _model->getRotation()); + Ragdoll::stepRagdollForward(deltaTime); + updateMuscles(); + int numConstraints = _muscleConstraints.size(); + for (int i = 0; i < numConstraints; ++i) { + _muscleConstraints[i]->enforce(); + } +} + +void SkeletonRagdoll::slamPointPositions() { + QVector& jointStates = _model->getJointStates(); + int numStates = jointStates.size(); + for (int i = 0; i < numStates; ++i) { + _ragdollPoints[i].initPosition(jointStates.at(i).getPosition()); + } +} + +// virtual +void SkeletonRagdoll::initRagdollPoints() { + clearRagdollConstraintsAndPoints(); + _muscleConstraints.clear(); + + initRagdollTransform(); + // one point for each joint + QVector& jointStates = _model->getJointStates(); + int numStates = jointStates.size(); + _ragdollPoints.fill(VerletPoint(), numStates); + slamPointPositions(); +} + +// virtual +void SkeletonRagdoll::buildRagdollConstraints() { + QVector& jointStates = _model->getJointStates(); + + // NOTE: the length of DistanceConstraints is computed and locked in at this time + // so make sure the ragdoll positions are in a normal configuration before here. + const int numPoints = _ragdollPoints.size(); + assert(numPoints == jointStates.size()); + + float minBone = FLT_MAX; + float maxBone = -FLT_MAX; + QMultiMap families; + for (int i = 0; i < numPoints; ++i) { + const JointState& state = jointStates.at(i); + int parentIndex = state.getParentIndex(); + if (parentIndex == -1) { + FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); + _fixedConstraints.push_back(anchor); + } else { + DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); + bone->setDistance(state.getDistanceToParent()); + _boneConstraints.push_back(bone); + families.insert(parentIndex, i); + } + float boneLength = glm::length(state.getPositionInParentFrame()); + if (boneLength > maxBone) { + maxBone = boneLength; + } else if (boneLength < minBone) { + minBone = boneLength; + } + } + // Joints that have multiple children effectively have rigid constraints between the children + // in the parent frame, so we add DistanceConstraints between children in the same family. + QMultiMap::iterator itr = families.begin(); + while (itr != families.end()) { + QList children = families.values(itr.key()); + int numChildren = children.size(); + if (numChildren > 1) { + for (int i = 1; i < numChildren; ++i) { + DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); + _boneConstraints.push_back(bone); + } + if (numChildren > 2) { + DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); + _boneConstraints.push_back(bone); + } + } + ++itr; + } + + float MAX_STRENGTH = 0.6f; + float MIN_STRENGTH = 0.05f; + // each joint gets a MuscleConstraint to its parent + for (int i = 1; i < numPoints; ++i) { + const JointState& state = jointStates.at(i); + int p = state.getParentIndex(); + if (p == -1) { + continue; + } + MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i])); + _muscleConstraints.push_back(constraint); + + // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: + // long = weak and short = strong. + constraint->setIndices(p, i); + float boneLength = glm::length(state.getPositionInParentFrame()); + + float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone); + if (!families.contains(i)) { + // Although muscles only pull on the children not parents, nevertheless those joints that have + // parents AND children are more stable than joints at the end such as fingers. For such joints we + // bestow maximum strength which helps reduce wiggle. + strength = MAX_MUSCLE_STRENGTH; + } + constraint->setStrength(strength); + } +} + +void SkeletonRagdoll::updateMuscles() { + QVector& jointStates = _model->getJointStates(); + int numConstraints = _muscleConstraints.size(); + glm::quat rotation = _model->getRotation(); + for (int i = 0; i < numConstraints; ++i) { + MuscleConstraint* constraint = _muscleConstraints[i]; + int j = constraint->getParentIndex(); + int k = constraint->getChildIndex(); + assert(j != -1 && k != -1); + // ragdollPoints are in simulation-frame but jointStates are in model-frame + constraint->setChildOffset(rotation * (jointStates.at(k).getPosition() - jointStates.at(j).getPosition())); + } +} diff --git a/interface/src/avatar/SkeletonRagdoll.h b/interface/src/avatar/SkeletonRagdoll.h new file mode 100644 index 0000000000..e9638eafac --- /dev/null +++ b/interface/src/avatar/SkeletonRagdoll.h @@ -0,0 +1,42 @@ +// +// SkeletonkRagdoll.h +// interface/src/avatar +// +// Created by Andrew Meadows 2014.08.14 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_SkeletonRagdoll_h +#define hifi_SkeletonRagdoll_h + +#include + +#include + +#include "../renderer/JointState.h" + +class MuscleConstraint; +class Model; + +class SkeletonRagdoll : public Ragdoll { +public: + + SkeletonRagdoll(Model* model); + virtual ~SkeletonRagdoll(); + + void slamPointPositions(); + virtual void stepRagdollForward(float deltaTime); + + virtual void initRagdollPoints(); + virtual void buildRagdollConstraints(); + + void updateMuscles(); +private: + Model* _model; + QVector _muscleConstraints; +}; + +#endif // hifi_SkeletonRagdoll_h diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 7a29b61420..da72d43133 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -164,6 +164,9 @@ public: const QVector& getLocalLights() const { return _localLights; } void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; } + + QVector& getJointStates() { return _jointStates; } + const QVector& getJointStates() const { return _jointStates; } protected: QSharedPointer _geometry; diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index ec5a561d1a..75f263149e 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -52,11 +52,11 @@ public: void setMassScale(float scale); float getMassScale() const { return _massScale; } -protected: void clearRagdollConstraintsAndPoints(); virtual void initRagdollPoints() = 0; virtual void buildRagdollConstraints() = 0; +protected: float _massScale; glm::vec3 _ragdollTranslation; // world-frame glm::quat _ragdollRotation; // world-frame From 60d411ead50f5701be7f6b88652ccd9ebe9610ba Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 14:41:51 -0700 Subject: [PATCH 2/5] cleanup Ragdoll API (less "ragdoll" qualifiers) --- interface/src/avatar/SkeletonModel.cpp | 16 ++++---- interface/src/avatar/SkeletonRagdoll.cpp | 30 +++++++-------- interface/src/avatar/SkeletonRagdoll.h | 6 +-- libraries/shared/src/PhysicsSimulation.cpp | 28 +++++++------- libraries/shared/src/Ragdoll.cpp | 44 +++++++++++----------- libraries/shared/src/Ragdoll.h | 26 ++++++------- 6 files changed, 75 insertions(+), 75 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 90145f0af8..ffe711b03b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -497,7 +497,7 @@ void SkeletonModel::renderRagdoll() { if (!_ragdoll) { return; } - const QVector& points = _ragdoll->getRagdollPoints(); + const QVector& points = _ragdoll->getPoints(); const int BALL_SUBDIVISIONS = 6; glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); @@ -531,7 +531,7 @@ void SkeletonModel::updateVisibleJointStates() { // no need to update visible transforms return; } - const QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + const QVector& ragdollPoints = _ragdoll->getPoints(); QVector points; points.reserve(_jointStates.size()); glm::quat invRotation = glm::inverse(_rotation); @@ -599,8 +599,8 @@ void SkeletonModel::buildShapes() { if (!_ragdoll) { _ragdoll = new SkeletonRagdoll(this); } - _ragdoll->initRagdollPoints(); - QVector& points = _ragdoll->getRagdollPoints(); + _ragdoll->initPoints(); + QVector& points = _ragdoll->getPoints(); float massScale = _ragdoll->getMassScale(); @@ -651,11 +651,11 @@ void SkeletonModel::buildShapes() { // joints that are currently colliding. disableCurrentSelfCollisions(); - _ragdoll->buildRagdollConstraints(); + _ragdoll->buildConstraints(); // ... then move shapes back to current joint positions _ragdoll->slamPointPositions(); - _ragdoll->enforceRagdollConstraints(); + _ragdoll->enforceConstraints(); } void SkeletonModel::moveShapesTowardJoints(float deltaTime) { @@ -663,7 +663,7 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { // unravel a skelton that has become tangled in its constraints. So let's keep this // around for a while just in case. const int numStates = _jointStates.size(); - QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + QVector& ragdollPoints = _ragdoll->getPoints(); assert(_jointStates.size() == ragdollPoints.size()); if (ragdollPoints.size() != numStates) { return; @@ -688,7 +688,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { QVector transforms; transforms.fill(glm::mat4(), numStates); - QVector& ragdollPoints = _ragdoll->getRagdollPoints(); + QVector& ragdollPoints = _ragdoll->getPoints(); // compute the default transforms and slam the ragdoll positions accordingly // (which puts the shapes where we want them) diff --git a/interface/src/avatar/SkeletonRagdoll.cpp b/interface/src/avatar/SkeletonRagdoll.cpp index b63197bd2c..503f38f00f 100644 --- a/interface/src/avatar/SkeletonRagdoll.cpp +++ b/interface/src/avatar/SkeletonRagdoll.cpp @@ -24,9 +24,9 @@ SkeletonRagdoll::~SkeletonRagdoll() { } // virtual -void SkeletonRagdoll::stepRagdollForward(float deltaTime) { - setRagdollTransform(_model->getTranslation(), _model->getRotation()); - Ragdoll::stepRagdollForward(deltaTime); +void SkeletonRagdoll::stepForward(float deltaTime) { + setTransform(_model->getTranslation(), _model->getRotation()); + Ragdoll::stepForward(deltaTime); updateMuscles(); int numConstraints = _muscleConstraints.size(); for (int i = 0; i < numConstraints; ++i) { @@ -38,30 +38,30 @@ void SkeletonRagdoll::slamPointPositions() { QVector& jointStates = _model->getJointStates(); int numStates = jointStates.size(); for (int i = 0; i < numStates; ++i) { - _ragdollPoints[i].initPosition(jointStates.at(i).getPosition()); + _points[i].initPosition(jointStates.at(i).getPosition()); } } // virtual -void SkeletonRagdoll::initRagdollPoints() { - clearRagdollConstraintsAndPoints(); +void SkeletonRagdoll::initPoints() { + clearConstraintsAndPoints(); _muscleConstraints.clear(); - initRagdollTransform(); + initTransform(); // one point for each joint QVector& jointStates = _model->getJointStates(); int numStates = jointStates.size(); - _ragdollPoints.fill(VerletPoint(), numStates); + _points.fill(VerletPoint(), numStates); slamPointPositions(); } // virtual -void SkeletonRagdoll::buildRagdollConstraints() { +void SkeletonRagdoll::buildConstraints() { QVector& jointStates = _model->getJointStates(); // NOTE: the length of DistanceConstraints is computed and locked in at this time // so make sure the ragdoll positions are in a normal configuration before here. - const int numPoints = _ragdollPoints.size(); + const int numPoints = _points.size(); assert(numPoints == jointStates.size()); float minBone = FLT_MAX; @@ -71,10 +71,10 @@ void SkeletonRagdoll::buildRagdollConstraints() { const JointState& state = jointStates.at(i); int parentIndex = state.getParentIndex(); if (parentIndex == -1) { - FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); + FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_points[i])); _fixedConstraints.push_back(anchor); } else { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); + DistanceConstraint* bone = new DistanceConstraint(&(_points[i]), &(_points[parentIndex])); bone->setDistance(state.getDistanceToParent()); _boneConstraints.push_back(bone); families.insert(parentIndex, i); @@ -94,11 +94,11 @@ void SkeletonRagdoll::buildRagdollConstraints() { int numChildren = children.size(); if (numChildren > 1) { for (int i = 1; i < numChildren; ++i) { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); + DistanceConstraint* bone = new DistanceConstraint(&(_points[children[i-1]]), &(_points[children[i]])); _boneConstraints.push_back(bone); } if (numChildren > 2) { - DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); + DistanceConstraint* bone = new DistanceConstraint(&(_points[children[numChildren-1]]), &(_points[children[0]])); _boneConstraints.push_back(bone); } } @@ -114,7 +114,7 @@ void SkeletonRagdoll::buildRagdollConstraints() { if (p == -1) { continue; } - MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i])); + MuscleConstraint* constraint = new MuscleConstraint(&(_points[p]), &(_points[i])); _muscleConstraints.push_back(constraint); // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: diff --git a/interface/src/avatar/SkeletonRagdoll.h b/interface/src/avatar/SkeletonRagdoll.h index e9638eafac..f9f99395ac 100644 --- a/interface/src/avatar/SkeletonRagdoll.h +++ b/interface/src/avatar/SkeletonRagdoll.h @@ -28,10 +28,10 @@ public: virtual ~SkeletonRagdoll(); void slamPointPositions(); - virtual void stepRagdollForward(float deltaTime); + virtual void stepForward(float deltaTime); - virtual void initRagdollPoints(); - virtual void buildRagdollConstraints(); + virtual void initPoints(); + virtual void buildConstraints(); void updateMuscles(); private: diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 6dcafc6a54..84f8282c9d 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -47,12 +47,12 @@ PhysicsSimulation::~PhysicsSimulation() { void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) { if (_ragdoll != ragdoll) { if (_ragdoll) { - _ragdoll->_ragdollSimulation = NULL; + _ragdoll->_simulation = NULL; } _ragdoll = ragdoll; if (_ragdoll) { - assert(!(_ragdoll->_ragdollSimulation)); - _ragdoll->_ragdollSimulation = this; + assert(!(_ragdoll->_simulation)); + _ragdoll->_simulation = this; } } } @@ -144,7 +144,7 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { // list is full return false; } - if (doll->_ragdollSimulation == this) { + if (doll->_simulation == this) { for (int i = 0; i < numDolls; ++i) { if (doll == _otherRagdolls[i]) { // already in list @@ -153,8 +153,8 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { } } // add to list - assert(!(doll->_ragdollSimulation)); - doll->_ragdollSimulation = this; + assert(!(doll->_simulation)); + doll->_simulation = this; _otherRagdolls.push_back(doll); // set the massScale of otherRagdolls artificially high @@ -164,7 +164,7 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { int numDolls = _otherRagdolls.size(); - if (doll->_ragdollSimulation != this) { + if (doll->_simulation != this) { return; } for (int i = 0; i < numDolls; ++i) { @@ -178,7 +178,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { _otherRagdolls.pop_back(); _otherRagdolls[i] = lastDoll; } - doll->_ragdollSimulation = NULL; + doll->_simulation = NULL; doll->setMassScale(1.0f); break; } @@ -199,9 +199,9 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter int numDolls = _otherRagdolls.size(); { PerformanceTimer perfTimer("enforce"); - _ragdoll->enforceRagdollConstraints(); + _ragdoll->enforceConstraints(); for (int i = 0; i < numDolls; ++i) { - _otherRagdolls[i]->enforceRagdollConstraints(); + _otherRagdolls[i]->enforceConstraints(); } } @@ -214,9 +214,9 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter { // enforce constraints PerformanceTimer perfTimer("enforce"); - error = _ragdoll->enforceRagdollConstraints(); + error = _ragdoll->enforceConstraints(); for (int i = 0; i < numDolls; ++i) { - error = glm::max(error, _otherRagdolls[i]->enforceRagdollConstraints()); + error = glm::max(error, _otherRagdolls[i]->enforceConstraints()); } } enforceContactConstraints(); @@ -230,10 +230,10 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter void PhysicsSimulation::moveRagdolls(float deltaTime) { PerformanceTimer perfTimer("integrate"); - _ragdoll->stepRagdollForward(deltaTime); + _ragdoll->stepForward(deltaTime); int numDolls = _otherRagdolls.size(); for (int i = 0; i < numDolls; ++i) { - _otherRagdolls[i]->stepRagdollForward(deltaTime); + _otherRagdolls[i]->stepForward(deltaTime); } } diff --git a/libraries/shared/src/Ragdoll.cpp b/libraries/shared/src/Ragdoll.cpp index 80e3c27e04..7eeaf0b609 100644 --- a/libraries/shared/src/Ragdoll.cpp +++ b/libraries/shared/src/Ragdoll.cpp @@ -19,27 +19,27 @@ #include "PhysicsSimulation.h" #include "SharedUtil.h" // for EPSILON -Ragdoll::Ragdoll() : _massScale(1.0f), _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { +Ragdoll::Ragdoll() : _massScale(1.0f), _translation(0.0f), _translationInSimulationFrame(0.0f), _simulation(NULL) { } Ragdoll::~Ragdoll() { - clearRagdollConstraintsAndPoints(); - if (_ragdollSimulation) { - _ragdollSimulation->removeRagdoll(this); + clearConstraintsAndPoints(); + if (_simulation) { + _simulation->removeRagdoll(this); } } -void Ragdoll::stepRagdollForward(float deltaTime) { - if (_ragdollSimulation) { - updateSimulationTransforms(_ragdollTranslation - _ragdollSimulation->getTranslation(), _ragdollRotation); +void Ragdoll::stepForward(float deltaTime) { + if (_simulation) { + updateSimulationTransforms(_translation - _simulation->getTranslation(), _rotation); } - int numPoints = _ragdollPoints.size(); + int numPoints = _points.size(); for (int i = 0; i < numPoints; ++i) { - _ragdollPoints[i].integrateForward(); + _points[i].integrateForward(); } } -void Ragdoll::clearRagdollConstraintsAndPoints() { +void Ragdoll::clearConstraintsAndPoints() { int numConstraints = _boneConstraints.size(); for (int i = 0; i < numConstraints; ++i) { delete _boneConstraints[i]; @@ -50,10 +50,10 @@ void Ragdoll::clearRagdollConstraintsAndPoints() { delete _fixedConstraints[i]; } _fixedConstraints.clear(); - _ragdollPoints.clear(); + _points.clear(); } -float Ragdoll::enforceRagdollConstraints() { +float Ragdoll::enforceConstraints() { float maxDistance = 0.0f; // enforce the bone constraints first int numConstraints = _boneConstraints.size(); @@ -68,16 +68,16 @@ float Ragdoll::enforceRagdollConstraints() { return maxDistance; } -void Ragdoll::initRagdollTransform() { - _ragdollTranslation = glm::vec3(0.0f); - _ragdollRotation = glm::quat(); +void Ragdoll::initTransform() { + _translation = glm::vec3(0.0f); + _rotation = glm::quat(); _translationInSimulationFrame = glm::vec3(0.0f); _rotationInSimulationFrame = glm::quat(); } -void Ragdoll::setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation) { - _ragdollTranslation = translation; - _ragdollRotation = rotation; +void Ragdoll::setTransform(const glm::vec3& translation, const glm::quat& rotation) { + _translation = translation; + _rotation = rotation; } void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) { @@ -93,9 +93,9 @@ void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame); // apply the deltas to all ragdollPoints - int numPoints = _ragdollPoints.size(); + int numPoints = _points.size(); for (int i = 0; i < numPoints; ++i) { - _ragdollPoints[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); + _points[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); } // remember the current transform @@ -109,9 +109,9 @@ void Ragdoll::setMassScale(float scale) { scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE); if (scale != _massScale) { float rescale = scale / _massScale; - int numPoints = _ragdollPoints.size(); + int numPoints = _points.size(); for (int i = 0; i < numPoints; ++i) { - _ragdollPoints[i].setMass(rescale * _ragdollPoints[i].getMass()); + _points[i].setMass(rescale * _points[i].getMass()); } _massScale = scale; } diff --git a/libraries/shared/src/Ragdoll.h b/libraries/shared/src/Ragdoll.h index 75f263149e..c82295d9a5 100644 --- a/libraries/shared/src/Ragdoll.h +++ b/libraries/shared/src/Ragdoll.h @@ -33,44 +33,44 @@ public: Ragdoll(); virtual ~Ragdoll(); - virtual void stepRagdollForward(float deltaTime); + virtual void stepForward(float deltaTime); /// \return max distance of point movement - float enforceRagdollConstraints(); + float enforceConstraints(); // both const and non-const getPoints() - const QVector& getRagdollPoints() const { return _ragdollPoints; } - QVector& getRagdollPoints() { return _ragdollPoints; } + const QVector& getPoints() const { return _points; } + QVector& getPoints() { return _points; } - void initRagdollTransform(); + void initTransform(); /// set the translation and rotation of the Ragdoll and adjust all VerletPoints. - void setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation); + void setTransform(const glm::vec3& translation, const glm::quat& rotation); const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } void setMassScale(float scale); float getMassScale() const { return _massScale; } - void clearRagdollConstraintsAndPoints(); - virtual void initRagdollPoints() = 0; - virtual void buildRagdollConstraints() = 0; + void clearConstraintsAndPoints(); + virtual void initPoints() = 0; + virtual void buildConstraints() = 0; protected: float _massScale; - glm::vec3 _ragdollTranslation; // world-frame - glm::quat _ragdollRotation; // world-frame + glm::vec3 _translation; // world-frame + glm::quat _rotation; // world-frame glm::vec3 _translationInSimulationFrame; glm::quat _rotationInSimulationFrame; - QVector _ragdollPoints; + QVector _points; QVector _boneConstraints; QVector _fixedConstraints; private: void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation); friend class PhysicsSimulation; - PhysicsSimulation* _ragdollSimulation; + PhysicsSimulation* _simulation; }; #endif // hifi_Ragdoll_h From 98d27ad2b53656da0f2b38761f6720d2a0dc45df Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 15:17:03 -0700 Subject: [PATCH 3/5] more correct names for ContactPoint API renamed (and disabled) the useless enforce() to applyFriction() changed the buildConstraints() method to more correct name: enforce() will eventually change how ContactPoint actually works, but later --- libraries/shared/src/ContactPoint.cpp | 39 ++++++++++++---------- libraries/shared/src/ContactPoint.h | 4 +-- libraries/shared/src/PhysicsSimulation.cpp | 24 ++++++------- libraries/shared/src/PhysicsSimulation.h | 4 +-- 4 files changed, 37 insertions(+), 34 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index 4c1cf7b842..4f1cf87da5 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -88,25 +88,7 @@ ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : } } -// virtual float ContactPoint::enforce() { - for (int i = 0; i < _numPoints; ++i) { - glm::vec3& position = _points[i]->_position; - // TODO: use a fast distance approximation - float newDistance = glm::distance(_contactPoint, position); - float constrainedDistance = _distances[i]; - // NOTE: these "distance" constraints only push OUT, don't pull IN. - if (newDistance > EPSILON && newDistance < constrainedDistance) { - glm::vec3 direction = (_contactPoint - position) / newDistance; - glm::vec3 center = 0.5f * (_contactPoint + position); - _contactPoint = center + (0.5f * constrainedDistance) * direction; - position = center - (0.5f * constrainedDistance) * direction; - } - } - return 0.0f; -} - -void ContactPoint::buildConstraints() { glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; glm::vec3 penetration = pointA - pointB; @@ -153,6 +135,27 @@ void ContactPoint::buildConstraints() { _distances[i] = glm::length(glm::length(_offsets[i])); } } + return 0.0f; +} + +// virtual +void ContactPoint::applyFriction() { + // TODO: Andrew to re-implement this + /* + for (int i = 0; i < _numPoints; ++i) { + glm::vec3& position = _points[i]->_position; + // TODO: use a fast distance approximation + float newDistance = glm::distance(_contactPoint, position); + float constrainedDistance = _distances[i]; + // NOTE: these "distance" constraints only push OUT, don't pull IN. + if (newDistance > EPSILON && newDistance < constrainedDistance) { + glm::vec3 direction = (_contactPoint - position) / newDistance; + glm::vec3 center = 0.5f * (_contactPoint + position); + _contactPoint = center + (0.5f * constrainedDistance) * direction; + position = center - (0.5f * constrainedDistance) * direction; + } + } + */ } void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) { diff --git a/libraries/shared/src/ContactPoint.h b/libraries/shared/src/ContactPoint.h index 5257fabee0..d584945970 100644 --- a/libraries/shared/src/ContactPoint.h +++ b/libraries/shared/src/ContactPoint.h @@ -26,8 +26,8 @@ public: ContactPoint(const CollisionInfo& collision, quint32 frame); virtual float enforce(); - - void buildConstraints(); + + void applyFriction(); void updateContact(const CollisionInfo& collision, quint32 frame); quint32 getLastFrame() const { return _lastFrame; } diff --git a/libraries/shared/src/PhysicsSimulation.cpp b/libraries/shared/src/PhysicsSimulation.cpp index 84f8282c9d..a62b3816af 100644 --- a/libraries/shared/src/PhysicsSimulation.cpp +++ b/libraries/shared/src/PhysicsSimulation.cpp @@ -195,7 +195,7 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter quint64 expiry = startTime + maxUsec; moveRagdolls(deltaTime); - buildContactConstraints(); + enforceContacts(); int numDolls = _otherRagdolls.size(); { PerformanceTimer perfTimer("enforce"); @@ -219,7 +219,7 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter error = glm::max(error, _otherRagdolls[i]->enforceConstraints()); } } - enforceContactConstraints(); + applyContactFriction(); ++iterations; now = usecTimestampNow(); @@ -288,16 +288,7 @@ void PhysicsSimulation::resolveCollisions() { } } -void PhysicsSimulation::buildContactConstraints() { - PerformanceTimer perfTimer("contacts"); - QMap::iterator itr = _contacts.begin(); - while (itr != _contacts.end()) { - itr.value().buildConstraints(); - ++itr; - } -} - -void PhysicsSimulation::enforceContactConstraints() { +void PhysicsSimulation::enforceContacts() { PerformanceTimer perfTimer("contacts"); QMap::iterator itr = _contacts.begin(); while (itr != _contacts.end()) { @@ -306,6 +297,15 @@ void PhysicsSimulation::enforceContactConstraints() { } } +void PhysicsSimulation::applyContactFriction() { + PerformanceTimer perfTimer("contacts"); + QMap::iterator itr = _contacts.begin(); + while (itr != _contacts.end()) { + itr.value().applyFriction(); + ++itr; + } +} + void PhysicsSimulation::updateContacts() { PerformanceTimer perfTimer("contacts"); int numCollisions = _collisions.size(); diff --git a/libraries/shared/src/PhysicsSimulation.h b/libraries/shared/src/PhysicsSimulation.h index 61ab1bf177..881007208b 100644 --- a/libraries/shared/src/PhysicsSimulation.h +++ b/libraries/shared/src/PhysicsSimulation.h @@ -56,8 +56,8 @@ protected: void computeCollisions(); void resolveCollisions(); - void buildContactConstraints(); - void enforceContactConstraints(); + void enforceContacts(); + void applyContactFriction(); void updateContacts(); void pruneContacts(); From 432c14408c05d1f99a7b09bed4c4a619f2d98035 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Aug 2014 15:29:57 -0700 Subject: [PATCH 4/5] removed hackery from ContactPoint enforcement --- libraries/shared/src/ContactPoint.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/libraries/shared/src/ContactPoint.cpp b/libraries/shared/src/ContactPoint.cpp index 4f1cf87da5..27a496d445 100644 --- a/libraries/shared/src/ContactPoint.cpp +++ b/libraries/shared/src/ContactPoint.cpp @@ -98,14 +98,6 @@ float ContactPoint::enforce() { // the contact point will be the average of the two points on the shapes _contactPoint = 0.5f * (pointA + pointB); - // TODO: Andrew to compute more correct lagrangian weights that provide a more realistic response. - // - // HACK: since the weights are naively equal for all points (which is what the above TODO is about) we - // don't want to use the full-strength delta because otherwise there can be annoying oscillations. We - // reduce this problem by in the short-term by attenuating the delta that is applied, the tradeoff is - // that this makes it easier for limbs to tunnel through during collisions. - const float HACK_STRENGTH = 0.5f; - if (constraintViolation) { for (int i = 0; i < _numPoints; ++i) { VerletPoint* point = _points[i]; @@ -128,7 +120,7 @@ float ContactPoint::enforce() { glm::vec3 targetPosition = point->_position + delta; _distances[i] = glm::distance(_contactPoint, targetPosition); - point->_position += HACK_STRENGTH * delta; + point->_position += delta; } } else { for (int i = 0; i < _numPoints; ++i) { @@ -140,7 +132,7 @@ float ContactPoint::enforce() { // virtual void ContactPoint::applyFriction() { - // TODO: Andrew to re-implement this + // TODO: Andrew to re-implement this in a different way /* for (int i = 0; i < _numPoints; ++i) { glm::vec3& position = _points[i]->_position; From 77047b01302b75692a7a751d69ac644c58f8ab0a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 18 Aug 2014 11:25:51 -0700 Subject: [PATCH 5/5] no NULL check on delete SkeletonModel::_ragdoll --- interface/src/avatar/SkeletonModel.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index ffe711b03b..4e954af46b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -34,10 +34,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : } SkeletonModel::~SkeletonModel() { - if (_ragdoll) { - delete _ragdoll; - _ragdoll = NULL; - } + delete _ragdoll; + _ragdoll = NULL; } void SkeletonModel::setJointStates(QVector states) {