Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Orbit WASDEQ Controls #3875

Merged
merged 39 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d012877
Updated the fly controller to use the z up basis
AlexandruPopovici Nov 21, 2024
e3a20bd
Fixed very important compiler error
AlexandruPopovici Nov 21, 2024
83063b0
Removed the annoying delay when first holding down WASD keys before m…
AlexandruPopovici Nov 21, 2024
59ae40d
Updated LegacyViewer to use the hybrid camera controls
AlexandruPopovici Nov 22, 2024
0b0cb8b
Merge branch 'main' into alex/advanced-camera-controls
AlexandruPopovici Nov 22, 2024
d1da6a7
Added big baker
AlexandruPopovici Nov 26, 2024
86d9d92
Merge branch 'main' into alex/advanced-camera-controls
AlexandruPopovici Nov 27, 2024
0ad6c44
Trying to figure out the essence of this
AlexandruPopovici Dec 11, 2024
d3d6d52
Partly works
AlexandruPopovici Dec 11, 2024
dabeefc
Pivotal coordinates now work
AlexandruPopovici Dec 18, 2024
fbab733
Smoothened out the math abit
AlexandruPopovici Dec 19, 2024
339cc79
Merged and removed debug spheres
AlexandruPopovici Dec 19, 2024
8fab92e
Fixed sandbox error
AlexandruPopovici Dec 19, 2024
28fff50
Enabled the pivot sphere
AlexandruPopovici Dec 20, 2024
688bb53
chore(viewer-lib): Merged with main
AlexandruPopovici Jan 9, 2025
8d6c043
Merge branch 'main' into alex/advanced-camera-controls
AlexandruPopovici Jan 9, 2025
3ded61f
feat(viewer-lib): Fixed some issues with orbiting around cursor
AlexandruPopovici Jan 9, 2025
a4dbf46
feat(viewer-lib): Updates to WEB-2313, orbiting around mouse cursor
AlexandruPopovici Jan 10, 2025
fc1cf44
feat(viewer-lib): Mouse orbiting now takes clipping planes into consi…
AlexandruPopovici Jan 10, 2025
8720874
chore(viewer-lib): Fixed sandbox build error
AlexandruPopovici Jan 10, 2025
b40e99e
fix(viewer-lib): Handled WEB-2449 and WEB-2450
AlexandruPopovici Jan 13, 2025
5de1bc5
fix(viewer-lib): Fixed the issue with focusing and other camera anima…
AlexandruPopovici Jan 13, 2025
cf0c1e8
Merge branch 'main' into alex/advanced-camera-controls
AlexandruPopovici Jan 14, 2025
572ae38
feat(viewer-lib): Updates on mouse orbiting:
AlexandruPopovici Jan 14, 2025
decb3d5
Merge branch 'main' into alex/advanced-camera-controls
AlexandruPopovici Jan 14, 2025
9be1585
feat(viewer-lib): Update for WASD aka fly mode:
AlexandruPopovici Jan 14, 2025
c6d71a8
fix(viewer-lib): Fixed sandbox compile error
AlexandruPopovici Jan 14, 2025
74b6ddc
feat(viewer-lib): Added the hybrid fly orbit controller to the legacy…
AlexandruPopovici Jan 14, 2025
886ef10
Merge branch 'main' into alex/advanced-camera-controls-wasd
AlexandruPopovici Jan 20, 2025
dd4556a
feat(viewer-lib): Added a slower movement speed to WASD navigation wh…
AlexandruPopovici Jan 20, 2025
ebf2322
fix(viewer-lib): Fixed the issue where opening the context menu while…
AlexandruPopovici Jan 21, 2025
59b5e15
Feat(viewer-lib): Update to WASD controls:
AlexandruPopovici Jan 22, 2025
e74227e
chore(viewer-lib): Tidied up a bit
AlexandruPopovici Jan 22, 2025
593768c
fix(viewer-lib): Fixed an ugly bug where the camera distance calculat…
AlexandruPopovici Jan 22, 2025
a6ec6e8
Merge branch 'main' into alex/advanced-camera-controls-wasd
AlexandruPopovici Jan 23, 2025
ead9c1f
chore(viewer-lib): Swapped E to up and Q to down
AlexandruPopovici Jan 23, 2025
a2c04d8
Re-nabled cursor orbiting
AlexandruPopovici Jan 29, 2025
be0635e
Merge branch 'main' into alex/advanced-camera-controls-wasd
AlexandruPopovici Jan 29, 2025
c6e39b0
Merge branch 'main' into alex/advanced-camera-controls-wasd
AlexandruPopovici Jan 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions packages/viewer-sandbox/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {
SelectionEvent,
ViewerEvent,
Viewer,
CameraController,
ViewModes,
SelectionExtension
SelectionExtension,
HybridCameraController
} from '@speckle/viewer'

import './style.css'
Expand All @@ -20,6 +20,7 @@ import {
import { SectionTool } from '@speckle/viewer'
import { SectionOutlines } from '@speckle/viewer'
import { ViewModesKeys } from './Extensions/ViewModesKeys'
// import { JSONSpeckleStream } from './JSONSpeckleStream'
import { BoxSelection } from './Extensions/BoxSelection'
import { PassReader } from './Extensions/PassReader'

Expand All @@ -45,7 +46,7 @@ const createViewer = async (containerName: string, _stream: string) => {
const viewer: Viewer = new Viewer(container, params)
await viewer.init()

const cameraController = viewer.createExtension(CameraController)
const cameraController = viewer.createExtension(HybridCameraController)
const selection = viewer.createExtension(SelectionExtension)
const sections = viewer.createExtension(SectionTool)
viewer.createExtension(SectionOutlines)
Expand Down Expand Up @@ -458,6 +459,8 @@ const getStream = () => {
// Perfectly flat
// 'https://app.speckle.systems/projects/344f803f81/models/5582ab673e'

// big baker
// 'https://latest.speckle.systems/projects/126cd4b7bb/models/032d09f716'
// 'https://speckle.xyz/streams/27e89d0ad6/commits/5ed4b74252'

//Gingerbread
Expand Down
3 changes: 2 additions & 1 deletion packages/viewer/src/modules/LegacyViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { BatchObject } from './batching/BatchObject.js'
import { SpeckleLoader } from './loaders/Speckle/SpeckleLoader.js'
import Logger from './utils/Logger.js'
import { ViewModes } from './extensions/ViewModes.js'
import { HybridCameraController } from './extensions/HybridCameraController.js'

class LegacySelectionExtension extends SelectionExtension {
/** FE2 'manually' selects objects pon it's own, so we're disabling the extension's event handler
Expand Down Expand Up @@ -120,7 +121,7 @@ export class LegacyViewer extends Viewer {
params: ViewerParams = DefaultViewerParams
) {
super(container, params)
this.cameraController = this.createExtension(CameraController)
this.cameraController = this.createExtension(HybridCameraController)
this.selection = this.createExtension(LegacySelectionExtension)
this.sections = this.createExtension(SectionTool)
this.createExtension(SectionOutlines)
Expand Down
2 changes: 1 addition & 1 deletion packages/viewer/src/modules/Viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export class Viewer extends EventEmitter implements IViewer {
}

private update() {
const delta = this.clock.getDelta()
const delta = this.clock.getDelta() * 1000 // turn to miliseconds
const extensions = Object.values(this.extensions)
extensions.forEach((ext: Extension) => {
ext.onEarlyUpdate(delta)
Expand Down
54 changes: 27 additions & 27 deletions packages/viewer/src/modules/extensions/CameraController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ import {
SmoothOrbitControls
} from './controls/SmoothOrbitControls.js'

// const UP: Vector3 = new Vector3(0, 1, 0)
// const quatBuff = new Quaternion()

export enum NearPlaneCalculation {
EMPIRIC,
ACCURATE
Expand Down Expand Up @@ -94,10 +91,13 @@ export const DefaultOrbitControlsOptions: Required<CameraControllerOptions> = {
touchAction: 'none',
infiniteZoom: true,
zoomToCursor: true,
orbitAroundCursor: true,
showOrbitPoint: true,
lookSpeed: 1,
moveSpeed: 1,
damperDecay: 30,
enableLook: true,
relativeUpDown: false,
nearPlaneCalculation: NearPlaneCalculation.ACCURATE
}

Expand All @@ -108,7 +108,8 @@ export class CameraController extends Extension implements SpeckleCamera {
protected _lastCameraChanged: boolean = false
protected _options: Required<CameraControllerOptions> = DefaultOrbitControlsOptions
protected _activeControls: SpeckleControls
protected _controlsList: SpeckleControls[] = []
protected _orbitControls: SmoothOrbitControls
protected _flyControls: FlyControls

get renderingCamera(): PerspectiveCamera | OrthographicCamera {
return this._renderingCamera
Expand Down Expand Up @@ -149,9 +150,8 @@ export class CameraController extends Extension implements SpeckleCamera {

public set options(value: CameraControllerOptions) {
Object.assign(this._options, value)
this._controlsList.forEach((controls: SpeckleControls) => {
controls.options = value
})
this._orbitControls.options = value
this._flyControls.options = value
}

public constructor(viewer: IViewer) {
Expand Down Expand Up @@ -180,32 +180,28 @@ export class CameraController extends Extension implements SpeckleCamera {
/** Perspective camera as default on startup */
this.renderingCamera = this.perspectiveCamera

const flyControls = new FlyControls(
this._flyControls = new FlyControls(
this._renderingCamera,
this.viewer.getContainer(),
this.viewer.World,
this._options
)
flyControls.enabled = false
flyControls.setDamperDecayTime(30)
flyControls.up = new Vector3(0, 0, 1)
this._flyControls.enabled = false
this._flyControls.setDamperDecayTime(30)
this._flyControls.up = new Vector3(0, 0, 1)

const orbitControls = new SmoothOrbitControls(
this._orbitControls = new SmoothOrbitControls(
this.perspectiveCamera,
this.viewer.getContainer(),
this.viewer.World,
this.viewer.getRenderer().scene,
this.viewer.getRenderer().intersections,
this.viewer.getRenderer(),
this._options
)
orbitControls.enabled = true
this._orbitControls.enabled = true

this.viewer.getRenderer().speckleCamera = this

this._controlsList.push(orbitControls)
this._controlsList.push(flyControls)

this._activeControls = orbitControls
this._activeControls = this._orbitControls

this.default()
}
Expand Down Expand Up @@ -238,18 +234,19 @@ export class CameraController extends Extension implements SpeckleCamera {
let newControls: SpeckleControls | undefined = undefined

if (this._activeControls instanceof SmoothOrbitControls) {
newControls = this._controlsList[1]
newControls = this._flyControls
} else if (this._activeControls instanceof FlyControls) {
newControls = this._controlsList[0]
newControls = this._orbitControls
}

if (!newControls) throw new Error('Not controls found!')

oldControls.enabled = false
newControls.enabled = true

newControls.fromPositionAndTarget(
oldControls.getPosition(),
oldControls.getTarget()
oldControls.getCurrentPosition(),
oldControls.getCurrentTarget()
)
newControls.jumpToGoal()
this._activeControls = newControls
Expand Down Expand Up @@ -295,8 +292,8 @@ export class CameraController extends Extension implements SpeckleCamera {
this.emit(CameraEvent.Dynamic)
}

public onEarlyUpdate() {
const changed = this._activeControls.update()
public onEarlyUpdate(_delta?: number) {
const changed = this._activeControls.update(_delta)
if (changed !== this._lastCameraChanged) {
this.emit(changed ? CameraEvent.Dynamic : CameraEvent.Stationary)
}
Expand Down Expand Up @@ -424,6 +421,9 @@ export class CameraController extends Extension implements SpeckleCamera {
fallback?: number
): number | undefined {
const minDist = this.getClosestGeometryDistance(fallback)
this._flyControls.minDist = minDist
this._orbitControls.minDist = minDist

if (minDist === Number.POSITIVE_INFINITY) {
return this.computeNearCameraPlaneEmpiric(targetVolume, offsetScale)
}
Expand Down Expand Up @@ -472,8 +472,8 @@ export class CameraController extends Extension implements SpeckleCamera {
}

protected getClosestGeometryDistance(fallback?: number): number {
const cameraPosition = this._renderingCamera.position
const cameraTarget = this.getTarget()
const cameraPosition = this._activeControls.getCurrentPosition()
const cameraTarget = this._activeControls.getCurrentTarget()
const cameraDir = new Vector3().subVectors(cameraTarget, cameraPosition).normalize()

const batches = this.viewer
Expand Down
58 changes: 40 additions & 18 deletions packages/viewer/src/modules/extensions/HybridCameraController.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { clamp } from 'three/src/math/MathUtils.js'
import { IViewer } from '../../IViewer.js'
import { CameraController } from './CameraController.js'
type MoveType = 'forward' | 'back' | 'left' | 'right' | 'up' | 'down'
Expand All @@ -12,13 +11,28 @@ export class HybridCameraController extends CameraController {
up: false,
down: false
}

protected contextMenuTriggered = false

public constructor(viewer: IViewer) {
super(viewer)
document.addEventListener('keydown', this.onKeyDown.bind(this))
document.addEventListener('keyup', this.onKeyUp.bind(this))
document.addEventListener('contextmenu', this.onContextMenu.bind(this))
}

public onEarlyUpdate(_delta?: number): void {
super.onEarlyUpdate(_delta)
/** We do this because sometimes while holding a kewy down you get an extra
* key down event **after** the context menu event, locking it in place
*/
if (this.contextMenuTriggered) {
this.cancelMove()
this.contextMenuTriggered = false
}
}

protected onKeyDown(event: KeyboardEvent) {
let moveSpeed = this.options.moveSpeed ? this.options.moveSpeed : 1
switch (event.code) {
case 'ArrowUp':
case 'KeyW':
Expand All @@ -41,27 +55,17 @@ export class HybridCameraController extends CameraController {
break

case 'PageUp':
case 'KeyQ':
case 'KeyE':
this.keyMap.up = true
break

case 'PageDown':
case 'KeyE':
case 'KeyQ':
this.keyMap.down = true
break
case 'KeyF':
moveSpeed += 0.25
moveSpeed = clamp(moveSpeed, 0.1, 5)
this.options = { moveSpeed }
break
case 'KeyC':
moveSpeed -= 0.25
moveSpeed = clamp(moveSpeed, 0.1, 5)
this.options = { moveSpeed }
break
}
if (
!this._controlsList[1].enabled &&
!this._flyControls.enabled &&
Object.values(this.keyMap).some((v) => v === true)
)
this.toggleControls()
Expand Down Expand Up @@ -90,17 +94,35 @@ export class HybridCameraController extends CameraController {
break

case 'PageUp':
case 'KeyQ':
case 'KeyE':
this.keyMap.up = false
break

case 'PageDown':
case 'KeyE':
case 'KeyQ':
this.keyMap.down = false
break
}
if (
this._controlsList[1].enabled &&
this._flyControls.enabled &&
Object.values(this.keyMap).every((v) => v === false)
)
this.toggleControls()
}

protected onContextMenu() {
this.contextMenuTriggered = true
}

protected cancelMove() {
this.keyMap.back = false
this.keyMap.forward = false
this.keyMap.down = false
this.keyMap.up = false
this.keyMap.left = false
this.keyMap.right = false
if (
this._flyControls.enabled &&
Object.values(this.keyMap).every((v) => v === false)
)
this.toggleControls()
Expand Down
Loading
Loading