Skip to content

Commit

Permalink
Camera controls fixes (#7337)
Browse files Browse the repository at this point in the history
* Adds a reset to multi orbit and fly

* Fixed excess spinning when resetting focus

* Changed flying/orbit switching to occur on mouse down and force switch for orbit only actions (focus, zoom)
  • Loading branch information
kpal81xd authored Feb 7, 2025
1 parent c723b9e commit de90864
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 40 deletions.
4 changes: 3 additions & 1 deletion examples/src/examples/camera/fly.example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ const calcEntityAABB = (bbox, entity) => {
* @returns {CameraControls} The camera-controls script.
*/
const createFlyCamera = (focus) => {
const start = new pc.Vec3(0, 20, 30);

const camera = new pc.Entity();
camera.addComponent('camera');
camera.addComponent('script');
camera.setPosition(0, 20, 30);
camera.setPosition(start);
app.root.addChild(camera);

const bbox = calcEntityAABB(new pc.BoundingBox(), focus);
Expand Down
33 changes: 23 additions & 10 deletions examples/src/examples/camera/multi.example.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// @config DESCRIPTION <div style='text-align:center'><div>(<b>WASDQE</b>) Move (Fly enabled)</div><div>(<b>LMB</b>) Orbit, (<b>LMB </b>(Orbit disabled)<b> / RMB</b>) Fly</div><div>(<b>Hold Shift / MMB / RMB </b>(Fly or Orbit disabled)) Pan</div><div>(<b>Scroll Wheel</b> (Orbit or Pan enabled)) Zoom</div><div>(<b>F</b>) Focus</div></div>
// @config DESCRIPTION <div style='text-align:center'><div>(<b>WASDQE</b>) Move (Fly enabled)</div><div>(<b>LMB</b>) Orbit, (<b>LMB </b>(Orbit disabled)<b> / RMB</b>) Fly</div><div>(<b>Hold Shift / MMB / RMB </b>(Fly or Orbit disabled)) Pan</div><div>(<b>Scroll Wheel</b> (Orbit or Pan enabled)) Zoom</div><div>(<b>F</b>) Focus (<b>R</b>) Reset</div></div>
import { data } from 'examples/observer';
import { deviceType, rootPath, fileImport } from 'examples/utils';
import * as pc from 'playcanvas';
Expand Down Expand Up @@ -84,14 +84,16 @@ const calcEntityAABB = (bbox, entity) => {
* @returns {CameraControls} The camera-controls script.
*/
const createMultiCamera = (focus) => {
const start = new pc.Vec3(0, 20, 30);

const camera = new pc.Entity();
camera.addComponent('camera');
camera.addComponent('script');
camera.setPosition(0, 20, 30);
camera.setPosition(start);
app.root.addChild(camera);

const bbox = calcEntityAABB(new pc.BoundingBox(), focus);
const cameraDist = camera.getPosition().distance(bbox.center);
const cameraDist = start.distance(bbox.center);

/** @type {CameraControls} */
const script = camera.script.create(CameraControls, {
Expand All @@ -103,13 +105,24 @@ const createMultiCamera = (focus) => {

// focus on entity when 'f' key is pressed
const onKeyDown = (/** @type {KeyboardEvent} */ e) => {
if (e.key === 'f') {
script.refocus(
bbox.center,
null,
data.get('example.zoomReset') ? cameraDist : null,
data.get('example.smoothedFocus')
);
switch (e.key) {
case 'f': {
script.refocus(
bbox.center,
null,
data.get('example.zoomReset') ? cameraDist : null,
data.get('example.smoothedFocus')
);
break;
}
case 'r': {
script.refocus(
bbox.center,
start,
data.get('example.zoomReset') ? cameraDist : null,
data.get('example.smoothedFocus')
);
}
}
};
window.addEventListener('keydown', onKeyDown);
Expand Down
33 changes: 23 additions & 10 deletions examples/src/examples/camera/orbit.example.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// @config DESCRIPTION <div style='text-align:center'><div>(<b>LMB</b>) Orbit</div><div>(<b>Hold Shift / MMB / RMB </b>) Pan</div><div>(<b>Scroll Wheel</b>) Zoom</div><div>(<b>F</b>) Focus</div></div>
// @config DESCRIPTION <div style='text-align:center'><div>(<b>LMB</b>) Orbit</div><div>(<b>Hold Shift / MMB / RMB </b>) Pan</div><div>(<b>Scroll Wheel</b>) Zoom</div><div>(<b>F</b>) Focus (<b>R</b>) Reset</div></div>
import { data } from 'examples/observer';
import { deviceType, rootPath, fileImport } from 'examples/utils';
import * as pc from 'playcanvas';
Expand Down Expand Up @@ -82,14 +82,16 @@ const calcEntityAABB = (bbox, entity) => {
* @returns {CameraControls} The camera-controls script.
*/
const createOrbitCamera = (focus) => {
const start = new pc.Vec3(0, 20, 30);

const camera = new pc.Entity();
camera.addComponent('camera');
camera.addComponent('script');
camera.setPosition(0, 20, 30);
camera.setPosition(start);
app.root.addChild(camera);

const bbox = calcEntityAABB(new pc.BoundingBox(), focus);
const cameraDist = camera.getPosition().distance(bbox.center);
const cameraDist = start.distance(bbox.center);

/** @type {CameraControls} */
const script = camera.script.create(CameraControls, {
Expand All @@ -102,13 +104,24 @@ const createOrbitCamera = (focus) => {

// focus on entity when 'f' key is pressed
const onKeyDown = (/** @type {KeyboardEvent} */ e) => {
if (e.key === 'f') {
script.refocus(
bbox.center,
null,
data.get('example.zoomReset') ? cameraDist : null,
data.get('example.smoothedFocus')
);
switch (e.key) {
case 'f': {
script.refocus(
bbox.center,
null,
data.get('example.zoomReset') ? cameraDist : null,
data.get('example.smoothedFocus')
);
break;
}
case 'r': {
script.refocus(
bbox.center,
start,
data.get('example.zoomReset') ? cameraDist : null,
data.get('example.smoothedFocus')
);
}
}
};
window.addEventListener('keydown', onKeyDown);
Expand Down
89 changes: 70 additions & 19 deletions scripts/esm/camera-controls.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,13 @@ class CameraControls extends Script {
* @type {boolean}
* @private
*/
_orbiting = false;
_dragging = false;

/**
* @type {boolean}
* @private
*/
_orbiting = true;

/**
* @type {boolean}
Expand Down Expand Up @@ -556,6 +562,43 @@ class CameraControls extends Script {
return event.button === 0;
}

/**
* @private
* @returns {boolean} Whether the switch to orbit was successful.
*/
_switchToOrbit() {
if (!this.enableOrbit) {
return false;
}
if (this._flying) {
this._flying = false;
this._focusDir(tmpV1);
this._origin.add(tmpV1);
this._position.add(tmpV1);
}
this._orbiting = true;
return true;
}

/**
* @private
* @returns {boolean} Whether the switch to fly was successful.
*/
_switchToFly() {
if (!this.enableFly) {
return false;
}
if (this._orbiting) {
this._orbiting = false;
this._zoomDist = this._cameraDist;
this._origin.copy(this.entity.getPosition());
this._position.copy(this._origin);
this._cameraTransform.setTranslate(0, 0, 0);
}
this._flying = true;
return true;
}

/**
* @private
* @param {PointerEvent} event - The pointer event.
Expand Down Expand Up @@ -587,18 +630,17 @@ class CameraControls extends Script {
// start mouse pan
this._lastPosition.set(event.clientX, event.clientY);
this._panning = true;
this._dragging = true;
}
if (startFly) {
// start fly
this._zoomDist = this._cameraDist;
this._origin.copy(this.entity.getPosition());
this._position.copy(this._origin);
this._cameraTransform.setTranslate(0, 0, 0);
this._flying = true;
this._switchToFly();
this._dragging = true;
}
if (startOrbit) {
// start orbit
this._orbiting = true;
this._switchToOrbit();
this._dragging = true;
}
}

Expand All @@ -612,6 +654,11 @@ class CameraControls extends Script {
}
this._pointerEvents.set(event.pointerId, event);

if (this._focusing) {
this._cancelSmoothTransform();
this._focusing = false;
}

if (this._pointerEvents.size === 1) {
if (this._panning) {
// mouse pan
Expand Down Expand Up @@ -649,17 +696,11 @@ class CameraControls extends Script {
this._lastPinchDist = -1;
this._panning = false;
}
if (this._orbiting) {
this._orbiting = false;
}
if (this._panning) {
this._panning = false;
}
if (this._flying) {
this._focusDir(tmpV1);
this._origin.add(tmpV1);
this._position.add(tmpV1);
this._flying = false;
if (this._dragging) {
this._dragging = false;
}
}

Expand Down Expand Up @@ -882,7 +923,12 @@ class CameraControls extends Script {
return;
}
if (this._flying) {
return;
if (this._dragging) {
return;
}
if (!this._switchToOrbit()) {
return;
}
}

if (!this._camera) {
Expand Down Expand Up @@ -911,8 +957,8 @@ class CameraControls extends Script {
_smoothTransform(dt) {
const ar = dt === -1 ? 1 : lerpRate(this._focusing ? this.focusDamping : this.rotateDamping, dt);
const am = dt === -1 ? 1 : lerpRate(this._focusing ? this.focusDamping : this.moveDamping, dt);
this._angles.x = math.lerp(this._angles.x, this._dir.x, ar);
this._angles.y = math.lerp(this._angles.y, this._dir.y, ar);
this._angles.x = math.lerpAngle(this._angles.x % 360, this._dir.x % 360, ar);
this._angles.y = math.lerpAngle(this._angles.y % 360, this._dir.y % 360, ar);
this._position.lerp(this._position, this._origin, am);
this._baseTransform.setTRS(this._position, tmpQ1.setFromEulerAngles(this._angles), Vec3.ONE);

Expand Down Expand Up @@ -960,7 +1006,12 @@ class CameraControls extends Script {
return;
}
if (this._flying) {
return;
if (this._dragging) {
return;
}
if (!this._switchToOrbit()) {
return;
}
}

if (start) {
Expand Down

0 comments on commit de90864

Please sign in to comment.