This commit is contained in:
Andrzej Kapolka 2014-02-13 17:38:23 -08:00
commit 91fac4eebe
14 changed files with 174 additions and 133 deletions

View file

@ -162,6 +162,7 @@ void Avatar::render(bool forceRenderHead) {
// render body // render body
if (Menu::getInstance()->isOptionChecked(MenuOption::CollisionProxies)) { if (Menu::getInstance()->isOptionChecked(MenuOption::CollisionProxies)) {
_skeletonModel.renderCollisionProxies(1.f); _skeletonModel.renderCollisionProxies(1.f);
//_head.getFaceModel().renderCollisionProxies(0.5f);
} }
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
@ -276,11 +277,14 @@ bool Avatar::findSphereCollisions(const glm::vec3& penetratorCenter, float penet
bool didPenetrate = false; bool didPenetrate = false;
glm::vec3 skeletonPenetration; glm::vec3 skeletonPenetration;
ModelCollisionInfo collisionInfo; ModelCollisionInfo collisionInfo;
/* Temporarily disabling collisions against the skeleton because the collision proxies up
* near the neck are bad and prevent the hand from hitting the face.
if (_skeletonModel.findSphereCollision(penetratorCenter, penetratorRadius, collisionInfo, 1.0f, skeletonSkipIndex)) { if (_skeletonModel.findSphereCollision(penetratorCenter, penetratorRadius, collisionInfo, 1.0f, skeletonSkipIndex)) {
collisionInfo._model = &_skeletonModel; collisionInfo._model = &_skeletonModel;
collisions.push_back(collisionInfo); collisions.push_back(collisionInfo);
didPenetrate = true; didPenetrate = true;
} }
*/
if (_head.getFaceModel().findSphereCollision(penetratorCenter, penetratorRadius, collisionInfo)) { if (_head.getFaceModel().findSphereCollision(penetratorCenter, penetratorRadius, collisionInfo)) {
collisionInfo._model = &(_head.getFaceModel()); collisionInfo._model = &(_head.getFaceModel());
collisions.push_back(collisionInfo); collisions.push_back(collisionInfo);
@ -445,20 +449,34 @@ float Avatar::getHeight() const {
return extents.maximum.y - extents.minimum.y; return extents.maximum.y - extents.minimum.y;
} }
bool Avatar::isPokeable(ModelCollisionInfo& collision) const { bool Avatar::collisionWouldMoveAvatar(ModelCollisionInfo& collision) const {
// ATM only the Skeleton is pokeable // ATM only the Skeleton is pokeable
// TODO: make poke affect head // TODO: make poke affect head
if (!collision._model) {
return false;
}
if (collision._model == &_skeletonModel && collision._jointIndex != -1) { if (collision._model == &_skeletonModel && collision._jointIndex != -1) {
return _skeletonModel.isPokeable(collision); // collision response of skeleton is temporarily disabled
return false;
//return _skeletonModel.collisionHitsMoveableJoint(collision);
}
if (collision._model == &(_head.getFaceModel())) {
return true;
} }
return false; return false;
} }
bool Avatar::poke(ModelCollisionInfo& collision) { void Avatar::applyCollision(ModelCollisionInfo& collision) {
if (collision._model == &_skeletonModel && collision._jointIndex != -1) { if (!collision._model) {
return _skeletonModel.poke(collision); return;
} }
return false; if (collision._model == &(_head.getFaceModel())) {
_head.applyCollision(collision);
}
// TODO: make skeleton respond to collisions
//if (collision._model == &_skeletonModel && collision._jointIndex != -1) {
// _skeletonModel.applyCollision(collision);
//}
} }
float Avatar::getPelvisFloatingHeight() const { float Avatar::getPelvisFloatingHeight() const {

View file

@ -129,11 +129,10 @@ public:
float getHeight() const; float getHeight() const;
/// \return true if we expect the avatar would move as a result of the collision /// \return true if we expect the avatar would move as a result of the collision
bool isPokeable(ModelCollisionInfo& collision) const; bool collisionWouldMoveAvatar(ModelCollisionInfo& collision) const;
/// \param collision a data structure for storing info about collisions against Models /// \param collision a data structure for storing info about collisions against Models
/// \return true if the collision affects the Avatar models void applyCollision(ModelCollisionInfo& collision);
bool poke(ModelCollisionInfo& collision);
public slots: public slots:
void updateCollisionFlags(); void updateCollisionFlags();

View file

@ -57,7 +57,6 @@ void Hand::simulate(float deltaTime, bool isMine) {
if (isMine) { if (isMine) {
_buckyBalls.simulate(deltaTime); _buckyBalls.simulate(deltaTime);
updateCollisions();
} }
calculateGeometry(); calculateGeometry();
@ -126,92 +125,105 @@ void Hand::simulate(float deltaTime, bool isMine) {
} }
} }
void Hand::updateCollisions() { void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
// use position to obtain the left and right palm indices if (!avatar || avatar == _owningAvatar) {
int leftPalmIndex, rightPalmIndex; // don't collide with our own hands (that is done elsewhere)
getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); return;
}
ModelCollisionList collisions; float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale();
// check for collisions
for (size_t i = 0; i < getNumPalms(); i++) { for (size_t i = 0; i < getNumPalms(); i++) {
PalmData& palm = getPalms()[i]; PalmData& palm = getPalms()[i];
if (!palm.isActive()) { if (!palm.isActive()) {
continue; continue;
} }
float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale();
glm::vec3 totalPenetration; glm::vec3 totalPenetration;
ModelCollisionList collisions;
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) { if (isMyHand && Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) {
// check other avatars // Check for palm collisions
foreach (const AvatarSharedPointer& avatarPointer, Application::getInstance()->getAvatarManager().getAvatarHash()) { glm::vec3 myPalmPosition = palm.getPosition();
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data()); float palmCollisionDistance = 0.1f;
if (avatar == _owningAvatar) { bool wasColliding = palm.getIsCollidingWithPalm();
// don't collid with our own hands palm.setIsCollidingWithPalm(false);
// If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound
for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) {
PalmData& otherPalm = avatar->getHand().getPalms()[j];
if (!otherPalm.isActive()) {
continue; continue;
} }
if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) { glm::vec3 otherPalmPosition = otherPalm.getPosition();
// Check for palm collisions if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) {
glm::vec3 myPalmPosition = palm.getPosition(); palm.setIsCollidingWithPalm(true);
float palmCollisionDistance = 0.1f; if (!wasColliding) {
bool wasColliding = palm.getIsCollidingWithPalm(); const float PALM_COLLIDE_VOLUME = 1.f;
palm.setIsCollidingWithPalm(false); const float PALM_COLLIDE_FREQUENCY = 1000.f;
// If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound const float PALM_COLLIDE_DURATION_MAX = 0.75f;
for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) { const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f;
PalmData& otherPalm = avatar->getHand().getPalms()[j]; Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME,
if (!otherPalm.isActive()) { PALM_COLLIDE_FREQUENCY,
continue; PALM_COLLIDE_DURATION_MAX,
} PALM_COLLIDE_DECAY_PER_SAMPLE);
glm::vec3 otherPalmPosition = otherPalm.getPosition(); // If the other person's palm is in motion, move mine downward to show I was hit
if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) { const float MIN_VELOCITY_FOR_SLAP = 0.05f;
palm.setIsCollidingWithPalm(true); if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) {
if (!wasColliding) { // add slapback here
const float PALM_COLLIDE_VOLUME = 1.f;
const float PALM_COLLIDE_FREQUENCY = 1000.f;
const float PALM_COLLIDE_DURATION_MAX = 0.75f;
const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f;
Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME,
PALM_COLLIDE_FREQUENCY,
PALM_COLLIDE_DURATION_MAX,
PALM_COLLIDE_DECAY_PER_SAMPLE);
// If the other person's palm is in motion, move mine downward to show I was hit
const float MIN_VELOCITY_FOR_SLAP = 0.05f;
if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) {
// add slapback here
}
}
}
}
}
if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) {
for (int j = 0; j < collisions.size(); ++j) {
// we don't resolve penetrations that would poke the other avatar
if (!avatar->isPokeable(collisions[j])) {
totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration);
} }
} }
} }
} }
} }
if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions)) {
if (Menu::getInstance()->isOptionChecked(MenuOption::HandsCollideWithSelf)) { for (int j = 0; j < collisions.size(); ++j) {
// and the current avatar (ignoring everything below the parent of the parent of the last free joint) if (isMyHand) {
collisions.clear(); if (!avatar->collisionWouldMoveAvatar(collisions[j])) {
const Model& skeletonModel = _owningAvatar->getSkeletonModel(); // we resolve the hand from collision when it belongs to MyAvatar AND the other Avatar is
int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex( // not expected to respond to the collision (hand hit unmovable part of their Avatar)
skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() : totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration);
(i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1))); }
if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions, skipIndex)) { } else {
for (int j = 0; j < collisions.size(); ++j) { // when !isMyHand then avatar is MyAvatar and we apply the collision
totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration); // which might not do anything (hand hit unmovable part of MyAvatar) however
// we don't resolve the hand's penetration because we expect the remote
// simulation to do the right thing.
avatar->applyCollision(collisions[j]);
} }
} }
} }
if (isMyHand) {
// un-penetrate // resolve penetration
palm.addToPosition(-totalPenetration); palm.addToPosition(-totalPenetration);
}
}
}
// we recycle the collisions container, so we clear it for the next loop void Hand::collideAgainstOurself() {
if (!Menu::getInstance()->isOptionChecked(MenuOption::HandsCollideWithSelf)) {
return;
}
ModelCollisionList collisions;
int leftPalmIndex, rightPalmIndex;
getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale();
for (size_t i = 0; i < getNumPalms(); i++) {
PalmData& palm = getPalms()[i];
if (!palm.isActive()) {
continue;
}
glm::vec3 totalPenetration;
// and the current avatar (ignoring everything below the parent of the parent of the last free joint)
collisions.clear(); collisions.clear();
const Model& skeletonModel = _owningAvatar->getSkeletonModel();
int skipIndex = skeletonModel.getParentJointIndex(skeletonModel.getParentJointIndex(
skeletonModel.getLastFreeJointIndex((i == leftPalmIndex) ? skeletonModel.getLeftHandJointIndex() :
(i == rightPalmIndex) ? skeletonModel.getRightHandJointIndex() : -1)));
if (_owningAvatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, collisions, skipIndex)) {
for (int j = 0; j < collisions.size(); ++j) {
totalPenetration = addPenetrations(totalPenetration, collisions[j]._penetration);
}
}
// resolve penetration
palm.addToPosition(-totalPenetration);
} }
} }

