give MyAvatar a VoxelShapeManager member

This commit is contained in:
Andrew Meadows 2014-09-03 13:19:41 -07:00
parent 83e04a0e8f
commit 2c1aa31d1e
2 changed files with 119 additions and 100 deletions

View file

@ -79,7 +79,8 @@ MyAvatar::MyAvatar() :
_lookAtTargetAvatar(), _lookAtTargetAvatar(),
_shouldRender(true), _shouldRender(true),
_billboardValid(false), _billboardValid(false),
_physicsSimulation() _physicsSimulation(),
_voxelShapeManager()
{ {
ShapeCollider::initDispatchTable(); ShapeCollider::initDispatchTable();
for (int i = 0; i < MAX_DRIVE_KEYS; i++) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
@ -90,11 +91,11 @@ MyAvatar::MyAvatar() :
_skeletonModel.setEnableShapes(true); _skeletonModel.setEnableShapes(true);
Ragdoll* ragdoll = _skeletonModel.buildRagdoll(); Ragdoll* ragdoll = _skeletonModel.buildRagdoll();
_physicsSimulation.setRagdoll(ragdoll); _physicsSimulation.setRagdoll(ragdoll);
_physicsSimulation.addEntity(&_voxelShapeManager);
} }
MyAvatar::~MyAvatar() { MyAvatar::~MyAvatar() {
_physicsSimulation.setRagdoll(NULL); _physicsSimulation.clear();
_physicsSimulation.setEntity(NULL);
_lookAtTargetAvatar.clear(); _lookAtTargetAvatar.clear();
} }
@ -1486,112 +1487,125 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
static CollisionList myCollisions(64); static CollisionList myCollisions(64);
void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) {
const float MAX_VOXEL_COLLISION_SPEED = 100.0f; if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) {
float speed = glm::length(_velocity); // compute the bounding cube around avatar
if (speed > MAX_VOXEL_COLLISION_SPEED) { float radius = 2.0f * getBoundingRadius();
// don't even bother to try to collide against voxles when moving very fast glm::vec3 corner = getPosition() - glm::vec3(radius);
_trapDuration = 0.0f; AACube boundingCube(corner, 2.0f * radius);
return;
}
bool isTrapped = false;
myCollisions.clear();
const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions, Octree::TryLock)) {
const float VOXEL_ELASTICITY = 0.0f;
const float VOXEL_DAMPING = 0.0f;
float capsuleRadius = boundingShape.getRadius();
float capsuleHalfHeight = boundingShape.getHalfHeight();
const float MAX_STEP_HEIGHT = capsuleRadius + capsuleHalfHeight;
const float MIN_STEP_HEIGHT = 0.0f;
glm::vec3 footBase = boundingShape.getTranslation() - (capsuleRadius + capsuleHalfHeight) * _worldUpDirection;
float highestStep = 0.0f;
float lowestStep = MAX_STEP_HEIGHT;
glm::vec3 floorPoint;
glm::vec3 stepPenetration(0.0f);
glm::vec3 totalPenetration(0.0f);
for (int i = 0; i < myCollisions.size(); ++i) { // query the VoxelTree for cubes that touch avatar's boundingCube
CollisionInfo* collision = myCollisions[i]; CubeList cubes;
glm::vec3 cubeCenter = collision->_vecData; if (Application::getInstance()->getVoxelTree()->findContentInCube(boundingCube, cubes)) {
float cubeSide = collision->_floatData; _voxelShapeManager.updateVoxels(cubes);
float verticalDepth = glm::dot(collision->_penetration, _worldUpDirection);
float horizontalDepth = glm::length(collision->_penetration - verticalDepth * _worldUpDirection);
const float MAX_TRAP_PERIOD = 0.125f;
if (horizontalDepth > capsuleRadius || fabsf(verticalDepth) > MAX_STEP_HEIGHT) {
isTrapped = true;
if (_trapDuration > MAX_TRAP_PERIOD) {
float distance = glm::dot(boundingShape.getTranslation() - cubeCenter, _worldUpDirection);
if (distance < 0.0f) {
distance = fabsf(distance) + 0.5f * cubeSide;
}
distance += capsuleRadius + capsuleHalfHeight;
totalPenetration = addPenetrations(totalPenetration, - distance * _worldUpDirection);
continue;
}
} else if (_trapDuration > MAX_TRAP_PERIOD) {
// we're trapped, ignore this collision
continue;
}
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
if (glm::dot(collision->_penetration, _velocity) >= 0.0f) {
glm::vec3 cubeTop = cubeCenter + (0.5f * cubeSide) * _worldUpDirection;
float stepHeight = glm::dot(_worldUpDirection, cubeTop - footBase);
if (stepHeight > highestStep) {
highestStep = stepHeight;
stepPenetration = collision->_penetration;
}
if (stepHeight < lowestStep) {
lowestStep = stepHeight;
floorPoint = collision->_contactPoint - collision->_penetration;
}
}
} }
if (lowestStep < MAX_STEP_HEIGHT) { } else {
_lastFloorContactPoint = floorPoint; const float MAX_VOXEL_COLLISION_SPEED = 100.0f;
} float speed = glm::length(_velocity);
if (speed > MAX_VOXEL_COLLISION_SPEED) {
float penetrationLength = glm::length(totalPenetration); // don't even bother to try to collide against voxles when moving very fast
if (penetrationLength < EPSILON) {
_trapDuration = 0.0f; _trapDuration = 0.0f;
return; return;
} }
float verticalPenetration = glm::dot(totalPenetration, _worldUpDirection); bool isTrapped = false;
if (highestStep > MIN_STEP_HEIGHT && highestStep < MAX_STEP_HEIGHT && verticalPenetration <= 0.0f) { myCollisions.clear();
// we're colliding against an edge const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
glm::vec3 targetVelocity = _motorVelocity; if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions, Octree::TryLock)) {
if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) { const float VOXEL_ELASTICITY = 0.0f;
// rotate _motorVelocity into world frame const float VOXEL_DAMPING = 0.0f;
glm::quat rotation = getHead()->getCameraOrientation(); float capsuleRadius = boundingShape.getRadius();
targetVelocity = rotation * _motorVelocity; float capsuleHalfHeight = boundingShape.getHalfHeight();
} const float MAX_STEP_HEIGHT = capsuleRadius + capsuleHalfHeight;
if (_wasPushing && glm::dot(targetVelocity, totalPenetration) > EPSILON) { const float MIN_STEP_HEIGHT = 0.0f;
// we're puhing into the edge, so we want to lift glm::vec3 footBase = boundingShape.getTranslation() - (capsuleRadius + capsuleHalfHeight) * _worldUpDirection;
float highestStep = 0.0f;
// remove unhelpful horizontal component of the step's penetration float lowestStep = MAX_STEP_HEIGHT;
totalPenetration -= stepPenetration - (glm::dot(stepPenetration, _worldUpDirection) * _worldUpDirection); glm::vec3 floorPoint;
glm::vec3 stepPenetration(0.0f);
// further adjust penetration to help lift glm::vec3 totalPenetration(0.0f);
float liftSpeed = glm::max(MAX_WALKING_SPEED, speed);
float thisStep = glm::min(liftSpeed * deltaTime, highestStep); for (int i = 0; i < myCollisions.size(); ++i) {
float extraStep = glm::dot(totalPenetration, _worldUpDirection) + thisStep; CollisionInfo* collision = myCollisions[i];
if (extraStep > 0.0f) { glm::vec3 cubeCenter = collision->_vecData;
totalPenetration -= extraStep * _worldUpDirection; float cubeSide = collision->_floatData;
float verticalDepth = glm::dot(collision->_penetration, _worldUpDirection);
float horizontalDepth = glm::length(collision->_penetration - verticalDepth * _worldUpDirection);
const float MAX_TRAP_PERIOD = 0.125f;
if (horizontalDepth > capsuleRadius || fabsf(verticalDepth) > MAX_STEP_HEIGHT) {
isTrapped = true;
if (_trapDuration > MAX_TRAP_PERIOD) {
float distance = glm::dot(boundingShape.getTranslation() - cubeCenter, _worldUpDirection);
if (distance < 0.0f) {
distance = fabsf(distance) + 0.5f * cubeSide;
}
distance += capsuleRadius + capsuleHalfHeight;
totalPenetration = addPenetrations(totalPenetration, - distance * _worldUpDirection);
continue;
}
} else if (_trapDuration > MAX_TRAP_PERIOD) {
// we're trapped, ignore this collision
continue;
}
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
if (glm::dot(collision->_penetration, _velocity) >= 0.0f) {
glm::vec3 cubeTop = cubeCenter + (0.5f * cubeSide) * _worldUpDirection;
float stepHeight = glm::dot(_worldUpDirection, cubeTop - footBase);
if (stepHeight > highestStep) {
highestStep = stepHeight;
stepPenetration = collision->_penetration;
}
if (stepHeight < lowestStep) {
lowestStep = stepHeight;
floorPoint = collision->_contactPoint - collision->_penetration;
}
}
}
if (lowestStep < MAX_STEP_HEIGHT) {
_lastFloorContactPoint = floorPoint;
}
float penetrationLength = glm::length(totalPenetration);
if (penetrationLength < EPSILON) {
_trapDuration = 0.0f;
return;
}
float verticalPenetration = glm::dot(totalPenetration, _worldUpDirection);
if (highestStep > MIN_STEP_HEIGHT && highestStep < MAX_STEP_HEIGHT && verticalPenetration <= 0.0f) {
// we're colliding against an edge
glm::vec3 targetVelocity = _motorVelocity;
if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) {
// rotate _motorVelocity into world frame
glm::quat rotation = getHead()->getCameraOrientation();
targetVelocity = rotation * _motorVelocity;
}
if (_wasPushing && glm::dot(targetVelocity, totalPenetration) > EPSILON) {
// we're puhing into the edge, so we want to lift
// remove unhelpful horizontal component of the step's penetration
totalPenetration -= stepPenetration - (glm::dot(stepPenetration, _worldUpDirection) * _worldUpDirection);
// further adjust penetration to help lift
float liftSpeed = glm::max(MAX_WALKING_SPEED, speed);
float thisStep = glm::min(liftSpeed * deltaTime, highestStep);
float extraStep = glm::dot(totalPenetration, _worldUpDirection) + thisStep;
if (extraStep > 0.0f) {
totalPenetration -= extraStep * _worldUpDirection;
}
_position -= totalPenetration;
} else {
// we're not pushing into the edge, so let the avatar fall
applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
} }
_position -= totalPenetration;
} else { } else {
// we're not pushing into the edge, so let the avatar fall
applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
} }
} else {
applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); // Don't make a collision sound against voxlels by default -- too annoying when walking
} //const float VOXEL_COLLISION_FREQUENCY = 0.5f;
//updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY);
// Don't make a collision sound against voxlels by default -- too annoying when walking }
//const float VOXEL_COLLISION_FREQUENCY = 0.5f; _trapDuration = isTrapped ? _trapDuration + deltaTime : 0.0f;
//updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); }
}
_trapDuration = isTrapped ? _trapDuration + deltaTime : 0.0f;
} }
void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) {
@ -1952,6 +1966,9 @@ void MyAvatar::updateMotionBehaviorsFromMenu() {
} else { } else {
_motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; _motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
} }
if (!(_collisionGroups | COLLISION_GROUP_VOXELS)) {
_voxelShapeManager.clearShapes();
}
} }
void MyAvatar::renderAttachments(RenderMode renderMode) { void MyAvatar::renderAttachments(RenderMode renderMode) {

View file

@ -17,6 +17,7 @@
#include <PhysicsSimulation.h> #include <PhysicsSimulation.h>
#include "Avatar.h" #include "Avatar.h"
#include "VoxelShapeManager.h"
class ModelItemID; class ModelItemID;
@ -214,6 +215,7 @@ private:
QList<AnimationHandlePointer> _animationHandles; QList<AnimationHandlePointer> _animationHandles;
PhysicsSimulation _physicsSimulation; PhysicsSimulation _physicsSimulation;
VoxelShapeManager _voxelShapeManager;
RecorderPointer _recorder; RecorderPointer _recorder;