| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Device Orientation Controls Plugin</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs", | |||||
| "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| #deviceOrientationOverlay{ | |||||
| position: absolute; top: 0; left: 0; right: 0; bottom: 0; height: 100%; width: 100%; | |||||
| display: flex; justify-content: center; align-items: center; cursor: pointer; | |||||
| font-size: 1.5rem; background: rgba(240,240,240,0.5); color: #333333; | |||||
| backdrop-filter: blur(16px); | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| <div id="deviceOrientationOverlay"> | |||||
| Tap the screen to enable device orientation controls <br/> | |||||
| (works only on devices with gyroscope) | |||||
| </div> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, DeviceOrientationControlsPlugin, IObject3D, ThreeViewer} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: true, | |||||
| plugins: [DeviceOrientationControlsPlugin], | |||||
| }) | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| ui.appendChild(viewer.scene.mainCamera.uiConfig) | |||||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||||
| await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }) | |||||
| const overlayEl = document.getElementById('deviceOrientationOverlay') as HTMLDivElement | |||||
| overlayEl.addEventListener('click', () => { | |||||
| viewer.scene.mainCamera.controlsMode = 'deviceOrientation' | |||||
| overlayEl.style.display = 'none' | |||||
| }) | |||||
| } | |||||
| init().then(_testFinish) |
| <li><a href="./transform-controls-plugin/">Transform Controls Plugin </a></li> | <li><a href="./transform-controls-plugin/">Transform Controls Plugin </a></li> | ||||
| <li><a href="./editor-view-widget-plugin/">Editor View Widget Plugin </a></li> | <li><a href="./editor-view-widget-plugin/">Editor View Widget Plugin </a></li> | ||||
| <li><a href="./fullscreen-plugin/">FullScreen Plugin </a></li> | <li><a href="./fullscreen-plugin/">FullScreen Plugin </a></li> | ||||
| <li><a href="./device-orientation-controls-plugin/">Device Orientation Controls Plugin (Gyroscope) </a></li> | |||||
| <li><a href="./pointer-lock-controls-plugin/">Pointer Lock(FPS) Controls Plugin </a></li> | |||||
| <li><a href="./three-first-person-controls-plugin/">Three First Person(look around) Controls Plugin </a></li> | |||||
| </ul> | </ul> | ||||
| <h2 class="category">Import</h2> | <h2 class="category">Import</h2> | ||||
| <ul> | <ul> |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Pointer Lock Controls Plugin</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs", | |||||
| "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| #pointerLockOverlay{ | |||||
| position: absolute; top: 0; left: 0; right: 0; bottom: 0; height: 100%; width: 100%; | |||||
| display: flex; justify-content: center; align-items: center; pointer-events: none; | |||||
| font-size: 1.5rem; background: rgba(240,240,240,0.5); color: #333333; | |||||
| backdrop-filter: blur(16px); | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| <div id="pointerLockOverlay"> | |||||
| Tap the screen to enable pointer lock controls | |||||
| </div> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, IObject3D, PointerLockControlsPlugin, ThreeViewer} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: true, | |||||
| plugins: [PointerLockControlsPlugin], | |||||
| }) | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| ui.appendChild(viewer.scene.mainCamera.uiConfig) | |||||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||||
| await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }) | |||||
| viewer.scene.mainCamera.controlsMode = 'pointerLock' | |||||
| const overlayEl = document.getElementById('pointerLockOverlay') as HTMLDivElement | |||||
| viewer.scene.mainCamera.controls?.addEventListener('lock', ()=> overlayEl.style.display = 'none') | |||||
| viewer.scene.mainCamera.controls?.addEventListener('unlock', ()=> overlayEl.style.display = 'flex') | |||||
| } | |||||
| init().then(_testFinish) |
| <!DOCTYPE html> | |||||
| <html lang="en"> | |||||
| <head> | |||||
| <meta charset="UTF-8"> | |||||
| <title>Three First Person Controls Plugin</title> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <!-- Import maps polyfill --> | |||||
| <!-- Remove this when import maps will be widely supported --> | |||||
| <script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script> | |||||
| <script type="importmap"> | |||||
| { | |||||
| "imports": { | |||||
| "threepipe": "./../../dist/index.mjs", | |||||
| "@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs" | |||||
| } | |||||
| } | |||||
| </script> | |||||
| <style id="example-style"> | |||||
| html, body, #canvas-container, #mcanvas { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| } | |||||
| #firstPersonControlsOverlay{ | |||||
| position: absolute; top: 0; left: 0; right: 0; bottom: 0; height: 100%; width: 100%; | |||||
| display: flex; justify-content: center; align-items: center; cursor: pointer; | |||||
| font-size: 1.5rem; background: rgba(240,240,240,0.5); color: #333333; | |||||
| backdrop-filter: blur(16px); | |||||
| } | |||||
| </style> | |||||
| <script type="module" src="../examples-utils/simple-code-preview.mjs"></script> | |||||
| <script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script> | |||||
| </head> | |||||
| <body> | |||||
| <div id="canvas-container"> | |||||
| <canvas id="mcanvas"></canvas> | |||||
| <div id="firstPersonControlsOverlay"> | |||||
| Tap the screen to enable three first person(look around) controls | |||||
| </div> | |||||
| </div> | |||||
| </body> |
| import {_testFinish, IObject3D, ThreeFirstPersonControlsPlugin, ThreeViewer} from 'threepipe' | |||||
| import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane' | |||||
| async function init() { | |||||
| const viewer = new ThreeViewer({ | |||||
| canvas: document.getElementById('mcanvas') as HTMLCanvasElement, | |||||
| msaa: true, | |||||
| plugins: [ThreeFirstPersonControlsPlugin], | |||||
| }) | |||||
| const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true)) | |||||
| ui.appendChild(viewer.scene.mainCamera.uiConfig) | |||||
| await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr') | |||||
| await viewer.load<IObject3D>('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', { | |||||
| autoCenter: true, | |||||
| autoScale: true, | |||||
| }) | |||||
| const overlayEl = document.getElementById('firstPersonControlsOverlay') as HTMLDivElement | |||||
| overlayEl.addEventListener('click', () => { | |||||
| viewer.scene.mainCamera.controlsMode = 'threeFirstPerson' | |||||
| overlayEl.style.display = 'none' | |||||
| }) | |||||
| } | |||||
| init().then(_testFinish) |
| ContactShadowGroundPlugin, | ContactShadowGroundPlugin, | ||||
| CustomBumpMapPlugin, | CustomBumpMapPlugin, | ||||
| DepthBufferPlugin, | DepthBufferPlugin, | ||||
| DeviceOrientationControlsPlugin, | |||||
| DropzonePlugin, | DropzonePlugin, | ||||
| EditorViewWidgetPlugin, | EditorViewWidgetPlugin, | ||||
| FilmicGrainPlugin, | FilmicGrainPlugin, | ||||
| Object3DWidgetsPlugin, | Object3DWidgetsPlugin, | ||||
| PickingPlugin, | PickingPlugin, | ||||
| PLYLoadPlugin, | PLYLoadPlugin, | ||||
| PointerLockControlsPlugin, | |||||
| ProgressivePlugin, | ProgressivePlugin, | ||||
| RenderTargetPreviewPlugin, | RenderTargetPreviewPlugin, | ||||
| Rhino3dmLoadPlugin, | Rhino3dmLoadPlugin, | ||||
| SceneUiConfigPlugin, | SceneUiConfigPlugin, | ||||
| STLLoadPlugin, | STLLoadPlugin, | ||||
| ThreeFirstPersonControlsPlugin, | |||||
| ThreeViewer, | ThreeViewer, | ||||
| TonemapPlugin, | TonemapPlugin, | ||||
| TransformControlsPlugin, | TransformControlsPlugin, | ||||
| GaussianSplattingPlugin, | GaussianSplattingPlugin, | ||||
| ContactShadowGroundPlugin, | ContactShadowGroundPlugin, | ||||
| CanvasSnapshotPlugin, | CanvasSnapshotPlugin, | ||||
| DeviceOrientationControlsPlugin, | |||||
| PointerLockControlsPlugin, | |||||
| ThreeFirstPersonControlsPlugin, | |||||
| ...extraImportPlugins, | ...extraImportPlugins, | ||||
| ]) | ]) | ||||
| editor.loadPlugins({ | editor.loadPlugins({ | ||||
| ['Viewer']: [ViewerUiConfigPlugin, SceneUiConfigPlugin, DropzonePlugin, FullScreenPlugin, TweakpaneUiPlugin], | ['Viewer']: [ViewerUiConfigPlugin, SceneUiConfigPlugin, DropzonePlugin, FullScreenPlugin, TweakpaneUiPlugin], | ||||
| ['Scene']: [ContactShadowGroundPlugin], | ['Scene']: [ContactShadowGroundPlugin], | ||||
| ['Interaction']: [HierarchyUiPlugin, TransformControlsPlugin, PickingPlugin, Object3DGeneratorPlugin, GeometryGeneratorPlugin, EditorViewWidgetPlugin, Object3DWidgetsPlugin], | |||||
| ['Interaction']: [HierarchyUiPlugin, TransformControlsPlugin, PickingPlugin, Object3DGeneratorPlugin, GeometryGeneratorPlugin, EditorViewWidgetPlugin, Object3DWidgetsPlugin, DeviceOrientationControlsPlugin, PointerLockControlsPlugin, ThreeFirstPersonControlsPlugin], | |||||
| ['GBuffer']: [GBufferPlugin, DepthBufferPlugin, NormalBufferPlugin], | ['GBuffer']: [GBufferPlugin, DepthBufferPlugin, NormalBufferPlugin], | ||||
| ['Post-processing']: [TonemapPlugin, ProgressivePlugin, FrameFadePlugin, VignettePlugin, ChromaticAberrationPlugin, FilmicGrainPlugin], | ['Post-processing']: [TonemapPlugin, ProgressivePlugin, FrameFadePlugin, VignettePlugin, ChromaticAberrationPlugin, FilmicGrainPlugin], | ||||
| ['Export']: [CanvasSnapshotPlugin], | ['Export']: [CanvasSnapshotPlugin], |
| import {AViewerPluginSync, ThreeViewer} from '../../viewer' | |||||
| import {TControlsCtor} from '../../core' | |||||
| export abstract class ACameraControlsPlugin extends AViewerPluginSync<''> { | |||||
| readonly enabled = true | |||||
| toJSON: any = undefined | |||||
| protected abstract _controlsCtor: TControlsCtor | |||||
| abstract readonly controlsKey: string | |||||
| onAdded(viewer: ThreeViewer): void { | |||||
| super.onAdded(viewer) | |||||
| this._cameraChanged({camera: viewer.scene.mainCamera}) | |||||
| viewer.scene.addEventListener('mainCameraChange', this._cameraChanged) | |||||
| } | |||||
| onRemove(viewer: ThreeViewer): void { | |||||
| this._cameraChanged({lastCamera: viewer.scene.mainCamera}) | |||||
| viewer.scene.removeEventListener('mainCameraChange', this._cameraChanged) | |||||
| super.onRemove(viewer) | |||||
| } | |||||
| private _cameraChanged = (e: any) => { | |||||
| e.lastCamera?.removeControlsCtor?.(this.controlsKey) | |||||
| e.camera?.setControlsCtor?.(this.controlsKey, this._controlsCtor) | |||||
| } | |||||
| } |
| export {PipelinePassPlugin} from './base/PipelinePassPlugin' | export {PipelinePassPlugin} from './base/PipelinePassPlugin' | ||||
| export {BaseImporterPlugin} from './base/BaseImporterPlugin' | export {BaseImporterPlugin} from './base/BaseImporterPlugin' | ||||
| export {BaseGroundPlugin} from './base/BaseGroundPlugin' | export {BaseGroundPlugin} from './base/BaseGroundPlugin' | ||||
| export {ACameraControlsPlugin} from './base/ACameraControlsPlugin' | |||||
| // pipeline | // pipeline | ||||
| export {ProgressivePlugin} from './pipeline/ProgressivePlugin' | export {ProgressivePlugin} from './pipeline/ProgressivePlugin' | ||||
| export {PickingPlugin} from './interaction/PickingPlugin' | export {PickingPlugin} from './interaction/PickingPlugin' | ||||
| export {TransformControlsPlugin} from './interaction/TransformControlsPlugin' | export {TransformControlsPlugin} from './interaction/TransformControlsPlugin' | ||||
| export {EditorViewWidgetPlugin} from './interaction/EditorViewWidgetPlugin' | export {EditorViewWidgetPlugin} from './interaction/EditorViewWidgetPlugin' | ||||
| export {DeviceOrientationControlsPlugin} from './interaction/DeviceOrientationControlsPlugin' | |||||
| export {PointerLockControlsPlugin} from './interaction/PointerLockControlsPlugin' | |||||
| export {ThreeFirstPersonControlsPlugin} from './interaction/ThreeFirstPersonControlsPlugin' | |||||
| // import | // import | ||||
| export {Rhino3dmLoadPlugin} from './import/Rhino3dmLoadPlugin' | export {Rhino3dmLoadPlugin} from './import/Rhino3dmLoadPlugin' |
| import {ACameraControlsPlugin} from '../base/ACameraControlsPlugin' | |||||
| import {TControlsCtor} from '../../core' | |||||
| import {DeviceOrientationControls2} from '../../three' | |||||
| export class DeviceOrientationControlsPlugin extends ACameraControlsPlugin { | |||||
| public static readonly PluginType = 'DeviceOrientationControlsPlugin' | |||||
| readonly controlsKey = 'deviceOrientation' | |||||
| protected _controlsCtor: TControlsCtor = (object, _domElement)=> new DeviceOrientationControls2(object) | |||||
| } |
| import {ACameraControlsPlugin} from '../base/ACameraControlsPlugin' | |||||
| import {TControlsCtor} from '../../core' | |||||
| import {PointerLockControls2} from '../../three' | |||||
| export class PointerLockControlsPlugin extends ACameraControlsPlugin { | |||||
| public static readonly PluginType = 'PointerLockControlsPlugin' | |||||
| readonly controlsKey = 'pointerLock' | |||||
| protected _controlsCtor: TControlsCtor = (object, domElement) => new PointerLockControls2(object, !domElement?.ownerDocument ? (domElement || document).documentElement : domElement) | |||||
| } |
| import {ACameraControlsPlugin} from '../base/ACameraControlsPlugin' | |||||
| import {TControlsCtor} from '../../core' | |||||
| import {FirstPersonControls2} from '../../three' | |||||
| export class ThreeFirstPersonControlsPlugin extends ACameraControlsPlugin { | |||||
| public static readonly PluginType = 'ThreeFirstPersonControlsPlugin' | |||||
| readonly controlsKey = 'threeFirstPerson' | |||||
| protected _controlsCtor: TControlsCtor = (object, domElement) => new FirstPersonControls2(object, domElement || document.documentElement) | |||||
| } |
| import {Euler, EulerOrder, EventDispatcher, MathUtils, Object3D, Quaternion, Vector3} from 'three' | import {Euler, EulerOrder, EventDispatcher, MathUtils, Object3D, Quaternion, Vector3} from 'three' | ||||
| import {IEvent, now, serialize} from 'ts-browser-helpers' | import {IEvent, now, serialize} from 'ts-browser-helpers' | ||||
| import {uiPanelContainer, uiSlider} from 'uiconfig.js' | |||||
| import {uiButton, uiPanelContainer, uiSlider} from 'uiconfig.js' | |||||
| import {ICameraControls} from '../../core' | import {ICameraControls} from '../../core' | ||||
| // eslint-disable-next-line @typescript-eslint/naming-convention | // eslint-disable-next-line @typescript-eslint/naming-convention | ||||
| private _initQuaternion = new Quaternion() | private _initQuaternion = new Quaternion() | ||||
| private _initQuaternionInvert = new Quaternion() | private _initQuaternionInvert = new Quaternion() | ||||
| private _initQuaternionDest = new Quaternion() | private _initQuaternionDest = new Quaternion() | ||||
| @uiButton('Reset View') | |||||
| resetView() { | |||||
| (this._initQuaternionDest as any).__init = false | |||||
| } | |||||
| @uiButton() | |||||
| connect() { | connect() { | ||||
| if (this.enabled) return | |||||
| this.onScreenOrientationChangeEvent() // run once on load | this.onScreenOrientationChangeEvent() // run once on load | ||||
| } | } | ||||
| @uiButton() | |||||
| disconnect() { | disconnect() { | ||||
| if (!this.enabled) return | |||||
| window.removeEventListener('orientationchange', this.onScreenOrientationChangeEvent) | window.removeEventListener('orientationchange', this.onScreenOrientationChangeEvent) | ||||
| window.removeEventListener('deviceorientation', this.onDeviceOrientationChangeEvent) | window.removeEventListener('deviceorientation', this.onDeviceOrientationChangeEvent) | ||||
| _q2.multiply(_q0.setFromAxisAngle(_zee, -orient)) // adjust for screen orientation | _q2.multiply(_q0.setFromAxisAngle(_zee, -orient)) // adjust for screen orientation | ||||
| // debugger | |||||
| if (!(this._initQuaternionDest as any).__init) { | if (!(this._initQuaternionDest as any).__init) { | ||||
| this._initQuaternionDest.copy(_q2).invert() | this._initQuaternionDest.copy(_q2).invert() | ||||
| ;(this._initQuaternionDest as any).__init = true | ;(this._initQuaternionDest as any).__init = true | ||||
| _q2.premultiply(this._initQuaternionDest) | _q2.premultiply(this._initQuaternionDest) | ||||
| const mTime = 1 / 60 | const mTime = 1 / 60 | ||||
| // this.object.quaternion.multiply(this._initQuaternionInvert) | |||||
| this.object.quaternion.multiply(this._initQuaternionInvert) | |||||
| this.object.quaternion.slerp(_q2, this.dampingFactor / (Math.min(1, time - this._lastTime) / mTime)) | this.object.quaternion.slerp(_q2, this.dampingFactor / (Math.min(1, time - this._lastTime) / mTime)) | ||||
| // this.object.quaternion.multiply(this._initQuaternion) | |||||
| this.object.quaternion.multiply(this._initQuaternion) | |||||
| // console.log(time - this._lastTime, mTime) | // console.log(time - this._lastTime, mTime) | ||||
| this._lastTime = time | this._lastTime = time |
| import {MathUtils, Object3D, Spherical, Vector3} from 'three' | |||||
| import {IEvent, now, serialize, SimpleEventDispatcher} from 'ts-browser-helpers' | |||||
| import {EventDispatcher, MathUtils, Object3D, Spherical, Vector3} from 'three' | |||||
| import {IEvent, now, serialize} from 'ts-browser-helpers' | |||||
| import {uiFolderContainer, uiInput, uiToggle} from 'uiconfig.js' | import {uiFolderContainer, uiInput, uiToggle} from 'uiconfig.js' | ||||
| import {ICameraControls} from '../../core' | |||||
| // eslint-disable-next-line @typescript-eslint/naming-convention | // eslint-disable-next-line @typescript-eslint/naming-convention | ||||
| const _lookDirection = new Vector3() | const _lookDirection = new Vector3() | ||||
| const _changeEvent: IEvent<'change'> = {type: 'change'} | const _changeEvent: IEvent<'change'> = {type: 'change'} | ||||
| @uiFolderContainer('First Person Controls') | @uiFolderContainer('First Person Controls') | ||||
| export class FirstPersonControls2 extends SimpleEventDispatcher<'change'> { | |||||
| export class FirstPersonControls2 extends EventDispatcher implements ICameraControls<'change'> { | |||||
| readonly object: Object3D | readonly object: Object3D | ||||
| readonly domElement: HTMLElement | Document | readonly domElement: HTMLElement | Document | ||||