Skeleton now creates VerletShape

This commit is contained in:
Andrew Meadows 2014-06-18 17:22:39 -07:00
parent 715cc3467d
commit d4b5550cda
10 changed files with 117 additions and 189 deletions

View file

@ -218,9 +218,6 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes);
bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes);
bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);
if (renderSkeleton || renderHead || renderBounding) {
updateShapePositions();
}
if (renderSkeleton) { if (renderSkeleton) {
_skeletonModel.renderJointCollisionShapes(0.7f); _skeletonModel.renderJointCollisionShapes(0.7f);
@ -590,18 +587,6 @@ bool Avatar::findPlaneCollisions(const glm::vec4& plane, CollisionList& collisio
getHead()->getFaceModel().findPlaneCollisions(plane, collisions); getHead()->getFaceModel().findPlaneCollisions(plane, collisions);
} }
void Avatar::updateShapePositions() {
_skeletonModel.updateShapePositions();
Model& headModel = getHead()->getFaceModel();
headModel.updateShapePositions();
/* KEEP FOR DEBUG: use this in rather than code above to see shapes
* in their default positions where the bounding shape is computed.
_skeletonModel.resetShapePositions();
Model& headModel = getHead()->getFaceModel();
headModel.resetShapePositions();
*/
}
bool Avatar::findCollisions(const QVector<const Shape*>& shapes, CollisionList& collisions) { bool Avatar::findCollisions(const QVector<const Shape*>& shapes, CollisionList& collisions) {
// TODO: Andrew to fix: also collide against _skeleton // TODO: Andrew to fix: also collide against _skeleton
//bool collided = _skeletonModel.findCollisions(shapes, collisions); //bool collided = _skeletonModel.findCollisions(shapes, collisions);

View file

@ -136,7 +136,6 @@ public:
/// \return bounding radius of avatar /// \return bounding radius of avatar
virtual float getBoundingRadius() const; virtual float getBoundingRadius() const;
void updateShapePositions();
quint32 getCollisionGroups() const { return _collisionGroups; } quint32 getCollisionGroups() const { return _collisionGroups; }
virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); } virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); }

View file

