Skip to content

Commit

Permalink
3rd person camera clipping option
Browse files Browse the repository at this point in the history
  • Loading branch information
HifiExperiments committed Jan 7, 2025
1 parent 27f4ce4 commit 18c7320
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 5 deletions.
30 changes: 30 additions & 0 deletions interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,36 @@ Flickable {
}
}
}
Item {
Layout.preferredWidth: parent.width
Layout.preferredHeight: 35
Layout.topMargin: 16

HifiStylesUit.RalewayRegular {
id: enableCameraClippingHeader
text: "3rd Person Camera Clipping"
anchors.left: parent.left
anchors.top: parent.top
width: 200
height: parent.height
size: 16
color: "#FFFFFF"
}

HifiControlsUit.CheckBox {
id: enableCameraClipping
checked: Render.cameraClippingEnabled
boxSize: 16
spacing: -1
colorScheme: hifi.colorSchemes.dark
anchors.left: enableCameraClippingHeader.right
anchors.leftMargin: 20
anchors.top: parent.top
onCheckedChanged: {
Render.cameraClippingEnabled = enableCameraClipping.checked;
}
}
}
}

ColumnLayout {
Expand Down
49 changes: 46 additions & 3 deletions interface/src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
#include <raypick/PointerScriptingInterface.h>
#include <raypick/RayPick.h>
#include <raypick/MouseTransformNode.h>
#include <CameraRootTransformNode.h>

#include "ResourceRequestObserver.h"

Expand Down Expand Up @@ -1004,6 +1005,7 @@ Application::Application(
_previousSessionCrashed(false), //setupEssentials(parser, false)),
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
_cameraClippingEnabled("cameraClippingEnabled", false),
_hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT),
_desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT),
_firstRun(Settings::firstRun, true),
Expand Down Expand Up @@ -2499,6 +2501,17 @@ void Application::initialize(const QCommandLineParser &parser) {
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
});

// Setup the camera clipping ray pick
{
_prevCameraClippingEnabled = _cameraClippingEnabled.get();
auto cameraRayPick = std::make_shared<RayPick>(Vectors::ZERO, -Vectors::UP,
PickFilter(PickScriptingInterface::getPickEntities() |
PickScriptingInterface::getPickLocalEntities()),
MyAvatar::ZOOM_MAX, 0.0f, _prevCameraClippingEnabled);
cameraRayPick->parentTransform = std::make_shared<CameraRootTransformNode>();
_cameraClippingRayPickID = DependencyManager::get<PickManager>()->addPick(PickQuery::Ray, cameraRayPick);
}

BillboardModeHelpers::setBillboardRotationOperator([](const glm::vec3& position, const glm::quat& rotation,
BillboardMode billboardMode, const glm::vec3& frustumPos, bool rotate90x) {
const glm::quat ROTATE_90X = glm::angleAxis(-(float)M_PI_2, Vectors::RIGHT);
Expand Down Expand Up @@ -3684,9 +3697,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
PROFILE_RANGE(render, __FUNCTION__);
PerformanceTimer perfTimer("updateCamera");

glm::vec3 boomOffset;
auto myAvatar = getMyAvatar();
boomOffset = myAvatar->getModelScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;

// The render mode is default or mirror if the camera is in mirror mode, assigned further below
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
Expand Down Expand Up @@ -3725,6 +3736,16 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
_myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat)));
_myCamera.setPosition(extractTranslation(worldCameraMat));
} else {
float boomLength = myAvatar->getBoomLength();
if (getCameraClippingEnabled()) {
auto result =
DependencyManager::get<PickManager>()->getPrevPickResultTyped<RayPickResult>(_cameraClippingRayPickID);
if (result && result->doesIntersect()) {
const float CAMERA_CLIPPING_EPSILON = 0.1f;
boomLength = std::min(boomLength, result->distance - CAMERA_CLIPPING_EPSILON);
}
}
glm::vec3 boomOffset = myAvatar->getModelScale() * boomLength * -IDENTITY_FORWARD;
_thirdPersonHMDCameraBoomValid = false;
if (mode == CAMERA_MODE_THIRD_PERSON) {
_myCamera.setOrientation(myAvatar->getHead()->getOrientation());
Expand Down Expand Up @@ -3802,7 +3823,19 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
_myCamera.update();
}

renderArgs._cameraMode = (int8_t)_myCamera.getMode();
renderArgs._cameraMode = (int8_t)mode;

const bool shouldEnableCameraClipping =
(mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) && !isHMDMode() &&
getCameraClippingEnabled();
if (_prevCameraClippingEnabled != shouldEnableCameraClipping) {
if (shouldEnableCameraClipping) {
DependencyManager::get<PickManager>()->enablePick(_cameraClippingRayPickID);
} else {
DependencyManager::get<PickManager>()->disablePick(_cameraClippingRayPickID);
}
_prevCameraClippingEnabled = shouldEnableCameraClipping;
}
}