View file

@ -58,6 +58,9 @@ public:
const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;}
const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;} const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;}
void collideAgainstAvatar(Avatar* avatar, bool isMyHand);
void collideAgainstOurself();
private: private:
// disallow copies of the Hand, copy of owning Avatar is disallowed too // disallow copies of the Hand, copy of owning Avatar is disallowed too
Hand(const Hand&); Hand(const Hand&);
@ -87,7 +90,6 @@ private:
void renderLeapHands(bool isMine); void renderLeapHands(bool isMine);
void renderLeapFingerTrails(); void renderLeapFingerTrails();
void updateCollisions();
void calculateGeometry(); void calculateGeometry();
void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime);

View file

@ -219,6 +219,34 @@ float Head::getTweakedRoll() const {
return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); return glm::clamp(_roll + _tweakedRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL);
} }
void Head::applyCollision(ModelCollisionInfo& collisionInfo) {
// 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(collisionInfo._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);
float neckLength = glm::length(_position - neckPosition);
if (neckLength > 0.f) {
float forward = glm::dot(collisionInfo._penetration, zAxis) / neckLength;
float sideways = - glm::dot(collisionInfo._penetration, xAxis) / neckLength;
addLean(sideways, forward);
}
}
}
}
void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
Application::getInstance()->getGlowEffect()->begin(); Application::getInstance()->getGlowEffect()->begin();