@ -210,7 +210,6 @@ void MyAvatar::simulate(float deltaTime) {
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.0f)); radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.0f));
radius *= COLLISION_RADIUS_SCALAR; radius *= COLLISION_RADIUS_SCALAR;
} }
updateShapePositions();
if (_collisionGroups & COLLISION_GROUP_ENVIRONMENT) { if (_collisionGroups & COLLISION_GROUP_ENVIRONMENT) {
PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithEnvironment"); PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithEnvironment");
updateCollisionWithEnvironment(deltaTime, radius); updateCollisionWithEnvironment(deltaTime, radius);
@ -1447,7 +1446,6 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
// don't collide with ourselves // don't collide with ourselves
continue; continue;
} }
avatar->updateShapePositions();
float distance = glm::length(_position - avatar->getPosition()); float distance = glm::length(_position - avatar->getPosition());
if (_distanceToNearestAvatar > distance) { if (_distanceToNearestAvatar > distance) {
_distanceToNearestAvatar = distance; _distanceToNearestAvatar = distance;

View file

@ -11,8 +11,8 @@
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
#include <CapsuleShape.h> #include <VerletCapsuleShape.h>
#include <SphereShape.h> #include <VerletSphereShape.h>
#include "Application.h" #include "Application.h"
#include "Avatar.h" #include "Avatar.h"
@ -31,20 +31,10 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
void SkeletonModel::setJointStates(QVector<JointState> states) { void SkeletonModel::setJointStates(QVector<JointState> states) {
Model::setJointStates(states); Model::setJointStates(states);
if (isActive() && _owningAvatar->isMyAvatar()) { clearShapes();
// extract lists of parentIndex and position from _jointStates... clearRagdollConstraintsAndPoints();
QVector<int> parentIndices; if (_enableShapes) {
QVector<glm::vec3> points; buildShapes();
int numJoints = _jointStates.size();
parentIndices.reserve(numJoints);
points.reserve(numJoints);
for (int i = 0; i < numJoints; ++i) {
JointState& state = _jointStates[i];
parentIndices.push_back(state.getFBXJoint().parentIndex);
points.push_back(state.getPosition());
}
// ... and feed the results to Ragdoll
initShapesAndPoints(&_shapes, parentIndices, points);
} }
} }
@ -110,14 +100,11 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
} }
void SkeletonModel::simulateRagdoll(float deltaTime) { void SkeletonModel::simulateRagdoll(float deltaTime) {
// move ragdoll _points toward joints // move _ragdollPoints toward joints
const int numStates = _jointStates.size(); const int numStates = _jointStates.size();
assert(numStates == _points.size()); assert(numStates == _ragdollPoints.size());
float fraction = 0.1f; // fraction = 0.1f left intentionally low for demo purposes float fraction = 0.1f; // fraction = 0.1f left intentionally low for demo purposes
float oneMinusFraction = 1.0f - fraction; moveShapesTowardJoints(fraction);
for (int i = 0; i < numStates; ++i) {
_points[i] = oneMinusFraction * _points[i] + fraction * _jointStates[i].getPosition();
}
// enforce the constraints // enforce the constraints
float MIN_CONSTRAINT_ERROR = 0.005f; // 5mm float MIN_CONSTRAINT_ERROR = 0.005f; // 5mm
@ -125,7 +112,7 @@ void SkeletonModel::simulateRagdoll(float deltaTime) {
int iterations = 0; int iterations = 0;
float delta = 0.0f; float delta = 0.0f;
do { do {
delta = enforceConstraints(); delta = enforceRagdollConstraints();
++iterations; ++iterations;
} while (delta > MIN_CONSTRAINT_ERROR && iterations < MAX_ITERATIONS); } while (delta > MIN_CONSTRAINT_ERROR && iterations < MAX_ITERATIONS);
} }
@ -274,16 +261,6 @@ void SkeletonModel::updateJointState(int index) {
} }
} }
void SkeletonModel::updateShapePositions() {
if (isActive() && _owningAvatar->isMyAvatar() &&
Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
// TODO: Andrew to move shape updates to SimulationEngine
//updateShapes(_rotation, _translation);
} else {
Model::updateShapePositions();
}
}
void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) {
if (!_owningAvatar->isMyAvatar() || Application::getInstance()->getPrioVR()->isActive()) { if (!_owningAvatar->isMyAvatar() || Application::getInstance()->getPrioVR()->isActive()) {
return; return;
@ -516,14 +493,14 @@ void SkeletonModel::renderRagdoll() {
glPushMatrix(); glPushMatrix();
Application::getInstance()->loadTranslatedViewMatrix(_translation); Application::getInstance()->loadTranslatedViewMatrix(_translation);
int numPoints = _points.size(); int numPoints = _ragdollPoints.size();
float alpha = 0.3f; float alpha = 0.3f;
float radius1 = 0.008f; float radius1 = 0.008f;
float radius2 = 0.01f; float radius2 = 0.01f;
for (int i = 0; i < numPoints; ++i) { for (int i = 0; i < numPoints; ++i) {
glPushMatrix(); glPushMatrix();
// draw each point as a yellow hexagon with black border // draw each point as a yellow hexagon with black border
glm::vec3 position = _rotation * _points[i]; glm::vec3 position = _rotation * _ragdollPoints[i];
glTranslatef(position.x, position.y, position.z); glTranslatef(position.x, position.y, position.z);
glColor4f(0.0f, 0.0f, 0.0f, alpha); glColor4f(0.0f, 0.0f, 0.0f, alpha);
glutSolidSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); glutSolidSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
@ -536,6 +513,22 @@ void SkeletonModel::renderRagdoll() {
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
} }
// virtual
void SkeletonModel::initRagdollPoints() {
assert(_ragdollPoints.size() == 0);
// one point for each joint
int numJoints = _jointStates.size();
_ragdollPoints.reserve(numJoints);
for (int i = 0; i < numJoints; ++i) {
const JointState& state = _jointStates.at(i);
_ragdollPoints.push_back(state.getPosition());
}
}
// virtual
void SkeletonModel::stepRagdollForward(float deltaTime) {
}
// virtual // virtual
void SkeletonModel::buildShapes() { void SkeletonModel::buildShapes() {
if (!_geometry || _rootIndex == -1) { if (!_geometry || _rootIndex == -1) {
@ -546,42 +539,53 @@ void SkeletonModel::buildShapes() {
if (geometry.joints.isEmpty()) { if (geometry.joints.isEmpty()) {
return; return;
} }
// We create the shapes with proper dimensions, but we set their transforms later.
float uniformScale = extractUniformScale(_scale);
for (int i = 0; i < _jointStates.size(); i++) {
const FBXJoint& joint = geometry.joints[i];
initRagdollPoints();
float uniformScale = extractUniformScale(_scale);
const int numStates = _jointStates.size();
for (int i = 0; i < numStates; i++) {
const FBXJoint& joint = geometry.joints[i];
float radius = uniformScale * joint.boneRadius; float radius = uniformScale * joint.boneRadius;
float halfHeight = 0.5f * uniformScale * joint.distanceToParent; float halfHeight = 0.5f * uniformScale * joint.distanceToParent;
Shape::Type type = joint.shapeType; Shape::Type type = joint.shapeType;
if (type == Shape::CAPSULE_SHAPE && halfHeight < EPSILON) { if (i == 0 || (type == Shape::CAPSULE_SHAPE && halfHeight < EPSILON)) {
// this capsule is effectively a sphere // this shape is forced to be a sphere
type = Shape::SPHERE_SHAPE; type = Shape::SPHERE_SHAPE;
} }
if (type == Shape::CAPSULE_SHAPE) { Shape* shape = NULL;
CapsuleShape* capsule = new CapsuleShape(radius, halfHeight); if (type == Shape::SPHERE_SHAPE) {
capsule->setEntity(this); shape = new VerletSphereShape(radius, &(_ragdollPoints[i]));
_shapes.push_back(capsule); shape->setEntity(this);
} else if (type == Shape::SPHERE_SHAPE) { } else if (type == Shape::CAPSULE_SHAPE) {
SphereShape* sphere = new SphereShape(radius, glm::vec3(0.0f)); int parentIndex = joint.parentIndex;
_shapes.push_back(sphere); assert(parentIndex != -1);
sphere->setEntity(this); shape = new VerletCapsuleShape(radius, &(_ragdollPoints[parentIndex]), &(_ragdollPoints[i]));
} else { shape->setEntity(this);
// this shape type is not handled and the joint shouldn't collide, }
// however we must have a Shape* for each joint, so we push NULL _shapes.push_back(shape);
_shapes.push_back(NULL);
}
} }
// This method moves the shapes to their default positions in Model frame // This method moves the shapes to their default positions in Model frame
// which is where we compute the bounding shape's parameters. // which is where we compute the bounding shape's parameters.
computeBoundingShape(geometry); computeBoundingShape(geometry);
// finally sync shapes to joint positions // move shapes to joint positions
_shapesAreDirty = true; moveShapesTowardJoints(1.0f);
updateShapePositions();
} }
void SkeletonModel::moveShapesTowardJoints(float fraction) {
assert(fraction >= 0.0f && fraction <= 1.0f);
if (_ragdollPoints.size() == _jointStates.size()) {
float oneMinusFraction = 1.0f - fraction;
int numJoints = _jointStates.size();
for (int i = 0; i < numJoints; ++i) {
_ragdollPoints[i] = oneMinusFraction * _ragdollPoints[i] + fraction * _jointStates.at(i).getPosition();
}
}
}
/* TODO: Andrew to remove this when done with ragdoll work.
void SkeletonModel::updateShapePositionsLegacy() { void SkeletonModel::updateShapePositionsLegacy() {
if (_shapesAreDirty && _shapes.size() == _jointStates.size()) { if (_shapesAreDirty && _shapes.size() == _jointStates.size()) {
glm::vec3 rootPosition(0.0f); glm::vec3 rootPosition(0.0f);
@ -612,65 +616,28 @@ void SkeletonModel::updateShapePositionsLegacy() {
_boundingShape.setRotation(_rotation); _boundingShape.setRotation(_rotation);
} }
} }
*/
void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
// compute default joint transforms and rotations // compute default joint transforms
// (in local frame, ignoring Model translation and rotation)
int numJoints = geometry.joints.size(); int numJoints = geometry.joints.size();
if (numJoints != _ragdollPoints.size()) {
return;
}
QVector<glm::mat4> transforms; QVector<glm::mat4> transforms;
transforms.fill(glm::mat4(), numJoints); transforms.fill(glm::mat4(), numJoints);
QVector<glm::quat> finalRotations;
finalRotations.fill(glm::quat(), numJoints);
QVector<bool> shapeIsSet; transforms[0] = glm::scale(_scale);
shapeIsSet.fill(false, numJoints); for (int i = 1; i < numJoints; i++) {
int numShapesSet = 0; const FBXJoint& joint = geometry.joints.at(i);
int lastNumShapesSet = -1; int parentIndex = joint.parentIndex;
while (numShapesSet < numJoints && numShapesSet != lastNumShapesSet) { assert(parentIndex != -1);
lastNumShapesSet = numShapesSet;
for (int i = 0; i < numJoints; i++) { glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation;
const FBXJoint& joint = geometry.joints.at(i); transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
int parentIndex = joint.parentIndex; * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform;
// setting the ragdollPoints here slams the VerletShapes into their default positions
if (parentIndex == -1) { _ragdollPoints[i] = extractTranslation(transforms[i]);
glm::mat4 baseTransform = glm::scale(_scale) * glm::translate(_offset);
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
glm::mat4 rootTransform = baseTransform * geometry.offset * glm::translate(joint.translation)
* joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform;
// remove the tranlsation part before we save the root transform
transforms[i] = glm::translate(- extractTranslation(rootTransform)) * rootTransform;
finalRotations[i] = combinedRotation;
++numShapesSet;
shapeIsSet[i] = true;
} else if (shapeIsSet[parentIndex]) {
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
* joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform;
finalRotations[i] = finalRotations[parentIndex] * combinedRotation;
++numShapesSet;
shapeIsSet[i] = true;
}
}
}
// sync shapes to joints
_boundingRadius = 0.0f;
float uniformScale = extractUniformScale(_scale);
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (!shape) {
continue;
}
const FBXJoint& joint = geometry.joints[i];
glm::vec3 jointToShapeOffset = uniformScale * (finalRotations[i] * joint.shapePosition);
glm::vec3 localPosition = extractTranslation(transforms[i]) + jointToShapeOffset;
shape->setTranslation(localPosition);
shape->setRotation(finalRotations[i] * joint.shapeRotation);
float distance = glm::length(localPosition) + shape->getBoundingRadius();
if (distance > _boundingRadius) {
_boundingRadius = distance;
}
} }
// compute bounding box // compute bounding box
@ -682,6 +649,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
if (!shape) { if (!shape) {
continue; continue;
} }
// TODO: skip hand and arm joints when computing bounding dimensions
Extents shapeExtents; Extents shapeExtents;
shapeExtents.reset(); shapeExtents.reset();
glm::vec3 localPosition = shape->getTranslation(); glm::vec3 localPosition = shape->getTranslation();
@ -715,6 +683,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
_boundingShape.setRadius(capsuleRadius); _boundingShape.setRadius(capsuleRadius);
_boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius); _boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius);
_boundingShapeLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum); _boundingShapeLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum);
_boundingRadius = 0.5f * glm::length(diagonal);
} }
void SkeletonModel::resetShapePositions() { void SkeletonModel::resetShapePositions() {

View file

@ -95,9 +95,12 @@ public:
/// \return whether or not both eye meshes were found /// \return whether or not both eye meshes were found
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
virtual void initRagdollPoints();
virtual void stepRagdollForward(float deltaTime);
void buildShapes(); void buildShapes();
void updateShapePositions(); void moveShapesTowardJoints(float fraction);
void updateShapePositionsLegacy(); //void updateShapePositionsLegacy(); // TODO: Andrew to remove this when done with ragdoll work
void computeBoundingShape(const FBXGeometry& geometry); void computeBoundingShape(const FBXGeometry& geometry);
void renderBoundingCollisionShapes(float alpha); void renderBoundingCollisionShapes(float alpha);

View file

@ -551,9 +551,6 @@ bool Model::updateGeometry() {
model->setURL(attachment.url); model->setURL(attachment.url);
_attachments.append(model); _attachments.append(model);
} }
if (_enableShapes) {
buildShapes();
}
needFullUpdate = true; needFullUpdate = true;
} }
return needFullUpdate; return needFullUpdate;

View file

@ -92,7 +92,7 @@ bool PhysicalEntity::findCollisions(const QVector<const Shape*> shapes, Collisio
} }
int numOurShapes = _shapes.size(); int numOurShapes = _shapes.size();
for (int j = 0; j < numOurShapes; ++j) { for (int j = 0; j < numOurShapes; ++j) {
const Shape* ourShape = _shapes[j]; const Shape* ourShape = _shapes.at(j);
if (ourShape && ShapeCollider::collideShapes(theirShape, ourShape, collisions)) { if (ourShape && ShapeCollider::collideShapes(theirShape, ourShape, collisions)) {
collided = true; collided = true;
} }
@ -142,7 +142,7 @@ bool PhysicalEntity::findPlaneCollisions(const glm::vec4& plane, CollisionList&
bool collided = false; bool collided = false;
PlaneShape planeShape(plane); PlaneShape planeShape(plane);
for (int i = 0; i < _shapes.size(); i++) { for (int i = 0; i < _shapes.size(); i++) {
if (_shapes[i] && ShapeCollider::collideShapes(&planeShape, _shapes[i], collisions)) { if (_shapes.at(i) && ShapeCollider::collideShapes(&planeShape, _shapes.at(i), collisions)) {
CollisionInfo* collision = collisions.getLastCollision(); CollisionInfo* collision = collisions.getLastCollision();
collision->_data = (void*)(this); collision->_data = (void*)(this);
collision->_intData = i; collision->_intData = i;

View file

@ -94,66 +94,55 @@ void DistanceConstraint::updateProxyShape(Shape* shape, const glm::quat& rotatio
// Ragdoll // Ragdoll
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
Ragdoll::Ragdoll() : _verletShapes(NULL) { Ragdoll::Ragdoll() {
} }
Ragdoll::~Ragdoll() { Ragdoll::~Ragdoll() {
clear(); clearRagdollConstraintsAndPoints();
} }
void Ragdoll::initShapesAndPoints(QVector<Shape*>* shapes, const QVector<int>& parentIndices, const QVector<glm::vec3>& points) { /*
void Ragdoll::useShapesAndCopyPoints(QVector<Shape*>* shapes, const QVector<int>& parentIndices, const QVector<glm::vec3>& points) {
clear(); clear();
_verletShapes = shapes; _verletShapes = shapes;
const int numPoints = points.size(); const int numPoints = points.size();
assert(numPoints == parentIndices.size()); assert(numPoints == parentIndices.size());
_points.reserve(numPoints); _ragdollPoints.reserve(numPoints);
for (int i = 0; i < numPoints; ++i) { for (int i = 0; i < numPoints; ++i) {
glm::vec3 position = points[i]; glm::vec3 position = points[i];
_points.push_back(position); _ragdollPoints.push_back(position);
int parentIndex = parentIndices[i]; int parentIndex = parentIndices[i];
assert(parentIndex < i && parentIndex >= -1); assert(parentIndex < i && parentIndex >= -1);
if (parentIndex == -1) { if (parentIndex == -1) {
FixedConstraint* anchor = new FixedConstraint(&(_points[i]), glm::vec3(0.0f)); FixedConstraint* anchor = new FixedConstraint(&(_ragdollPoints[i]), glm::vec3(0.0f));
_constraints.push_back(anchor); _ragdollConstraints.push_back(anchor);
} else { } else {
DistanceConstraint* stick = new DistanceConstraint(&(_points[i]), &(_points[parentIndex])); DistanceConstraint* stick = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex]));
_constraints.push_back(stick); _ragdollConstraints.push_back(stick);
} }
} }
} }
*/
/// Delete all data. /// Delete all data.
void Ragdoll::clear() { void Ragdoll::clearRagdollConstraintsAndPoints() {
int numConstraints = _constraints.size(); int numConstraints = _ragdollConstraints.size();
for (int i = 0; i < numConstraints; ++i) { for (int i = 0; i < numConstraints; ++i) {
delete _constraints[i]; delete _ragdollConstraints[i];
} }
_constraints.clear(); _ragdollConstraints.clear();
_points.clear(); _ragdollPoints.clear();
_verletShapes = NULL;
} }
float Ragdoll::enforceConstraints() { float Ragdoll::enforceRagdollConstraints() {
float maxDistance = 0.0f; float maxDistance = 0.0f;
const int numConstraints = _constraints.size(); const int numConstraints = _ragdollConstraints.size();
for (int i = 0; i < numConstraints; ++i) { for (int i = 0; i < numConstraints; ++i) {
DistanceConstraint* c = static_cast<DistanceConstraint*>(_constraints[i]); DistanceConstraint* c = static_cast<DistanceConstraint*>(_ragdollConstraints[i]);
//maxDistance = glm::max(maxDistance, _constraints[i]->enforce()); //maxDistance = glm::max(maxDistance, _ragdollConstraints[i]->enforce());
maxDistance = glm::max(maxDistance, c->enforce()); maxDistance = glm::max(maxDistance, c->enforce());
} }
return maxDistance; return maxDistance;
} }
void Ragdoll::updateShapes(const glm::quat& rotation, const glm::vec3& translation) const {
if (!_verletShapes) {
return;
}
int numShapes = _verletShapes->size();
int numConstraints = _constraints.size();
// NOTE: we assume a one-to-one relationship between shapes and constraints
for (int i = 0; i < numShapes && i < numConstraints; ++i) {
_constraints[i]->updateProxyShape((*_verletShapes)[i], rotation, translation);
}
}

View file

@ -66,38 +66,24 @@ public:
Ragdoll(); Ragdoll();
virtual ~Ragdoll(); virtual ~Ragdoll();
/// Create points and constraints based on topology of collection of joints
/// \param joints list of connected joint states
void initShapesAndPoints(QVector<Shape*>* shapes, const QVector<int>& parentIndices, const QVector<glm::vec3>& points);
/// Delete all data. /// Delete all data.
void clear(); void clearRagdollConstraintsAndPoints();
// TODO: Andrew to implement this virtual void initRagdollPoints() = 0;
void stepForward(float deltaTime) {} virtual void stepRagdollForward(float deltaTime) = 0;
/// Enforce contraints. /// Enforce contraints.
/// \return max distance of point movement /// \return max distance of point movement
float enforceConstraints(); float enforceRagdollConstraints();
// both const and non-const getPoints() // both const and non-const getPoints()
const QVector<glm::vec3>& getPoints() const { return _points; } const QVector<glm::vec3>& getRagdollPoints() const { return _ragdollPoints; }
QVector<glm::vec3>& getPoints() { return _points; } QVector<glm::vec3>& getRagdollPoints() { return _ragdollPoints; }
/// \param rotation rotation into shapes' collision frame
/// \param translation translation into shapes' collision frame
/// Moves and modifies elements of _verletShapes to agree with state of _points
void updateShapes(const glm::quat& rotation, const glm::vec3& translation) const;
const QVector<Shape*>* getShapes() const { return _verletShapes; }
protected: protected:
QVector<glm::vec3> _points; QVector<glm::vec3> _ragdollPoints;
QVector<Constraint*> _constraints; QVector<Constraint*> _ragdollConstraints;
// the Ragdoll does NOT own the data in _verletShapes.
QVector<Shape*>* _verletShapes;
}; };
#endif // hifi_Ragdoll_h #endif // hifi_Ragdoll_h

View file

@ -67,6 +67,7 @@ void SimulationEngine::removeRagdoll(Ragdoll* doll) {
} }
void SimulationEngine::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) { void SimulationEngine::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) {
/* TODO: Andrew to make this work
int iterations = 0; int iterations = 0;
float delta = 0.0f; float delta = 0.0f;
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
@ -82,7 +83,7 @@ void SimulationEngine::stepForward(float deltaTime, float minError, int maxItera
// (4) collisions move points (SpecialCapsuleShape would help solve this) // (4) collisions move points (SpecialCapsuleShape would help solve this)
// (5) enforce constraints // (5) enforce constraints
// (6) add and enforce angular contraints for joints // (6) add and enforce angular contraints for joints
_dolls.at(i)->stepForward(deltaTime); //_dolls.at(i)->stepForward(deltaTime);
} }
@ -128,6 +129,7 @@ void SimulationEngine::stepForward(float deltaTime, float minError, int maxItera
_enforcementIterations = iterations; _enforcementIterations = iterations;
_enforcementError = delta; _enforcementError = delta;
_enforcementTime = now - startTime; _enforcementTime = now - startTime;
*/
} }
int SimulationEngine::computeCollisions() { int SimulationEngine::computeCollisions() {