void Application::runTests() {
Expand All @@ -3817,6 +3850,16 @@ void Application::setFieldOfView(float fov) {
}
}

void Application::setCameraClippingEnabled(bool enabled) {
_cameraClippingEnabled.set(enabled);
_prevCameraClippingEnabled = enabled;
if (enabled) {
DependencyManager::get<PickManager>()->enablePick(_cameraClippingRayPickID);
} else {
DependencyManager::get<PickManager>()->disablePick(_cameraClippingRayPickID);
}
}

void Application::setHMDTabletScale(float hmdTabletScale) {
_hmdTabletScale.set(hmdTabletScale);
}
Expand Down
7 changes: 7 additions & 0 deletions interface/src/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ class Application : public QApplication,
float getFieldOfView() { return _fieldOfView.get(); }
void setFieldOfView(float fov);

bool getCameraClippingEnabled() { return _cameraClippingEnabled.get(); }
void setCameraClippingEnabled(bool enabled);

float getHMDTabletScale() { return _hmdTabletScale.get(); }
void setHMDTabletScale(float hmdTabletScale);
float getDesktopTabletScale() { return _desktopTabletScale.get(); }
Expand Down Expand Up @@ -719,6 +722,7 @@ private slots:

Setting::Handle<QString> _previousScriptLocation;
Setting::Handle<float> _fieldOfView;
Setting::Handle<float> _cameraClippingEnabled;
Setting::Handle<float> _hmdTabletScale;
Setting::Handle<float> _desktopTabletScale;
Setting::Handle<bool> _firstRun;
Expand Down Expand Up @@ -893,5 +897,8 @@ private slots:
DiscordPresence* _discordPresence{ nullptr };

bool _profilingInitialized { false };

bool _prevCameraClippingEnabled { false };
unsigned int _cameraClippingRayPickID;
};
#endif // hifi_Application_h
48 changes: 48 additions & 0 deletions interface/src/CameraRootTransformNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// Created by HifiExperiments on 10/30/2024
// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

#include "CameraRootTransformNode.h"

#include "Application.h"
#include "DependencyManager.h"
#include "avatar/AvatarManager.h"
#include "avatar/MyAvatar.h"

Transform CameraRootTransformNode::getTransform() {
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();

glm::vec3 pos;
glm::quat ori;

CameraMode mode = qApp->getCamera().getMode();
if (mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_THIRD_PERSON) {
pos = myAvatar->getDefaultEyePosition();
ori = myAvatar->getHeadOrientation();
} else if (mode == CAMERA_MODE_FIRST_PERSON_LOOK_AT) {
pos = myAvatar->getCameraEyesPosition(0.0f);
ori = myAvatar->getLookAtRotation();
} else {
ori = myAvatar->getLookAtRotation();
pos = myAvatar->getLookAtPivotPoint();

if (mode == CAMERA_MODE_SELFIE) {
ori = ori * glm::angleAxis(PI, ori * Vectors::UP);
}
}

ori = ori * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT);

glm::vec3 scale = glm::vec3(myAvatar->scaleForChildren());
return Transform(ori, scale, pos);
}

QVariantMap CameraRootTransformNode::toVariantMap() const {
QVariantMap map;
map["joint"] = "CameraRoot";
return map;
}
20 changes: 20 additions & 0 deletions interface/src/CameraRootTransformNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Created by HifiExperiments on 10/30/2024
// Copyright 2024 Overte e.V.
//
// 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_CameraRootTransformNode_h
#define hifi_CameraRootTransformNode_h

#include "TransformNode.h"

class CameraRootTransformNode : public TransformNode {
public:
CameraRootTransformNode() {}
Transform getTransform() override;
QVariantMap toVariantMap() const override;
};

#endif // hifi_CameraRootTransformNode_h
4 changes: 4 additions & 0 deletions interface/src/raypick/PickScriptingInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "ParabolaPick.h"
#include "CollisionPick.h"

#include "CameraRootTransformNode.h"
#include "SpatialParentFinder.h"
#include "PickTransformNode.h"
#include "MouseTransformNode.h"
Expand Down Expand Up @@ -537,6 +538,9 @@ void PickScriptingInterface::setParentTransform(std::shared_ptr<PickQuery> pick,
} else if (joint == "Avatar") {
pick->parentTransform = std::make_shared<MyAvatarHeadTransformNode>();
return;
} else if (joint == "CameraRoot") {
pick->parentTransform = std::make_shared<CameraRootTransformNode>();
return;
} else {
parentUuid = myAvatar->getSessionUUID();
parentJointIndex = myAvatar->getJointIndex(joint);
Expand Down
7 changes: 7 additions & 0 deletions interface/src/scripting/RenderScriptingInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,13 @@ void RenderScriptingInterface::setVerticalFieldOfView(float fieldOfView) {
}
}

void RenderScriptingInterface::setCameraClippingEnabled(bool enabled) {
if (qApp->getCameraClippingEnabled() != enabled) {
qApp->setCameraClippingEnabled(enabled);
emit settingsChanged();
}
}

QStringList RenderScriptingInterface::getScreens() const {
QStringList screens;

Expand Down
18 changes: 17 additions & 1 deletion interface/src/scripting/RenderScriptingInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* they're disabled.
* @property {integer} antialiasingMode - The active anti-aliasing mode.
* @property {number} viewportResolutionScale - The view port resolution scale, <code>&gt; 0.0</code>.
* @property {boolean} cameraClippingEnabled - <code>true</code> if third person camera clipping is enabled, <code>false</code> if it's disabled.
*/
class RenderScriptingInterface : public QObject {
Q_OBJECT
Expand All @@ -49,6 +50,7 @@ class RenderScriptingInterface : public QObject {
Q_PROPERTY(AntialiasingConfig::Mode antialiasingMode READ getAntialiasingMode WRITE setAntialiasingMode NOTIFY settingsChanged)
Q_PROPERTY(float viewportResolutionScale READ getViewportResolutionScale WRITE setViewportResolutionScale NOTIFY settingsChanged)
Q_PROPERTY(float verticalFieldOfView READ getVerticalFieldOfView WRITE setVerticalFieldOfView NOTIFY settingsChanged)
Q_PROPERTY(bool cameraClippingEnabled READ getCameraClippingEnabled WRITE setCameraClippingEnabled NOTIFY settingsChanged)

public:
RenderScriptingInterface();
Expand Down Expand Up @@ -261,7 +263,21 @@ public slots:
* @function Render.setVerticalFieldOfView
* @param {number} fieldOfView - The vertical field of view in degrees to set.
*/
void setVerticalFieldOfView( float fieldOfView );
void setVerticalFieldOfView(float fieldOfView);

/*@jsdoc
* Gets whether or not third person camera clipping is enabled.
* @function Render.getCameraClippingEnabled
* @returns {boolean} <code>true</code> if camera clipping is enabled, <code>false</code> if it's disabled.
*/
bool getCameraClippingEnabled() { return qApp->getCameraClippingEnabled(); }

/*@jsdoc
* Sets whether or not third person camera clipping is enabled.
* @function Render.setCameraClippingEnabled
* @param {boolean} enabled - <code>true</code> to enable third person camera clipping, <code>false</code> to disable.
*/
void setCameraClippingEnabled(bool enabled);

signals:

Expand Down
7 changes: 6 additions & 1 deletion interface/src/ui/PreferencesDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ void setupPreferences() {
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Show Graphics icon on tablet and toolbar", getter, setter));
}

static const QString VIEW_CATEGORY{ "View" };
static const QString VIEW_CATEGORY { "View" };
{
auto getter = [myAvatar]()->float { return myAvatar->getRealWorldFieldOfView(); };
auto setter = [myAvatar](float value) { myAvatar->setRealWorldFieldOfView(value); };
Expand All @@ -249,6 +249,11 @@ void setupPreferences() {
preference->setStep(1);
preferences->addPreference(preference);
}
{
auto getter = []()->bool { return qApp->getCameraClippingEnabled(); };
auto setter = [](bool value) { qApp->setCameraClippingEnabled(value); };
preferences->addPreference(new CheckPreference(VIEW_CATEGORY, "Enable 3rd Person Camera Clipping?", getter, setter));
}

// Snapshots
static const QString SNAPSHOTS { "Snapshots" };
Expand Down
5 changes: 5 additions & 0 deletions scripts/system/create/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@
visible: false
});

var savedClippingEnabled = false;

function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
// Adjust the position such that the bounding box (registration, dimensions and orientation) lies behind the original
// position in the given direction.
Expand Down Expand Up @@ -1195,6 +1197,7 @@
selectionDisplay.disableTriggerMapping();
tablet.landscape = false;
Controller.disableMapping(CONTROLLER_MAPPING_NAME);
Render.cameraClippingEnabled = savedClippingEnabled;
} else {
if (shouldUseEditTabletApp()) {
tablet.loadQMLSource(Script.resolvePath("qml/Edit.qml"), true);
Expand All @@ -1212,6 +1215,8 @@
print("starting tablet in landscape mode");
tablet.landscape = true;
Controller.enableMapping(CONTROLLER_MAPPING_NAME);
savedClippingEnabled = Render.cameraClippingEnabled;
Render.cameraClippingEnabled = false;
// Not sure what the following was meant to accomplish, but it currently causes
// everybody else to think that Interface has lost focus overall. fogbugzid:558
// Window.setFocus();
Expand Down

0 comments on commit 18c7320

Please sign in to comment.