Three.js mousewheel to move camera up/down instead of zoom-in/out

∥☆過路亽.° 提交于 2021-01-29 09:51:24

问题


How do you do this? I created a scene using the Three.js Editor and downloaded the project using the "Publish" option. I edited the app.js file to import OrbitControls, so now I can use the mouse wheel (or in my case the Apple Magic Mouse 2 trackpad surface) to zoom in/out of the scene. However, I don't want the mouse wheel to zoom, I want it to "scroll" (move the camera up/down along the Y-axis as opposed the Z-axis). Is there a way to do that? Is OrbitControls the way to get there or does that just add complexity? Here is my app.js:

import {OrbitControls} from './OrbitControls.js'; // Added
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 ) );
            var controls = new OrbitControls( camera, renderer.domElement ); // Added
            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 };
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>

回答1:


I don't have the details of your project but you need implement your own stroller module.

How can I do that Teo?

Well my young padawan, we need to implement a function that moves the camera up/down as you mentioned.

So, you mean that OrbitControls just add complexity?

Now, if that is the only camera you need, then yupe it does, adding OrbitControls.

Let's implement it.

First we add window.addEventListener('wheel', onMouseWheel, false); to listen the mouse wheel. Now we call event.preventDefault(); method to prevent the zoom.

Now we calculate the scroll modifier camera.position.y += event.deltaY / 1000;. In this case we use the delta in the Y-axis. For this example the value was so high so I divided by 1000 to have a more smooth scrolling.

Finally we add camera.position.clampScalar(0, 10); to prevent the scrolling out of bounds.

var camera, scene, renderer;
var geometry, material, mesh;

init();
animate();

function init() {
  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);

  camera.position.z = 1;

  scene = new THREE.Scene();

  geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
  material = new THREE.MeshNormalMaterial();

  mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  renderer = new THREE.WebGLRenderer({
    antialias: true
  });

  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  window.addEventListener('wheel', onMouseWheel, false);
  window.addEventListener('resize', onWindowResize, false);
}


function animate() {

  requestAnimationFrame(animate);

  mesh.rotation.x += 0.01;
  mesh.rotation.y += 0.02;

  renderer.render(scene, camera);
}


function onMouseWheel(ev) {
  event.preventDefault();

  camera.position.y += event.deltaY / 1000;

  // prevent scrolling beyond a min/max value
  camera.position.clampScalar(0, 10);
}


function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>



回答2:


If vertical scroll is the only behavior you need, then yes, adding OrbitControls is adding unnecessary complexity because you could easily achieve it with the default JavaScript APIs:

// Add listener to respond to the "wheel" event
window.addEventListener("wheel", onMouseWheel);

function onMouseWheel(event){
    camera.position.y += event.deltaY * 10;
}

The * 10 multiplier depends on the size of your scene, and how fast you want your camera to move vertically.



来源:https://stackoverflow.com/questions/59776570/three-js-mousewheel-to-move-camera-up-down-instead-of-zoom-in-out

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!