mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 20:16:16 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into avatarUI
This commit is contained in:
commit
80df8caefb
12 changed files with 177 additions and 257 deletions
|
@ -138,7 +138,7 @@
|
||||||
<h3>Import models</h3>
|
<h3>Import models</h3>
|
||||||
<img class="grid-img" src="img/models.png" alt"Import models"></img>
|
<img class="grid-img" src="img/models.png" alt"Import models"></img>
|
||||||
<p>
|
<p>
|
||||||
Use the editEntitles.js script to<br>
|
Use the <strong>edit.js</strong> script to<br>
|
||||||
add FBX models in-world. You<br>
|
add FBX models in-world. You<br>
|
||||||
can use grids and fine tune<br>
|
can use grids and fine tune<br>
|
||||||
placement-related parameters<br>
|
placement-related parameters<br>
|
||||||
|
|
|
@ -987,12 +987,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
resetSensors();
|
resetSensors();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Qt::Key_G:
|
|
||||||
if (isShifted) {
|
|
||||||
Menu::getInstance()->triggerOption(MenuOption::ObeyEnvironmentalGravity);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Qt::Key_A:
|
case Qt::Key_A:
|
||||||
if (isShifted) {
|
if (isShifted) {
|
||||||
Menu::getInstance()->triggerOption(MenuOption::Atmosphere);
|
Menu::getInstance()->triggerOption(MenuOption::Atmosphere);
|
||||||
|
@ -1165,10 +1159,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Qt::Key_Comma: {
|
|
||||||
_myAvatar->togglePhysicsEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
event->ignore();
|
event->ignore();
|
||||||
break;
|
break;
|
||||||
|
@ -2192,7 +2182,6 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("physics");
|
PerformanceTimer perfTimer("physics");
|
||||||
_myAvatar->preSimulation();
|
|
||||||
_physicsEngine.stepSimulation();
|
_physicsEngine.stepSimulation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,9 +201,7 @@ Menu::Menu() {
|
||||||
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true);
|
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true);
|
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true);
|
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false,
|
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true,
|
||||||
avatar, SLOT(updateMotionBehavior()));
|
|
||||||
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::StandOnNearbyFloors, 0, true,
|
|
||||||
avatar, SLOT(updateMotionBehavior()));
|
avatar, SLOT(updateMotionBehavior()));
|
||||||
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false,
|
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false,
|
||||||
avatar, SLOT(updateMotionBehavior()));
|
avatar, SLOT(updateMotionBehavior()));
|
||||||
|
|
|
@ -153,6 +153,7 @@ namespace MenuOption {
|
||||||
const QString EchoServerAudio = "Echo Server Audio";
|
const QString EchoServerAudio = "Echo Server Audio";
|
||||||
const QString EditEntitiesHelp = "Edit Entities Help...";
|
const QString EditEntitiesHelp = "Edit Entities Help...";
|
||||||
const QString Enable3DTVMode = "Enable 3DTV Mode";
|
const QString Enable3DTVMode = "Enable 3DTV Mode";
|
||||||
|
const QString EnableCharacterController = "Enable avatar collisions";
|
||||||
const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)";
|
const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)";
|
||||||
const QString EnableVRMode = "Enable VR Mode";
|
const QString EnableVRMode = "Enable VR Mode";
|
||||||
const QString Entities = "Entities";
|
const QString Entities = "Entities";
|
||||||
|
@ -185,7 +186,6 @@ namespace MenuOption {
|
||||||
const QString MuteAudio = "Mute Microphone";
|
const QString MuteAudio = "Mute Microphone";
|
||||||
const QString MuteEnvironment = "Mute Environment";
|
const QString MuteEnvironment = "Mute Environment";
|
||||||
const QString NoFaceTracking = "None";
|
const QString NoFaceTracking = "None";
|
||||||
const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
|
|
||||||
const QString OctreeStats = "Entity Statistics";
|
const QString OctreeStats = "Entity Statistics";
|
||||||
const QString OffAxisProjection = "Off-Axis Projection";
|
const QString OffAxisProjection = "Off-Axis Projection";
|
||||||
const QString OnlyDisplayTopTen = "Only Display Top Ten";
|
const QString OnlyDisplayTopTen = "Only Display Top Ten";
|
||||||
|
@ -236,7 +236,6 @@ namespace MenuOption {
|
||||||
const QString SixenseEnabled = "Enable Hydra Support";
|
const QString SixenseEnabled = "Enable Hydra Support";
|
||||||
const QString SixenseMouseInput = "Enable Sixense Mouse Input";
|
const QString SixenseMouseInput = "Enable Sixense Mouse Input";
|
||||||
const QString SixenseLasers = "Enable Sixense UI Lasers";
|
const QString SixenseLasers = "Enable Sixense UI Lasers";
|
||||||
const QString StandOnNearbyFloors = "Stand on nearby floors";
|
|
||||||
const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations";
|
const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations";
|
||||||
const QString Stars = "Stars";
|
const QString Stars = "Stars";
|
||||||
const QString Stats = "Stats";
|
const QString Stats = "Stats";
|
||||||
|
|
|
@ -81,7 +81,6 @@ MyAvatar::MyAvatar() :
|
||||||
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
||||||
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
||||||
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
||||||
_enablePhysics(false),
|
|
||||||
_characterController(this),
|
_characterController(this),
|
||||||
_lookAtTargetAvatar(),
|
_lookAtTargetAvatar(),
|
||||||
_shouldRender(true),
|
_shouldRender(true),
|
||||||
|
@ -101,6 +100,7 @@ MyAvatar::MyAvatar() :
|
||||||
// connect to AddressManager signal for location jumps
|
// connect to AddressManager signal for location jumps
|
||||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||||
this, &MyAvatar::goToLocation);
|
this, &MyAvatar::goToLocation);
|
||||||
|
_characterController.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
MyAvatar::~MyAvatar() {
|
MyAvatar::~MyAvatar() {
|
||||||
|
@ -147,10 +147,6 @@ void MyAvatar::update(float deltaTime) {
|
||||||
head->setAudioLoudness(audio->getLastInputLoudness());
|
head->setAudioLoudness(audio->getLastInputLoudness());
|
||||||
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
|
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
|
||||||
|
|
||||||
if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) {
|
|
||||||
setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition()));
|
|
||||||
}
|
|
||||||
|
|
||||||
simulate(deltaTime);
|
simulate(deltaTime);
|
||||||
if (_feetTouchFloor) {
|
if (_feetTouchFloor) {
|
||||||
_skeletonModel.updateStandingFoot();
|
_skeletonModel.updateStandingFoot();
|
||||||
|
@ -174,11 +170,7 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("transform");
|
PerformanceTimer perfTimer("transform");
|
||||||
updateOrientation(deltaTime);
|
updateOrientation(deltaTime);
|
||||||
if (isPhysicsEnabled()) {
|
updatePosition(deltaTime);
|
||||||
updatePositionWithPhysics(deltaTime);
|
|
||||||
} else {
|
|
||||||
updatePosition(deltaTime);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -484,26 +476,6 @@ void MyAvatar::loadLastRecording() {
|
||||||
_player->loadRecording(_recorder->getRecording());
|
_player->loadRecording(_recorder->getRecording());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setLocalGravity(glm::vec3 gravity) {
|
|
||||||
_motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY;
|
|
||||||
// Environmental and Local gravities are incompatible. Since Local is being set here
|
|
||||||
// the environmental setting must be removed.
|
|
||||||
_motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY;
|
|
||||||
setGravity(gravity);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::setGravity(const glm::vec3& gravity) {
|
|
||||||
_gravity = gravity;
|
|
||||||
|
|
||||||
// use the gravity to determine the new world up direction, if possible
|
|
||||||
float gravityLength = glm::length(gravity);
|
|
||||||
if (gravityLength > EPSILON) {
|
|
||||||
_worldUpDirection = _gravity / -gravityLength;
|
|
||||||
}
|
|
||||||
// NOTE: the else case here it to leave _worldUpDirection unchanged
|
|
||||||
// so it continues to point opposite to the previous gravity setting.
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationHandlePointer MyAvatar::addAnimationHandle() {
|
AnimationHandlePointer MyAvatar::addAnimationHandle() {
|
||||||
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
|
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
|
||||||
_animationHandles.append(handle);
|
_animationHandles.append(handle);
|
||||||
|
@ -1258,128 +1230,38 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe
|
||||||
return localVelocity + motorEfficiency * deltaVelocity;
|
return localVelocity + motorEfficiency * deltaVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float NEARBY_FLOOR_THRESHOLD = 5.0f;
|
|
||||||
|
|
||||||
void MyAvatar::updatePosition(float deltaTime) {
|
void MyAvatar::updatePosition(float deltaTime) {
|
||||||
|
|
||||||
// check for floor by casting a ray straight down from avatar's position
|
|
||||||
float heightAboveFloor = FLT_MAX;
|
|
||||||
bool hasFloor = false;
|
|
||||||
const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
|
|
||||||
const float maxFloorDistance = boundingShape.getBoundingRadius() * NEARBY_FLOOR_THRESHOLD;
|
|
||||||
|
|
||||||
RayIntersectionInfo intersection;
|
|
||||||
// NOTE: avatar is center of PhysicsSimulation, so rayStart is the origin for the purposes of the raycast
|
|
||||||
intersection._rayStart = glm::vec3(0.0f);
|
|
||||||
intersection._rayDirection = - _worldUpDirection;
|
|
||||||
intersection._rayLength = 4.0f * boundingShape.getBoundingRadius();
|
|
||||||
|
|
||||||
// velocity is initialized to the measured _velocity but will be modified by friction, external thrust, etc
|
|
||||||
glm::vec3 velocity = _velocity;
|
|
||||||
|
|
||||||
bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f;
|
|
||||||
if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) {
|
|
||||||
const float MAX_SPEED_UNDER_GRAVITY = 2.0f * _scale * MAX_WALKING_SPEED;
|
|
||||||
if (pushingUp || glm::length2(velocity) > MAX_SPEED_UNDER_GRAVITY * MAX_SPEED_UNDER_GRAVITY) {
|
|
||||||
// we're pushing up or moving quickly, so disable gravity
|
|
||||||
setLocalGravity(glm::vec3(0.0f));
|
|
||||||
hasFloor = false;
|
|
||||||
} else {
|
|
||||||
if (heightAboveFloor > maxFloorDistance) {
|
|
||||||
// disable local gravity when floor is too far away
|
|
||||||
setLocalGravity(glm::vec3(0.0f));
|
|
||||||
hasFloor = false;
|
|
||||||
} else {
|
|
||||||
// enable gravity
|
|
||||||
setLocalGravity(-_worldUpDirection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool zeroDownwardVelocity = false;
|
|
||||||
bool gravityEnabled = (glm::length2(_gravity) > EPSILON);
|
|
||||||
if (gravityEnabled) {
|
|
||||||
const float SLOP = 0.002f;
|
|
||||||
if (heightAboveFloor < SLOP) {
|
|
||||||
if (heightAboveFloor < 0.0) {
|
|
||||||
// Gravity is in effect so we assume that the avatar is colliding against the world and we need
|
|
||||||
// to lift avatar out of floor, but we don't want to do it too fast (keep it smooth).
|
|
||||||
float distanceToLift = glm::min(-heightAboveFloor, MAX_WALKING_SPEED * deltaTime);
|
|
||||||
|
|
||||||
// We don't use applyPositionDelta() for this lift distance because we don't want the avatar
|
|
||||||
// to come flying out of the floor. Instead we update position directly, and set a boolean
|
|
||||||
// that will remind us later to zero any downward component of the velocity.
|
|
||||||
_position += distanceToLift * _worldUpDirection;
|
|
||||||
}
|
|
||||||
zeroDownwardVelocity = true;
|
|
||||||
}
|
|
||||||
if (!zeroDownwardVelocity) {
|
|
||||||
velocity += (deltaTime * GRAVITY_EARTH) * _gravity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotate velocity into camera frame
|
|
||||||
glm::quat rotation = getHead()->getCameraOrientation();
|
|
||||||
glm::vec3 localVelocity = glm::inverse(rotation) * velocity;
|
|
||||||
|
|
||||||
// apply motors in camera frame
|
|
||||||
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor);
|
|
||||||
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
|
||||||
|
|
||||||
// rotate back into world-frame
|
|
||||||
velocity = rotation * newLocalVelocity;
|
|
||||||
|
|
||||||
// apply thrust
|
|
||||||
velocity += _thrust * deltaTime;
|
|
||||||
_thrust = glm::vec3(0.0f);
|
|
||||||
|
|
||||||
// remove downward velocity so we don't push into floor
|
|
||||||
if (zeroDownwardVelocity) {
|
|
||||||
float verticalSpeed = glm::dot(velocity, _worldUpDirection);
|
|
||||||
if (verticalSpeed < 0.0f || !pushingUp) {
|
|
||||||
velocity -= verticalSpeed * _worldUpDirection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cap avatar speed
|
|
||||||
float speed = glm::length(velocity);
|
|
||||||
if (speed > MAX_AVATAR_SPEED) {
|
|
||||||
velocity *= MAX_AVATAR_SPEED / speed;
|
|
||||||
speed = MAX_AVATAR_SPEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update position
|
|
||||||
if (speed > MIN_AVATAR_SPEED) {
|
|
||||||
applyPositionDelta(deltaTime * velocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update _moving flag based on speed
|
|
||||||
const float MOVING_SPEED_THRESHOLD = 0.01f;
|
|
||||||
_moving = speed > MOVING_SPEED_THRESHOLD;
|
|
||||||
|
|
||||||
measureMotionDerivatives(deltaTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::updatePositionWithPhysics(float deltaTime) {
|
|
||||||
// rotate velocity into camera frame
|
// rotate velocity into camera frame
|
||||||
glm::quat rotation = getHead()->getCameraOrientation();
|
glm::quat rotation = getHead()->getCameraOrientation();
|
||||||
glm::vec3 localVelocity = glm::inverse(rotation) * _velocity;
|
glm::vec3 localVelocity = glm::inverse(rotation) * _velocity;
|
||||||
|
|
||||||
bool hasFloor = false;
|
bool isOnGround = _characterController.onGround();
|
||||||
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor);
|
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isOnGround);
|
||||||
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
||||||
|
|
||||||
// cap avatar speed
|
|
||||||
float speed = glm::length(newLocalVelocity);
|
|
||||||
if (speed > MAX_WALKING_SPEED) {
|
|
||||||
newLocalVelocity *= MAX_WALKING_SPEED / speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotate back into world-frame
|
// rotate back into world-frame
|
||||||
_velocity = rotation * newLocalVelocity;
|
_velocity = rotation * newLocalVelocity;
|
||||||
|
|
||||||
_velocity += _thrust * deltaTime;
|
_velocity += _thrust * deltaTime;
|
||||||
_thrust = glm::vec3(0.0f);
|
_thrust = glm::vec3(0.0f);
|
||||||
|
|
||||||
|
// cap avatar speed
|
||||||
|
float speed = glm::length(_velocity);
|
||||||
|
if (speed > MAX_AVATAR_SPEED) {
|
||||||
|
_velocity *= MAX_AVATAR_SPEED / speed;
|
||||||
|
speed = MAX_AVATAR_SPEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) {
|
||||||
|
// update position ourselves
|
||||||
|
applyPositionDelta(deltaTime * _velocity);
|
||||||
|
measureMotionDerivatives(deltaTime);
|
||||||
|
} // else physics will move avatar later
|
||||||
|
|
||||||
|
// update _moving flag based on speed
|
||||||
|
const float MOVING_SPEED_THRESHOLD = 0.01f;
|
||||||
|
_moving = speed > MOVING_SPEED_THRESHOLD;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) {
|
void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) {
|
||||||
|
@ -1496,23 +1378,6 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition,
|
||||||
|
|
||||||
void MyAvatar::updateMotionBehavior() {
|
void MyAvatar::updateMotionBehavior() {
|
||||||
Menu* menu = Menu::getInstance();
|
Menu* menu = Menu::getInstance();
|
||||||
if (menu->isOptionChecked(MenuOption::ObeyEnvironmentalGravity)) {
|
|
||||||
_motionBehaviors |= AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY;
|
|
||||||
// Environmental and Local gravities are incompatible. Environmental setting trumps local.
|
|
||||||
_motionBehaviors &= ~AVATAR_MOTION_OBEY_LOCAL_GRAVITY;
|
|
||||||
} else {
|
|
||||||
_motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY;
|
|
||||||
}
|
|
||||||
if (! (_motionBehaviors & (AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | AVATAR_MOTION_OBEY_LOCAL_GRAVITY))) {
|
|
||||||
setGravity(glm::vec3(0.0f));
|
|
||||||
}
|
|
||||||
if (menu->isOptionChecked(MenuOption::StandOnNearbyFloors)) {
|
|
||||||
_motionBehaviors |= AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
|
|
||||||
// standing on floors requires collision with voxels
|
|
||||||
// TODO: determine what to do with this now that voxels are gone
|
|
||||||
} else {
|
|
||||||
_motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
|
|
||||||
}
|
|
||||||
if (menu->isOptionChecked(MenuOption::KeyboardMotorControl)) {
|
if (menu->isOptionChecked(MenuOption::KeyboardMotorControl)) {
|
||||||
_motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED;
|
_motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1523,6 +1388,7 @@ void MyAvatar::updateMotionBehavior() {
|
||||||
} else {
|
} else {
|
||||||
_motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
|
_motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
|
||||||
}
|
}
|
||||||
|
_characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController));
|
||||||
_feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations);
|
_feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1581,10 +1447,6 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
|
||||||
return palm->getPosition();
|
return palm->getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::preSimulation() {
|
|
||||||
_characterController.setEnabled(_enablePhysics);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::clearDriveKeys() {
|
void MyAvatar::clearDriveKeys() {
|
||||||
for (int i = 0; i < MAX_DRIVE_KEYS; ++i) {
|
for (int i = 0; i < MAX_DRIVE_KEYS; ++i) {
|
||||||
_driveKeys[i] = 0.0f;
|
_driveKeys[i] = 0.0f;
|
||||||
|
|
|
@ -25,7 +25,7 @@ class MyAvatar : public Avatar {
|
||||||
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
|
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
|
||||||
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
|
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
|
||||||
Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame)
|
Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame)
|
||||||
Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setLocalGravity)
|
//TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MyAvatar();
|
MyAvatar();
|
||||||
|
@ -44,13 +44,11 @@ public:
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
void setLeanScale(float scale) { _leanScale = scale; }
|
void setLeanScale(float scale) { _leanScale = scale; }
|
||||||
void setLocalGravity(glm::vec3 gravity);
|
|
||||||
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
|
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
|
||||||
void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); }
|
void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); }
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
float getLeanScale() const { return _leanScale; }
|
float getLeanScale() const { return _leanScale; }
|
||||||
glm::vec3 getGravity() const { return _gravity; }
|
|
||||||
Q_INVOKABLE glm::vec3 getDefaultEyePosition() const;
|
Q_INVOKABLE glm::vec3 getDefaultEyePosition() const;
|
||||||
bool getShouldRenderLocally() const { return _shouldRender; }
|
bool getShouldRenderLocally() const { return _shouldRender; }
|
||||||
float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); }
|
float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); }
|
||||||
|
@ -148,11 +146,6 @@ public:
|
||||||
|
|
||||||
const RecorderPointer getRecorder() const { return _recorder; }
|
const RecorderPointer getRecorder() const { return _recorder; }
|
||||||
const PlayerPointer getPlayer() const { return _player; }
|
const PlayerPointer getPlayer() const { return _player; }
|
||||||
|
|
||||||
void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; }
|
|
||||||
bool isPhysicsEnabled() { return _enablePhysics; }
|
|
||||||
void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; }
|
|
||||||
void preSimulation();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void increaseSize();
|
void increaseSize();
|
||||||
|
@ -209,7 +202,6 @@ private:
|
||||||
int _scriptedMotorFrame;
|
int _scriptedMotorFrame;
|
||||||
quint32 _motionBehaviors;
|
quint32 _motionBehaviors;
|
||||||
|
|
||||||
bool _enablePhysics;
|
|
||||||
CharacterController _characterController;
|
CharacterController _characterController;
|
||||||
|
|
||||||
QWeakPointer<AvatarData> _lookAtTargetAvatar;
|
QWeakPointer<AvatarData> _lookAtTargetAvatar;
|
||||||
|
@ -234,10 +226,8 @@ private:
|
||||||
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor);
|
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor);
|
||||||
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
|
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
|
||||||
void updatePosition(float deltaTime);
|
void updatePosition(float deltaTime);
|
||||||
void updatePositionWithPhysics(float deltaTime);
|
|
||||||
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
|
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
|
||||||
void maybeUpdateBillboard();
|
void maybeUpdateBillboard();
|
||||||
void setGravity(const glm::vec3& gravity);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_MyAvatar_h
|
#endif // hifi_MyAvatar_h
|
||||||
|
|
|
@ -61,21 +61,13 @@ typedef unsigned long long quint64;
|
||||||
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
|
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
|
||||||
const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1;
|
const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1;
|
||||||
|
|
||||||
const quint32 AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY = 1U << 2;
|
|
||||||
const quint32 AVATAR_MOTION_OBEY_LOCAL_GRAVITY = 1U << 3;
|
|
||||||
const quint32 AVATAR_MOTION_STAND_ON_NEARBY_FLOORS = 1U << 4;
|
|
||||||
|
|
||||||
const quint32 AVATAR_MOTION_DEFAULTS =
|
const quint32 AVATAR_MOTION_DEFAULTS =
|
||||||
AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED |
|
AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED |
|
||||||
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED |
|
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
|
||||||
AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
|
|
||||||
|
|
||||||
// these bits will be expanded as features are exposed
|
// these bits will be expanded as features are exposed
|
||||||
const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
|
const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
|
||||||
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED |
|
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
|
||||||
AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY |
|
|
||||||
AVATAR_MOTION_OBEY_LOCAL_GRAVITY |
|
|
||||||
AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
|
|
||||||
|
|
||||||
|
|
||||||
// Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of
|
// Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of
|
||||||
|
@ -365,8 +357,8 @@ protected:
|
||||||
HeadData* _headData;
|
HeadData* _headData;
|
||||||
HandData* _handData;
|
HandData* _handData;
|
||||||
|
|
||||||
QUrl _faceModelURL = DEFAULT_HEAD_MODEL_URL;
|
QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
||||||
QUrl _skeletonModelURL = DEFAULT_BODY_MODEL_URL;
|
QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
||||||
QVector<AttachmentData> _attachmentData;
|
QVector<AttachmentData> _attachmentData;
|
||||||
QString _displayName;
|
QString _displayName;
|
||||||
|
|
||||||
|
|
|
@ -282,7 +282,7 @@ void AccountManager::processReply() {
|
||||||
} else {
|
} else {
|
||||||
passErrorToCallback(requestReply);
|
passErrorToCallback(requestReply);
|
||||||
}
|
}
|
||||||
delete requestReply;
|
requestReply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
|
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
|
||||||
|
|
|
@ -40,6 +40,24 @@ static btVector3 getNormalizedVector(const btVector3& v) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback {
|
||||||
|
public:
|
||||||
|
btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) :
|
||||||
|
btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) {
|
||||||
|
_me = me;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) {
|
||||||
|
if (rayResult.m_collisionObject == _me) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
btCollisionObject* _me;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
|
class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
|
||||||
public:
|
public:
|
||||||
btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
|
btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
|
||||||
|
@ -199,9 +217,7 @@ CharacterController::CharacterController(AvatarData* avatarData) {
|
||||||
assert(avatarData);
|
assert(avatarData);
|
||||||
_avatarData = avatarData;
|
_avatarData = avatarData;
|
||||||
|
|
||||||
// cache the "PhysicsEnabled" state of _avatarData
|
|
||||||
_enabled = false;
|
_enabled = false;
|
||||||
|
|
||||||
_ghostObject = NULL;
|
_ghostObject = NULL;
|
||||||
_convexShape = NULL;
|
_convexShape = NULL;
|
||||||
|
|
||||||
|
@ -210,11 +226,13 @@ CharacterController::CharacterController(AvatarData* avatarData) {
|
||||||
_velocityTimeInterval = 0.0f;
|
_velocityTimeInterval = 0.0f;
|
||||||
_verticalVelocity = 0.0f;
|
_verticalVelocity = 0.0f;
|
||||||
_verticalOffset = 0.0f;
|
_verticalOffset = 0.0f;
|
||||||
_gravity = 9.8f;
|
_gravity = 5.0f; // slower than Earth's
|
||||||
_maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s.
|
_maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s.
|
||||||
_jumpSpeed = 7.0f;
|
_jumpSpeed = 5.0f;
|
||||||
_wasOnGround = false;
|
_isOnGround = false;
|
||||||
_wasJumping = false;
|
_isJumping = false;
|
||||||
|
_isHovering = true;
|
||||||
|
_jumpToHoverStart = 0;
|
||||||
setMaxSlope(btRadians(45.0f));
|
setMaxSlope(btRadians(45.0f));
|
||||||
_lastStepUp = 0.0f;
|
_lastStepUp = 0.0f;
|
||||||
_pendingFlags = 0;
|
_pendingFlags = 0;
|
||||||
|
@ -325,6 +343,26 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl
|
||||||
return penetration;
|
return penetration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterController::scanDown(btCollisionWorld* world) {
|
||||||
|
// we test with downward raycast and if we don't find floor close enough then turn on "hover"
|
||||||
|
btKinematicClosestNotMeRayResultCallback callback(_ghostObject);
|
||||||
|
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||||
|
callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||||
|
|
||||||
|
btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS);
|
||||||
|
btVector3 start = _currentPosition;
|
||||||
|
const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight + _radius; // closest possible floor for disabling hover
|
||||||
|
const btScalar MIN_HOVER_HEIGHT = 3.0f + _halfHeight + _radius; // distance to floor for enabling hover
|
||||||
|
btVector3 end = start - MAX_SCAN_HEIGHT * up;
|
||||||
|
|
||||||
|
world->rayTest(start, end, callback);
|
||||||
|
if (!callback.hasHit()) {
|
||||||
|
_isHovering = true;
|
||||||
|
} else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) {
|
||||||
|
_isHovering = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::stepUp(btCollisionWorld* world) {
|
void CharacterController::stepUp(btCollisionWorld* world) {
|
||||||
// phase 1: up
|
// phase 1: up
|
||||||
|
|
||||||
|
@ -334,7 +372,7 @@ void CharacterController::stepUp(btCollisionWorld* world) {
|
||||||
btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS);
|
btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS);
|
||||||
start.setOrigin(_currentPosition + up * (_convexShape->getMargin() + _addedMargin));
|
start.setOrigin(_currentPosition + up * (_convexShape->getMargin() + _addedMargin));
|
||||||
|
|
||||||
_targetPosition = _currentPosition + up * _stepHeight;
|
_targetPosition = _currentPosition + up * _stepUpHeight;
|
||||||
end.setIdentity();
|
end.setIdentity();
|
||||||
end.setOrigin(_targetPosition);
|
end.setOrigin(_targetPosition);
|
||||||
|
|
||||||
|
@ -352,15 +390,15 @@ void CharacterController::stepUp(btCollisionWorld* world) {
|
||||||
|
|
||||||
// Only modify the position if the hit was a slope and not a wall or ceiling.
|
// Only modify the position if the hit was a slope and not a wall or ceiling.
|
||||||
if (callback.m_hitNormalWorld.dot(up) > 0.0f) {
|
if (callback.m_hitNormalWorld.dot(up) > 0.0f) {
|
||||||
_lastStepUp = _stepHeight * callback.m_closestHitFraction;
|
_lastStepUp = _stepUpHeight * callback.m_closestHitFraction;
|
||||||
_currentPosition.setInterpolate3(_currentPosition, _targetPosition, callback.m_closestHitFraction);
|
_currentPosition.setInterpolate3(_currentPosition, _targetPosition, callback.m_closestHitFraction);
|
||||||
} else {
|
} else {
|
||||||
_lastStepUp = _stepHeight;
|
_lastStepUp = _stepUpHeight;
|
||||||
_currentPosition = _targetPosition;
|
_currentPosition = _targetPosition;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_currentPosition = _targetPosition;
|
_currentPosition = _targetPosition;
|
||||||
_lastStepUp = _stepHeight;
|
_lastStepUp = _stepUpHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,12 +449,12 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt
|
||||||
btScalar margin = _convexShape->getMargin();
|
btScalar margin = _convexShape->getMargin();
|
||||||
_convexShape->setMargin(margin + _addedMargin);
|
_convexShape->setMargin(margin + _addedMargin);
|
||||||
|
|
||||||
const btScalar MIN_STEP_DISTANCE = 0.0001f;
|
const btScalar MIN_STEP_DISTANCE_SQUARED = 1.0e-6f;
|
||||||
btVector3 step = _targetPosition - _currentPosition;
|
btVector3 step = _targetPosition - _currentPosition;
|
||||||
btScalar stepLength2 = step.length2();
|
btScalar stepLength2 = step.length2();
|
||||||
int maxIter = 10;
|
int maxIter = 10;
|
||||||
|
|
||||||
while (stepLength2 > MIN_STEP_DISTANCE && maxIter-- > 0) {
|
while (stepLength2 > MIN_STEP_DISTANCE_SQUARED && maxIter-- > 0) {
|
||||||
start.setOrigin(_currentPosition);
|
start.setOrigin(_currentPosition);
|
||||||
end.setOrigin(_targetPosition);
|
end.setOrigin(_targetPosition);
|
||||||
|
|
||||||
|
@ -477,13 +515,16 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
|
||||||
end.setOrigin(_targetPosition);
|
end.setOrigin(_targetPosition);
|
||||||
_ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
_ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||||
|
|
||||||
|
_isOnGround = false;
|
||||||
if (callback.hasHit()) {
|
if (callback.hasHit()) {
|
||||||
_currentPosition += callback.m_closestHitFraction * step;
|
_currentPosition += callback.m_closestHitFraction * step;
|
||||||
_verticalVelocity = 0.0f;
|
_verticalVelocity = 0.0f;
|
||||||
_verticalOffset = 0.0f;
|
_verticalOffset = 0.0f;
|
||||||
_wasJumping = false;
|
_isJumping = false;
|
||||||
} else if (!_wasJumping) {
|
_isOnGround = true;
|
||||||
|
} else if (!_isJumping) {
|
||||||
// sweep again for floor within downStep threshold
|
// sweep again for floor within downStep threshold
|
||||||
|
step = -_stepDownHeight * up;
|
||||||
StepDownConvexResultCallback callback2 (_ghostObject,
|
StepDownConvexResultCallback callback2 (_ghostObject,
|
||||||
up,
|
up,
|
||||||
_currentPosition, step,
|
_currentPosition, step,
|
||||||
|
@ -495,8 +536,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
|
||||||
callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||||
|
|
||||||
_currentPosition = _targetPosition;
|
_currentPosition = _targetPosition;
|
||||||
btVector3 oldPosition = _currentPosition;
|
|
||||||
step = (- _stepHeight) * up;
|
|
||||||
_targetPosition = _currentPosition + step;
|
_targetPosition = _currentPosition + step;
|
||||||
|
|
||||||
start.setOrigin(_currentPosition);
|
start.setOrigin(_currentPosition);
|
||||||
|
@ -507,10 +546,10 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
|
||||||
_currentPosition += callback2.m_closestHitFraction * step;
|
_currentPosition += callback2.m_closestHitFraction * step;
|
||||||
_verticalVelocity = 0.0f;
|
_verticalVelocity = 0.0f;
|
||||||
_verticalOffset = 0.0f;
|
_verticalOffset = 0.0f;
|
||||||
_wasJumping = false;
|
_isJumping = false;
|
||||||
|
_isOnGround = true;
|
||||||
} else {
|
} else {
|
||||||
// nothing to step down on, so remove the stepUp effect
|
// nothing to step down on
|
||||||
_currentPosition = oldPosition - _lastStepUp * up;
|
|
||||||
_lastStepUp = 0.0f;
|
_lastStepUp = 0.0f;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -534,8 +573,8 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity,
|
||||||
void CharacterController::reset(btCollisionWorld* collisionWorld) {
|
void CharacterController::reset(btCollisionWorld* collisionWorld) {
|
||||||
_verticalVelocity = 0.0;
|
_verticalVelocity = 0.0;
|
||||||
_verticalOffset = 0.0;
|
_verticalOffset = 0.0;
|
||||||
_wasOnGround = false;
|
_isOnGround = false;
|
||||||
_wasJumping = false;
|
_isJumping = false;
|
||||||
_walkDirection.setValue(0,0,0);
|
_walkDirection.setValue(0,0,0);
|
||||||
_velocityTimeInterval = 0.0;
|
_velocityTimeInterval = 0.0;
|
||||||
|
|
||||||
|
@ -581,14 +620,17 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
|
||||||
return; // no motion
|
return; // no motion
|
||||||
}
|
}
|
||||||
|
|
||||||
_wasOnGround = onGround();
|
|
||||||
|
|
||||||
// Update fall velocity.
|
// Update fall velocity.
|
||||||
_verticalVelocity -= _gravity * dt;
|
if (_isHovering) {
|
||||||
if (_verticalVelocity > _jumpSpeed) {
|
const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f;
|
||||||
_verticalVelocity = _jumpSpeed;
|
_verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE);
|
||||||
} else if (_verticalVelocity < -_maxFallSpeed) {
|
} else {
|
||||||
_verticalVelocity = -_maxFallSpeed;
|
_verticalVelocity -= _gravity * dt;
|
||||||
|
if (_verticalVelocity > _jumpSpeed) {
|
||||||
|
_verticalVelocity = _jumpSpeed;
|
||||||
|
} else if (_verticalVelocity < -_maxFallSpeed) {
|
||||||
|
_verticalVelocity = -_maxFallSpeed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_verticalOffset = _verticalVelocity * dt;
|
_verticalOffset = _verticalVelocity * dt;
|
||||||
|
|
||||||
|
@ -600,11 +642,14 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
|
||||||
// (2) step the character forward
|
// (2) step the character forward
|
||||||
// (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started
|
// (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started
|
||||||
|
|
||||||
|
scanDown(collisionWorld);
|
||||||
|
|
||||||
stepUp(collisionWorld);
|
stepUp(collisionWorld);
|
||||||
|
|
||||||
// compute substep and decrement total interval
|
// compute substep and decrement total interval
|
||||||
btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval;
|
btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval;
|
||||||
_velocityTimeInterval -= dt;
|
_velocityTimeInterval -= dt;
|
||||||
|
_stepDt += dt;
|
||||||
|
|
||||||
// stepForward substep
|
// stepForward substep
|
||||||
btVector3 move = _walkDirection * dtMoving;
|
btVector3 move = _walkDirection * dtMoving;
|
||||||
|
@ -629,11 +674,25 @@ void CharacterController::setMaxJumpHeight(btScalar maxJumpHeight) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterController::canJump() const {
|
bool CharacterController::canJump() const {
|
||||||
return onGround();
|
return _isOnGround;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::jump() {
|
void CharacterController::jump() {
|
||||||
_pendingFlags |= PENDING_FLAG_JUMP;
|
_pendingFlags |= PENDING_FLAG_JUMP;
|
||||||
|
|
||||||
|
// check for case where user is holding down "jump" key...
|
||||||
|
// we'll eventually tansition to "hover"
|
||||||
|
if (!_isHovering) {
|
||||||
|
if (!_isJumping) {
|
||||||
|
_jumpToHoverStart = usecTimestampNow();
|
||||||
|
} else {
|
||||||
|
quint64 now = usecTimestampNow();
|
||||||
|
const quint64 JUMP_TO_HOVER_PERIOD = USECS_PER_SECOND;
|
||||||
|
if (now - _jumpToHoverStart < JUMP_TO_HOVER_PERIOD) {
|
||||||
|
_isHovering = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setGravity(btScalar gravity) {
|
void CharacterController::setGravity(btScalar gravity) {
|
||||||
|
@ -654,7 +713,7 @@ btScalar CharacterController::getMaxSlope() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterController::onGround() const {
|
bool CharacterController::onGround() const {
|
||||||
return _enabled && _verticalVelocity == 0.0f && _verticalOffset == 0.0f;
|
return _isOnGround;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::debugDraw(btIDebugDraw* debugDrawer) {
|
void CharacterController::debugDraw(btIDebugDraw* debugDrawer) {
|
||||||
|
@ -684,10 +743,12 @@ void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm
|
||||||
if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) {
|
if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) {
|
||||||
// shape hasn't changed --> nothing to do
|
// shape hasn't changed --> nothing to do
|
||||||
} else {
|
} else {
|
||||||
// we always need to: REMOVE when UPDATE_SHAPE, to avoid deleting shapes out from under the PhysicsEngine
|
if (_dynamicsWorld) {
|
||||||
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION
|
// must REMOVE from world prior to shape update
|
||||||
| PENDING_FLAG_UPDATE_SHAPE;
|
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||||
// but only need to ADD back when we happen to be enabled
|
}
|
||||||
|
_pendingFlags |= PENDING_FLAG_UPDATE_SHAPE;
|
||||||
|
// only need to ADD back when we happen to be enabled
|
||||||
if (_enabled) {
|
if (_enabled) {
|
||||||
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
|
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
|
||||||
}
|
}
|
||||||
|
@ -711,11 +772,13 @@ void CharacterController::setEnabled(bool enabled) {
|
||||||
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
|
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
|
||||||
// Setting the ADD bit here works for all cases so we don't even bother checking other bits.
|
// Setting the ADD bit here works for all cases so we don't even bother checking other bits.
|
||||||
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
|
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
|
||||||
|
_isHovering = true;
|
||||||
} else {
|
} else {
|
||||||
// Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case
|
if (_dynamicsWorld) {
|
||||||
// it was previously set by something else (e.g. an UPDATE_SHAPE event).
|
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||||
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
}
|
||||||
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
|
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
|
||||||
|
_isOnGround = false;
|
||||||
}
|
}
|
||||||
_enabled = enabled;
|
_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
@ -729,17 +792,23 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||||
}
|
}
|
||||||
_dynamicsWorld = world;
|
_dynamicsWorld = world;
|
||||||
if (_dynamicsWorld) {
|
if (_dynamicsWorld) {
|
||||||
_pendingFlags &= ~ (PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_JUMP);
|
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||||
_dynamicsWorld->addCollisionObject(getGhostObject(),
|
_dynamicsWorld->addCollisionObject(getGhostObject(),
|
||||||
btBroadphaseProxy::CharacterFilter,
|
btBroadphaseProxy::CharacterFilter,
|
||||||
btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
|
btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
|
||||||
_dynamicsWorld->addAction(this);
|
_dynamicsWorld->addAction(this);
|
||||||
reset(_dynamicsWorld);
|
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 {
|
} else {
|
||||||
_pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
_pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_pendingFlags &= ~ (PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_ADD_TO_SIMULATION);
|
_pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,10 +841,8 @@ void CharacterController::updateShapeIfNecessary() {
|
||||||
_ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
_ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
||||||
glmToBullet(_avatarData->getPosition())));
|
glmToBullet(_avatarData->getPosition())));
|
||||||
// stepHeight affects the heights of ledges that the character can ascend
|
// stepHeight affects the heights of ledges that the character can ascend
|
||||||
// however the actual ledge height is some function of _stepHeight
|
_stepUpHeight = _radius + 0.25f * _halfHeight + 0.1f;
|
||||||
// due to character shape and this CharacterController algorithm
|
_stepDownHeight = _radius;
|
||||||
// (the function is approximately 2*_stepHeight)
|
|
||||||
_stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f;
|
|
||||||
|
|
||||||
// create new shape
|
// create new shape
|
||||||
_convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
_convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
||||||
|
@ -799,9 +866,12 @@ void CharacterController::preSimulation(btScalar timeStep) {
|
||||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||||
if (canJump()) {
|
if (canJump()) {
|
||||||
_verticalVelocity = _jumpSpeed;
|
_verticalVelocity = _jumpSpeed;
|
||||||
_wasJumping = true;
|
_isJumping = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// remember last position so we can throttle the total motion from the next step
|
||||||
|
_lastPosition = position;
|
||||||
|
_stepDt = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -809,9 +879,24 @@ void CharacterController::postSimulation() {
|
||||||
if (_enabled) {
|
if (_enabled) {
|
||||||
const btTransform& avatarTransform = _ghostObject->getWorldTransform();
|
const btTransform& avatarTransform = _ghostObject->getWorldTransform();
|
||||||
glm::quat rotation = bulletToGLM(avatarTransform.getRotation());
|
glm::quat rotation = bulletToGLM(avatarTransform.getRotation());
|
||||||
glm::vec3 offset = rotation * _shapeLocalOffset;
|
glm::vec3 position = bulletToGLM(avatarTransform.getOrigin());
|
||||||
|
|
||||||
|
// cap the velocity of the step so that the character doesn't POP! so hard on steps
|
||||||
|
glm::vec3 finalStep = position - _lastPosition;
|
||||||
|
btVector3 finalVelocity = _walkDirection;
|
||||||
|
btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS);
|
||||||
|
finalVelocity += _verticalVelocity * up;
|
||||||
|
const btScalar MAX_RESOLUTION_SPEED = 5.0f; // m/sec
|
||||||
|
btScalar maxStepLength = glm::max(MAX_RESOLUTION_SPEED, 2.0f * finalVelocity.length()) * _stepDt;
|
||||||
|
btScalar stepLength = glm::length(finalStep);
|
||||||
|
if (stepLength > maxStepLength) {
|
||||||
|
position = _lastPosition + (maxStepLength / stepLength) * finalStep;
|
||||||
|
// NOTE: we don't need to move ghostObject to throttled position unless
|
||||||
|
// we want to support do async ray-traces/collision-queries against character
|
||||||
|
}
|
||||||
|
|
||||||
_avatarData->setOrientation(rotation);
|
_avatarData->setOrientation(rotation);
|
||||||
_avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset);
|
_avatarData->setPosition(position - rotation * _shapeLocalOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,8 @@ protected:
|
||||||
btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization)
|
btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization)
|
||||||
btScalar _gravity;
|
btScalar _gravity;
|
||||||
|
|
||||||
btScalar _stepHeight; // height of stepUp prior to stepForward
|
btScalar _stepUpHeight; // height of stepUp prior to stepForward
|
||||||
|
btScalar _stepDownHeight; // height of stepDown
|
||||||
|
|
||||||
btScalar _addedMargin;//@todo: remove this and fix the code
|
btScalar _addedMargin;//@todo: remove this and fix the code
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ protected:
|
||||||
btVector3 _currentPosition;
|
btVector3 _currentPosition;
|
||||||
btQuaternion _currentRotation;
|
btQuaternion _currentRotation;
|
||||||
btVector3 _targetPosition;
|
btVector3 _targetPosition;
|
||||||
|
glm::vec3 _lastPosition;
|
||||||
btScalar _lastStepUp;
|
btScalar _lastStepUp;
|
||||||
|
|
||||||
///keep track of the contact manifolds
|
///keep track of the contact manifolds
|
||||||
|
@ -80,9 +82,12 @@ protected:
|
||||||
btVector3 _floorNormal; // points from object to character
|
btVector3 _floorNormal; // points from object to character
|
||||||
|
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
bool _wasOnGround;
|
bool _isOnGround;
|
||||||
bool _wasJumping;
|
bool _isJumping;
|
||||||
|
bool _isHovering;
|
||||||
|
quint64 _jumpToHoverStart;
|
||||||
btScalar _velocityTimeInterval;
|
btScalar _velocityTimeInterval;
|
||||||
|
btScalar _stepDt;
|
||||||
uint32_t _pendingFlags;
|
uint32_t _pendingFlags;
|
||||||
|
|
||||||
glm::vec3 _shapeLocalOffset;
|
glm::vec3 _shapeLocalOffset;
|
||||||
|
@ -95,6 +100,7 @@ protected:
|
||||||
btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal);
|
btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal);
|
||||||
|
|
||||||
bool recoverFromPenetration(btCollisionWorld* collisionWorld);
|
bool recoverFromPenetration(btCollisionWorld* collisionWorld);
|
||||||
|
void scanDown(btCollisionWorld* collisionWorld);
|
||||||
void stepUp(btCollisionWorld* collisionWorld);
|
void stepUp(btCollisionWorld* collisionWorld);
|
||||||
void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0));
|
void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0));
|
||||||
void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove);
|
void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove);
|
||||||
|
@ -161,6 +167,7 @@ public:
|
||||||
bool needsRemoval() const;
|
bool needsRemoval() const;
|
||||||
bool needsAddition() const;
|
bool needsAddition() const;
|
||||||
void setEnabled(bool enabled);
|
void setEnabled(bool enabled);
|
||||||
|
bool isEnabled() const { return _enabled; }
|
||||||
void setDynamicsWorld(btDynamicsWorld* world);
|
void setDynamicsWorld(btDynamicsWorld* world);
|
||||||
|
|
||||||
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
|
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
|
||||||
|
|
|
@ -360,10 +360,6 @@ void ScriptEngine::init() {
|
||||||
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
||||||
globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT)));
|
globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT)));
|
||||||
globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS)));
|
globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS)));
|
||||||
|
|
||||||
globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY)));
|
|
||||||
globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY)));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "XMLHttpRequestClass.h"
|
#include "XMLHttpRequestClass.h"
|
||||||
#include "ScriptEngine.h"
|
#include "ScriptEngine.h"
|
||||||
|
|
||||||
|
const QString METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/";
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QByteArray*)
|
Q_DECLARE_METATYPE(QByteArray*)
|
||||||
|
|
||||||
XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
|
XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
|
||||||
|
@ -207,7 +209,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
|
||||||
notImplemented();
|
notImplemented();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (url.toLower().left(33) == "https://metaverse.highfidelity.com/api/") {
|
if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
|
||||||
AccountManager& accountManager = AccountManager::getInstance();
|
AccountManager& accountManager = AccountManager::getInstance();
|
||||||
|
|
||||||
if (accountManager.hasValidAccessToken()) {
|
if (accountManager.hasValidAccessToken()) {
|
||||||
|
|
Loading…
Reference in a new issue