Add new LookAt camera

This commit is contained in:
luiscuenca 2019-09-05 16:36:14 -07:00
parent d88c43614c
commit ff8f2c5c16
No known key found for this signature in database
GPG key ID: 2387ECD129A6961D
5 changed files with 65 additions and 23 deletions

View file

@ -709,6 +709,7 @@ static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson";
static const QString STATE_CAMERA_THIRD_PERSON = "CameraThirdPerson"; static const QString STATE_CAMERA_THIRD_PERSON = "CameraThirdPerson";
static const QString STATE_CAMERA_ENTITY = "CameraEntity"; static const QString STATE_CAMERA_ENTITY = "CameraEntity";
static const QString STATE_CAMERA_INDEPENDENT = "CameraIndependent"; static const QString STATE_CAMERA_INDEPENDENT = "CameraIndependent";
static const QString STATE_CAMERA_LOOK_AT = "CameraLookAt";
static const QString STATE_SNAP_TURN = "SnapTurn"; static const QString STATE_SNAP_TURN = "SnapTurn";
static const QString STATE_ADVANCED_MOVEMENT_CONTROLS = "AdvancedMovement"; static const QString STATE_ADVANCED_MOVEMENT_CONTROLS = "AdvancedMovement";
static const QString STATE_GROUNDED = "Grounded"; static const QString STATE_GROUNDED = "Grounded";
@ -925,7 +926,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<AudioInjectorManager>(); DependencyManager::set<AudioInjectorManager>();
DependencyManager::set<MessagesClient>(); DependencyManager::set<MessagesClient>();
controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR,
STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_CAMERA_LOOK_AT,
STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED,
STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID, STATE_LEFT_HAND_DOMINANT, STATE_RIGHT_HAND_DOMINANT, STATE_STRAFE_ENABLED } }); STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID, STATE_LEFT_HAND_DOMINANT, STATE_RIGHT_HAND_DOMINANT, STATE_STRAFE_ENABLED } });
DependencyManager::set<UserInputMapper>(); DependencyManager::set<UserInputMapper>();
@ -1872,6 +1873,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_applicationStateDevice->setInputVariant(STATE_CAMERA_THIRD_PERSON, []() -> float { _applicationStateDevice->setInputVariant(STATE_CAMERA_THIRD_PERSON, []() -> float {
return qApp->getCamera().getMode() == CAMERA_MODE_THIRD_PERSON ? 1 : 0; return qApp->getCamera().getMode() == CAMERA_MODE_THIRD_PERSON ? 1 : 0;
}); });
// Look at camera and third person camera use the same input mapping
_applicationStateDevice->setInputVariant(STATE_CAMERA_THIRD_PERSON, []() -> float {
return qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT ? 1 : 0;
});
_applicationStateDevice->setInputVariant(STATE_CAMERA_ENTITY, []() -> float { _applicationStateDevice->setInputVariant(STATE_CAMERA_ENTITY, []() -> float {
return qApp->getCamera().getMode() == CAMERA_MODE_ENTITY ? 1 : 0; return qApp->getCamera().getMode() == CAMERA_MODE_ENTITY ? 1 : 0;
}); });
@ -3607,8 +3612,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()); _myCamera.setPosition(myAvatar->getDefaultEyePosition());
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation()); _myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
} }
} } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON || _myCamera.getMode() == CAMERA_MODE_LOOK_AT) {
else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
if (isHMDMode()) { if (isHMDMode()) {
if (!_thirdPersonHMDCameraBoomValid) { if (!_thirdPersonHMDCameraBoomValid) {
@ -3625,22 +3629,24 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
_myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat))); _myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat)));
_myCamera.setPosition(extractTranslation(worldCameraMat)); _myCamera.setPosition(extractTranslation(worldCameraMat));
} } else {
else {
_thirdPersonHMDCameraBoomValid = false; _thirdPersonHMDCameraBoomValid = false;
if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
_myCamera.setOrientation(myAvatar->getHead()->getOrientation()); _myCamera.setOrientation(myAvatar->getHead()->getOrientation());
if (isOptionChecked(MenuOption::CenterPlayerInView)) { if (isOptionChecked(MenuOption::CenterPlayerInView)) {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ _myCamera.getOrientation() * boomOffset);
} else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ myAvatar->getWorldOrientation() * boomOffset);
}
} else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition() _myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ _myCamera.getOrientation() * boomOffset); + myAvatar->getLookAtOffset() * boomOffset);
} _myCamera.lookAt(myAvatar->getDefaultEyePosition());
else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ myAvatar->getWorldOrientation() * boomOffset);
} }
} }
} } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
_thirdPersonHMDCameraBoomValid= false; _thirdPersonHMDCameraBoomValid= false;
if (isHMDMode()) { if (isHMDMode()) {

View file

@ -451,7 +451,7 @@ QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropF
_globalBoundingBoxDimensions.y = _characterController.getCapsuleHalfHeight(); _globalBoundingBoxDimensions.y = _characterController.getCapsuleHalfHeight();
_globalBoundingBoxDimensions.z = _characterController.getCapsuleRadius(); _globalBoundingBoxDimensions.z = _characterController.getCapsuleRadius();
_globalBoundingBoxOffset = _characterController.getCapsuleLocalOffset(); _globalBoundingBoxOffset = _characterController.getCapsuleLocalOffset();
if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT || mode == CAMERA_MODE_LOOK_AT) {
// fake the avatar position that is sent up to the AvatarMixer // fake the avatar position that is sent up to the AvatarMixer
glm::vec3 oldPosition = getWorldPosition(); glm::vec3 oldPosition = getWorldPosition();
setWorldPosition(getSkeletonPosition()); setWorldPosition(getSkeletonPosition());
@ -2556,7 +2556,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
glm::vec3 MyAvatar::getSkeletonPosition() const { glm::vec3 MyAvatar::getSkeletonPosition() const {
CameraMode mode = qApp->getCamera().getMode(); CameraMode mode = qApp->getCamera().getMode();
if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT || mode == CAMERA_MODE_LOOK_AT) {
// The avatar is rotated PI about the yAxis, so we have to correct for it // The avatar is rotated PI about the yAxis, so we have to correct for it
// to get the skeleton offset contribution in the world-frame. // to get the skeleton offset contribution in the world-frame.
const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
@ -3322,11 +3322,15 @@ void MyAvatar::setRotationThreshold(float angleRadians) {
} }
void MyAvatar::updateOrientation(float deltaTime) { void MyAvatar::updateOrientation(float deltaTime) {
// Smoothly rotate body with arrow keys // Smoothly rotate body with arrow keys
float targetSpeed = getDriveKey(YAW) * _yawSpeed; float targetSpeed = getDriveKey(YAW) * _yawSpeed;
bool faceForward = false;
if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT) {
targetSpeed = (getDriveKey(YAW) + getDriveKey(STEP_YAW) + getDriveKey(DELTA_YAW)) * _yawSpeed;
faceForward = getDriveKey(TRANSLATE_Z) != 0.0f;
}
if (targetSpeed != 0.0f) { if (targetSpeed != 0.0f) {
const float ROTATION_RAMP_TIMESCALE = 0.1f; const float ROTATION_RAMP_TIMESCALE = 0.5f;
float blend = deltaTime / ROTATION_RAMP_TIMESCALE; float blend = deltaTime / ROTATION_RAMP_TIMESCALE;
if (blend > 1.0f) { if (blend > 1.0f) {
blend = 1.0f; blend = 1.0f;
@ -3349,7 +3353,9 @@ void MyAvatar::updateOrientation(float deltaTime) {
float totalBodyYaw = _bodyYawDelta * deltaTime; float totalBodyYaw = _bodyYawDelta * deltaTime;
// Rotate directly proportional to delta yaw and delta pitch from right-click mouse movement. // Rotate directly proportional to delta yaw and delta pitch from right-click mouse movement.
totalBodyYaw += getDriveKey(DELTA_YAW) * _yawSpeed / YAW_SPEED_DEFAULT; if (qApp->getCamera().getMode() != CAMERA_MODE_LOOK_AT) {
totalBodyYaw += getDriveKey(DELTA_YAW) * _yawSpeed / YAW_SPEED_DEFAULT;
}
// Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll // Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
// get an instantaneous 15 degree turn. If you keep holding the key down you'll get another // get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
@ -3394,7 +3400,19 @@ void MyAvatar::updateOrientation(float deltaTime) {
// update body orientation by movement inputs // update body orientation by movement inputs
glm::quat initialOrientation = getOrientationOutbound(); glm::quat initialOrientation = getOrientationOutbound();
setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)))); if (qApp->getCamera().getMode() != CAMERA_MODE_LOOK_AT) {
setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f))));
} else {
// Set look at vector
float pitchIncrement = getDriveKey(PITCH) * _pitchSpeed * deltaTime
+ getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT;
_lookAtOffsetYaw = _lookAtOffsetYaw * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)));
_lookAtOffsetPitch = _lookAtOffsetPitch * glm::quat(glm::radians(glm::vec3(pitchIncrement, 0.0f, 0.0f)));
if (faceForward) {
setWorldOrientation(glm::slerp(getWorldOrientation(), _lookAtOffsetYaw, 0.25f));
}
}
if (snapTurn) { if (snapTurn) {
// Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position.
@ -3417,7 +3435,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
head->setBaseRoll(ROLL(euler)); head->setBaseRoll(ROLL(euler));
} else { } else {
head->setBaseYaw(0.0f); head->setBaseYaw(0.0f);
head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime
+ getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT); + getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT);
head->setBaseRoll(0.0f); head->setBaseRoll(0.0f);
} }
@ -3486,7 +3504,15 @@ glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 rig
} }
} else { } else {
// Desktop mode. // Desktop mode.
direction = (zSpeed * forward) + (xSpeed * right); if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT) {
//glm::vec3 frontVector = getWorldOrientation() * IDENTITY_FORWARD;
//glm::vec3 frontVectorXY = glm::normalize(glm::vec3(frontVector.x, frontVector.y, 0.0f));
//direction = (zSpeed * forward) + (1.0f - glm::abs(glm::dot(frontVectorXY, forward))) * right;
direction = (zSpeed * forward);
} else {
direction = (zSpeed * forward) + (xSpeed * right);
}
auto length = glm::length(direction); auto length = glm::length(direction);
if (length > EPSILON) { if (length > EPSILON) {
direction /= length; direction /= length;

View file

@ -1747,6 +1747,8 @@ public:
glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); } glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); }
void prepareAvatarEntityDataForReload(); void prepareAvatarEntityDataForReload();
glm::quat getLookAtOffset() { return _lookAtOffsetYaw * _lookAtOffsetPitch; }
/**jsdoc /**jsdoc
* Creates a new grab that grabs an entity. * Creates a new grab that grabs an entity.
* @function MyAvatar.grab * @function MyAvatar.grab
@ -2618,6 +2620,9 @@ private:
glm::vec3 _trackedHeadPosition; glm::vec3 _trackedHeadPosition;
glm::quat _lookAtOffsetPitch;
glm::quat _lookAtOffsetYaw;
Setting::Handle<float> _realWorldFieldOfView; Setting::Handle<float> _realWorldFieldOfView;
Setting::Handle<bool> _useAdvancedMovementControls; Setting::Handle<bool> _useAdvancedMovementControls;
Setting::Handle<bool> _showPlayArea; Setting::Handle<bool> _showPlayArea;

View file

@ -67,6 +67,8 @@ CameraMode stringToMode(const QString& mode) {
return CAMERA_MODE_INDEPENDENT; return CAMERA_MODE_INDEPENDENT;
} else if (mode == "entity") { } else if (mode == "entity") {
return CAMERA_MODE_ENTITY; return CAMERA_MODE_ENTITY;
} else if (mode == "look at") {
return CAMERA_MODE_LOOK_AT;
} }
return CAMERA_MODE_NULL; return CAMERA_MODE_NULL;
} }
@ -82,6 +84,8 @@ QString modeToString(CameraMode mode) {
return "independent"; return "independent";
} else if (mode == CAMERA_MODE_ENTITY) { } else if (mode == CAMERA_MODE_ENTITY) {
return "entity"; return "entity";
} else if (mode == CAMERA_MODE_LOOK_AT) {
return "look at";
} }
return "unknown"; return "unknown";
} }

View file

@ -23,6 +23,7 @@ enum CameraMode
CAMERA_MODE_MIRROR, CAMERA_MODE_MIRROR,
CAMERA_MODE_INDEPENDENT, CAMERA_MODE_INDEPENDENT,
CAMERA_MODE_ENTITY, CAMERA_MODE_ENTITY,
CAMERA_MODE_LOOK_AT,
NUM_CAMERA_MODES NUM_CAMERA_MODES
}; };