Merge pull request #1585 from AndrewMeadows/paddle-fixes

Paddle fixes
This commit is contained in:
Philip Rosedale 2014-01-17 16:50:10 -08:00
commit 317af4c927
12 changed files with 93 additions and 36 deletions

View file

@ -350,7 +350,6 @@ Menu::Menu() :
SLOT(setFilter(bool))); SLOT(setFilter(bool)));
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayLeapHands, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayLeapHands, 0, true);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::BallFromHand, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false);

View file

@ -156,7 +156,6 @@ namespace MenuOption {
const QString Avatars = "Avatars"; const QString Avatars = "Avatars";
const QString Atmosphere = "Atmosphere"; const QString Atmosphere = "Atmosphere";
const QString AutomaticallyAuditTree = "Automatically Audit Tree Stats"; const QString AutomaticallyAuditTree = "Automatically Audit Tree Stats";
const QString BallFromHand = "Ball from Hand";
const QString Bandwidth = "Bandwidth Display"; const QString Bandwidth = "Bandwidth Display";
const QString BandwidthDetails = "Bandwidth Details"; const QString BandwidthDetails = "Bandwidth Details";
const QString ChatCircling = "Chat Circling"; const QString ChatCircling = "Chat Circling";

View file

@ -317,7 +317,7 @@ bool Avatar::findSphereCollision(const glm::vec3& sphereCenter, float sphereRadi
if (handData) { if (handData) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
const PalmData* palm = handData->getPalm(i); const PalmData* palm = handData->getPalm(i);
if (palm) { if (palm && palm->hasPaddle()) {
// create a disk collision proxy where the hand is // create a disk collision proxy where the hand is
glm::vec3 fingerAxis(0.f); glm::vec3 fingerAxis(0.f);
for (size_t f = 0; f < palm->getNumFingers(); ++f) { for (size_t f = 0; f < palm->getNumFingers(); ++f) {
@ -339,10 +339,12 @@ bool Avatar::findSphereCollision(const glm::vec3& sphereCenter, float sphereRadi
} }
glm::vec3 diskCenter = handPosition + HAND_PADDLE_OFFSET * fingerAxis; glm::vec3 diskCenter = handPosition + HAND_PADDLE_OFFSET * fingerAxis;
glm::vec3 diskNormal = palm->getNormal(); glm::vec3 diskNormal = palm->getNormal();
float diskThickness = 0.08f;
// collide against the disk // collide against the disk
if (findSphereDiskPenetration(sphereCenter, sphereRadius, if (findSphereDiskPenetration(sphereCenter, sphereRadius,
diskCenter, HAND_PADDLE_RADIUS, diskNormal, collision._penetration)) { diskCenter, HAND_PADDLE_RADIUS, diskThickness, diskNormal,
collision._penetration)) {
collision._addedVelocity = palm->getVelocity(); collision._addedVelocity = palm->getVelocity();
return true; return true;
} }

View file

@ -83,7 +83,6 @@ void Hand::reset() {
void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, float deltaTime) { void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, float deltaTime) {
Application* app = Application::getInstance(); Application* app = Application::getInstance();
ParticleTree* particles = app->getParticles()->getTree(); ParticleTree* particles = app->getParticles()->getTree();
bool ballFromHand = Menu::getInstance()->isOptionChecked(MenuOption::BallFromHand);
int handID = palm.getSixenseID(); int handID = palm.getSixenseID();
const int NEW_BALL_BUTTON = BUTTON_3; const int NEW_BALL_BUTTON = BUTTON_3;
@ -93,7 +92,8 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
bool ballAlreadyInHand = _toyBallInHand[handID]; bool ballAlreadyInHand = _toyBallInHand[handID];
glm::vec3 targetPosition = (ballFromHand ? palm.getPosition() : fingerTipPosition) / (float)TREE_SCALE; glm::vec3 targetPosition;
palm.getBallHoldPosition(targetPosition);
float targetRadius = CATCH_RADIUS / (float)TREE_SCALE; float targetRadius = CATCH_RADIUS / (float)TREE_SCALE;
// If I don't currently have a ball in my hand, then try to catch closest one // If I don't currently have a ball in my hand, then try to catch closest one
@ -148,7 +148,8 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
if ((palm.getControllerButtons() & NEW_BALL_BUTTON) && (_toyBallInHand[handID] == false)) { if ((palm.getControllerButtons() & NEW_BALL_BUTTON) && (_toyBallInHand[handID] == false)) {
_toyBallInHand[handID] = true; _toyBallInHand[handID] = true;
// Create a particle on the particle server // Create a particle on the particle server
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; glm::vec3 ballPosition;
palm.getBallHoldPosition(ballPosition);
_ballParticleEditHandles[handID] = app->makeParticle( _ballParticleEditHandles[handID] = app->makeParticle(
ballPosition / (float)TREE_SCALE, ballPosition / (float)TREE_SCALE,
TOY_BALL_RADIUS / (float) TREE_SCALE, TOY_BALL_RADIUS / (float) TREE_SCALE,
@ -171,7 +172,8 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
xColor colorForParticleInHand = particleInHand ? particleInHand->getXColor() xColor colorForParticleInHand = particleInHand ? particleInHand->getXColor()
: TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]]; : TOY_BALL_ON_SERVER_COLOR[_whichBallColor[handID]];
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; glm::vec3 ballPosition;
palm.getBallHoldPosition(ballPosition);
_ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE, _ballParticleEditHandles[handID]->updateParticle(ballPosition / (float)TREE_SCALE,
TOY_BALL_RADIUS / (float) TREE_SCALE, TOY_BALL_RADIUS / (float) TREE_SCALE,
colorForParticleInHand, colorForParticleInHand,
@ -187,8 +189,10 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f
const float THROWN_VELOCITY_SCALING = 1.5f; const float THROWN_VELOCITY_SCALING = 1.5f;
_toyBallInHand[handID] = false; _toyBallInHand[handID] = false;
glm::vec3 ballPosition = ballFromHand ? palm.getPosition() : fingerTipPosition; palm.updateCollisionlessPaddleExpiry();
glm::vec3 ballVelocity = ballFromHand ? palm.getRawVelocity() : palm.getTipVelocity(); glm::vec3 ballPosition;
palm.getBallHoldPosition(ballPosition);
glm::vec3 ballVelocity = palm.getTipVelocity();
glm::quat avatarRotation = _owningAvatar->getOrientation(); glm::quat avatarRotation = _owningAvatar->getOrientation();
ballVelocity = avatarRotation * ballVelocity; ballVelocity = avatarRotation * ballVelocity;
ballVelocity *= THROWN_VELOCITY_SCALING; ballVelocity *= THROWN_VELOCITY_SCALING;
@ -550,7 +554,6 @@ void Hand::renderLeapHands(bool isMine) {
//const glm::vec3 handColor = _ballColor; //const glm::vec3 handColor = _ballColor;
const glm::vec3 handColor(1.0, 0.84, 0.66); // use the skin color const glm::vec3 handColor(1.0, 0.84, 0.66); // use the skin color
bool ballFromHand = Menu::getInstance()->isOptionChecked(MenuOption::BallFromHand);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
@ -561,7 +564,8 @@ void Hand::renderLeapHands(bool isMine) {
if (!palm.isActive()) { if (!palm.isActive()) {
continue; continue;
} }
glm::vec3 targetPosition = ballFromHand ? palm.getPosition() : palm.getTipPosition(); glm::vec3 targetPosition;
palm.getBallHoldPosition(targetPosition);
glPushMatrix(); glPushMatrix();
ParticleTree* particles = Application::getInstance()->getParticles()->getTree(); ParticleTree* particles = Application::getInstance()->getParticles()->getTree();

View file

@ -31,7 +31,7 @@ class Avatar;
class ProgramObject; class ProgramObject;
const float HAND_PADDLE_OFFSET = 0.1f; const float HAND_PADDLE_OFFSET = 0.1f;
const float HAND_PADDLE_THICKNESS = 0.05f; const float HAND_PADDLE_THICKNESS = 0.01f;
const float HAND_PADDLE_RADIUS = 0.15f; const float HAND_PADDLE_RADIUS = 0.15f;
class Hand : public HandData { class Hand : public HandData {

View file

@ -98,6 +98,15 @@ void SixenseManager::update(float deltaTime) {
// Compute current velocity from position change // Compute current velocity from position change
glm::vec3 rawVelocity = (position - palm->getRawPosition()) / deltaTime / 1000.f; glm::vec3 rawVelocity = (position - palm->getRawPosition()) / deltaTime / 1000.f;
palm->setRawVelocity(rawVelocity); // meters/sec palm->setRawVelocity(rawVelocity); // meters/sec
/*
if (i == 0)
{
printf("ADEBUG rawVelocity = [%e, %e, %e]\n",
rawVelocity.x,
rawVelocity.y,
rawVelocity.z);
}
*/
palm->setRawPosition(position); palm->setRawPosition(position);
// use the velocity to determine whether there's any movement (if the hand isn't new) // use the velocity to determine whether there's any movement (if the hand isn't new)

View file

@ -79,7 +79,8 @@ _sixenseID(SIXENSEID_INVALID),
_numFramesWithoutData(0), _numFramesWithoutData(0),
_owningHandData(owningHandData), _owningHandData(owningHandData),
_isCollidingWithVoxel(false), _isCollidingWithVoxel(false),
_isCollidingWithPalm(false) _isCollidingWithPalm(false),
_collisionlessPaddleExpiry(0)
{ {
for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) { for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) {
_fingers.push_back(FingerData(this, owningHandData)); _fingers.push_back(FingerData(this, owningHandData));
@ -294,6 +295,15 @@ const glm::vec3& FingerData::getTrailPosition(int index) {
return _tipTrailPositions[posIndex]; return _tipTrailPositions[posIndex];
} }
void PalmData::getBallHoldPosition(glm::vec3& position) const {
const float BALL_FORWARD_OFFSET = 0.08f; // put the ball a bit forward of fingers
position = BALL_FORWARD_OFFSET * getNormal();
if (_fingers.size() > 0) {
position += _fingers[0].getTipPosition();
} else {
position += getPosition();
}
}

View file

@ -15,6 +15,8 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include "SharedUtil.h"
class AvatarData; class AvatarData;
class FingerData; class FingerData;
class PalmData; class PalmData;
@ -51,7 +53,7 @@ public:
return _basePosition + _baseOrientation * (leapPosition * LEAP_UNIT_SCALE); return _basePosition + _baseOrientation * (leapPosition * LEAP_UNIT_SCALE);
} }
glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) { glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) {
return glm::normalize(_baseOrientation * leapDirection); return _baseOrientation * leapDirection;
} }
glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const; glm::vec3 worldPositionToLeapPosition(const glm::vec3& worldPosition) const;
glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const; glm::vec3 worldVectorToLeapVector(const glm::vec3& worldVector) const;
@ -193,6 +195,12 @@ public:
bool getIsCollidingWithPalm() const { return _isCollidingWithPalm; } bool getIsCollidingWithPalm() const { return _isCollidingWithPalm; }
void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; } void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; }
bool hasPaddle() const { return _collisionlessPaddleExpiry < usecTimestampNow(); }
void updateCollisionlessPaddleExpiry() { _collisionlessPaddleExpiry = usecTimestampNow() + USECS_PER_SECOND; }
/// Store position where the palm holds the ball.
void getBallHoldPosition(glm::vec3& position) const;
private: private:
std::vector<FingerData> _fingers; std::vector<FingerData> _fingers;
glm::quat _rawRotation; glm::quat _rawRotation;
@ -217,7 +225,7 @@ private:
bool _isCollidingWithVoxel; /// Whether the finger of this palm is inside a leaf voxel bool _isCollidingWithVoxel; /// Whether the finger of this palm is inside a leaf voxel
bool _isCollidingWithPalm; bool _isCollidingWithPalm;
uint64_t _collisionlessPaddleExpiry; /// Timestamp after which paddle starts colliding
}; };
#endif /* defined(__hifi__HandData__) */ #endif /* defined(__hifi__HandData__) */

View file

@ -145,7 +145,7 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE); glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE);
float radius = particle->getRadius() * (float)(TREE_SCALE); float radius = particle->getRadius() * (float)(TREE_SCALE);
const float ELASTICITY = 0.95f; const float ELASTICITY = 0.9f;
const float DAMPING = 0.0f; const float DAMPING = 0.0f;
const float COLLISION_FREQUENCY = 0.5f; const float COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration; glm::vec3 penetration;
@ -155,12 +155,27 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
AvatarData* avatar = (AvatarData*)_selfAvatar; AvatarData* avatar = (AvatarData*)_selfAvatar;
CollisionInfo collision; CollisionInfo collision;
if (avatar->findSphereCollision(center, radius, collision)) { if (avatar->findSphereCollision(center, radius, collision)) {
if (glm::dot(particle->getVelocity(), collision._addedVelocity) < 0.f) {
// only collide when particle and collision point are moving toward each other
collision._penetration /= (float)(TREE_SCALE);
collision._addedVelocity /= (float)(TREE_SCALE); collision._addedVelocity /= (float)(TREE_SCALE);
glm::vec3 relativeVelocity = collision._addedVelocity - particle->getVelocity();
if (glm::dot(relativeVelocity, collision._penetration) < 0.f) {
// only collide when particle and collision point are moving toward each other
// (doing this prevents some "collision snagging" when particle penetrates the object)
// HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against the avatar.
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
// TODO: make this less hacky when we have more per-collision details
float elasticity = ELASTICITY;
float SLOW_PADDLE_SPEED = 5.0e-5f;
float attenuationFactor = glm::length(collision._addedVelocity) / SLOW_PADDLE_SPEED;
if (attenuationFactor < 1.f) {
collision._addedVelocity *= attenuationFactor;
elasticity *= attenuationFactor;
}
// HACK END
collision._penetration /= (float)(TREE_SCALE);
updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY); updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY);
applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity); applyHardCollision(particle, collision._penetration, elasticity, DAMPING, collision._addedVelocity);
} }
} }
} }
@ -170,13 +185,24 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
//qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n"; //qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n";
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData()); AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData());
CollisionInfo collision; CollisionInfo collision;
if (avatar->findSphereCollision(center, radius, collision)) { if (avatar->findSphereCollision(center, radius, collision)) {
if (glm::dot(particle->getVelocity(), collision._addedVelocity) < 0.f) {
// only collide when particle and collision point are moving toward each other
collision._penetration /= (float)(TREE_SCALE);
collision._addedVelocity /= (float)(TREE_SCALE); collision._addedVelocity /= (float)(TREE_SCALE);
glm::vec3 relativeVelocity = collision._addedVelocity - particle->getVelocity();
if (glm::dot(relativeVelocity, collision._penetration) < 0.f) {
// HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against the avatar.
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
// TODO: make this less hacky when we have more per-collision details
float elasticity = ELASTICITY;
float SLOW_PADDLE_SPEED = 5.0e-5f;
float attenuationFactor = glm::length(collision._addedVelocity) / SLOW_PADDLE_SPEED;
if (attenuationFactor < 1.f) {
collision._addedVelocity *= attenuationFactor;
elasticity *= attenuationFactor;
}
// HACK END
collision._penetration /= (float)(TREE_SCALE);
updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY); updateCollisionSound(particle, collision._penetration, COLLISION_FREQUENCY);
applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity); applyHardCollision(particle, collision._penetration, ELASTICITY, DAMPING, collision._addedVelocity);
} }

