Hands can collide with avatar head again

This commit is contained in:
Andrew Meadows 2014-03-06 12:38:07 -08:00
parent bca0ea1502
commit 37b088ebfa
9 changed files with 96 additions and 100 deletions

View file

@ -489,13 +489,19 @@ bool Avatar::findSphereCollisions(const glm::vec3& penetratorCenter, float penet
//return getHead()->getFaceModel().findSphereCollisions(penetratorCenter, penetratorRadius, collisions);
}
bool Avatar::findCollisions(const QVector<const Shape*>& shapes, CollisionList& collisions) {
void Avatar::updateShapePositions() {
_skeletonModel.updateShapePositions();
bool collided = _skeletonModel.findCollisions(shapes, collisions);
Model& headModel = getHead()->getFaceModel();
headModel.updateShapePositions();
collided = headModel.findCollisions(shapes, collisions);
}
bool Avatar::findCollisions(const QVector<const Shape*>& shapes, CollisionList& collisions) {
// TODO: Andrew to fix: also collide against _skeleton
//bool collided = _skeletonModel.findCollisions(shapes, collisions);
Model& headModel = getHead()->getFaceModel();
//collided = headModel.findCollisions(shapes, collisions) || collided;
bool collided = headModel.findCollisions(shapes, collisions);
return collided;
}
@ -710,15 +716,14 @@ bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const {
return false;
}
void Avatar::applyCollision(CollisionInfo& collision) {
if (!collision._data || collision._type != MODEL_COLLISION) {
return;
}
// TODO: make skeleton also respond to collisions
Model* model = static_cast<Model*>(collision._data);
if (model == &(getHead()->getFaceModel())) {
getHead()->applyCollision(collision);
}
void Avatar::applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) {
// ATM we only support collision with head
getHead()->applyCollision(contactPoint, penetration);
}
float Avatar::getBoundingRadius() const {
// TODO: also use head model when computing the avatar's bounding radius
return _skeletonModel.getBoundingRadius();
}
float Avatar::getPelvisFloatingHeight() const {

View file

@ -138,10 +138,11 @@ public:
/// \return true if we expect the avatar would move as a result of the collision
bool collisionWouldMoveAvatar(CollisionInfo& collision) const;
/// \param collision a data structure for storing info about collisions against Models
void applyCollision(CollisionInfo& collision);
void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration);
float getBoundingRadius() const { return 0.5f * getSkeletonHeight(); }
/// \return bounding radius of avatar
virtual float getBoundingRadius() const;
void updateShapePositions();
public slots:
void updateCollisionFlags();

View file

@ -145,10 +145,7 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
jointIndices[0] = skeletonModel.getLeftHandJointIndex();
jointIndices[1] = skeletonModel.getRightHandJointIndex();
palmIndices[1] = -1; // adebug temporarily disable right hand
jointIndices[1] = -1; // adebug temporarily disable right hand
for (size_t i = 0; i < 1; i++) {
for (size_t i = 0; i < 2; i++) {
int palmIndex = palmIndices[i];
int jointIndex = jointIndices[i];
if (palmIndex == -1 || jointIndex == -1) {
@ -165,9 +162,8 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
handCollisions.clear();
QVector<const Shape*> shapes;
skeletonModel.getHandShapes(jointIndex, shapes);
bool collided = isMyHand ? avatar->findCollisions(shapes, handCollisions) : avatar->findCollisions(shapes, handCollisions);
if (collided) {
//if (avatar->findCollisions(shapes, handCollisions)) {
if (avatar->findCollisions(shapes, handCollisions)) {
glm::vec3 averagePenetration;
glm::vec3 averageContactPoint;
for (int j = 0; j < handCollisions.size(); ++j) {
@ -180,13 +176,14 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
// our hand against other avatar
// for now we resolve it to test shapes/collisions
// TODO: only partially resolve this penetration
palm.addToPosition(-averagePenetration);
palm.addToPenetration(averagePenetration);
} else {
// someone else's hand against MyAvatar
// TODO: submit collision info to MyAvatar which should lean accordingly
averageContactPoint /= float(handCollisions.size());
avatar->applyCollision(averageContactPoint, averagePenetration);
}
}
}
}
}
@ -218,7 +215,7 @@ void Hand::collideAgainstOurself() {
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
}
// resolve penetration
palm.addToPosition(-totalPenetration);
palm.addToPenetration(totalPenetration);
}
}
}
@ -428,19 +425,3 @@ void Hand::renderLeapHands(bool isMine) {
glPopMatrix();
}
void Hand::setLeapHands(const std::vector<glm::vec3>& handPositions,
const std::vector<glm::vec3>& handNormals) {
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
if (i < handPositions.size()) {
palm.setActive(true);
palm.setRawPosition(handPositions[i]);
palm.setRawNormal(handNormals[i]);
}
else {
palm.setActive(false);
}
}
}

View file

@ -79,10 +79,6 @@ private:
float _collisionAge;
float _collisionDuration;
// private methods
void setLeapHands(const std::vector<glm::vec3>& handPositions,
const std::vector<glm::vec3>& handNormals);
void renderLeapHands(bool isMine);
void renderLeapFingerTrails();

View file

@ -213,32 +213,25 @@ float Head::getTweakedRoll() const {
return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL);
}
void Head::applyCollision(CollisionInfo& collision) {
// HACK: the collision proxies for the FaceModel are bad. As a temporary workaround
// we collide against a hard coded collision proxy.
// TODO: get a better collision proxy here.
const float HEAD_RADIUS = 0.15f;
const glm::vec3 HEAD_CENTER = _position;
// collide the contactPoint against the collision proxy to obtain a new penetration
// NOTE: that penetration is in opposite direction (points the way out for the point, not the sphere)
glm::vec3 penetration;
if (findPointSpherePenetration(collision._contactPoint, HEAD_CENTER, HEAD_RADIUS, penetration)) {
// compute lean angles
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
glm::quat bodyRotation = owningAvatar->getOrientation();
glm::vec3 neckPosition;
if (owningAvatar->getSkeletonModel().getNeckPosition(neckPosition)) {
glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f);
glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f);
void Head::applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) {
// compute lean angles
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar);
glm::quat bodyRotation = owningAvatar->getOrientation();
glm::vec3 neckPosition;
if (owningAvatar->getSkeletonModel().getNeckPosition(neckPosition)) {
glm::vec3 yAxis = bodyRotation * glm::vec3(0.f, 1.f, 0.f);
glm::vec3 leverArm = _position - neckPosition;
if (glm::dot(leverArm, yAxis) > 0.f) {
float neckLength = glm::length(_position - neckPosition);
if (neckLength > 0.f) {
float forward = glm::dot(collision._penetration, zAxis) / neckLength;
float sideways = - glm::dot(collision._penetration, xAxis) / neckLength;
glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f);
glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f);
float forward = glm::dot(penetration, zAxis) / neckLength;
float sideways = - glm::dot(penetration, xAxis) / neckLength;
addLean(sideways, forward);
}
}
}
}
}
void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {

View file

@ -78,7 +78,8 @@ public:
virtual float getTweakedYaw() const;
virtual float getTweakedRoll() const;
void applyCollision(CollisionInfo& collisionInfo);
// move the head to avoid given collision info
void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration);
private:
// disallow copies of the Head, copy of owning Avatar is disallowed too

View file

