diff --git a/examples/edit.js b/examples/edit.js
index 52e565f3f9..2529b617d9 100644
--- a/examples/edit.js
+++ b/examples/edit.js
@@ -88,13 +88,7 @@ var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode";
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."
var modelURLs = [
- HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx",
- HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx",
- HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush6.fbx",
- HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed.fbx",
- HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed2.fbx",
- HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed4.fbx",
- HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed7.fbx"
+ "Insert the URL to your FBX"
];
var mode = 0;
@@ -387,9 +381,7 @@ var toolBar = (function () {
position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_LIGHT_DIMENSIONS), DEFAULT_LIGHT_DIMENSIONS),
dimensions: DEFAULT_LIGHT_DIMENSIONS,
isSpotlight: false,
- diffuseColor: { red: 255, green: 255, blue: 255 },
- ambientColor: { red: 255, green: 255, blue: 255 },
- specularColor: { red: 0, green: 0, blue: 0 },
+ color: { red: 150, green: 150, blue: 150 },
constantAttenuation: 1,
linearAttenuation: 0,
diff --git a/interface/resources/html/interface-welcome.html b/interface/resources/html/interface-welcome.html
index ed905eb392..26ae6ff5c0 100644
--- a/interface/resources/html/interface-welcome.html
+++ b/interface/resources/html/interface-welcome.html
@@ -138,7 +138,7 @@
Import models
- Use the editEntitles.js script to
+ Use the edit.js script to
add FBX models in-world. You
can use grids and fine tune
placement-related parameters
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index a69fc3659d..619f664c21 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -796,7 +796,7 @@ void Application::paintGL() {
DependencyManager::get()->render();
- if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) {
+ {
PerformanceTimer perfTimer("renderOverlay");
_applicationOverlay.renderOverlay(true);
_applicationOverlay.displayOverlayTexture();
@@ -994,12 +994,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
resetSensors();
break;
- case Qt::Key_G:
- if (isShifted) {
- Menu::getInstance()->triggerOption(MenuOption::ObeyEnvironmentalGravity);
- }
- break;
-
case Qt::Key_A:
if (isShifted) {
Menu::getInstance()->triggerOption(MenuOption::Atmosphere);
@@ -1134,13 +1128,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror);
}
break;
- case Qt::Key_Slash:
- Menu::getInstance()->triggerOption(MenuOption::UserInterface);
- break;
case Qt::Key_P:
Menu::getInstance()->triggerOption(MenuOption::FirstPerson);
break;
- case Qt::Key_Percent:
+ case Qt::Key_Slash:
Menu::getInstance()->triggerOption(MenuOption::Stats);
break;
case Qt::Key_Plus:
@@ -1175,10 +1166,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
break;
}
- case Qt::Key_Comma: {
- _myAvatar->togglePhysicsEnabled();
- }
-
default:
event->ignore();
break;
@@ -2205,7 +2192,6 @@ void Application::update(float deltaTime) {
{
PerformanceTimer perfTimer("physics");
- _myAvatar->preSimulation();
_physicsEngine.stepSimulation();
}
@@ -3029,8 +3015,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
_nodeBoundsDisplay.draw();
// Render the world box
- if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
- Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) {
+ if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
PerformanceTimer perfTimer("worldBox");
renderWorldBox();
}
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index 8d3c01320f..5867dd29e2 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -201,9 +201,7 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true);
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true);
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true);
- addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false,
- avatar, SLOT(updateMotionBehavior()));
- addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::StandOnNearbyFloors, 0, true,
+ addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true,
avatar, SLOT(updateMotionBehavior()));
addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false,
avatar, SLOT(updateMotionBehavior()));
@@ -230,7 +228,6 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
qApp, SLOT(cameraMenuChanged()));
- addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H,
false,
@@ -259,14 +256,13 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
- addDisabledActionAndSeparator(viewMenu, "Stats");
- addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Percent);
+ addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, qApp, SLOT(toggleLogDialog()));
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0,
dialogsManager.data(), SLOT(bandwidthDetails()));
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0,
dialogsManager.data(), SLOT(octreeStatsDetails()));
- addActionToQMenuAndActionHash(viewMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp()));
+
QMenu* developerMenu = addMenu("Developer");
@@ -538,10 +534,12 @@ Menu::Menu() {
statsRenderer.data(),
SLOT(toggleShowInjectedStreams()));
-#ifndef Q_OS_MAC
QMenu* helpMenu = addMenu("Help");
- QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp);
- connect(helpAction, SIGNAL(triggered()), qApp, SLOT(aboutApp()));
+ addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp()));
+
+#ifndef Q_OS_MAC
+ QAction* aboutAction = helpMenu->addAction(MenuOption::AboutApp);
+ connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutApp()));
#endif
}
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index 60fe5d4cd2..a4e644f20f 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -153,6 +153,7 @@ namespace MenuOption {
const QString EchoServerAudio = "Echo Server Audio";
const QString EditEntitiesHelp = "Edit Entities Help...";
const QString Enable3DTVMode = "Enable 3DTV Mode";
+ const QString EnableCharacterController = "Enable avatar collisions";
const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)";
const QString EnableVRMode = "Enable VR Mode";
const QString Entities = "Entities";
@@ -184,12 +185,9 @@ namespace MenuOption {
const QString Mirror = "Mirror";
const QString MuteAudio = "Mute Microphone";
const QString MuteEnvironment = "Mute Environment";
- const QString NewVoxelCullingMode = "New Voxel Culling Mode";
const QString NoFaceTracking = "None";
- const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity";
- const QString OctreeStats = "Voxel and Entity Statistics";
+ const QString OctreeStats = "Entity Statistics";
const QString OffAxisProjection = "Off-Axis Projection";
- const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
const QString OnlyDisplayTopTen = "Only Display Top Ten";
const QString Pair = "Pair";
const QString PipelineWarnings = "Log Render Pipeline Warnings";
@@ -233,13 +231,11 @@ namespace MenuOption {
const QString ScriptEditor = "Script Editor...";
const QString ScriptedMotorControl = "Enable Scripted Motor Control";
const QString ShowBordersEntityNodes = "Show Entity Nodes";
- const QString ShowBordersVoxelNodes = "Show Voxel Nodes";
const QString ShowIKConstraints = "Show IK Constraints";
const QString SimpleShadows = "Simple";
const QString SixenseEnabled = "Enable Hydra Support";
const QString SixenseMouseInput = "Enable Sixense Mouse Input";
const QString SixenseLasers = "Enable Sixense UI Lasers";
- const QString StandOnNearbyFloors = "Stand on nearby floors";
const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations";
const QString Stars = "Stars";
const QString Stats = "Stats";
@@ -251,7 +247,6 @@ namespace MenuOption {
const QString TransmitterDrive = "Transmitter Drive";
const QString TurnWithHead = "Turn using Head";
const QString PackageModel = "Package Model";
- const QString UserInterface = "User Interface";
const QString Visage = "Visage";
const QString Wireframe = "Wireframe";
}
diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp
index 49d4ae566f..f552d67a98 100644
--- a/interface/src/ModelPackager.cpp
+++ b/interface/src/ModelPackager.cpp
@@ -14,6 +14,8 @@
#include
#include
+#include
+
#include "ModelSelector.h"
#include "ModelPropertiesDialog.h"
diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h
index c62388f196..2c90395e56 100644
--- a/interface/src/ModelPackager.h
+++ b/interface/src/ModelPackager.h
@@ -15,8 +15,6 @@
#include
#include
-#include
-
#include "ui/ModelsBrowser.h"
class ModelPackager : public QObject {
diff --git a/interface/src/ModelPropertiesDialog.cpp b/interface/src/ModelPropertiesDialog.cpp
index de98407a2a..81fe9ce7fd 100644
--- a/interface/src/ModelPropertiesDialog.cpp
+++ b/interface/src/ModelPropertiesDialog.cpp
@@ -19,6 +19,7 @@
#include
#include
+#include
#include
#include "ModelPropertiesDialog.h"
diff --git a/interface/src/ModelPropertiesDialog.h b/interface/src/ModelPropertiesDialog.h
index 65c5be6c21..5af4d173f1 100644
--- a/interface/src/ModelPropertiesDialog.h
+++ b/interface/src/ModelPropertiesDialog.h
@@ -23,19 +23,6 @@ class QComboBox;
class QCheckBox;
class QVBoxLayout;
-static const QString NAME_FIELD = "name";
-static const QString FILENAME_FIELD = "filename";
-static const QString TEXDIR_FIELD = "texdir";
-static const QString LOD_FIELD = "lod";
-static const QString JOINT_INDEX_FIELD = "jointIndex";
-static const QString SCALE_FIELD = "scale";
-static const QString TRANSLATION_X_FIELD = "tx";
-static const QString TRANSLATION_Y_FIELD = "ty";
-static const QString TRANSLATION_Z_FIELD = "tz";
-static const QString JOINT_FIELD = "joint";
-static const QString FREE_JOINT_FIELD = "freeJoint";
-static const QString BLENDSHAPE_FIELD = "bs";
-
/// A dialog that allows customization of various model properties.
class ModelPropertiesDialog : public QDialog {
Q_OBJECT
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 2f42544f28..26b777b35b 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -81,7 +81,6 @@ MyAvatar::MyAvatar() :
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
- _enablePhysics(false),
_characterController(this),
_lookAtTargetAvatar(),
_shouldRender(true),
@@ -101,6 +100,7 @@ MyAvatar::MyAvatar() :
// connect to AddressManager signal for location jumps
connect(DependencyManager::get().data(), &AddressManager::locationChangeRequired,
this, &MyAvatar::goToLocation);
+ _characterController.setEnabled(true);
}
MyAvatar::~MyAvatar() {
@@ -147,10 +147,6 @@ void MyAvatar::update(float deltaTime) {
head->setAudioLoudness(audio->getLastInputLoudness());
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
- if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) {
- setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition()));
- }
-
simulate(deltaTime);
if (_feetTouchFloor) {
_skeletonModel.updateStandingFoot();
@@ -174,11 +170,7 @@ void MyAvatar::simulate(float deltaTime) {
{
PerformanceTimer perfTimer("transform");
updateOrientation(deltaTime);
- if (isPhysicsEnabled()) {
- updatePositionWithPhysics(deltaTime);
- } else {
- updatePosition(deltaTime);
- }
+ updatePosition(deltaTime);
}
{
@@ -484,26 +476,6 @@ void MyAvatar::loadLastRecording() {
_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 handle = _skeletonModel.createAnimationHandle();
_animationHandles.append(handle);
@@ -1258,128 +1230,38 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe
return localVelocity + motorEfficiency * deltaVelocity;
}
-const float NEARBY_FLOOR_THRESHOLD = 5.0f;
-
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
glm::quat rotation = getHead()->getCameraOrientation();
glm::vec3 localVelocity = glm::inverse(rotation) * _velocity;
- bool hasFloor = false;
- glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor);
+ bool isOnGround = _characterController.onGround();
+ glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isOnGround);
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
_velocity = rotation * newLocalVelocity;
_velocity += _thrust * deltaTime;
_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) {
@@ -1496,23 +1378,6 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition,
void MyAvatar::updateMotionBehavior() {
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)) {
_motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED;
} else {
@@ -1523,6 +1388,7 @@ void MyAvatar::updateMotionBehavior() {
} else {
_motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
}
+ _characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController));
_feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations);
}
@@ -1581,10 +1447,6 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
return palm->getPosition();
}
-void MyAvatar::preSimulation() {
- _characterController.setEnabled(_enablePhysics);
-}
-
void MyAvatar::clearDriveKeys() {
for (int i = 0; i < MAX_DRIVE_KEYS; ++i) {
_driveKeys[i] = 0.0f;
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index a37d1c6a30..99c0bdb5df 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -25,7 +25,7 @@ class MyAvatar : public Avatar {
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
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:
MyAvatar();
@@ -44,13 +44,11 @@ public:
// setters
void setLeanScale(float scale) { _leanScale = scale; }
- void setLocalGravity(glm::vec3 gravity);
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); }
// getters
float getLeanScale() const { return _leanScale; }
- glm::vec3 getGravity() const { return _gravity; }
Q_INVOKABLE glm::vec3 getDefaultEyePosition() const;
bool getShouldRenderLocally() const { return _shouldRender; }
float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); }
@@ -148,11 +146,6 @@ public:
const RecorderPointer getRecorder() const { return _recorder; }
const PlayerPointer getPlayer() const { return _player; }
-
- void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; }
- bool isPhysicsEnabled() { return _enablePhysics; }
- void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; }
- void preSimulation();
public slots:
void increaseSize();
@@ -209,7 +202,6 @@ private:
int _scriptedMotorFrame;
quint32 _motionBehaviors;
- bool _enablePhysics;
CharacterController _characterController;
QWeakPointer _lookAtTargetAvatar;
@@ -234,10 +226,8 @@ private:
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor);
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
void updatePosition(float deltaTime);
- void updatePositionWithPhysics(float deltaTime);
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
void maybeUpdateBillboard();
- void setGravity(const glm::vec3& gravity);
};
#endif // hifi_MyAvatar_h
diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp
index b5f57301f1..f082c6de47 100644
--- a/interface/src/devices/TV3DManager.cpp
+++ b/interface/src/devices/TV3DManager.cpp
@@ -104,7 +104,6 @@ void TV3DManager::display(Camera& whichCamera) {
// We only need to render the overlays to a texture once, then we just render the texture as a quad
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
applicationOverlay.renderOverlay(true);
- const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::UserInterface);
DependencyManager::get()->prepare();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -135,9 +134,7 @@ void TV3DManager::display(Camera& whichCamera) {
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
- if (displayOverlays) {
- applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
- }
+ applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
_activeEye = NULL;
}
glPopMatrix();
@@ -166,9 +163,7 @@ void TV3DManager::display(Camera& whichCamera) {
eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0));
Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO);
- if (displayOverlays) {
- applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
- }
+ applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov);
_activeEye = NULL;
}
glPopMatrix();
diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp
index 0c5941366f..d9adaf02e6 100644
--- a/interface/src/ui/ApplicationOverlay.cpp
+++ b/interface/src/ui/ApplicationOverlay.cpp
@@ -176,18 +176,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
_textureAspectRatio = (float)glCanvas->getDeviceWidth() / (float)glCanvas->getDeviceHeight();
//Handle fading and deactivation/activation of UI
- if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) {
- _alpha += FADE_SPEED;
- if (_alpha > 1.0f) {
- _alpha = 1.0f;
- }
- } else {
- _alpha -= FADE_SPEED;
- if (_alpha <= 0.0f) {
- _alpha = 0.0f;
- }
- }
-
+
// Render 2D overlay
glMatrixMode(GL_PROJECTION);
glDisable(GL_DEPTH_TEST);
diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h
index 64161e4a31..58b79adcda 100644
--- a/interface/src/ui/ApplicationOverlay.h
+++ b/interface/src/ui/ApplicationOverlay.h
@@ -114,7 +114,7 @@ private:
quint64 _lastMouseMove;
bool _magnifier;
- float _alpha;
+ float _alpha = 1.0f;
float _oculusUIRadius;
float _trailingAudioLoudness;
diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h
index a2feb98798..ad90c88aaa 100644
--- a/libraries/avatars/src/AvatarData.h
+++ b/libraries/avatars/src/AvatarData.h
@@ -61,21 +61,13 @@ typedef unsigned long long quint64;
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
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 =
AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED |
- AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED |
- AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
+ AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
// these bits will be expanded as features are exposed
const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
- AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED |
- AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY |
- AVATAR_MOTION_OBEY_LOCAL_GRAVITY |
- AVATAR_MOTION_STAND_ON_NEARBY_FLOORS;
+ AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
// Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of
@@ -365,8 +357,8 @@ protected:
HeadData* _headData;
HandData* _handData;
- QUrl _faceModelURL = DEFAULT_HEAD_MODEL_URL;
- QUrl _skeletonModelURL = DEFAULT_BODY_MODEL_URL;
+ QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit
+ QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit
QVector _attachmentData;
QString _displayName;
diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp
index a2c217c97d..1cd3bba73a 100644
--- a/libraries/fbx/src/FBXReader.cpp
+++ b/libraries/fbx/src/FBXReader.cpp
@@ -458,41 +458,6 @@ FBXNode parseFBX(QIODevice* device) {
return top;
}
-QVariantHash parseMapping(QIODevice* device) {
- QVariantHash properties;
-
- QByteArray line;
- while (!(line = device->readLine()).isEmpty()) {
- if ((line = line.trimmed()).startsWith('#')) {
- continue; // comment
- }
- QList sections = line.split('=');
- if (sections.size() < 2) {
- continue;
- }
- QByteArray name = sections.at(0).trimmed();
- if (sections.size() == 2) {
- properties.insertMulti(name, sections.at(1).trimmed());
-
- } else if (sections.size() == 3) {
- QVariantHash heading = properties.value(name).toHash();
- heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed());
- properties.insert(name, heading);
-
- } else if (sections.size() >= 4) {
- QVariantHash heading = properties.value(name).toHash();
- QVariantList contents;
- for (int i = 2; i < sections.size(); i++) {
- contents.append(sections.at(i).trimmed());
- }
- heading.insertMulti(sections.at(1).trimmed(), contents);
- properties.insert(name, heading);
- }
- }
-
- return properties;
-}
-
QVector createVec3Vector(const QVector& doubleVector) {
QVector values;
for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) {
@@ -2473,39 +2438,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
return geometry;
}
-QVariantHash readMapping(const QByteArray& data) {
- QBuffer buffer(const_cast(&data));
- buffer.open(QIODevice::ReadOnly);
- return parseMapping(&buffer);
-}
-
-QByteArray writeMapping(const QVariantHash& mapping) {
- QBuffer buffer;
- buffer.open(QIODevice::WriteOnly);
- for (QVariantHash::const_iterator first = mapping.constBegin(); first != mapping.constEnd(); first++) {
- QByteArray key = first.key().toUtf8() + " = ";
- QVariantHash hashValue = first.value().toHash();
- if (hashValue.isEmpty()) {
- buffer.write(key + first.value().toByteArray() + "\n");
- continue;
- }
- for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) {
- QByteArray extendedKey = key + second.key().toUtf8();
- QVariantList listValue = second.value().toList();
- if (listValue.isEmpty()) {
- buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n");
- continue;
- }
- buffer.write(extendedKey);
- for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) {
- buffer.write(" = " + third->toByteArray());
- }
- buffer.write("\n");
- }
- }
- return buffer.data();
-}
-
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) {
QBuffer buffer(const_cast(&model));
buffer.open(QIODevice::ReadOnly);
diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h
index ecce607575..6cb6b19c05 100644
--- a/libraries/fbx/src/FBXReader.h
+++ b/libraries/fbx/src/FBXReader.h
@@ -261,12 +261,6 @@ public:
Q_DECLARE_METATYPE(FBXGeometry)
-/// Reads an FST mapping from the supplied data.
-QVariantHash readMapping(const QByteArray& data);
-
-/// Writes an FST mapping to a byte array.
-QByteArray writeMapping(const QVariantHash& mapping);
-
/// Reads FBX geometry from the supplied model and mapping data.
/// \exception QString if an error occurs in parsing
FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f);
diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp
new file mode 100644
index 0000000000..f1ffe11996
--- /dev/null
+++ b/libraries/fbx/src/FSTReader.cpp
@@ -0,0 +1,99 @@
+//
+// FSTReader.cpp
+//
+//
+// Created by Clement on 3/26/15.
+// 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
+
+#include "FSTReader.h"
+
+QVariantHash parseMapping(QIODevice* device) {
+ QVariantHash properties;
+
+ QByteArray line;
+ while (!(line = device->readLine()).isEmpty()) {
+ if ((line = line.trimmed()).startsWith('#')) {
+ continue; // comment
+ }
+ QList sections = line.split('=');
+ if (sections.size() < 2) {
+ continue;
+ }
+ QByteArray name = sections.at(0).trimmed();
+ if (sections.size() == 2) {
+ properties.insertMulti(name, sections.at(1).trimmed());
+
+ } else if (sections.size() == 3) {
+ QVariantHash heading = properties.value(name).toHash();
+ heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed());
+ properties.insert(name, heading);
+
+ } else if (sections.size() >= 4) {
+ QVariantHash heading = properties.value(name).toHash();
+ QVariantList contents;
+ for (int i = 2; i < sections.size(); i++) {
+ contents.append(sections.at(i).trimmed());
+ }
+ heading.insertMulti(sections.at(1).trimmed(), contents);
+ properties.insert(name, heading);
+ }
+ }
+
+ return properties;
+}
+
+QVariantHash readMapping(const QByteArray& data) {
+ QBuffer buffer(const_cast(&data));
+ buffer.open(QIODevice::ReadOnly);
+ return parseMapping(&buffer);
+}
+
+void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) {
+ QByteArray key = it.key().toUtf8() + " = ";
+ QVariantHash hashValue = it.value().toHash();
+ if (hashValue.isEmpty()) {
+ buffer.write(key + it.value().toByteArray() + "\n");
+ return;
+ }
+ for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) {
+ QByteArray extendedKey = key + second.key().toUtf8();
+ QVariantList listValue = second.value().toList();
+ if (listValue.isEmpty()) {
+ buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n");
+ continue;
+ }
+ buffer.write(extendedKey);
+ for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) {
+ buffer.write(" = " + third->toByteArray());
+ }
+ buffer.write("\n");
+ }
+}
+
+QByteArray writeMapping(const QVariantHash& mapping) {
+ static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << SCALE_FIELD << FILENAME_FIELD
+ << TEXDIR_FIELD << JOINT_FIELD << FREE_JOINT_FIELD
+ << BLENDSHAPE_FIELD << JOINT_INDEX_FIELD;
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+
+ for (auto key : PREFERED_ORDER) {
+ auto it = mapping.find(key);
+ if (it != mapping.constEnd()) {
+ writeVariant(buffer, it);
+ }
+ }
+
+ for (auto it = mapping.constBegin(); it != mapping.constEnd(); it++) {
+ if (!PREFERED_ORDER.contains(it.key())) {
+ writeVariant(buffer, it);
+ }
+ }
+ return buffer.data();
+}
\ No newline at end of file
diff --git a/libraries/fbx/src/FSTReader.h b/libraries/fbx/src/FSTReader.h
new file mode 100644
index 0000000000..59559dea74
--- /dev/null
+++ b/libraries/fbx/src/FSTReader.h
@@ -0,0 +1,36 @@
+//
+// FSTReader.h
+//
+//
+// Created by Clement on 3/26/15.
+// 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_FSTReader_h
+#define hifi_FSTReader_h
+
+#include
+
+static const QString NAME_FIELD = "name";
+static const QString FILENAME_FIELD = "filename";
+static const QString TEXDIR_FIELD = "texdir";
+static const QString LOD_FIELD = "lod";
+static const QString JOINT_INDEX_FIELD = "jointIndex";
+static const QString SCALE_FIELD = "scale";
+static const QString TRANSLATION_X_FIELD = "tx";
+static const QString TRANSLATION_Y_FIELD = "ty";
+static const QString TRANSLATION_Z_FIELD = "tz";
+static const QString JOINT_FIELD = "joint";
+static const QString FREE_JOINT_FIELD = "freeJoint";
+static const QString BLENDSHAPE_FIELD = "bs";
+
+/// Reads an FST mapping from the supplied data.
+QVariantHash readMapping(const QByteArray& data);
+
+/// Writes an FST mapping to a byte array.
+QByteArray writeMapping(const QVariantHash& mapping);
+
+#endif // hifi_FSTReader_h
\ No newline at end of file
diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp
index 5858c0926d..46c6418c63 100644
--- a/libraries/networking/src/AccountManager.cpp
+++ b/libraries/networking/src/AccountManager.cpp
@@ -282,7 +282,7 @@ void AccountManager::processReply() {
} else {
passErrorToCallback(requestReply);
}
- delete requestReply;
+ requestReply->deleteLater();
}
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp
index e84df7d644..09c6b5599f 100644
--- a/libraries/physics/src/CharacterController.cpp
+++ b/libraries/physics/src/CharacterController.cpp
@@ -40,6 +40,24 @@ static btVector3 getNormalizedVector(const btVector3& v) {
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 {
public:
btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
@@ -199,9 +217,7 @@ CharacterController::CharacterController(AvatarData* avatarData) {
assert(avatarData);
_avatarData = avatarData;
- // cache the "PhysicsEnabled" state of _avatarData
_enabled = false;
-
_ghostObject = NULL;
_convexShape = NULL;
@@ -210,11 +226,13 @@ CharacterController::CharacterController(AvatarData* avatarData) {
_velocityTimeInterval = 0.0f;
_verticalVelocity = 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.
- _jumpSpeed = 7.0f;
- _wasOnGround = false;
- _wasJumping = false;
+ _jumpSpeed = 5.0f;
+ _isOnGround = false;
+ _isJumping = false;
+ _isHovering = true;
+ _jumpToHoverStart = 0;
setMaxSlope(btRadians(45.0f));
_lastStepUp = 0.0f;
_pendingFlags = 0;
@@ -325,6 +343,26 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl
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) {
// phase 1: up
@@ -334,7 +372,7 @@ void CharacterController::stepUp(btCollisionWorld* world) {
btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS);
start.setOrigin(_currentPosition + up * (_convexShape->getMargin() + _addedMargin));
- _targetPosition = _currentPosition + up * _stepHeight;
+ _targetPosition = _currentPosition + up * _stepUpHeight;
end.setIdentity();
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.
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);
} else {
- _lastStepUp = _stepHeight;
+ _lastStepUp = _stepUpHeight;
_currentPosition = _targetPosition;
}
} else {
_currentPosition = _targetPosition;
- _lastStepUp = _stepHeight;
+ _lastStepUp = _stepUpHeight;
}
}
@@ -411,12 +449,12 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt
btScalar margin = _convexShape->getMargin();
_convexShape->setMargin(margin + _addedMargin);
- const btScalar MIN_STEP_DISTANCE = 0.0001f;
+ const btScalar MIN_STEP_DISTANCE_SQUARED = 1.0e-6f;
btVector3 step = _targetPosition - _currentPosition;
btScalar stepLength2 = step.length2();
int maxIter = 10;
- while (stepLength2 > MIN_STEP_DISTANCE && maxIter-- > 0) {
+ while (stepLength2 > MIN_STEP_DISTANCE_SQUARED && maxIter-- > 0) {
start.setOrigin(_currentPosition);
end.setOrigin(_targetPosition);
@@ -477,13 +515,16 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
end.setOrigin(_targetPosition);
_ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
+ _isOnGround = false;
if (callback.hasHit()) {
_currentPosition += callback.m_closestHitFraction * step;
_verticalVelocity = 0.0f;
_verticalOffset = 0.0f;
- _wasJumping = false;
- } else if (!_wasJumping) {
+ _isJumping = false;
+ _isOnGround = true;
+ } else if (!_isJumping) {
// sweep again for floor within downStep threshold
+ step = -_stepDownHeight * up;
StepDownConvexResultCallback callback2 (_ghostObject,
up,
_currentPosition, step,
@@ -495,8 +536,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
_currentPosition = _targetPosition;
- btVector3 oldPosition = _currentPosition;
- step = (- _stepHeight) * up;
_targetPosition = _currentPosition + step;
start.setOrigin(_currentPosition);
@@ -507,10 +546,10 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
_currentPosition += callback2.m_closestHitFraction * step;
_verticalVelocity = 0.0f;
_verticalOffset = 0.0f;
- _wasJumping = false;
+ _isJumping = false;
+ _isOnGround = true;
} else {
- // nothing to step down on, so remove the stepUp effect
- _currentPosition = oldPosition - _lastStepUp * up;
+ // nothing to step down on
_lastStepUp = 0.0f;
}
} else {
@@ -534,8 +573,8 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity,
void CharacterController::reset(btCollisionWorld* collisionWorld) {
_verticalVelocity = 0.0;
_verticalOffset = 0.0;
- _wasOnGround = false;
- _wasJumping = false;
+ _isOnGround = false;
+ _isJumping = false;
_walkDirection.setValue(0,0,0);
_velocityTimeInterval = 0.0;
@@ -581,14 +620,17 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
return; // no motion
}
- _wasOnGround = onGround();
-
// Update fall velocity.
- _verticalVelocity -= _gravity * dt;
- if (_verticalVelocity > _jumpSpeed) {
- _verticalVelocity = _jumpSpeed;
- } else if (_verticalVelocity < -_maxFallSpeed) {
- _verticalVelocity = -_maxFallSpeed;
+ if (_isHovering) {
+ const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f;
+ _verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE);
+ } else {
+ _verticalVelocity -= _gravity * dt;
+ if (_verticalVelocity > _jumpSpeed) {
+ _verticalVelocity = _jumpSpeed;
+ } else if (_verticalVelocity < -_maxFallSpeed) {
+ _verticalVelocity = -_maxFallSpeed;
+ }
}
_verticalOffset = _verticalVelocity * dt;
@@ -600,11 +642,14 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
// (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
+ scanDown(collisionWorld);
+
stepUp(collisionWorld);
// compute substep and decrement total interval
btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval;
_velocityTimeInterval -= dt;
+ _stepDt += dt;
// stepForward substep
btVector3 move = _walkDirection * dtMoving;
@@ -629,11 +674,25 @@ void CharacterController::setMaxJumpHeight(btScalar maxJumpHeight) {
}
bool CharacterController::canJump() const {
- return onGround();
+ return _isOnGround;
}
void CharacterController::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) {
@@ -654,7 +713,7 @@ btScalar CharacterController::getMaxSlope() const {
}
bool CharacterController::onGround() const {
- return _enabled && _verticalVelocity == 0.0f && _verticalOffset == 0.0f;
+ return _isOnGround;
}
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) {
// shape hasn't changed --> nothing to do
} else {
- // we always need to: REMOVE when UPDATE_SHAPE, to avoid deleting shapes out from under the PhysicsEngine
- _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION
- | PENDING_FLAG_UPDATE_SHAPE;
- // but only need to ADD back when we happen to be enabled
+ if (_dynamicsWorld) {
+ // must REMOVE from world prior to shape update
+ _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
+ }
+ _pendingFlags |= PENDING_FLAG_UPDATE_SHAPE;
+ // only need to ADD back when we happen to be enabled
if (_enabled) {
_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.
// Setting the ADD bit here works for all cases so we don't even bother checking other bits.
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
+ _isHovering = true;
} else {
- // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case
- // it was previously set by something else (e.g. an UPDATE_SHAPE event).
- _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
+ if (_dynamicsWorld) {
+ _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
+ }
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
+ _isOnGround = false;
}
_enabled = enabled;
}
@@ -729,17 +792,23 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
}
_dynamicsWorld = world;
if (_dynamicsWorld) {
- _pendingFlags &= ~ (PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_JUMP);
+ _pendingFlags &= ~ PENDING_FLAG_JUMP;
_dynamicsWorld->addCollisionObject(getGhostObject(),
btBroadphaseProxy::CharacterFilter,
btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
_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_REMOVE_FROM_SIMULATION;
+ _pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION;
}
} 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()),
glmToBullet(_avatarData->getPosition())));
// stepHeight affects the heights of ledges that the character can ascend
- // however the actual ledge height is some function of _stepHeight
- // due to character shape and this CharacterController algorithm
- // (the function is approximately 2*_stepHeight)
- _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f;
+ _stepUpHeight = _radius + 0.25f * _halfHeight + 0.1f;
+ _stepDownHeight = _radius;
// create new shape
_convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
@@ -799,9 +866,12 @@ void CharacterController::preSimulation(btScalar timeStep) {
_pendingFlags &= ~ PENDING_FLAG_JUMP;
if (canJump()) {
_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) {
const btTransform& avatarTransform = _ghostObject->getWorldTransform();
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->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset);
+ _avatarData->setPosition(position - rotation * _shapeLocalOffset);
}
}
diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h
index 323529b1cd..eeaa5836dd 100644
--- a/libraries/physics/src/CharacterController.h
+++ b/libraries/physics/src/CharacterController.h
@@ -59,7 +59,8 @@ protected:
btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization)
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
@@ -71,6 +72,7 @@ protected:
btVector3 _currentPosition;
btQuaternion _currentRotation;
btVector3 _targetPosition;
+ glm::vec3 _lastPosition;
btScalar _lastStepUp;
///keep track of the contact manifolds
@@ -80,9 +82,12 @@ protected:
btVector3 _floorNormal; // points from object to character
bool _enabled;
- bool _wasOnGround;
- bool _wasJumping;
+ bool _isOnGround;
+ bool _isJumping;
+ bool _isHovering;
+ quint64 _jumpToHoverStart;
btScalar _velocityTimeInterval;
+ btScalar _stepDt;
uint32_t _pendingFlags;
glm::vec3 _shapeLocalOffset;
@@ -95,6 +100,7 @@ protected:
btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal);
bool recoverFromPenetration(btCollisionWorld* collisionWorld);
+ void scanDown(btCollisionWorld* collisionWorld);
void stepUp(btCollisionWorld* collisionWorld);
void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0));
void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove);
@@ -161,6 +167,7 @@ public:
bool needsRemoval() const;
bool needsAddition() const;
void setEnabled(bool enabled);
+ bool isEnabled() const { return _enabled; }
void setDynamicsWorld(btDynamicsWorld* world);
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp
index c18dfa4d5f..f8fc4633cc 100644
--- a/libraries/render-utils/src/GeometryCache.cpp
+++ b/libraries/render-utils/src/GeometryCache.cpp
@@ -21,6 +21,7 @@
#include
#include
+#include
#include
#include "TextureCache.h"
diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp
index 716af1d188..831db73a0a 100644
--- a/libraries/script-engine/src/ScriptEngine.cpp
+++ b/libraries/script-engine/src/ScriptEngine.cpp
@@ -360,10 +360,6 @@ void ScriptEngine::init() {
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT)));
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) {
diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp
index 8755527860..3054472a3c 100644
--- a/libraries/script-engine/src/XMLHttpRequestClass.cpp
+++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp
@@ -22,6 +22,8 @@
#include "XMLHttpRequestClass.h"
#include "ScriptEngine.h"
+const QString METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/";
+
Q_DECLARE_METATYPE(QByteArray*)
XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) :
@@ -207,7 +209,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
notImplemented();
}
} 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();
if (accountManager.hasValidAccessToken()) {