Skip to content

Commit

Permalink
Add DeviceOrientationControls2, FirstPersonControls2, OrbitControls2,…
Browse files Browse the repository at this point in the history
… PointerLockControls2, RGBM to linear conversion functions on cpu.
  • Loading branch information
repalash committed Mar 9, 2024
1 parent 77a4228 commit 6d6d7e5
Show file tree
Hide file tree
Showing 10 changed files with 853 additions and 8 deletions.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "threepipe",
"version": "0.0.22",
"version": "0.0.23",
"description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.",
"main": "dist/index.js",
"module": "dist/index.mjs",
Expand Down
182 changes: 182 additions & 0 deletions src/three/controls/DeviceOrientationControls2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import {Euler, EulerOrder, EventDispatcher, MathUtils, Object3D, Quaternion, Vector3} from 'three'
import {IEvent, now, serialize} from 'ts-browser-helpers'
import {uiPanelContainer, uiSlider} from 'uiconfig.js'
import {ICameraControls} from '../../core'

// eslint-disable-next-line @typescript-eslint/naming-convention
const _zee = new Vector3(0, 0, 1)
// eslint-disable-next-line @typescript-eslint/naming-convention
const _euler = new Euler()
// eslint-disable-next-line @typescript-eslint/naming-convention
const _q0 = new Quaternion()
// eslint-disable-next-line @typescript-eslint/naming-convention
const _q1 = new Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)) // - PI/2 around the x-axis
// eslint-disable-next-line @typescript-eslint/naming-convention
const _q2 = new Quaternion() // - PI/2 around the x-axis

// eslint-disable-next-line @typescript-eslint/naming-convention
const _changeEvent: IEvent<'change'> = {type: 'change'}

const EPS = 0.000001

@uiPanelContainer('Device Orientation Controls')
export class DeviceOrientationControls2 extends EventDispatcher implements ICameraControls<'change'> {
object: Object3D
enabled = false // do not serialize this as it signifies weather this is active.
deviceOrientation?: DeviceOrientationEvent
screenOrientation?: ScreenOrientation
lastOrder: EulerOrder = 'XYZ'
@serialize()
@uiSlider('Damping', [0, 1], 0.01)
dampingFactor = 0.05
lastQuaternion = new Quaternion()

constructor(object: Object3D) {

super()

if (window.isSecureContext === false) {

console.error('DeviceOrientationControls2: DeviceOrientationEvent is only available in secure contexts (https)')

}

this.object = object

this.lastOrder = this.object.rotation.order
this.object.rotation.reorder('YXZ')

// this.enabled = true

this.connect()

}

onDeviceOrientationChangeEvent = (event: DeviceOrientationEvent) => {
this.deviceOrientation = event
}

onScreenOrientationChangeEvent = () => {
this.screenOrientation = screen.orientation
}

private _initQuaternion = new Quaternion()
private _initQuaternionInvert = new Quaternion()
private _initQuaternionDest = new Quaternion()
connect() {

this.onScreenOrientationChangeEvent() // run once on load

// iOS 13+

if (window.DeviceOrientationEvent !== undefined && typeof (window.DeviceOrientationEvent as any).requestPermission === 'function') {

(window.DeviceOrientationEvent as any).requestPermission().then((response: string)=>{

if (response == 'granted') {

window.addEventListener('orientationchange', this.onScreenOrientationChangeEvent)
window.addEventListener('deviceorientation', this.onDeviceOrientationChangeEvent)

}

}).catch((error: any)=>{

console.error('DeviceOrientationControls2: Unable to use DeviceOrientation API:', error)

})

} else {

window.addEventListener('orientationchange', this.onScreenOrientationChangeEvent)
window.addEventListener('deviceorientation', this.onDeviceOrientationChangeEvent)

}

this.enabled = true
this._initQuaternion.copy(this.object.quaternion)
this._initQuaternionInvert.copy(this.object.quaternion).invert()

}

disconnect() {

window.removeEventListener('orientationchange', this.onScreenOrientationChangeEvent)
window.removeEventListener('deviceorientation', this.onDeviceOrientationChangeEvent)
this._initQuaternion.identity()
this._initQuaternionInvert.identity()
this._initQuaternionDest = new Quaternion() // need to set a new instance here.
this.object.rotation.reorder(this.lastOrder)
this.lastOrder = 'XYZ'

this.enabled = false

}

update() {

if (!this.enabled) return

const device = this.deviceOrientation

if (device) {

const alpha = device.alpha !== null ? MathUtils.degToRad(device.alpha) : 0 // Z

const beta = device.beta !== null ? MathUtils.degToRad(device.beta) : 0 // X'

const gamma = device.gamma !== null ? MathUtils.degToRad(device.gamma) : 0 // Y''

const orient = this.screenOrientation ? MathUtils.degToRad(this.screenOrientation.angle) : 0 // O

this.setObjectQuaternion(alpha, beta, gamma, orient)

if (8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > EPS) {

this.lastQuaternion.copy(this.object.quaternion)
this.dispatchEvent(_changeEvent)

}

}

}

dispose() {

this.disconnect()

}

private _lastTime = -1

// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
setObjectQuaternion(alpha: number, beta: number, gamma: number, orient: number): void {
// if(_lastTime < 0)
const time = now() / 1000

_euler.set(beta, alpha, -gamma, 'YXZ') // 'ZXY' for the device, but 'YXZ' for us

_q2.setFromEuler(_euler) // orient the device

_q2.multiply(_q1) // camera looks out the back of the device, not the top

_q2.multiply(_q0.setFromAxisAngle(_zee, -orient)) // adjust for screen orientation

if (!(this._initQuaternionDest as any).__init) {
this._initQuaternionDest.copy(_q2).invert()
;(this._initQuaternionDest as any).__init = true
}

_q2.premultiply(this._initQuaternionDest)

const mTime = 1 / 60
// this.object.quaternion.multiply(this._initQuaternionInvert)
this.object.quaternion.slerp(_q2, this.dampingFactor / (Math.min(1, time - this._lastTime) / mTime))
// this.object.quaternion.multiply(this._initQuaternion)
// console.log(time - this._lastTime, mTime)

this._lastTime = time
}

}

0 comments on commit 6d6d7e5

Please sign in to comment.