@ -182,26 +182,6 @@ void MyAvatar::simulate(float deltaTime) {
_velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime);
}
if (_collisionFlags != 0) {
Camera* myCamera = Application::getInstance()->getCamera();
float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE;
if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) {
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f));
radius *= COLLISION_RADIUS_SCALAR;
}
if (_collisionFlags & COLLISION_GROUP_ENVIRONMENT) {
updateCollisionWithEnvironment(deltaTime, radius);
}
if (_collisionFlags & COLLISION_GROUP_VOXELS) {
updateCollisionWithVoxels(deltaTime, radius);
}
if (_collisionFlags & COLLISION_GROUP_AVATARS) {
updateCollisionWithAvatars(deltaTime);
}
}
// add thrust to velocity
_velocity += _thrust * deltaTime;
@ -318,6 +298,30 @@ void MyAvatar::simulate(float deltaTime) {
// Zero thrust out now that we've added it to velocity in this frame
_thrust = glm::vec3(0, 0, 0);
// now that we're done stepping the avatar forward in time, compute new collisions
if (_collisionFlags != 0) {
Camera* myCamera = Application::getInstance()->getCamera();
float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE;
if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) {
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f));
radius *= COLLISION_RADIUS_SCALAR;
}
if (_collisionFlags & COLLISION_GROUP_ENVIRONMENT) {
updateCollisionWithEnvironment(deltaTime, radius);
}
if (_collisionFlags & COLLISION_GROUP_VOXELS) {
updateCollisionWithVoxels(deltaTime, radius);
}
if (_collisionFlags & COLLISION_GROUP_AVATARS) {
updateCollisionWithAvatars(deltaTime);
}
}
// resolve collision results
_skeletonModel.syncToPalms();
// consider updating our billboard
maybeUpdateBillboard();
@ -919,14 +923,17 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
// no need to compute a bunch of stuff if we have one or fewer avatars
return;
}
updateShapePositions();
float myBoundingRadius = getBoundingRadius();
/* TODO: Andrew to fix Avatar-Avatar body collisions
// HACK: body-body collision uses two coaxial capsules with axes parallel to y-axis
// TODO: make the collision work without assuming avatar orientation
Extents myStaticExtents = _skeletonModel.getStaticExtents();
glm::vec3 staticScale = myStaticExtents.maximum - myStaticExtents.minimum;
float myCapsuleRadius = 0.25f * (staticScale.x + staticScale.z);
float myCapsuleHeight = staticScale.y;
*/
CollisionInfo collisionInfo;
foreach (const AvatarSharedPointer& avatarPointer, avatars) {
@ -935,16 +942,13 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
// don't collide with ourselves
continue;
}
avatar->updateShapePositions();
float distance = glm::length(_position - avatar->getPosition());
if (_distanceToNearestAvatar > distance) {
_distanceToNearestAvatar = distance;
}
float theirBoundingRadius = avatar->getBoundingRadius();
if (distance < myBoundingRadius + theirBoundingRadius) {
_skeletonModel.updateShapePositions();
Model& headModel = getHead()->getFaceModel();
headModel.updateShapePositions();
/* TODO: Andrew to fix Avatar-Avatar body collisions
Extents theirStaticExtents = _skeletonModel.getStaticExtents();
glm::vec3 staticScale = theirStaticExtents.maximum - theirStaticExtents.minimum;

View file

@ -62,6 +62,19 @@ void SkeletonModel::simulate(float deltaTime, bool delayLoad) {
}
}
void SkeletonModel::syncToPalms() {
int leftPalmIndex, rightPalmIndex;
Hand* hand = _owningAvatar->getHand();
hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (leftPalmIndex != -1 && rightPalmIndex != -1) {
applyPalmData(geometry.leftHandJointIndex, geometry.leftFingerJointIndices, geometry.leftFingertipJointIndices,
hand->getPalms()[leftPalmIndex]);
applyPalmData(geometry.rightHandJointIndex, geometry.rightFingerJointIndices, geometry.rightFingertipJointIndices,
hand->getPalms()[rightPalmIndex]);
}
}
bool SkeletonModel::render(float alpha) {
if (_jointStates.isEmpty()) {
@ -154,7 +167,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
// no point in continuing if there are no fingers
if (palm.getNumFingers() == 0 || fingerJointIndices.isEmpty()) {
stretchArm(jointIndex, palm.getPosition());
stretchArm(jointIndex, palm);
return;
}
@ -173,7 +186,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
setJointRotation(fingerJointIndex, rotationBetween(palmRotation * jointVector, fingerVector) * palmRotation, true);
}
stretchArm(jointIndex, palm.getPosition());
stretchArm(jointIndex, palm);
}
void SkeletonModel::updateJointState(int index) {
@ -196,7 +209,8 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const
glm::angleAxis(-_owningAvatar->getHead()->getLeanForward(), glm::normalize(inverse * axes[0])) * joint.rotation;
}
void SkeletonModel::stretchArm(int jointIndex, const glm::vec3& position) {
void SkeletonModel::stretchArm(int jointIndex, PalmData& palm) {
// const glm::vec3& position) {
// find out where the hand is pointing
glm::quat handRotation;
getJointRotation(jointIndex, handRotation, true);
@ -212,11 +226,11 @@ void SkeletonModel::stretchArm(int jointIndex, const glm::vec3& position) {
glm::quat elbowRotation;
getJointRotation(joint.parentIndex, elbowRotation, true);
applyRotationDelta(joint.parentIndex, rotationBetween(elbowRotation * forwardVector, handVector), false);
// set position according to normal length
float scale = extractUniformScale(_scale);
glm::vec3 handPosition = position - _translation;
glm::vec3 elbowPosition = handPosition - handVector * joint.distanceToParent * scale;
palm.resolvePenetrations();
glm::vec3 elbowPosition = palm.getPosition() - _translation; - handVector * (joint.distanceToParent * scale);
// set shoulder orientation to point to elbow
const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);

View file

@ -23,12 +23,13 @@ public:
SkeletonModel(Avatar* owningAvatar);
void simulate(float deltaTime, bool delayLoad = false);
void syncToPalms();
bool render(float alpha);
/// \param jointIndex index of hand joint
/// \param shapes[out] list in which is stored pointers to hand shapes
void getHandShapes(int jointIndex, QVector<const Shape*>& shapes) const;
protected:
void applyHandPosition(int jointIndex, const glm::vec3& position);
@ -45,7 +46,7 @@ private:
/// Using the current position and rotation of the identified (hand) joint, computes a
/// reasonable stretched configuration for the connected arm.
void stretchArm(int jointIndex, const glm::vec3& position);
void stretchArm(int jointIndex, PalmData& palm);
Avatar* _owningAvatar;
};