mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 18:44:00 +02:00
Hands can collide with avatar head again
This commit is contained in:
parent
bca0ea1502
commit
37b088ebfa
9 changed files with 96 additions and 100 deletions
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue