-
-
Notifications
You must be signed in to change notification settings - Fork 256
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { EventDispatcher } from '../dist/camera-controls.module.js'; | ||
|
||
/** | ||
* Represents a pseudo element, works in WebWorker. | ||
* @extends EventDispatcher | ||
*/ | ||
export class PseudoElement extends EventDispatcher { | ||
|
||
/** @type {PseudoDocument} */ | ||
ownerDocument = new PseudoDocument(); | ||
/** @type {any} */ | ||
style = {}; | ||
/** @private @type {DOMRect} */ | ||
_domRect = new DOMRect(); | ||
|
||
constructor() { | ||
|
||
super(); | ||
|
||
} | ||
|
||
/** | ||
* @returns {DOMRect} The DOMRect. | ||
*/ | ||
getBoundingClientRect() { | ||
|
||
return DOMRect.fromRect( this._domRect ); | ||
|
||
} | ||
|
||
/** | ||
* Just for compatibility. doesn't work. | ||
* @returns {Promise<void>} A promise that rejects. | ||
*/ | ||
requestPointerLock() { | ||
|
||
return Promise.reject(); | ||
|
||
} | ||
|
||
/** | ||
* Just for compatibility. do nothing. | ||
* @param {string} _ The attribute name. | ||
* @param {string} __ The attribute value. | ||
*/ | ||
setAttribute( _, __ ) {} | ||
|
||
/** | ||
* Updates the PseudoElement size based on a given bound. | ||
* @param {DOMRect} bound The new bound. | ||
*/ | ||
update( bound ) { | ||
|
||
this._domRect.x = bound.x; | ||
this._domRect.y = bound.y; | ||
this._domRect.width = bound.width; | ||
this._domRect.height = bound.height; | ||
|
||
} | ||
|
||
} | ||
|
||
/** | ||
* Represents a pseudo document. | ||
* @extends EventDispatcher | ||
*/ | ||
class PseudoDocument extends EventDispatcher { | ||
|
||
/** | ||
* Creates an instance of PseudoDocument. | ||
*/ | ||
constructor() { | ||
|
||
super(); | ||
|
||
} | ||
|
||
/** | ||
* Exits pointer lock. | ||
*/ | ||
exitPointerLock() {} | ||
|
||
/** | ||
* Just for compatibility. do nothing. | ||
* @returns {PseudoElement|null} The element locking the pointer. | ||
*/ | ||
get pointerLockElement() { | ||
|
||
return null; | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width"> | ||
<title>=^.^=</title> | ||
<link rel="stylesheet" href="./style.css"> | ||
</head> | ||
<body> | ||
<div class="info"> | ||
<p><a href="https://github.com/yomotsu/camera-controls">GitHub repo</a></p> | ||
<button id="resetButton">reset</button> | ||
</div> | ||
|
||
<canvas></canvas> | ||
|
||
<script type="module"> | ||
const canvas = document.querySelector( 'canvas' ); | ||
canvas.width = window.innerWidth; | ||
canvas.height = window.innerHeight; | ||
const canvasBounds = canvas.getBoundingClientRect(); | ||
const offscreenCanvas = canvas.transferControlToOffscreen(); | ||
|
||
const worker = new Worker( './worker.js', { type: 'module' } ); | ||
worker.postMessage( { | ||
action: 'init', | ||
payload: { | ||
canvas: offscreenCanvas, | ||
left: canvasBounds.left, | ||
top: canvasBounds.top, | ||
width: canvasBounds.width, | ||
height: canvasBounds.height, | ||
} }, | ||
[ offscreenCanvas ] | ||
); | ||
|
||
const onPointerDown = ( event ) => { | ||
|
||
const pseudoPointerEvent = { | ||
pointerId: event.pointerId, | ||
pointerType: event.pointerType, | ||
clientX: event.clientX, | ||
clientY: event.clientY, | ||
buttons: event.buttons, | ||
}; | ||
|
||
canvas.ownerDocument.removeEventListener( 'pointermove', onPointerMove, { passive: false } ); | ||
canvas.ownerDocument.removeEventListener( 'pointerup', onPointerUp ); | ||
|
||
canvas.ownerDocument.addEventListener( 'pointermove', onPointerMove, { passive: false } ); | ||
canvas.ownerDocument.addEventListener( 'pointerup', onPointerUp ); | ||
|
||
worker.postMessage( { action: 'pointerdown', payload: { event: pseudoPointerEvent } } ); | ||
|
||
}; | ||
|
||
const onPointerMove = ( event ) => { | ||
|
||
if ( event.cancelable ) event.preventDefault(); | ||
|
||
const pseudoPointerEvent = { | ||
pointerId: event.pointerId, | ||
pointerType: event.pointerType, | ||
clientX: event.clientX, | ||
clientY: event.clientY, | ||
movementX: event.movementX, | ||
movementY: event.movementY, | ||
buttons: event.buttons, | ||
} | ||
|
||
worker.postMessage( { action: 'pointermove', payload: { event: pseudoPointerEvent } } ); | ||
|
||
}; | ||
|
||
const onPointerUp = ( event ) => { | ||
|
||
const pseudoPointerEvent = { | ||
pointerId: event.pointerId, | ||
pointerType: event.pointerType, | ||
}; | ||
|
||
worker.postMessage( { action: 'pointerup', payload: { event: pseudoPointerEvent } } ); | ||
|
||
} | ||
|
||
const endDragging = () => { | ||
|
||
canvas.ownerDocument.removeEventListener( 'pointermove', onPointerMove, { passive: false } ); | ||
canvas.ownerDocument.removeEventListener( 'pointerup', onPointerUp ); | ||
|
||
}; | ||
|
||
worker.addEventListener( 'message', ( { data } ) => data?.action === 'controlend' && endDragging() ); | ||
canvas.addEventListener( 'pointerdown', onPointerDown ); | ||
|
||
|
||
resetButton.addEventListener( 'click', () => worker.postMessage( { action: 'reset' } ) ); | ||
|
||
// debug log | ||
worker.addEventListener( 'message', ( { data } ) => console.log( data ) ); | ||
</script> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import * as THREE from 'https://unpkg.com/three@0.161.0/build/three.module.js'; | ||
import CameraControls from '../dist/camera-controls.module.js'; | ||
import { PseudoElement } from './PseudoElement.js'; | ||
|
||
CameraControls.install( { THREE } ); | ||
|
||
// DOM element doesn't exist in WebWorker. use a virtual element in CameraControls instead. | ||
const pseudoElement = new PseudoElement(); | ||
let cameraControls; | ||
|
||
self.onmessage = ( { data } ) => { | ||
|
||
const { action, payload } = data; | ||
|
||
switch ( action ) { | ||
|
||
case 'init': { | ||
|
||
const { canvas, left, top, width, height } = payload; | ||
canvas.style = { width: '', height: '' }; | ||
|
||
const clock = new THREE.Clock(); | ||
const scene = new THREE.Scene(); | ||
const camera = new THREE.PerspectiveCamera( 60, width / height, 0.01, 100 ); | ||
camera.position.set( 0, 0, 5 ); | ||
const renderer = new THREE.WebGLRenderer( { canvas } ); | ||
renderer.setSize( width, height ); | ||
|
||
pseudoElement.update( { left, top, width, height } ); | ||
cameraControls = new CameraControls( camera, pseudoElement, self ); | ||
cameraControls.addEventListener( 'controlend', () => self.postMessage( { action: 'controlend' } ) ); | ||
|
||
const mesh = new THREE.Mesh( | ||
new THREE.BoxGeometry( 1, 1, 1 ), | ||
new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } ) | ||
); | ||
scene.add( mesh ); | ||
|
||
const gridHelper = new THREE.GridHelper( 50, 50 ); | ||
gridHelper.position.y = - 1; | ||
scene.add( gridHelper ); | ||
|
||
renderer.render( scene, camera ); | ||
|
||
( function anim() { | ||
|
||
const delta = clock.getDelta(); | ||
// const elapsed = clock.getElapsedTime(); | ||
const updated = cameraControls.update( delta ); | ||
|
||
// if ( elapsed > 30 ) return; | ||
|
||
requestAnimationFrame( anim ); | ||
|
||
if ( updated ) { | ||
|
||
renderer.render( scene, camera ); | ||
self.postMessage( 'rendered' ); | ||
|
||
} | ||
|
||
} )(); | ||
|
||
break; | ||
|
||
} | ||
|
||
case 'pointerdown': | ||
case 'pointermove': | ||
case 'pointerup': { | ||
|
||
const { event } = payload; | ||
pseudoElement.dispatchEvent( { type: action, ...event } ); | ||
break; | ||
|
||
} | ||
|
||
case 'reset': { | ||
|
||
cameraControls.reset( true ); | ||
break; | ||
|
||
} | ||
|
||
} | ||
|
||
// debug log | ||
self.postMessage( data.action ); | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters