mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
Merge pull request #6200 from AndrewMeadows/character-controller
Move DynamicCharacterController to MyAvatarController
This commit is contained in:
commit
21afcf48ae
10 changed files with 432 additions and 278 deletions
|
@ -2756,7 +2756,6 @@ void Application::update(float deltaTime) {
|
|||
|
||||
{
|
||||
PerformanceTimer perfTimer("physics");
|
||||
myAvatar->relayDriveKeysToCharacterController();
|
||||
|
||||
static VectorOfMotionStates motionStates;
|
||||
_entitySimulation.getObjectsToDelete(motionStates);
|
||||
|
@ -2783,6 +2782,8 @@ void Application::update(float deltaTime) {
|
|||
avatarManager->getObjectsToChange(motionStates);
|
||||
_physicsEngine->changeObjects(motionStates);
|
||||
|
||||
myAvatar->prepareForPhysicsSimulation();
|
||||
|
||||
_entities.getTree()->withWriteLock([&] {
|
||||
_physicsEngine->stepSimulation();
|
||||
});
|
||||
|
@ -2807,6 +2808,8 @@ void Application::update(float deltaTime) {
|
|||
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
||||
_entities.update(); // update the models...
|
||||
}
|
||||
|
||||
myAvatar->harvestResultsFromPhysicsSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,8 @@ void MyAvatar::reset(bool andReload) {
|
|||
}
|
||||
|
||||
// Reset dynamic state.
|
||||
_wasPushing = _isPushing = _isBraking = _billboardValid = _straighteningLean = false;
|
||||
_wasPushing = _isPushing = _isBraking = _billboardValid = false;
|
||||
_isFollowingHMD = false;
|
||||
_skeletonModel.reset();
|
||||
getHead()->reset();
|
||||
_targetVelocity = glm::vec3(0.0f);
|
||||
|
@ -304,7 +305,7 @@ glm::mat4 MyAvatar::getSensorToWorldMatrix() const {
|
|||
|
||||
// returns true if pos is OUTSIDE of the vertical capsule
|
||||
// where the middle cylinder length is defined by capsuleLen and the radius by capsuleRad.
|
||||
static bool capsuleCheck(const glm::vec3& pos, float capsuleLen, float capsuleRad) {
|
||||
static bool pointIsOutsideCapsule(const glm::vec3& pos, float capsuleLen, float capsuleRad) {
|
||||
const float halfCapsuleLen = capsuleLen / 2.0f;
|
||||
if (fabs(pos.y) <= halfCapsuleLen) {
|
||||
// cylinder check for middle capsule
|
||||
|
@ -325,6 +326,10 @@ static bool capsuleCheck(const glm::vec3& pos, float capsuleLen, float capsuleRa
|
|||
// This can also update the avatar's position to follow the HMD
|
||||
// as it moves through the world.
|
||||
void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
||||
// update the sensorMatrices based on the new hmd pose
|
||||
_hmdSensorMatrix = hmdSensorMatrix;
|
||||
_hmdSensorPosition = extractTranslation(hmdSensorMatrix);
|
||||
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
||||
|
||||
// calc deltaTime
|
||||
auto now = usecTimestampNow();
|
||||
|
@ -334,11 +339,6 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||
float deltaTime = glm::clamp((float)actualDeltaTime, 0.0f, BIGGEST_DELTA_TIME_SECS);
|
||||
|
||||
// update the sensorMatrices based on the new hmd pose
|
||||
_hmdSensorMatrix = hmdSensorMatrix;
|
||||
_hmdSensorPosition = extractTranslation(hmdSensorMatrix);
|
||||
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
||||
|
||||
bool hmdIsAtRest = _hmdAtRestDetector.update(deltaTime, _hmdSensorPosition, _hmdSensorOrientation);
|
||||
|
||||
// It can be more accurate/smooth to use velocity rather than position,
|
||||
|
@ -360,58 +360,60 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
bool justStartedMoving = (_lastIsMoving != isMoving) && isMoving;
|
||||
_lastIsMoving = isMoving;
|
||||
|
||||
if (shouldBeginStraighteningLean() || hmdIsAtRest || justStartedMoving) {
|
||||
beginStraighteningLean();
|
||||
if (shouldFollowHMD() || hmdIsAtRest || justStartedMoving) {
|
||||
beginFollowingHMD();
|
||||
}
|
||||
|
||||
processStraighteningLean(deltaTime);
|
||||
followHMD(deltaTime);
|
||||
}
|
||||
|
||||
void MyAvatar::beginStraighteningLean() {
|
||||
glm::vec3 MyAvatar::getHMDCorrectionVelocity() const {
|
||||
// TODO: impelement this
|
||||
return Vectors::ZERO;
|
||||
}
|
||||
|
||||
void MyAvatar::beginFollowingHMD() {
|
||||
// begin homing toward derived body position.
|
||||
if (!_straighteningLean) {
|
||||
_straighteningLean = true;
|
||||
_straighteningLeanAlpha = 0.0f;
|
||||
if (!_isFollowingHMD) {
|
||||
_isFollowingHMD = true;
|
||||
_followHMDAlpha = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
bool MyAvatar::shouldBeginStraighteningLean() const {
|
||||
// define a vertical capsule
|
||||
const float STRAIGHTENING_LEAN_CAPSULE_RADIUS = 0.2f; // meters
|
||||
const float STRAIGHTENING_LEAN_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters.
|
||||
|
||||
// detect if the derived body position is outside of a capsule around the _bodySensorMatrix
|
||||
auto newBodySensorMatrix = deriveBodyFromHMDSensor();
|
||||
glm::vec3 diff = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix);
|
||||
bool isBodyPosOutsideCapsule = capsuleCheck(diff, STRAIGHTENING_LEAN_CAPSULE_LENGTH, STRAIGHTENING_LEAN_CAPSULE_RADIUS);
|
||||
|
||||
if (isBodyPosOutsideCapsule) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
bool MyAvatar::shouldFollowHMD() const {
|
||||
if (!_isFollowingHMD) {
|
||||
// define a vertical capsule
|
||||
const float FOLLOW_HMD_CAPSULE_RADIUS = 0.2f; // meters
|
||||
const float FOLLOW_HMD_CAPSULE_LENGTH = 0.05f; // length of the cylinder part of the capsule in meters.
|
||||
|
||||
// detect if the derived body position is outside of a capsule around the _bodySensorMatrix
|
||||
auto newBodySensorMatrix = deriveBodyFromHMDSensor();
|
||||
glm::vec3 localPoint = extractTranslation(newBodySensorMatrix) - extractTranslation(_bodySensorMatrix);
|
||||
return pointIsOutsideCapsule(localPoint, FOLLOW_HMD_CAPSULE_LENGTH, FOLLOW_HMD_CAPSULE_RADIUS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MyAvatar::processStraighteningLean(float deltaTime) {
|
||||
if (_straighteningLean) {
|
||||
void MyAvatar::followHMD(float deltaTime) {
|
||||
if (_isFollowingHMD) {
|
||||
|
||||
const float STRAIGHTENING_LEAN_DURATION = 0.5f; // seconds
|
||||
const float FOLLOW_HMD_DURATION = 0.5f; // seconds
|
||||
|
||||
auto newBodySensorMatrix = deriveBodyFromHMDSensor();
|
||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||
glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||
glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
||||
|
||||
_straighteningLeanAlpha += (1.0f / STRAIGHTENING_LEAN_DURATION) * deltaTime;
|
||||
_followHMDAlpha += (1.0f / FOLLOW_HMD_DURATION) * deltaTime;
|
||||
|
||||
if (_straighteningLeanAlpha >= 1.0f) {
|
||||
_straighteningLean = false;
|
||||
if (_followHMDAlpha >= 1.0f) {
|
||||
_isFollowingHMD = false;
|
||||
nextAttitude(worldBodyPos, worldBodyRot);
|
||||
_bodySensorMatrix = newBodySensorMatrix;
|
||||
} else {
|
||||
// interp position toward the desired pos
|
||||
glm::vec3 pos = lerp(getPosition(), worldBodyPos, _straighteningLeanAlpha);
|
||||
glm::quat rot = glm::normalize(safeMix(getOrientation(), worldBodyRot, _straighteningLeanAlpha));
|
||||
glm::vec3 pos = lerp(getPosition(), worldBodyPos, _followHMDAlpha);
|
||||
glm::quat rot = glm::normalize(safeMix(getOrientation(), worldBodyRot, _followHMDAlpha));
|
||||
nextAttitude(pos, rot);
|
||||
|
||||
// interp sensor matrix toward desired
|
||||
|
@ -419,8 +421,8 @@ void MyAvatar::processStraighteningLean(float deltaTime) {
|
|||
glm::quat nextBodyRot = glm::normalize(glm::quat_cast(newBodySensorMatrix));
|
||||
glm::vec3 prevBodyPos = extractTranslation(_bodySensorMatrix);
|
||||
glm::quat prevBodyRot = glm::normalize(glm::quat_cast(_bodySensorMatrix));
|
||||
pos = lerp(prevBodyPos, nextBodyPos, _straighteningLeanAlpha);
|
||||
rot = glm::normalize(safeMix(prevBodyRot, nextBodyRot, _straighteningLeanAlpha));
|
||||
pos = lerp(prevBodyPos, nextBodyPos, _followHMDAlpha);
|
||||
rot = glm::normalize(safeMix(prevBodyRot, nextBodyRot, _followHMDAlpha));
|
||||
_bodySensorMatrix = createMatFromQuatAndPos(rot, pos);
|
||||
}
|
||||
}
|
||||
|
@ -1274,6 +1276,23 @@ void MyAvatar::rebuildSkeletonBody() {
|
|||
_characterController.setLocalBoundingBox(corner, scale);
|
||||
}
|
||||
|
||||
void MyAvatar::prepareForPhysicsSimulation() {
|
||||
relayDriveKeysToCharacterController();
|
||||
_characterController.setTargetVelocity(getTargetVelocity());
|
||||
_characterController.setAvatarPositionAndOrientation(getPosition(), getOrientation());
|
||||
_characterController.setHMDVelocity(getHMDCorrectionVelocity());
|
||||
}
|
||||
|
||||
void MyAvatar::harvestResultsFromPhysicsSimulation() {
|
||||
glm::vec3 position = getPosition();
|
||||
glm::quat orientation = getOrientation();
|
||||
_characterController.getAvatarPositionAndOrientation(position, orientation);
|
||||
nextAttitude(position, orientation);
|
||||
setVelocity(_characterController.getLinearVelocity());
|
||||
// TODO: harvest HMD shift here
|
||||
//glm::vec3 hmdShift = _characterController.getHMDShift();
|
||||
}
|
||||
|
||||
QString MyAvatar::getScriptedMotorFrame() const {
|
||||
QString frame = "avatar";
|
||||
if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) {
|
||||
|
|
|
@ -12,12 +12,15 @@
|
|||
#ifndef hifi_MyAvatar_h
|
||||
#define hifi_MyAvatar_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include <DynamicCharacterController.h>
|
||||
#include <Rig.h>
|
||||
|
||||
#include "Avatar.h"
|
||||
#include "AtRestDetector.h"
|
||||
#include "MyCharacterController.h"
|
||||
|
||||
|
||||
class ModelItemID;
|
||||
|
||||
|
@ -72,6 +75,8 @@ public:
|
|||
// as it moves through the world.
|
||||
void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix);
|
||||
|
||||
glm::vec3 getHMDCorrectionVelocity() const;
|
||||
|
||||
// best called at end of main loop, just before rendering.
|
||||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
|
@ -154,10 +159,12 @@ public:
|
|||
|
||||
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
|
||||
|
||||
DynamicCharacterController* getCharacterController() { return &_characterController; }
|
||||
MyCharacterController* getCharacterController() { return &_characterController; }
|
||||
|
||||
void prepareForPhysicsSimulation();
|
||||
void harvestResultsFromPhysicsSimulation();
|
||||
|
||||
const QString& getCollisionSoundURL() {return _collisionSoundURL; }
|
||||
const QString& getCollisionSoundURL() { return _collisionSoundURL; }
|
||||
void setCollisionSoundURL(const QString& url);
|
||||
|
||||
void clearScriptableSettings();
|
||||
|
@ -262,9 +269,9 @@ private:
|
|||
const RecorderPointer getRecorder() const { return _recorder; }
|
||||
const PlayerPointer getPlayer() const { return _player; }
|
||||
|
||||
void beginStraighteningLean();
|
||||
bool shouldBeginStraighteningLean() const;
|
||||
void processStraighteningLean(float deltaTime);
|
||||
void beginFollowingHMD();
|
||||
bool shouldFollowHMD() const;
|
||||
void followHMD(float deltaTime);
|
||||
|
||||
bool cameraInsideHead() const;
|
||||
|
||||
|
@ -295,7 +302,7 @@ private:
|
|||
quint32 _motionBehaviors;
|
||||
QString _collisionSoundURL;
|
||||
|
||||
DynamicCharacterController _characterController;
|
||||
MyCharacterController _characterController;
|
||||
|
||||
AvatarWeakPointer _lookAtTargetAvatar;
|
||||
glm::vec3 _targetAvatarPosition;
|
||||
|
@ -348,21 +355,21 @@ private:
|
|||
RigPointer _rig;
|
||||
bool _prevShouldDrawHead;
|
||||
|
||||
bool _enableDebugDrawBindPose = false;
|
||||
bool _enableDebugDrawAnimPose = false;
|
||||
AnimSkeleton::ConstPointer _debugDrawSkeleton = nullptr;
|
||||
bool _enableDebugDrawBindPose { false };
|
||||
bool _enableDebugDrawAnimPose { false };
|
||||
AnimSkeleton::ConstPointer _debugDrawSkeleton { nullptr };
|
||||
|
||||
AudioListenerMode _audioListenerMode;
|
||||
glm::vec3 _customListenPosition;
|
||||
glm::quat _customListenOrientation;
|
||||
|
||||
bool _straighteningLean = false;
|
||||
float _straighteningLeanAlpha = 0.0f;
|
||||
bool _isFollowingHMD { false };
|
||||
float _followHMDAlpha { 0.0f };
|
||||
|
||||
quint64 _lastUpdateFromHMDTime = usecTimestampNow();
|
||||
quint64 _lastUpdateFromHMDTime { usecTimestampNow() };
|
||||
AtRestDetector _hmdAtRestDetector;
|
||||
glm::vec3 _lastPosition;
|
||||
bool _lastIsMoving = false;
|
||||
bool _lastIsMoving { false };
|
||||
};
|
||||
|
||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||
|
|
|
@ -1,13 +1,26 @@
|
|||
//
|
||||
// MyCharacterController.h
|
||||
// interface/src/avatar
|
||||
//
|
||||
// Created by AndrewMeadows 2015.10.21
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "MyCharacterController.h"
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btMultiSphereShape.h>
|
||||
#include <BulletDynamics/Dynamics/btRigidBody.h>
|
||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||
#include <LinearMath/btDefaultMotionState.h>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <PhysicsLogging.h>
|
||||
#include <PhysicsCollisionGroups.h>
|
||||
|
||||
#include "BulletUtil.h"
|
||||
#include "DynamicCharacterController.h"
|
||||
#include "PhysicsLogging.h"
|
||||
#include "MyAvatar.h"
|
||||
|
||||
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
|
||||
const float DEFAULT_GRAVITY = -5.0f;
|
||||
|
@ -15,11 +28,6 @@ const float JUMP_SPEED = 3.5f;
|
|||
|
||||
const float MAX_FALL_HEIGHT = 20.0f;
|
||||
|
||||
const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0;
|
||||
const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1;
|
||||
const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2;
|
||||
const uint32_t PENDING_FLAG_JUMP = 1U << 3;
|
||||
|
||||
// TODO: improve walking up steps
|
||||
// TODO: make avatars able to walk up and down steps/slopes
|
||||
// TODO: make avatars stand on steep slope
|
||||
|
@ -41,19 +49,18 @@ protected:
|
|||
btRigidBody* _me;
|
||||
};
|
||||
|
||||
DynamicCharacterController::DynamicCharacterController(AvatarData* avatarData) {
|
||||
MyCharacterController::MyCharacterController(MyAvatar* avatar) {
|
||||
_halfHeight = 1.0f;
|
||||
_shape = nullptr;
|
||||
_rigidBody = nullptr;
|
||||
|
||||
assert(avatarData);
|
||||
_avatarData = avatarData;
|
||||
assert(avatar);
|
||||
_avatar = avatar;
|
||||
|
||||
_enabled = false;
|
||||
|
||||
_floorDistance = MAX_FALL_HEIGHT;
|
||||
|
||||
_walkVelocity.setValue(0.0f,0.0f,0.0f);
|
||||
_walkVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||
_hmdVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||
_jumpSpeed = JUMP_SPEED;
|
||||
_isOnGround = false;
|
||||
_isJumping = false;
|
||||
|
@ -61,21 +68,16 @@ DynamicCharacterController::DynamicCharacterController(AvatarData* avatarData) {
|
|||
_isHovering = true;
|
||||
_isPushingUp = false;
|
||||
_jumpToHoverStart = 0;
|
||||
_lastStepDuration = 0.0f;
|
||||
|
||||
_pendingFlags = PENDING_FLAG_UPDATE_SHAPE;
|
||||
updateShapeIfNecessary();
|
||||
}
|
||||
|
||||
DynamicCharacterController::~DynamicCharacterController() {
|
||||
MyCharacterController::~MyCharacterController() {
|
||||
}
|
||||
|
||||
// virtual
|
||||
void DynamicCharacterController::setWalkDirection(const btVector3& walkDirection) {
|
||||
// do nothing -- walkVelocity is upated in preSimulation()
|
||||
//_walkVelocity = walkDirection;
|
||||
}
|
||||
|
||||
void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) {
|
||||
void MyCharacterController::preStep(btCollisionWorld* collisionWorld) {
|
||||
// trace a ray straight down to see if we're standing on the ground
|
||||
const btTransform& xform = _rigidBody->getWorldTransform();
|
||||
|
||||
|
@ -96,7 +98,7 @@ void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) {
|
|||
}
|
||||
}
|
||||
|
||||
void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
||||
void MyCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
||||
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
|
||||
btScalar actualSpeed = actualVelocity.length();
|
||||
|
||||
|
@ -158,9 +160,20 @@ void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScala
|
|||
_rigidBody->setLinearVelocity(actualVelocity + tau * velocityCorrection);
|
||||
}
|
||||
}
|
||||
|
||||
// Rather than add _hmdVelocity to the velocity of the RigidBody, we explicitly teleport
|
||||
// the RigidBody forward according to the formula: distance = rate * time
|
||||
if (_hmdVelocity.length2() > 0.0f) {
|
||||
btTransform bodyTransform = _rigidBody->getWorldTransform();
|
||||
bodyTransform.setOrigin(bodyTransform.getOrigin() + dt * _hmdVelocity);
|
||||
_rigidBody->setWorldTransform(bodyTransform);
|
||||
}
|
||||
// MyAvatar will ask us how far we stepped for HMD motion, which will depend on how
|
||||
// much time has accumulated in _lastStepDuration.
|
||||
_lastStepDuration += dt;
|
||||
}
|
||||
|
||||
void DynamicCharacterController::jump() {
|
||||
void MyCharacterController::jump() {
|
||||
// check for case where user is holding down "jump" key...
|
||||
// we'll eventually tansition to "hover"
|
||||
if (!_isJumping) {
|
||||
|
@ -178,12 +191,12 @@ void DynamicCharacterController::jump() {
|
|||
}
|
||||
}
|
||||
|
||||
bool DynamicCharacterController::onGround() const {
|
||||
bool MyCharacterController::onGround() const {
|
||||
const btScalar FLOOR_PROXIMITY_THRESHOLD = 0.3f * _radius;
|
||||
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD;
|
||||
}
|
||||
|
||||
void DynamicCharacterController::setHovering(bool hover) {
|
||||
void MyCharacterController::setHovering(bool hover) {
|
||||
if (hover != _isHovering) {
|
||||
_isHovering = hover;
|
||||
_isJumping = false;
|
||||
|
@ -198,7 +211,7 @@ void DynamicCharacterController::setHovering(bool hover) {
|
|||
}
|
||||
}
|
||||
|
||||
void DynamicCharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
|
||||
void MyCharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
|
||||
_boxScale = scale;
|
||||
|
||||
float x = _boxScale.x;
|
||||
|
@ -231,15 +244,7 @@ void DynamicCharacterController::setLocalBoundingBox(const glm::vec3& corner, co
|
|||
_shapeLocalOffset = corner + 0.5f * _boxScale;
|
||||
}
|
||||
|
||||
bool DynamicCharacterController::needsRemoval() const {
|
||||
return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION);
|
||||
}
|
||||
|
||||
bool DynamicCharacterController::needsAddition() const {
|
||||
return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION);
|
||||
}
|
||||
|
||||
void DynamicCharacterController::setEnabled(bool enabled) {
|
||||
void MyCharacterController::setEnabled(bool enabled) {
|
||||
if (enabled != _enabled) {
|
||||
if (enabled) {
|
||||
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
|
||||
|
@ -257,46 +262,9 @@ void DynamicCharacterController::setEnabled(bool enabled) {
|
|||
}
|
||||
}
|
||||
|
||||
void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||
if (_dynamicsWorld != world) {
|
||||
if (_dynamicsWorld) {
|
||||
if (_rigidBody) {
|
||||
_dynamicsWorld->removeRigidBody(_rigidBody);
|
||||
_dynamicsWorld->removeAction(this);
|
||||
}
|
||||
_dynamicsWorld = nullptr;
|
||||
}
|
||||
if (world && _rigidBody) {
|
||||
_dynamicsWorld = world;
|
||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||
_dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR);
|
||||
_dynamicsWorld->addAction(this);
|
||||
//reset(_dynamicsWorld);
|
||||
}
|
||||
}
|
||||
if (_dynamicsWorld) {
|
||||
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
||||
// shouldn't fall in here, but if we do make sure both ADD and REMOVE bits are still set
|
||||
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||
} else {
|
||||
_pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION;
|
||||
}
|
||||
} else {
|
||||
_pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicCharacterController::updateShapeIfNecessary() {
|
||||
void MyCharacterController::updateShapeIfNecessary() {
|
||||
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
||||
// make sure there is NO pending removal from simulation at this point
|
||||
// (don't want to delete _rigidBody out from under the simulation)
|
||||
assert(!(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION));
|
||||
_pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE;
|
||||
// delete shape and RigidBody
|
||||
delete _rigidBody;
|
||||
_rigidBody = nullptr;
|
||||
delete _shape;
|
||||
_shape = nullptr;
|
||||
|
||||
// compute new dimensions from avatar's bounding box
|
||||
float x = _boxScale.x;
|
||||
|
@ -310,19 +278,27 @@ void DynamicCharacterController::updateShapeIfNecessary() {
|
|||
// NOTE: _shapeLocalOffset is already computed
|
||||
|
||||
if (_radius > 0.0f) {
|
||||
// create new shape
|
||||
_shape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
||||
|
||||
// HACK: use some simple mass property defaults for now
|
||||
float mass = 100.0f;
|
||||
btVector3 inertia(30.0f, 8.0f, 30.0f);
|
||||
|
||||
// create new body
|
||||
_rigidBody = new btRigidBody(mass, nullptr, _shape, inertia);
|
||||
// create RigidBody if it doesn't exist
|
||||
if (!_rigidBody) {
|
||||
btCollisionShape* shape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
||||
_rigidBody = new btRigidBody(mass, nullptr, shape, inertia);
|
||||
} else {
|
||||
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
||||
if (shape) {
|
||||
delete shape;
|
||||
}
|
||||
shape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
||||
_rigidBody->setCollisionShape(shape);
|
||||
}
|
||||
|
||||
_rigidBody->setSleepingThresholds(0.0f, 0.0f);
|
||||
_rigidBody->setAngularFactor(0.0f);
|
||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
||||
glmToBullet(_avatarData->getPosition())));
|
||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()),
|
||||
glmToBullet(_avatar->getPosition())));
|
||||
if (_isHovering) {
|
||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
} else {
|
||||
|
@ -335,7 +311,7 @@ void DynamicCharacterController::updateShapeIfNecessary() {
|
|||
}
|
||||
}
|
||||
|
||||
void DynamicCharacterController::updateUpAxis(const glm::quat& rotation) {
|
||||
void MyCharacterController::updateUpAxis(const glm::quat& rotation) {
|
||||
btVector3 oldUp = _currentUp;
|
||||
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
|
||||
if (!_isHovering) {
|
||||
|
@ -346,24 +322,50 @@ void DynamicCharacterController::updateUpAxis(const glm::quat& rotation) {
|
|||
}
|
||||
}
|
||||
|
||||
void DynamicCharacterController::preSimulation(btScalar timeStep) {
|
||||
void MyCharacterController::setAvatarPositionAndOrientation(
|
||||
const glm::vec3& position,
|
||||
const glm::quat& orientation) {
|
||||
// TODO: update gravity if up has changed
|
||||
updateUpAxis(orientation);
|
||||
|
||||
btQuaternion bodyOrientation = glmToBullet(orientation);
|
||||
btVector3 bodyPosition = glmToBullet(position + orientation * _shapeLocalOffset);
|
||||
_avatarBodyTransform = btTransform(bodyOrientation, bodyPosition);
|
||||
}
|
||||
|
||||
void MyCharacterController::getAvatarPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const {
|
||||
if (_enabled && _rigidBody) {
|
||||
const btTransform& avatarTransform = _rigidBody->getWorldTransform();
|
||||
rotation = bulletToGLM(avatarTransform.getRotation());
|
||||
position = bulletToGLM(avatarTransform.getOrigin()) - rotation * _shapeLocalOffset;
|
||||
}
|
||||
}
|
||||
|
||||
void MyCharacterController::setTargetVelocity(const glm::vec3& velocity) {
|
||||
//_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
|
||||
_walkVelocity = glmToBullet(velocity);
|
||||
}
|
||||
|
||||
void MyCharacterController::setHMDVelocity(const glm::vec3& velocity) {
|
||||
_hmdVelocity = glmToBullet(velocity);
|
||||
}
|
||||
|
||||
glm::vec3 MyCharacterController::getLinearVelocity() const {
|
||||
glm::vec3 velocity(0.0f);
|
||||
if (_rigidBody) {
|
||||
velocity = bulletToGLM(_rigidBody->getLinearVelocity());
|
||||
}
|
||||
return velocity;
|
||||
}
|
||||
|
||||
void MyCharacterController::preSimulation() {
|
||||
if (_enabled && _dynamicsWorld) {
|
||||
glm::quat rotation = _avatarData->getOrientation();
|
||||
|
||||
// TODO: update gravity if up has changed
|
||||
updateUpAxis(rotation);
|
||||
|
||||
glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset;
|
||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position)));
|
||||
|
||||
// the rotation is dictated by AvatarData
|
||||
btTransform xform = _rigidBody->getWorldTransform();
|
||||
xform.setRotation(glmToBullet(rotation));
|
||||
_rigidBody->setWorldTransform(xform);
|
||||
// slam body to where it is supposed to be
|
||||
_rigidBody->setWorldTransform(_avatarBodyTransform);
|
||||
|
||||
// scan for distant floor
|
||||
// rayStart is at center of bottom sphere
|
||||
btVector3 rayStart = xform.getOrigin() - _halfHeight * _currentUp;
|
||||
btVector3 rayStart = _avatarBodyTransform.getOrigin() - _halfHeight * _currentUp;
|
||||
|
||||
// rayEnd is straight down MAX_FALL_HEIGHT
|
||||
btScalar rayLength = _radius + MAX_FALL_HEIGHT;
|
||||
|
@ -388,8 +390,6 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) {
|
|||
setHovering(true);
|
||||
}
|
||||
|
||||
_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
|
||||
|
||||
if (_pendingFlags & PENDING_FLAG_JUMP) {
|
||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||
if (onGround()) {
|
||||
|
@ -400,15 +400,9 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) {
|
|||
}
|
||||
}
|
||||
}
|
||||
_lastStepDuration = 0.0f;
|
||||
}
|
||||
|
||||
void DynamicCharacterController::postSimulation() {
|
||||
if (_enabled && _rigidBody) {
|
||||
const btTransform& avatarTransform = _rigidBody->getWorldTransform();
|
||||
glm::quat rotation = bulletToGLM(avatarTransform.getRotation());
|
||||
glm::vec3 position = bulletToGLM(avatarTransform.getOrigin());
|
||||
|
||||
_avatarData->nextAttitude(position - rotation * _shapeLocalOffset, rotation);
|
||||
_avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity()));
|
||||
}
|
||||
void MyCharacterController::postSimulation() {
|
||||
// postSimulation() exists for symmetry and just in case we need to do something here later
|
||||
}
|
106
interface/src/avatar/MyCharacterController.h
Normal file
106
interface/src/avatar/MyCharacterController.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// MyCharacterController.h
|
||||
// interface/src/avatar
|
||||
//
|
||||
// Created by AndrewMeadows 2015.10.21
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#ifndef hifi_MyCharacterController_h
|
||||
#define hifi_MyCharacterController_h
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <BulletUtil.h>
|
||||
#include <CharacterController.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
class btCollisionShape;
|
||||
class MyAvatar;
|
||||
|
||||
class MyCharacterController : public CharacterController {
|
||||
public:
|
||||
MyCharacterController(MyAvatar* avatar);
|
||||
~MyCharacterController ();
|
||||
|
||||
// TODO: implement these when needed
|
||||
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) override { assert(false); }
|
||||
virtual void reset(btCollisionWorld* collisionWorld) override { }
|
||||
virtual void warp(const btVector3& origin) override { }
|
||||
virtual void debugDraw(btIDebugDraw* debugDrawer) override { }
|
||||
virtual void setUpInterpolate(bool value) override { }
|
||||
|
||||
// overrides from btCharacterControllerInterface
|
||||
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) override {
|
||||
preStep(collisionWorld);
|
||||
playerStep(collisionWorld, deltaTime);
|
||||
}
|
||||
virtual void preStep(btCollisionWorld* collisionWorld) override;
|
||||
virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt) override;
|
||||
virtual bool canJump() const override { assert(false); return false; } // never call this
|
||||
virtual void jump() override; // call this every frame the jump button is pressed
|
||||
virtual bool onGround() const override;
|
||||
|
||||
// overrides from CharacterController
|
||||
virtual void preSimulation() override;
|
||||
virtual void postSimulation() override;
|
||||
|
||||
bool isHovering() const { return _isHovering; }
|
||||
void setHovering(bool enabled);
|
||||
|
||||
void setEnabled(bool enabled);
|
||||
bool isEnabled() const { return _enabled && _dynamicsWorld; }
|
||||
|
||||
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
|
||||
|
||||
virtual void updateShapeIfNecessary() override;
|
||||
|
||||
void setAvatarPositionAndOrientation( const glm::vec3& position, const glm::quat& orientation);
|
||||
void getAvatarPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const;
|
||||
|
||||
void setTargetVelocity(const glm::vec3& velocity);
|
||||
void setHMDVelocity(const glm::vec3& velocity);
|
||||
glm::vec3 getHMDShift() const { return _lastStepDuration * bulletToGLM(_hmdVelocity); }
|
||||
|
||||
glm::vec3 getLinearVelocity() const;
|
||||
|
||||
protected:
|
||||
void updateUpAxis(const glm::quat& rotation);
|
||||
|
||||
protected:
|
||||
btVector3 _currentUp;
|
||||
btVector3 _walkVelocity;
|
||||
btVector3 _hmdVelocity;
|
||||
btTransform _avatarBodyTransform;
|
||||
|
||||
glm::vec3 _shapeLocalOffset;
|
||||
glm::vec3 _boxScale; // used to compute capsule shape
|
||||
|
||||
quint64 _jumpToHoverStart;
|
||||
|
||||
MyAvatar* _avatar { nullptr };
|
||||
|
||||
btScalar _halfHeight;
|
||||
btScalar _radius;
|
||||
|
||||
btScalar _floorDistance;
|
||||
|
||||
btScalar _gravity;
|
||||
|
||||
btScalar _jumpSpeed;
|
||||
btScalar _lastStepDuration;
|
||||
|
||||
bool _enabled;
|
||||
bool _isOnGround;
|
||||
bool _isJumping;
|
||||
bool _isFalling;
|
||||
bool _isHovering;
|
||||
bool _isPushingUp;
|
||||
};
|
||||
|
||||
#endif // hifi_MyCharacterController_h
|
52
libraries/physics/src/CharacterController.cpp
Normal file
52
libraries/physics/src/CharacterController.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// CharacterControllerInterface.cpp
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2015.10.21
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "CharacterController.h"
|
||||
|
||||
#include "PhysicsCollisionGroups.h"
|
||||
|
||||
bool CharacterController::needsRemoval() const {
|
||||
return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION);
|
||||
}
|
||||
|
||||
bool CharacterController::needsAddition() const {
|
||||
return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION);
|
||||
}
|
||||
|
||||
void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||
if (_dynamicsWorld != world) {
|
||||
if (_dynamicsWorld) {
|
||||
if (_rigidBody) {
|
||||
_dynamicsWorld->removeRigidBody(_rigidBody);
|
||||
_dynamicsWorld->removeAction(this);
|
||||
}
|
||||
_dynamicsWorld = nullptr;
|
||||
}
|
||||
if (world && _rigidBody) {
|
||||
_dynamicsWorld = world;
|
||||
_pendingFlags &= ~PENDING_FLAG_JUMP;
|
||||
_dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR);
|
||||
_dynamicsWorld->addAction(this);
|
||||
//reset(_dynamicsWorld);
|
||||
}
|
||||
}
|
||||
if (_dynamicsWorld) {
|
||||
if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) {
|
||||
// shouldn't fall in here, but if we do make sure both ADD and REMOVE bits are still set
|
||||
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||
} else {
|
||||
_pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION;
|
||||
}
|
||||
} else {
|
||||
_pendingFlags &= ~PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||
}
|
||||
}
|
||||
|
59
libraries/physics/src/CharacterController.h
Normal file
59
libraries/physics/src/CharacterController.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// CharacterControllerInterface.h
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2015.10.21
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_CharacterControllerInterface_h
|
||||
#define hifi_CharacterControllerInterface_h
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <BulletDynamics/Character/btCharacterControllerInterface.h>
|
||||
|
||||
const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0;
|
||||
const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1;
|
||||
const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2;
|
||||
const uint32_t PENDING_FLAG_JUMP = 1U << 3;
|
||||
|
||||
|
||||
class btRigidBody;
|
||||
class btCollisionWorld;
|
||||
class btDynamicsWorld;
|
||||
|
||||
class CharacterController : public btCharacterControllerInterface {
|
||||
public:
|
||||
bool needsRemoval() const;
|
||||
bool needsAddition() const;
|
||||
void setDynamicsWorld(btDynamicsWorld* world);
|
||||
btCollisionObject* getCollisionObject() { return _rigidBody; }
|
||||
|
||||
virtual void updateShapeIfNecessary() = 0;
|
||||
virtual void preSimulation() = 0;
|
||||
virtual void postSimulation() = 0;
|
||||
|
||||
virtual void setWalkDirection(const btVector3 &walkDirection) { assert(false); }
|
||||
|
||||
/* these from btCharacterControllerInterface remain to be overridden
|
||||
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void warp(const btVector3 &origin) = 0;
|
||||
virtual void preStep(btCollisionWorld *collisionWorld) = 0;
|
||||
virtual void playerStep(btCollisionWorld *collisionWorld, btScalar dt) = 0;
|
||||
virtual bool canJump() const = 0;
|
||||
virtual void jump() = 0;
|
||||
virtual bool onGround() const = 0;
|
||||
*/
|
||||
protected:
|
||||
btDynamicsWorld* _dynamicsWorld { nullptr };
|
||||
btRigidBody* _rigidBody { nullptr };
|
||||
uint32_t _pendingFlags { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_CharacterControllerInterface_h
|
|
@ -1,95 +0,0 @@
|
|||
#ifndef hifi_DynamicCharacterController_h
|
||||
#define hifi_DynamicCharacterController_h
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <BulletDynamics/Character/btCharacterControllerInterface.h>
|
||||
|
||||
#include <AvatarData.h>
|
||||
|
||||
class btCollisionShape;
|
||||
class btRigidBody;
|
||||
class btCollisionWorld;
|
||||
|
||||
const int NUM_CHARACTER_CONTROLLER_RAYS = 2;
|
||||
|
||||
class DynamicCharacterController : public btCharacterControllerInterface
|
||||
{
|
||||
protected:
|
||||
btScalar _halfHeight;
|
||||
btScalar _radius;
|
||||
btCollisionShape* _shape;
|
||||
btRigidBody* _rigidBody;
|
||||
|
||||
btVector3 _currentUp;
|
||||
|
||||
btScalar _floorDistance;
|
||||
|
||||
btVector3 _walkVelocity;
|
||||
btScalar _gravity;
|
||||
|
||||
glm::vec3 _shapeLocalOffset;
|
||||
glm::vec3 _boxScale; // used to compute capsule shape
|
||||
AvatarData* _avatarData = nullptr;
|
||||
|
||||
bool _enabled;
|
||||
bool _isOnGround;
|
||||
bool _isJumping;
|
||||
bool _isFalling;
|
||||
bool _isHovering;
|
||||
bool _isPushingUp;
|
||||
quint64 _jumpToHoverStart;
|
||||
uint32_t _pendingFlags;
|
||||
|
||||
btDynamicsWorld* _dynamicsWorld = nullptr;
|
||||
|
||||
btScalar _jumpSpeed;
|
||||
|
||||
public:
|
||||
DynamicCharacterController(AvatarData* avatarData);
|
||||
~DynamicCharacterController ();
|
||||
|
||||
virtual void setWalkDirection(const btVector3& walkDirection);
|
||||
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) { assert(false); }
|
||||
|
||||
// TODO: implement these when needed
|
||||
virtual void reset(btCollisionWorld* collisionWorld) { }
|
||||
virtual void warp(const btVector3& origin) { }
|
||||
virtual void debugDraw(btIDebugDraw* debugDrawer) { }
|
||||
virtual void setUpInterpolate(bool value) { }
|
||||
|
||||
btCollisionObject* getCollisionObject() { return _rigidBody; }
|
||||
|
||||
///btActionInterface interface
|
||||
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) {
|
||||
preStep(collisionWorld);
|
||||
playerStep(collisionWorld, deltaTime);
|
||||
}
|
||||
|
||||
virtual void preStep(btCollisionWorld* collisionWorld);
|
||||
virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt);
|
||||
|
||||
virtual bool canJump() const { assert(false); return false; } // never call this
|
||||
virtual void jump(); // call this every frame the jump button is pressed
|
||||
virtual bool onGround() const;
|
||||
bool isHovering() const { return _isHovering; }
|
||||
void setHovering(bool enabled);
|
||||
|
||||
bool needsRemoval() const;
|
||||
bool needsAddition() const;
|
||||
void setEnabled(bool enabled);
|
||||
bool isEnabled() const { return _enabled && _dynamicsWorld; }
|
||||
|
||||
void setDynamicsWorld(btDynamicsWorld* world);
|
||||
|
||||
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
|
||||
bool needsShapeUpdate() const;
|
||||
void updateShapeIfNecessary();
|
||||
|
||||
void preSimulation(btScalar timeStep);
|
||||
void postSimulation();
|
||||
|
||||
protected:
|
||||
void updateUpAxis(const glm::quat& rotation);
|
||||
};
|
||||
|
||||
#endif // hifi_DynamicCharacterController_h
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <PhysicsCollisionGroups.h>
|
||||
|
||||
#include "CharacterController.h"
|
||||
#include "ObjectMotionState.h"
|
||||
#include "PhysicsEngine.h"
|
||||
#include "PhysicsHelpers.h"
|
||||
|
@ -23,7 +24,7 @@ uint32_t PhysicsEngine::getNumSubsteps() {
|
|||
|
||||
PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
|
||||
_originOffset(offset),
|
||||
_characterController(nullptr) {
|
||||
_myAvatarController(nullptr) {
|
||||
// build table of masks with their group as the key
|
||||
_collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEFAULT), COLLISION_MASK_DEFAULT);
|
||||
_collisionMasks.insert(btHashInt((int)COLLISION_GROUP_STATIC), COLLISION_MASK_STATIC);
|
||||
|
@ -38,8 +39,8 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
|
|||
}
|
||||
|
||||
PhysicsEngine::~PhysicsEngine() {
|
||||
if (_characterController) {
|
||||
_characterController->setDynamicsWorld(nullptr);
|
||||
if (_myAvatarController) {
|
||||
_myAvatarController->setDynamicsWorld(nullptr);
|
||||
}
|
||||
delete _collisionConfig;
|
||||
delete _collisionDispatcher;
|
||||
|
@ -239,16 +240,23 @@ void PhysicsEngine::stepSimulation() {
|
|||
_clock.reset();
|
||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||
|
||||
// TODO: move character->preSimulation() into relayIncomingChanges
|
||||
if (_characterController) {
|
||||
if (_characterController->needsRemoval()) {
|
||||
_characterController->setDynamicsWorld(nullptr);
|
||||
if (_myAvatarController) {
|
||||
// ADEBUG TODO: move this stuff outside and in front of stepSimulation, because
|
||||
// the updateShapeIfNecessary() call needs info from MyAvatar and should
|
||||
// be done on the main thread during the pre-simulation stuff
|
||||
if (_myAvatarController->needsRemoval()) {
|
||||
_myAvatarController->setDynamicsWorld(nullptr);
|
||||
|
||||
// We must remove any existing contacts for the avatar so that any new contacts will have
|
||||
// valid data. MyAvatar's RigidBody is the ONLY one in the simulation that does not yet
|
||||
// have a MotionState so we pass nullptr to removeContacts().
|
||||
removeContacts(nullptr);
|
||||
}
|
||||
_characterController->updateShapeIfNecessary();
|
||||
if (_characterController->needsAddition()) {
|
||||
_characterController->setDynamicsWorld(_dynamicsWorld);
|
||||
_myAvatarController->updateShapeIfNecessary();
|
||||
if (_myAvatarController->needsAddition()) {
|
||||
_myAvatarController->setDynamicsWorld(_dynamicsWorld);
|
||||
}
|
||||
_characterController->preSimulation(timeStep);
|
||||
_myAvatarController->preSimulation();
|
||||
}
|
||||
|
||||
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, PHYSICS_ENGINE_MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
|
@ -257,8 +265,8 @@ void PhysicsEngine::stepSimulation() {
|
|||
_numSubsteps += (uint32_t)numSubsteps;
|
||||
ObjectMotionState::setWorldSimulationStep(_numSubsteps);
|
||||
|
||||
if (_characterController) {
|
||||
_characterController->postSimulation();
|
||||
if (_myAvatarController) {
|
||||
_myAvatarController->postSimulation();
|
||||
}
|
||||
updateContactMap();
|
||||
_hasOutgoingChanges = true;
|
||||
|
@ -268,7 +276,7 @@ void PhysicsEngine::stepSimulation() {
|
|||
void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) {
|
||||
BT_PROFILE("ownershipInfection");
|
||||
|
||||
const btCollisionObject* characterObject = _characterController ? _characterController->getCollisionObject() : nullptr;
|
||||
const btCollisionObject* characterObject = _myAvatarController ? _myAvatarController->getCollisionObject() : nullptr;
|
||||
|
||||
ObjectMotionState* motionStateA = static_cast<ObjectMotionState*>(objectA->getUserPointer());
|
||||
ObjectMotionState* motionStateB = static_cast<ObjectMotionState*>(objectB->getUserPointer());
|
||||
|
@ -431,15 +439,15 @@ void PhysicsEngine::bump(ObjectMotionState* motionState) {
|
|||
}
|
||||
}
|
||||
|
||||
void PhysicsEngine::setCharacterController(DynamicCharacterController* character) {
|
||||
if (_characterController != character) {
|
||||
if (_characterController) {
|
||||
void PhysicsEngine::setCharacterController(CharacterController* character) {
|
||||
if (_myAvatarController != character) {
|
||||
if (_myAvatarController) {
|
||||
// remove the character from the DynamicsWorld immediately
|
||||
_characterController->setDynamicsWorld(nullptr);
|
||||
_characterController = nullptr;
|
||||
_myAvatarController->setDynamicsWorld(nullptr);
|
||||
_myAvatarController = nullptr;
|
||||
}
|
||||
// the character will be added to the DynamicsWorld later
|
||||
_characterController = character;
|
||||
_myAvatarController = character;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,13 +21,14 @@
|
|||
|
||||
#include "BulletUtil.h"
|
||||
#include "ContactInfo.h"
|
||||
#include "DynamicCharacterController.h"
|
||||
#include "ObjectMotionState.h"
|
||||
#include "ThreadSafeDynamicsWorld.h"
|
||||
#include "ObjectAction.h"
|
||||
|
||||
const float HALF_SIMULATION_EXTENT = 512.0f; // meters
|
||||
|
||||
class CharacterController;
|
||||
|
||||
// simple class for keeping track of contacts
|
||||
class ContactKey {
|
||||
public:
|
||||
|
@ -87,7 +88,7 @@ public:
|
|||
|
||||
void removeRigidBody(btRigidBody* body);
|
||||
|
||||
void setCharacterController(DynamicCharacterController* character);
|
||||
void setCharacterController(CharacterController* character);
|
||||
|
||||
void dumpNextStats() { _dumpNextStats = true; }
|
||||
|
||||
|
@ -117,7 +118,7 @@ private:
|
|||
uint32_t _lastNumSubstepsAtUpdateInternal = 0;
|
||||
|
||||
/// character collisions
|
||||
DynamicCharacterController* _characterController = NULL;
|
||||
CharacterController* _myAvatarController;
|
||||
|
||||
bool _dumpNextStats = false;
|
||||
bool _hasOutgoingChanges = false;
|
||||
|
|
Loading…
Reference in a new issue