Reputation: 352
Using the Three.js Editor, I exported a project with a simple scene (two boxes). Everything loads fine—I see the two boxes from my PerspectiveCamera that I added. I want to control my camera view with the mouse wheel. Here is the script in the index.html:
<script type="module">
import * as THREE from './js/three.module.js';
import { APP } from './js/app.js';
import {OrbitControls} from './js/OrbitControls.js'; // I added this part.
// OrbitControls here?
var loader = new THREE.FileLoader();
loader.load( 'app.json', function ( text ) {
var player = new APP.Player( THREE );
player.load( JSON.parse( text ) );
player.setSize( window.innerWidth, window.innerHeight );
player.play();
document.body.appendChild( player.dom );
window.addEventListener( 'resize', function () {
player.setSize( window.innerWidth, window.innerHeight );
} );
} );
</script>
How do I utilize OrbitControls for this? Everything I've attempted (based on similar threads) leads to errors of things being undefined (like "camera" or "controls" depending on where I put it).
Alternatively (and even more ideally), is there a way to define the camera behavior I want within the Three.js Editor itself? That would be extra awesome!
EDIT
Thanks to @Mugen87 's original answer (basically that this isn't possible without editing app.js) here is the status of the question now. I removed the OrbitControls import from my index.html (above) and added it to my app.js. So my app.js currently looks like this:
import {OrbitControls} from './OrbitControls.js';
var APP = {
Player: function ( THREE ) {
window.THREE = THREE; // FIX for editor scripts (they require THREE in global namespace)
var loader = new THREE.ObjectLoader();
var camera, scene, renderer;
var events = {};
var dom = document.createElement( 'div' );
dom.className = "threejs-app";
this.dom = dom;
this.width = 500;
this.height = 500;
this.load = function ( json ) {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.setClearColor( 0x000000 );
renderer.setPixelRatio( window.devicePixelRatio );
var project = json.project;
if ( project.shadows ) renderer.shadowMap.enabled = true;
if ( project.vr ) renderer.xr.enabled = true;
dom.appendChild( renderer.domElement );
this.setScene( loader.parse( json.scene ) );
this.setCamera( loader.parse( json.camera ) );
events = {
init: [],
start: [],
stop: [],
keydown: [],
keyup: [],
mousedown: [],
mouseup: [],
mousemove: [],
touchstart: [],
touchend: [],
touchmove: [],
update: []
};
var scriptWrapParams = 'player,renderer,scene,camera';
var scriptWrapResultObj = {};
for ( var eventKey in events ) {
scriptWrapParams += ',' + eventKey;
scriptWrapResultObj[ eventKey ] = eventKey;
}
var scriptWrapResult = JSON.stringify( scriptWrapResultObj ).replace( /\"/g, '' );
for ( var uuid in json.scripts ) {
var object = scene.getObjectByProperty( 'uuid', uuid, true );
if ( object === undefined ) {
console.warn( 'APP.Player: Script without object.', uuid );
continue;
}
var scripts = json.scripts[ uuid ];
for ( var i = 0; i < scripts.length; i ++ ) {
var script = scripts[ i ];
var functions = ( new Function( scriptWrapParams, script.source + '\nreturn ' + scriptWrapResult + ';' ).bind( object ) )( this, renderer, scene, camera );
for ( var name in functions ) {
if ( functions[ name ] === undefined ) continue;
if ( events[ name ] === undefined ) {
console.warn( 'APP.Player: Event type not supported (', name, ')' );
continue;
}
events[ name ].push( functions[ name ].bind( object ) );
}
}
}
dispatch( events.init, arguments );
};
this.setCamera = function ( value ) {
camera = value;
camera.aspect = this.width / this.height;
camera.updateProjectionMatrix();
};
this.setScene = function ( value ) {
scene = value;
};
this.setSize = function ( width, height ) {
this.width = width;
this.height = height;
if ( camera ) {
camera.aspect = this.width / this.height;
camera.updateProjectionMatrix();
}
if ( renderer ) {
renderer.setSize( width, height );
}
};
function dispatch( array, event ) {
for ( var i = 0, l = array.length; i < l; i ++ ) {
array[ i ]( event );
}
}
var time, prevTime;
function animate() {
time = performance.now();
try {
dispatch( events.update, { time: time, delta: time - prevTime } );
} catch ( e ) {
console.error( ( e.message || e ), ( e.stack || "" ) );
}
renderer.render( scene, camera );
prevTime = time;
}
this.play = function () {
prevTime = performance.now();
document.addEventListener( 'keydown', onDocumentKeyDown );
document.addEventListener( 'keyup', onDocumentKeyUp );
document.addEventListener( 'mousedown', onDocumentMouseDown );
document.addEventListener( 'mouseup', onDocumentMouseUp );
document.addEventListener( 'mousemove', onDocumentMouseMove );
document.addEventListener( 'touchstart', onDocumentTouchStart );
document.addEventListener( 'touchend', onDocumentTouchEnd );
document.addEventListener( 'touchmove', onDocumentTouchMove );
dispatch( events.start, arguments );
renderer.setAnimationLoop( animate );
};
this.stop = function () {
document.removeEventListener( 'keydown', onDocumentKeyDown );
document.removeEventListener( 'keyup', onDocumentKeyUp );
document.removeEventListener( 'mousedown', onDocumentMouseDown );
document.removeEventListener( 'mouseup', onDocumentMouseUp );
document.removeEventListener( 'mousemove', onDocumentMouseMove );
document.removeEventListener( 'touchstart', onDocumentTouchStart );
document.removeEventListener( 'touchend', onDocumentTouchEnd );
document.removeEventListener( 'touchmove', onDocumentTouchMove );
dispatch( events.stop, arguments );
renderer.setAnimationLoop( null );
};
this.dispose = function () {
while ( dom.children.length ) {
dom.removeChild( dom.firstChild );
}
renderer.dispose();
camera = undefined;
scene = undefined;
renderer = undefined;
};
//
function onDocumentKeyDown( event ) {
dispatch( events.keydown, event );
}
function onDocumentKeyUp( event ) {
dispatch( events.keyup, event );
}
function onDocumentMouseDown( event ) {
dispatch( events.mousedown, event );
}
function onDocumentMouseUp( event ) {
dispatch( events.mouseup, event );
}
function onDocumentMouseMove( event ) {
dispatch( events.mousemove, event );
}
function onDocumentTouchStart( event ) {
dispatch( events.touchstart, event );
}
function onDocumentTouchEnd( event ) {
dispatch( events.touchend, event );
}
function onDocumentTouchMove( event ) {
dispatch( events.touchmove, event );
}
}
};
export { APP };
Side note: I'm noticing there are already many event listeners that were already generated by the Three.js Editor. They currently don't seem to do anything, but maybe they're there to be called from outside the script, such as in my index.html???
Anyway, where and how in the app.js file do I need to put the OrbitControls, in order to control the Y-axis position of the PerspectiveCamera with the mousewheel?
Upvotes: 2
Views: 3625
Reputation: 31026
Alternatively (and even more ideally), is there a way to define the camera behavior I want within the Three.js Editor itself?
Unfortunately no. You can only use the default controls which are defined by EditorControls
, a class similar to OrbitControls
but only used in the editor.
How do I utilize OrbitControls for this?
I'm afraid this is not possible without changing app.js
. The camera and the renderer are created in within APP.Player
and are not public accessible. Since you need both objects for creating OrbitControls
, it's not possible to instantiate the controls in index.html
.
If you decide to change app.js
, use the following code to create the controls if you include OrbitControls
via ES6 imports:
var controls = new OrbitControls( camera, renderer.domElement );
three.js R112
Upvotes: 2