View file

@ -18,7 +18,7 @@ public:
//glm::vec3 _point; //glm::vec3 _point;
//glm::vec3 _normal; //glm::vec3 _normal;
glm::vec3 _penetration; glm::vec3 _penetration; // depth that bodyA is penetrates bodyB
glm::vec3 _addedVelocity; glm::vec3 _addedVelocity;
}; };

View file

@ -6,6 +6,7 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include <cstring> #include <cstring>
#include <cmath>
#include "SharedUtil.h" #include "SharedUtil.h"
#include "GeometryUtil.h" #include "GeometryUtil.h"
@ -115,20 +116,18 @@ bool findSpherePlanePenetration(const glm::vec3& sphereCenter, float sphereRadiu
} }
bool findSphereDiskPenetration(const glm::vec3& sphereCenter, float sphereRadius, bool findSphereDiskPenetration(const glm::vec3& sphereCenter, float sphereRadius,
const glm::vec3& diskCenter, float diskRadius, const glm::vec3& diskNormal, const glm::vec3& diskCenter, float diskRadius, float diskThickness, const glm::vec3& diskNormal,
glm::vec3& penetration) { glm::vec3& penetration) {
glm::vec3 localCenter = sphereCenter - diskCenter; glm::vec3 localCenter = sphereCenter - diskCenter;
float verticalDistance = glm::dot(localCenter, diskNormal); float axialDistance = glm::dot(localCenter, diskNormal);
if (std::fabs(axialDistance) < (sphereRadius + 0.5f * diskThickness)) {
if (abs(verticalDistance) < sphereRadius) {
// sphere hit the plane, but does it hit the disk? // sphere hit the plane, but does it hit the disk?
// Note: this algorithm ignores edge hits. // Note: this algorithm ignores edge hits.
glm::vec3 verticalOffset = verticalDistance * diskNormal; glm::vec3 axialOffset = axialDistance * diskNormal;
if (glm::length(localCenter - verticalOffset) < diskRadius) { if (glm::length(localCenter - axialOffset) < diskRadius) {
// yes, hit the disk // yes, hit the disk
penetration = (sphereRadius - abs(verticalDistance)) * diskNormal; penetration = (std::fabs(axialDistance) - (sphereRadius + 0.5f * diskThickness) ) * diskNormal;
if (verticalDistance < 0.f) { if (axialDistance < 0.f) {
// hit the backside of the disk, so negate penetration vector // hit the backside of the disk, so negate penetration vector
penetration *= -1.f; penetration *= -1.f;
} }

View file

@ -17,7 +17,7 @@ glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec
/// \param point the point location relative to sphere center (origin) /// \param point the point location relative to sphere center (origin)
/// \param defaultDirection the direction of the pentration when the point is near the origin /// \param defaultDirection the direction of the pentration when the point is near the origin
/// \param sphereRadius the radius of the sphere /// \param sphereRadius the radius of the sphere
/// \param penetration the displacement that would move the point out of penetration with the sphere /// \param penetration[out] the displacement that would move the point out of penetration with the sphere
/// \return true if point is inside sphere, otherwise false /// \return true if point is inside sphere, otherwise false
bool findSpherePenetration(const glm::vec3& point, const glm::vec3& defaultDirection, bool findSpherePenetration(const glm::vec3& point, const glm::vec3& defaultDirection,
float sphereRadius, glm::vec3& penetration); float sphereRadius, glm::vec3& penetration);
@ -53,9 +53,10 @@ bool findSpherePlanePenetration(const glm::vec3& sphereCenter, float sphereRadiu
/// \param diskCenter center of disk /// \param diskCenter center of disk
/// \param diskRadius radius of disk /// \param diskRadius radius of disk
/// \param diskNormal normal of disk plan /// \param diskNormal normal of disk plan
/// \param penetration[out] the depth that the sphere penetrates the disk
/// \return true if sphere touches disk (does not handle collisions with disk edge) /// \return true if sphere touches disk (does not handle collisions with disk edge)
bool findSphereDiskPenetration(const glm::vec3& sphereCenter, float sphereRadius, bool findSphereDiskPenetration(const glm::vec3& sphereCenter, float sphereRadius,
const glm::vec3& diskCenter, float diskRadius, const glm::vec3& diskNormal, const glm::vec3& diskCenter, float diskRadius, float diskThickness, const glm::vec3& diskNormal,
glm::vec3& penetration); glm::vec3& penetration);
bool findCapsuleSpherePenetration(const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius, bool findCapsuleSpherePenetration(const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius,