History

PhysicsEngine doesn't need AvatarData

MyAvatar now owns its CharacterController fix for bug of phantom collision obj when avatar's physics are disabled

Andrew Meadows committed 11 years ago

Commit 44eca081 parent 49f5de28 files · +194 −137Browse files

Showing the changes to libraries/physics/src/CharacterController.cpp (1 of 8 files). Show all

Unified · Split

libraries/physics/src/CharacterController.cpp+142−81
@@ -21,6 +21,12 @@ subject to the following restrictions: · 20 unmodified lines
21#include "BulletUtil.h"21#include "BulletUtil.h"
22#include "CharacterController.h"22#include "CharacterController.h"
23 23
24const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0;
25const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1;
26//const uint32_t PENDING_FLAG_ENABLE = 1U << 0;
27//const uint32_t PENDING_FLAG_DISABLE = 1U << 1;
28const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2;
29const uint32_t PENDING_FLAG_JUMP = 1U << 4;
24 30
25// static helper method31// static helper method
26static btVector3 getNormalizedVector(const btVector3& v) {32static btVector3 getNormalizedVector(const btVector3& v) {
@@ -223,11 +229,10 @@ CharacterController::CharacterController(AvatarData* avatarData) { · 196 unmodified lines
223 _avatarData = avatarData;229 _avatarData = avatarData;
224 230
225 // cache the "PhysicsEnabled" state of _avatarData231 // cache the "PhysicsEnabled" state of _avatarData
226 _avatarData->lockForRead();232 _enabled = false;
227 _enabled = _avatarData->isPhysicsEnabled();
228 _avatarData->unlock();
229 233
230 createShapeAndGhost();234 _ghostObject = NULL;
235 _convexShape = NULL;
231 236
232 _addedMargin = 0.02f;237 _addedMargin = 0.02f;
233 _walkDirection.setValue(0.0f,0.0f,0.0f);238 _walkDirection.setValue(0.0f,0.0f,0.0f);
@@ -242,6 +247,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { · 8 unmodified lines
242 _wasJumping = false;247 _wasJumping = false;
243 setMaxSlope(btRadians(45.0f));248 setMaxSlope(btRadians(45.0f));
244 _lastStepUp = 0.0f;249 _lastStepUp = 0.0f;
250 _pendingFlags = 0;
245}251}
246 252
247CharacterController::~CharacterController() {253CharacterController::~CharacterController() {
@@ -349,7 +355,7 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl · 101 unmodified lines
349 return penetration;355 return penetration;
350}356}
351 357
352void CharacterController::stepUp( btCollisionWorld* world) {358void CharacterController::stepUp(btCollisionWorld* world) {
353 // phase 1: up359 // phase 1: up
354 360
355 // compute start and end361 // compute start and end
@@ -416,7 +422,7 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& · 60 unmodified lines
416 }422 }
417}423}
418 424
419void CharacterController::stepForward( btCollisionWorld* collisionWorld, const btVector3& movement) {425void CharacterController::stepForward(btCollisionWorld* collisionWorld, const btVector3& movement) {
420 // phase 2: forward426 // phase 2: forward
421 _targetPosition = _currentPosition + movement;427 _targetPosition = _currentPosition + movement;
422 428
@@ -472,7 +478,7 @@ void CharacterController::stepForward( btCollisionWorld* collisionWorld, const b · 49 unmodified lines
472 _convexShape->setMargin(margin);478 _convexShape->setMargin(margin);
473}479}
474 480
475void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar dt) {481void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt) {
476 // phase 3: down482 // phase 3: down
477 //483 //
478 // The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase. 484 // The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase.
@@ -558,7 +564,7 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, · 79 unmodified lines
558 _velocityTimeInterval += timeInterval;564 _velocityTimeInterval += timeInterval;
559}565}
560 566
561void CharacterController::reset( btCollisionWorld* collisionWorld ) {567void CharacterController::reset(btCollisionWorld* collisionWorld) {
562 _verticalVelocity = 0.0;568 _verticalVelocity = 0.0;
563 _verticalOffset = 0.0;569 _verticalOffset = 0.0;
564 _wasOnGround = false;570 _wasOnGround = false;
@@ -583,7 +589,7 @@ void CharacterController::warp(const btVector3& origin) { · 18 unmodified lines
583}589}
584 590
585 591
586void CharacterController::preStep( btCollisionWorld* collisionWorld) {592void CharacterController::preStep(btCollisionWorld* collisionWorld) {
587 if (!_enabled) {593 if (!_enabled) {
588 return;594 return;
589 }595 }
@@ -603,7 +609,7 @@ void CharacterController::preStep( btCollisionWorld* collisionWorld) { · 13 unmodified lines
603 _targetPosition = _currentPosition;609 _targetPosition = _currentPosition;
604}610}
605 611
606void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt) {612void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar dt) {
607 if (!_enabled || (!_useWalkDirection && _velocityTimeInterval <= 0.0)) {613 if (!_enabled || (!_useWalkDirection && _velocityTimeInterval <= 0.0)) {
608 return; // no motion614 return; // no motion
609 }615 }
@@ -710,106 +716,163 @@ void CharacterController::setUpInterpolate(bool value) { · 100 unmodified lines
710 // (interpolate = true, and now default behavior) or happily penetrate objects above the avatar.716 // (interpolate = true, and now default behavior) or happily penetrate objects above the avatar.
711}717}
712 718
719/*
713// protected720// protected
714void CharacterController::createShapeAndGhost() {721void CharacterController::createShapeAndGhost() {
715 // get new dimensions from avatar722 // get new dimensions from avatar
716 _avatarData->lockForRead();723 float x = _boxScale.x;
717 AABox box = _avatarData->getLocalAABox();724 float z = _boxScale.z;
718 725 _radius = 0.5f * sqrtf(0.5f * (x * x + z * z));
719 // create new ghost726 _halfHeight = 0.5f * _boxScale.y - _radius;
720 _ghostObject = new btPairCachingGhostObject();
721 _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
722 glmToBullet(_avatarData->getPosition())));
723 _avatarData->unlock();
724
725 const glm::vec3& diagonal = box.getScale();
726 _radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z));
727 _halfHeight = 0.5f * diagonal.y - _radius;
728 float MIN_HALF_HEIGHT = 0.1f;727 float MIN_HALF_HEIGHT = 0.1f;
729 if (_halfHeight < MIN_HALF_HEIGHT) {728 if (_halfHeight < MIN_HALF_HEIGHT) {
730 _halfHeight = MIN_HALF_HEIGHT;729 _halfHeight = MIN_HALF_HEIGHT;
731 }730 }
732 glm::vec3 offset = box.getCorner() + 0.5f * diagonal;731 // NOTE: _shapeLocalOffset is already computed
733 _shapeLocalOffset = offset;732
734 733 if (_radius > 0.0f) {
735 // stepHeight affects the heights of ledges that the character can ascend734 // create new ghost
736 // however the actual ledge height is some function of _stepHeight 735 _ghostObject = new btPairCachingGhostObject();
737 // due to character shape and this CharacterController algorithm 736 _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
738 // (the function is approximately 2*_stepHeight)737 glmToBullet(_avatarData->getPosition())));
739 _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f;738 // stepHeight affects the heights of ledges that the character can ascend
740 739 // however the actual ledge height is some function of _stepHeight
741 // create new shape740 // due to character shape and this CharacterController algorithm
742 _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight);741 // (the function is approximately 2*_stepHeight)
743 _ghostObject->setCollisionShape(_convexShape);742 _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f;
744 _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);743
744 // create new shape
745 _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
746 _ghostObject->setCollisionShape(_convexShape);
747 _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
748 } else {
749 // TODO: handle this failure case
750 }
751 _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE;
745}752}
753*/
746 754
747bool CharacterController::needsShapeUpdate() {755void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
748 // get new dimensions from avatar756 _boxScale = scale;
749 _avatarData->lockForRead();
750 AABox box = _avatarData->getLocalAABox();
751 _avatarData->unlock();
752 757
753 const glm::vec3& diagonal = box.getScale();758 float x = _boxScale.x;
754 float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z));759 float z = _boxScale.z;
755 float halfHeight = 0.5f * diagonal.y - radius;760 float radius = 0.5f * sqrtf(0.5f * (x * x + z * z));
761 float halfHeight = 0.5f * _boxScale.y - radius;
756 float MIN_HALF_HEIGHT = 0.1f;762 float MIN_HALF_HEIGHT = 0.1f;
757 if (halfHeight < MIN_HALF_HEIGHT) {763 if (halfHeight < MIN_HALF_HEIGHT) {
758 halfHeight = MIN_HALF_HEIGHT;764 halfHeight = MIN_HALF_HEIGHT;
759 }765 }
760 glm::vec3 offset = box.getCorner() + 0.5f * diagonal;
761 766
762 // compare dimensions (and offset)767 // compare dimensions
763 float radiusDelta = glm::abs(radius - _radius);768 float radiusDelta = glm::abs(radius - _radius);
764 float heightDelta = glm::abs(halfHeight - _halfHeight);769 float heightDelta = glm::abs(halfHeight - _halfHeight);
765 if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) {770 if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) {
766 // shape hasn't changed --> nothing to do771 // shape hasn't changed --> nothing to do
767 float offsetDelta = glm::distance(offset, _shapeLocalOffset);772 } else {
768 if (offsetDelta > FLT_EPSILON) {773 // we need to: remove, update, add
769 // if only the offset changes then we can update it --> no need to rebuild shape774 _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION
770 _shapeLocalOffset = offset;775 | PENDING_FLAG_UPDATE_SHAPE
771 }776 | PENDING_FLAG_ADD_TO_SIMULATION;
772 return false;
773 }777 }
774 return true;
775}
776 778
777void CharacterController::updateShape() {779 // it's ok to change offset immediately -- there are no thread safety issues here
778 // DANGER: make sure this CharacterController and its GhostShape have been removed from780 _shapeLocalOffset = corner + 0.5f * _boxScale;
779 // the PhysicsEngine before calling this.781}
780 782
781 // delete shape and GhostObject783bool CharacterController::needsAddition() const {
782 delete _ghostObject;784 return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION);
783 _ghostObject = NULL;
784 delete _convexShape;
785 _convexShape = NULL;
786
787 createShapeAndGhost();
788}785}
789 786
790void CharacterController::preSimulation(btScalar timeStep) {787bool CharacterController::needsRemoval() const {
791 bool wasEnabled = _enabled;788 return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION);
789}
792 790
793 // lock avatarData, get everything we need from it ASAP, then unlock791void CharacterController::setEnabled(bool enabled) {
794 _avatarData->lockForRead();792 if (enabled != _enabled) {
795 _enabled = _avatarData->isPhysicsEnabled();793 if (enabled) {
796 glm::quat rotation = _avatarData->getOrientation();794 _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
797 glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset;795 } else {
798 // TODO: Andrew to implement: harvest jump event here796 _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
799 btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity());797 _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
798 }
799 _enabled = enabled;
800 }
801}
800 802
801 _avatarData->unlock();803void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
804 if (_dynamicsWorld != world) {
805 if (_dynamicsWorld) {
806 _dynamicsWorld->removeCollisionObject(getGhostObject());
807 _dynamicsWorld->removeAction(this);
808 }
809 _dynamicsWorld = world;
810 if (_dynamicsWorld) {
811 _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
812 _dynamicsWorld->addCollisionObject(getGhostObject(),
813 btBroadphaseProxy::CharacterFilter,
814 btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
815 _dynamicsWorld->addAction(this);
816 reset(_dynamicsWorld);
817 } else {
818 _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION;
819 }
820 } else {
821 _pendingFlags &= ~ (PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_ADD_TO_SIMULATION);
822 }
823}
802 824
803 if (wasEnabled != _enabled) {825void CharacterController::updateShape() {
804 if (_enabled) {826 if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
805 // TODO: Andrew to implement: add collision shape back into world827 assert(!(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION));
828 _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE;
829 // make sure there is NO pending removal from simulation at this point
830 // (don't want to delete _ghostObject out from under the simulation)
831 // delete shape and GhostObject
832 delete _ghostObject;
833 _ghostObject = NULL;
834 delete _convexShape;
835 _convexShape = NULL;
836
837 // compute new dimensions from avatar's bounding box
838 float x = _boxScale.x;
839 float z = _boxScale.z;
840 _radius = 0.5f * sqrtf(0.5f * (x * x + z * z));
841 _halfHeight = 0.5f * _boxScale.y - _radius;
842 float MIN_HALF_HEIGHT = 0.1f;
843 if (_halfHeight < MIN_HALF_HEIGHT) {
844 _halfHeight = MIN_HALF_HEIGHT;
845 }
846 // NOTE: _shapeLocalOffset is already computed
847
848 if (_radius > 0.0f) {
849 // create new ghost
850 _ghostObject = new btPairCachingGhostObject();
851 _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
852 glmToBullet(_avatarData->getPosition())));
853 // stepHeight affects the heights of ledges that the character can ascend
854 // however the actual ledge height is some function of _stepHeight
855 // due to character shape and this CharacterController algorithm
856 // (the function is approximately 2*_stepHeight)
857 _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f;
858
859 // create new shape
860 _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
861 _ghostObject->setCollisionShape(_convexShape);
862 _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
806 } else {863 } else {
807 // TODO: Andrew to implement: remove collision shape from world,864 // TODO: handle this failure case
808 // otherwise things will continue to collide with it
809 }865 }
810 }866 }
867}
868
869void CharacterController::preSimulation(btScalar timeStep) {
870 if (_enabled && _dynamicsWorld) {
871 glm::quat rotation = _avatarData->getOrientation();
872 glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset;
873 // TODO: harvest jump event here
874 btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity());
811 875
812 if (_enabled) {
813 _ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position)));876 _ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position)));
814 setVelocityForTimeInterval(walkVelocity, timeStep);877 setVelocityForTimeInterval(walkVelocity, timeStep);
815 }878 }
@@ -817,13 +880,11 @@ void CharacterController::preSimulation(btScalar timeStep) { · 1 unmodified line
817 880
818void CharacterController::postSimulation() {881void CharacterController::postSimulation() {
819 if (_enabled) {882 if (_enabled) {
820 _avatarData->lockForWrite();
821 const btTransform& avatarTransform = _ghostObject->getWorldTransform(); 883 const btTransform& avatarTransform = _ghostObject->getWorldTransform();
822 glm::quat rotation = bulletToGLM(avatarTransform.getRotation());884 glm::quat rotation = bulletToGLM(avatarTransform.getRotation());
823 glm::vec3 offset = rotation * _shapeLocalOffset;885 glm::vec3 offset = rotation * _shapeLocalOffset;
824 _avatarData->setOrientation(rotation);886 _avatarData->setOrientation(rotation);
825 _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); 887 _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset);
826 _avatarData->unlock();
827 }888 }
828}889}
829 890

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t