Joe Rhoney
Joe Rhoney

Reputation: 352

How to use OrbitControls in Three.js Editor project

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

Answers (1)

Mugen87
Mugen87

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

Related Questions