View file

@ -79,6 +79,8 @@ public:
float getTweakedPitch() const; float getTweakedPitch() const;
float getTweakedYaw() const; float getTweakedYaw() const;
float getTweakedRoll() const; float getTweakedRoll() const;
void applyCollision(ModelCollisionInfo& collisionInfo);
private: private:
// disallow copies of the Head, copy of owning Avatar is disallowed too // disallow copies of the Head, copy of owning Avatar is disallowed too

View file

@ -112,23 +112,7 @@ void MyAvatar::updateTransmitter(float deltaTime) {
void MyAvatar::update(float deltaTime) { void MyAvatar::update(float deltaTime) {
updateTransmitter(deltaTime); updateTransmitter(deltaTime);
// TODO: resurrect touch interactions between avatars updateFromGyros(deltaTime);
//// rotate body yaw for yaw received from multitouch
//setOrientation(getOrientation() * glm::quat(glm::vec3(0, _yawFromTouch, 0)));
//_yawFromTouch = 0.f;
//
//// apply pitch from touch
//_head.setPitch(_head.getPitch() + _pitchFromTouch);
//_pitchFromTouch = 0.0f;
//
//float TOUCH_YAW_SCALE = -0.25f;
//float TOUCH_PITCH_SCALE = -12.5f;
//float FIXED_TOUCH_TIMESTEP = 0.016f;
//_yawFromTouch += ((_touchAvgX - _lastTouchAvgX) * TOUCH_YAW_SCALE * FIXED_TOUCH_TIMESTEP);
//_pitchFromTouch += ((_touchAvgY - _lastTouchAvgY) * TOUCH_PITCH_SCALE * FIXED_TOUCH_TIMESTEP);
// Update my avatar's state from gyros
updateFromGyros(Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead));
// Update head mouse from faceshift if active // Update head mouse from faceshift if active
Faceshift* faceshift = Application::getInstance()->getFaceshift(); Faceshift* faceshift = Application::getInstance()->getFaceshift();
@ -329,6 +313,7 @@ void MyAvatar::simulate(float deltaTime) {
_position += _velocity * deltaTime; _position += _velocity * deltaTime;
// update avatar skeleton and simulate hand and head // update avatar skeleton and simulate hand and head
_hand.collideAgainstOurself();
_hand.simulate(deltaTime, true); _hand.simulate(deltaTime, true);
_skeletonModel.simulate(deltaTime); _skeletonModel.simulate(deltaTime);
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
@ -348,7 +333,7 @@ void MyAvatar::simulate(float deltaTime) {
const float MAX_PITCH = 90.0f; const float MAX_PITCH = 90.0f;
// Update avatar head rotation with sensor data // Update avatar head rotation with sensor data
void MyAvatar::updateFromGyros(bool turnWithHead) { void MyAvatar::updateFromGyros(float deltaTime) {
Faceshift* faceshift = Application::getInstance()->getFaceshift(); Faceshift* faceshift = Application::getInstance()->getFaceshift();
glm::vec3 estimatedPosition, estimatedRotation; glm::vec3 estimatedPosition, estimatedRotation;
@ -356,7 +341,7 @@ void MyAvatar::updateFromGyros(bool turnWithHead) {
estimatedPosition = faceshift->getHeadTranslation(); estimatedPosition = faceshift->getHeadTranslation();
estimatedRotation = safeEulerAngles(faceshift->getHeadRotation()); estimatedRotation = safeEulerAngles(faceshift->getHeadRotation());
// Rotate the body if the head is turned beyond the screen // Rotate the body if the head is turned beyond the screen
if (turnWithHead) { if (Menu::getInstance()->isOptionChecked(MenuOption::TurnWithHead)) {
const float FACESHIFT_YAW_TURN_SENSITIVITY = 0.5f; const float FACESHIFT_YAW_TURN_SENSITIVITY = 0.5f;
const float FACESHIFT_MIN_YAW_TURN = 15.f; const float FACESHIFT_MIN_YAW_TURN = 15.f;
const float FACESHIFT_MAX_YAW_TURN = 50.f; const float FACESHIFT_MAX_YAW_TURN = 50.f;
@ -371,11 +356,12 @@ void MyAvatar::updateFromGyros(bool turnWithHead) {
} }
} else { } else {
// restore rotation, lean to neutral positions // restore rotation, lean to neutral positions
const float RESTORE_RATE = 0.05f; const float RESTORE_PERIOD = 1.f; // seconds
_head.setYaw(glm::mix(_head.getYaw(), 0.0f, RESTORE_RATE)); float restorePercentage = glm::clamp(deltaTime/RESTORE_PERIOD, 0.f, 1.f);
_head.setRoll(glm::mix(_head.getRoll(), 0.0f, RESTORE_RATE)); _head.setYaw(glm::mix(_head.getYaw(), 0.0f, restorePercentage));
_head.setLeanSideways(glm::mix(_head.getLeanSideways(), 0.0f, RESTORE_RATE)); _head.setRoll(glm::mix(_head.getRoll(), 0.0f, restorePercentage));
_head.setLeanForward(glm::mix(_head.getLeanForward(), 0.0f, RESTORE_RATE)); _head.setLeanSideways(glm::mix(_head.getLeanSideways(), 0.0f, restorePercentage));
_head.setLeanForward(glm::mix(_head.getLeanForward(), 0.0f, restorePercentage));
return; return;
} }
@ -854,7 +840,6 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
} }
} }
void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) {
const float VOXEL_ELASTICITY = 0.4f; const float VOXEL_ELASTICITY = 0.4f;
const float VOXEL_DAMPING = 0.0f; const float VOXEL_DAMPING = 0.0f;
@ -1003,6 +988,12 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
// move the avatar out by half the penetration // move the avatar out by half the penetration
setPosition(_position - 0.5f * penetration); setPosition(_position - 0.5f * penetration);
} }
// collide our hands against them
_hand.collideAgainstAvatar(avatar, true);
// collide their hands against us
avatar->getHand().collideAgainstAvatar(this, false);
} }
} }
} }

View file

@ -34,7 +34,7 @@ public:
void reset(); void reset();
void update(float deltaTime); void update(float deltaTime);
void simulate(float deltaTime); void simulate(float deltaTime);
void updateFromGyros(bool turnWithHead); void updateFromGyros(float deltaTime);
void updateTransmitter(float deltaTime); void updateTransmitter(float deltaTime);
void render(bool forceRenderHead); void render(bool forceRenderHead);

View file

@ -36,23 +36,24 @@ void SkeletonModel::simulate(float deltaTime) {
HandData& hand = _owningAvatar->getHand(); HandData& hand = _owningAvatar->getHand();
hand.getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); hand.getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
const float HAND_RESTORATION_RATE = 0.25f; const float HAND_RESTORATION_PERIOD = 1.f; // seconds
float handRestorePercent = glm::clamp(deltaTime / HAND_RESTORATION_PERIOD, 0.f, 1.f);
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (leftPalmIndex == -1) { if (leftPalmIndex == -1) {
// no Leap data; set hands from mouse // no Leap data; set hands from mouse
if (_owningAvatar->getHandState() == HAND_STATE_NULL) { if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
restoreRightHandPosition(HAND_RESTORATION_RATE); restoreRightHandPosition(handRestorePercent);
} else { } else {
applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition()); applyHandPosition(geometry.rightHandJointIndex, _owningAvatar->getHandPosition());
} }
restoreLeftHandPosition(HAND_RESTORATION_RATE); restoreLeftHandPosition(handRestorePercent);
} else if (leftPalmIndex == rightPalmIndex) { } else if (leftPalmIndex == rightPalmIndex) {
// right hand only // right hand only
applyPalmData(geometry.rightHandJointIndex, geometry.rightFingerJointIndices, geometry.rightFingertipJointIndices, applyPalmData(geometry.rightHandJointIndex, geometry.rightFingerJointIndices, geometry.rightFingertipJointIndices,
hand.getPalms()[leftPalmIndex]); hand.getPalms()[leftPalmIndex]);
restoreLeftHandPosition(HAND_RESTORATION_RATE); restoreLeftHandPosition(handRestorePercent);
} else { } else {
applyPalmData(geometry.leftHandJointIndex, geometry.leftFingerJointIndices, geometry.leftFingertipJointIndices, applyPalmData(geometry.leftHandJointIndex, geometry.leftFingerJointIndices, geometry.leftFingertipJointIndices,

View file

@ -488,7 +488,10 @@ bool Model::findSphereCollision(const glm::vec3& penetratorCenter, float penetra
if (findSphereCapsuleConePenetration(relativeCenter, penetratorRadius, start, end, if (findSphereCapsuleConePenetration(relativeCenter, penetratorRadius, start, end,
startRadius, endRadius, bonePenetration)) { startRadius, endRadius, bonePenetration)) {
totalPenetration = addPenetrations(totalPenetration, bonePenetration); totalPenetration = addPenetrations(totalPenetration, bonePenetration);
// TODO: Andrew to try to keep the joint furthest toward the root // BUG: we currently overwrite the jointIndex with the last one found
// which can cause incorrect collisions when colliding against more than
// one joint.
// TODO: fix this.
jointIndex = i; jointIndex = i;
} }
outerContinue: ; outerContinue: ;
@ -733,7 +736,7 @@ void Model::renderCollisionProxies(float alpha) {
glPopMatrix(); glPopMatrix();
} }
bool Model::isPokeable(ModelCollisionInfo& collision) const { bool Model::collisionHitsMoveableJoint(ModelCollisionInfo& collision) const {
// the joint is pokable by a collision if it exists and is free to move // the joint is pokable by a collision if it exists and is free to move
const FBXJoint& joint = _geometry->getFBXGeometry().joints[collision._jointIndex]; const FBXJoint& joint = _geometry->getFBXGeometry().joints[collision._jointIndex];
if (joint.parentIndex == -1 || _jointStates.isEmpty()) { if (joint.parentIndex == -1 || _jointStates.isEmpty()) {
@ -745,7 +748,7 @@ bool Model::isPokeable(ModelCollisionInfo& collision) const {
return !freeLineage.isEmpty(); return !freeLineage.isEmpty();
} }
bool Model::poke(ModelCollisionInfo& collision) { void Model::applyCollision(ModelCollisionInfo& collision) {
// This needs work. At the moment it can wiggle joints that are free to move (such as arms) // This needs work. At the moment it can wiggle joints that are free to move (such as arms)
// but unmovable joints (such as torso) cannot be influenced at all. // but unmovable joints (such as torso) cannot be influenced at all.
glm::vec3 jointPosition(0.f); glm::vec3 jointPosition(0.f);
@ -769,11 +772,10 @@ bool Model::poke(ModelCollisionInfo& collision) {
getJointPosition(jointIndex, end); getJointPosition(jointIndex, end);
glm::vec3 newEnd = start + glm::angleAxis(glm::degrees(angle), axis) * (end - start); glm::vec3 newEnd = start + glm::angleAxis(glm::degrees(angle), axis) * (end - start);
// try to move it // try to move it
return setJointPosition(jointIndex, newEnd, -1, true); setJointPosition(jointIndex, newEnd, -1, true);
} }
} }
} }
return false;
} }
void Model::deleteGeometry() { void Model::deleteGeometry() {

View file

@ -167,12 +167,12 @@ public:
void renderCollisionProxies(float alpha); void renderCollisionProxies(float alpha);
/// \return true if the collision would move the model /// \return true if the collision is against a moveable joint
bool isPokeable(ModelCollisionInfo& collision) const; bool collisionHitsMoveableJoint(ModelCollisionInfo& collision) const;
/// \param collisionInfo info about the collision /// \param collisionInfo info about the collision
/// \return true if collision affects the Model /// Use the collisionInfo to affect the model
bool poke(ModelCollisionInfo& collisionInfo); void applyCollision(ModelCollisionInfo& collisionInfo);
protected: protected:

View file

@ -2,7 +2,7 @@
// AvatarHashMap.cpp // AvatarHashMap.cpp
// hifi // hifi
// //
// Created by Stephen AndrewMeadows on 1/28/2014. // Created by AndrewMeadows on 1/28/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
// //

View file

@ -45,10 +45,3 @@ void HeadData::addLean(float sideways, float forwards) {
_leanForward += forwards; _leanForward += forwards;
} }
bool HeadData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration) const {
// we would like to update this to determine collisions/penetrations with the Avatar's head sphere...
// but right now it does not appear as if the HeadData has a position and radius.
// this is a placeholder for now.
return false;
}

View file

@ -58,13 +58,6 @@ public:
void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; } void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; }
friend class AvatarData; friend class AvatarData;
/// Checks for penetration between the described sphere and the hand.
/// \param penetratorCenter the center of the penetration test sphere
/// \param penetratorRadius the radius of the penetration test sphere
/// \param penetration[out] the vector in which to store the penetration
/// \return whether or not the sphere penetrated
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration) const;
protected: protected:
float _yaw; float _yaw;