2017-09-17 248 views
0

我想通过只使用鼠标移动来移动摄像头绕过我的JSON场景。但是,我希望摄像头只随着鼠标的移动和鼠标的方向移动,而不必单击并拖动。THREE.js用限制鼠标移动摄像头

我已经开发了这个的部分工作版本,但它不是我需要它的地方。我也在寻找相机停止移动在某一点,除了相机不改变它本身和动画JSON之间的距离。

这里是我的代码:

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
     <title>three.js webgl - animation - keyframes - json</title> 
     <meta charset="utf-8"> 
     <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> 
     <style> 

      body { 
       color: #fff; 
       font-family:Monospace; 
       font-size:13px; 
       text-align:center; 
       background-color: #fff; 
       margin: 0px; 
       overflow: hidden; 
      } 

      #info { 
       position: absolute; 
       top: 0px; width: 100%; 
       padding: 5px; 
      } 

      a { 
       color: #2983ff; 
      } 

     </style> 
    </head> 

    <body> 

     <div id="container"></div> 

     <div id="info"> 
      <a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - animation - keyframes - json 
     </div> 

     <script src="three.min.js"></script> 

     <script src="Detector.js"></script> 
     <script src="stats.min.js"></script> 

     <script> 

      var mouseX = 0, mouseY = 0; 
      var windowHalfX = window.innerWidth/2; 
      var windowHalfY = window.innerHeight/2; 


      var scene, camera, pointLight, stats; 
      var model; 
      var renderer, mixer, animationClip; 

      var clock = new THREE.Clock(); 
      var container = document.getElementById('container'); 

      stats = new Stats(); 
      container.appendChild(stats.dom); 

      renderer = new THREE.WebGLRenderer({ antialias: true }); 
      renderer.setPixelRatio(window.devicePixelRatio); 
      renderer.setSize(window.innerWidth, window.innerHeight); 
      container.appendChild(renderer.domElement); 

      document.addEventListener('mousemove', onDocumentMouseMove, false); 

      window.addEventListener('resize', onresize, false); 

      scene = new THREE.Scene(); 

      var grid = new THREE.GridHelper(20, 20, 0x888888, 0x888888); 
      grid.position.set(0, - 1.1, 0); 
      scene.add(grid); 

      camera = new THREE.PerspectiveCamera(70, window.innerWidth/window.innerHeight, 1, 1000); 
      camera.position.z = 30; 
      camera.position.y = 30; 
      // camera.position.x = 0; 
      // camera.position.set(- 5.00, 3.43, 11.31); 
      // camera.lookAt(new THREE.Vector3(- 1.22, 2.18, 4.58)); 

      scene.add(new THREE.AmbientLight(0x404040)); 

      pointLight = new THREE.PointLight(0xffffff, 1); 
      pointLight.position.copy(camera.position); 
      scene.add(pointLight); 

      new THREE.ObjectLoader().load('FuckIt2.json', function (model) { 

       scene.add(model); 

       mixer = new THREE.AnimationMixer(model); 
       mixer.clipAction(model.animations[ 0 ]).play(); 
       // 
       // model.position.y = 0; 
       // model.position.x = 0; 

       animate(); 

      }); 

      function onDocumentMouseMove(event) { 

       mouseY = (event.clientY - windowHalfX)/5; 
       mouseX = (event.clientX - windowHalfY)/5; 

      } 



      window.onresize = function() { 

       windowHalfX = window.innerWidth/1; 
       windowHalfY = window.innerHeight/1; 

       camera.aspect = window.innerWidth/window.innerHeight; 
       camera.updateProjectionMatrix(); 

       renderer.setSize(window.innerWidth, window.innerHeight); 

      }; 


      function animate() { 

       requestAnimationFrame(animate); 

       mixer.update(clock.getDelta()); 

       stats.update(); 

       render(); 
      } 

      function render() { 

       camera.position.x += (mouseX - camera.position.x) * 0.003; 
       camera.position.y += (- mouseY - camera.position.y) * 0.003; 
       camera.lookAt(scene.position); 
       renderer.render(scene, camera); 

} 
     </script> 

    </body> 
    </html> 

请让我知道我能做些什么来改变这个!任何和所有的帮助表示赞赏。谢谢!

回答

0

为什么重新发明轮子?我只是重复使用TrackballControls.js代码并根据需要对其进行修改,如果您不想按住并拖动鼠标旋转摄像头,则修改事件处理行为并默认启用旋转模式,就像我在这 - 脏 - codepen

/** 
* @author Eberhard Graether/http://egraether.com/ 
* @author Mark Lundin/http://mark-lundin.com 
* @author Simone Manini/http://daron1337.github.io 
* @author Luca Antiga/http://lantiga.github.io 
*/ 

THREE.MyTrackballControls = function (object, domElement) { 

    var _this = this; 
    var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; 

    this.object = object; 
    this.domElement = (domElement !== undefined) ? domElement : document; 

    // API 

    this.enabled = true; 

    this.screen = { left: 0, top: 0, width: 0, height: 0 }; 

    this.rotateSpeed = 1.0; 
    this.zoomSpeed = 1.2; 
    this.panSpeed = 0.3; 

    this.noRotate = false; 
    this.noZoom = false; 
    this.noPan = false; 

    this.staticMoving = false; 
    this.dynamicDampingFactor = 0.2; 

    this.minDistance = 0; 
    this.maxDistance = Infinity; 

    this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; 

    // internals 

    this.target = new THREE.Vector3(); 

    var EPS = 0.000001; 

    var lastPosition = new THREE.Vector3(); 

    var _state = STATE.ROTATE, 
    _prevState = STATE.NONE, 


    _eye = new THREE.Vector3(), 

    _movePrev = new THREE.Vector2(), 
    _moveCurr = new THREE.Vector2(), 

    _lastAxis = new THREE.Vector3(), 
    _lastAngle = 0, 

    _zoomStart = new THREE.Vector2(), 
    _zoomEnd = new THREE.Vector2(), 

    _touchZoomDistanceStart = 0, 
    _touchZoomDistanceEnd = 0, 

    _panStart = new THREE.Vector2(), 
    _panEnd = new THREE.Vector2(); 

    // for reset 

    this.target0 = this.target.clone(); 
    this.position0 = this.object.position.clone(); 
    this.up0 = this.object.up.clone(); 

    // events 

    var changeEvent = { type: 'change' }; 
    var startEvent = { type: 'start' }; 
    var endEvent = { type: 'end' }; 


    // methods 

    this.handleResize = function() { 

    if (this.domElement === document) { 

     this.screen.left = 0; 
     this.screen.top = 0; 
     this.screen.width = window.innerWidth; 
     this.screen.height = window.innerHeight; 

    } else { 

     var box = this.domElement.getBoundingClientRect(); 
     // adjustments come from similar code in the jquery offset() function 
     var d = this.domElement.ownerDocument.documentElement; 
     this.screen.left = box.left + window.pageXOffset - d.clientLeft; 
     this.screen.top = box.top + window.pageYOffset - d.clientTop; 
     this.screen.width = box.width; 
     this.screen.height = box.height; 

    } 

    }; 

    this.handleEvent = function (event) { 

    if (typeof this[ event.type ] == 'function') { 

     this[ event.type ](event); 

    } 

    }; 

    var getMouseOnScreen = (function() { 

    var vector = new THREE.Vector2(); 

    return function getMouseOnScreen(pageX, pageY) { 

     vector.set(
     (pageX - _this.screen.left)/_this.screen.width, 
     (pageY - _this.screen.top)/_this.screen.height 
    ); 

     return vector; 

    }; 

    }()); 

    var getMouseOnCircle = (function() { 

    var vector = new THREE.Vector2(); 

    return function getMouseOnCircle(pageX, pageY) { 

     vector.set(
     ((pageX - _this.screen.width * 0.5 - _this.screen.left)/(_this.screen.width * 0.5)), 
     ((_this.screen.height + 2 * (_this.screen.top - pageY))/_this.screen.width) // screen.width intentional 
    ); 

     return vector; 

    }; 

    }()); 

    this.rotateCamera = (function() { 

    var axis = new THREE.Vector3(), 
     quaternion = new THREE.Quaternion(), 
     eyeDirection = new THREE.Vector3(), 
     objectUpDirection = new THREE.Vector3(), 
     objectSidewaysDirection = new THREE.Vector3(), 
     moveDirection = new THREE.Vector3(), 
     angle; 

    return function rotateCamera() { 

     moveDirection.set(_moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0); 
     angle = moveDirection.length(); 

     if (angle) { 

     _eye.copy(_this.object.position).sub(_this.target); 

     eyeDirection.copy(_eye).normalize(); 
     objectUpDirection.copy(_this.object.up).normalize(); 
     objectSidewaysDirection.crossVectors(objectUpDirection, eyeDirection).normalize(); 

     objectUpDirection.setLength(_moveCurr.y - _movePrev.y); 
     objectSidewaysDirection.setLength(_moveCurr.x - _movePrev.x); 

     moveDirection.copy(objectUpDirection.add(objectSidewaysDirection)); 

     axis.crossVectors(moveDirection, _eye).normalize(); 

     angle *= _this.rotateSpeed; 
     quaternion.setFromAxisAngle(axis, angle); 

     _eye.applyQuaternion(quaternion); 
     _this.object.up.applyQuaternion(quaternion); 

     _lastAxis.copy(axis); 
     _lastAngle = angle; 

     } else if (! _this.staticMoving && _lastAngle) { 

     _lastAngle *= Math.sqrt(1.0 - _this.dynamicDampingFactor); 
     _eye.copy(_this.object.position).sub(_this.target); 
     quaternion.setFromAxisAngle(_lastAxis, _lastAngle); 
     _eye.applyQuaternion(quaternion); 
     _this.object.up.applyQuaternion(quaternion); 

     } 

     _movePrev.copy(_moveCurr); 

    }; 

    }()); 


    this.zoomCamera = function() { 

    var factor; 

    if (_state === STATE.TOUCH_ZOOM_PAN) { 

     factor = _touchZoomDistanceStart/_touchZoomDistanceEnd; 
     _touchZoomDistanceStart = _touchZoomDistanceEnd; 
     _eye.multiplyScalar(factor); 

    } else { 

     factor = 1.0 + (_zoomEnd.y - _zoomStart.y) * _this.zoomSpeed; 

     if (factor !== 1.0 && factor > 0.0) { 

     _eye.multiplyScalar(factor); 

     } 

     if (_this.staticMoving) { 

     _zoomStart.copy(_zoomEnd); 

     } else { 

     _zoomStart.y += (_zoomEnd.y - _zoomStart.y) * this.dynamicDampingFactor; 

     } 

    } 

    }; 

    this.panCamera = (function() { 

    var mouseChange = new THREE.Vector2(), 
     objectUp = new THREE.Vector3(), 
     pan = new THREE.Vector3(); 

    return function panCamera() { 

     mouseChange.copy(_panEnd).sub(_panStart); 

     if (mouseChange.lengthSq()) { 

     mouseChange.multiplyScalar(_eye.length() * _this.panSpeed); 

     pan.copy(_eye).cross(_this.object.up).setLength(mouseChange.x); 
     pan.add(objectUp.copy(_this.object.up).setLength(mouseChange.y)); 

     _this.object.position.add(pan); 
     _this.target.add(pan); 

     if (_this.staticMoving) { 

      _panStart.copy(_panEnd); 

     } else { 

      _panStart.add(mouseChange.subVectors(_panEnd, _panStart).multiplyScalar(_this.dynamicDampingFactor)); 

     } 

     } 

    }; 

    }()); 

    this.checkDistances = function() { 

    if (! _this.noZoom || ! _this.noPan) { 

     if (_eye.lengthSq() > _this.maxDistance * _this.maxDistance) { 

     _this.object.position.addVectors(_this.target, _eye.setLength(_this.maxDistance)); 
     _zoomStart.copy(_zoomEnd); 

     } 

     if (_eye.lengthSq() < _this.minDistance * _this.minDistance) { 

     _this.object.position.addVectors(_this.target, _eye.setLength(_this.minDistance)); 
     _zoomStart.copy(_zoomEnd); 

     } 

    } 

    }; 

    this.update = function() { 

    _eye.subVectors(_this.object.position, _this.target); 

    if (! _this.noRotate) { 

     _this.rotateCamera(); 

    } 

    if (! _this.noZoom) { 

     _this.zoomCamera(); 

    } 

    if (! _this.noPan) { 

     _this.panCamera(); 

    } 

    _this.object.position.addVectors(_this.target, _eye); 

    _this.checkDistances(); 

    _this.object.lookAt(_this.target); 

    if (lastPosition.distanceToSquared(_this.object.position) > EPS) { 

     _this.dispatchEvent(changeEvent); 

     lastPosition.copy(_this.object.position); 

    } 

    }; 

    this.reset = function() { 

    _state = STATE.NONE; 
    _prevState = STATE.NONE; 

    _this.target.copy(_this.target0); 
    _this.object.position.copy(_this.position0); 
    _this.object.up.copy(_this.up0); 

    _eye.subVectors(_this.object.position, _this.target); 

    _this.object.lookAt(_this.target); 

    _this.dispatchEvent(changeEvent); 

    lastPosition.copy(_this.object.position); 

    }; 

    // listeners 

    function keydown(event) { 

    if (_this.enabled === false) return; 

    window.removeEventListener('keydown', keydown); 

    _prevState = _state; 

    if (_state !== STATE.NONE) { 

     return; 

    } else if (event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate) { 

     _state = STATE.ROTATE; 

    } else if (event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom) { 

     _state = STATE.ZOOM; 

    } else if (event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan) { 

     _state = STATE.PAN; 

    } 

    } 

    function keyup(event) { 

    if (_this.enabled === false) return; 

    _state = _prevState; 

    window.addEventListener('keydown', keydown, false); 

    } 

    function mousedown(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    if (_state === STATE.NONE) { 

     _state = event.button; 

    } 

    if (_state === STATE.ROTATE && ! _this.noRotate) { 

     _moveCurr.copy(getMouseOnCircle(event.pageX, event.pageY)); 
     _movePrev.copy(_moveCurr); 

    } else if (_state === STATE.ZOOM && ! _this.noZoom) { 

     _zoomStart.copy(getMouseOnScreen(event.pageX, event.pageY)); 
     _zoomEnd.copy(_zoomStart); 

    } else if (_state === STATE.PAN && ! _this.noPan) { 

     _panStart.copy(getMouseOnScreen(event.pageX, event.pageY)); 
     _panEnd.copy(_panStart); 

    } 

    //added by default 
    //document.addEventListener('mousemove', mousemove, false); 
    //document.addEventListener('mouseup', mouseup, false); 

    _this.dispatchEvent(startEvent); 

    } 

    function mousemove(event) { 



    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    if (_state === STATE.ROTATE && ! _this.noRotate) { 

     _movePrev.copy(_moveCurr); 
     _moveCurr.copy(getMouseOnCircle(event.pageX, event.pageY)); 

    } else if (_state === STATE.ZOOM && ! _this.noZoom) { 

     _zoomEnd.copy(getMouseOnScreen(event.pageX, event.pageY)); 

    } else if (_state === STATE.PAN && ! _this.noPan) { 

     _panEnd.copy(getMouseOnScreen(event.pageX, event.pageY)); 

    } 

    } 

    function mouseup(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    //_state = STATE.NONE; 

    //document.removeEventListener('mousemove', mousemove); 
    //document.removeEventListener('mouseup', mouseup); 
    _this.dispatchEvent(endEvent); 

    } 

    function mousewheel(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    switch (event.deltaMode) { 

     case 2: 
     // Zoom in pages 
     _zoomStart.y -= event.deltaY * 0.025; 
     break; 

     case 1: 
     // Zoom in lines 
     _zoomStart.y -= event.deltaY * 0.01; 
     break; 

     default: 
     // undefined, 0, assume pixels 
     _zoomStart.y -= event.deltaY * 0.00025; 
     break; 

    } 

    _this.dispatchEvent(startEvent); 
    _this.dispatchEvent(endEvent); 

    } 

    function touchstart(event) { 

    if (_this.enabled === false) return; 

    switch (event.touches.length) { 

     case 1: 
     _state = STATE.TOUCH_ROTATE; 
     _moveCurr.copy(getMouseOnCircle(event.touches[ 0 ].pageX, event.touches[ 0 ].pageY)); 
     _movePrev.copy(_moveCurr); 
     break; 

     default: // 2 or more 
     _state = STATE.TOUCH_ZOOM_PAN; 
     var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 
     var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 
     _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy); 

     var x = (event.touches[ 0 ].pageX + event.touches[ 1 ].pageX)/2; 
     var y = (event.touches[ 0 ].pageY + event.touches[ 1 ].pageY)/2; 
     _panStart.copy(getMouseOnScreen(x, y)); 
     _panEnd.copy(_panStart); 
     break; 

    } 

    _this.dispatchEvent(startEvent); 

    } 

    function touchmove(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    switch (event.touches.length) { 

     case 1: 
     _movePrev.copy(_moveCurr); 
     _moveCurr.copy(getMouseOnCircle(event.touches[ 0 ].pageX, event.touches[ 0 ].pageY)); 
     break; 

     default: // 2 or more 
     var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 
     var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 
     _touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy); 

     var x = (event.touches[ 0 ].pageX + event.touches[ 1 ].pageX)/2; 
     var y = (event.touches[ 0 ].pageY + event.touches[ 1 ].pageY)/2; 
     _panEnd.copy(getMouseOnScreen(x, y)); 
     break; 

    } 

    } 

    function touchend(event) { 

    if (_this.enabled === false) return; 

    switch (event.touches.length) { 

     case 0: 
     _state = STATE.NONE; 
     break; 

     case 1: 
     _state = STATE.TOUCH_ROTATE; 
     _moveCurr.copy(getMouseOnCircle(event.touches[ 0 ].pageX, event.touches[ 0 ].pageY)); 
     _movePrev.copy(_moveCurr); 
     break; 

    } 

    _this.dispatchEvent(endEvent); 

    } 

    function contextmenu(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 

    } 

    this.dispose = function() { 

    this.domElement.removeEventListener('contextmenu', contextmenu, false); 
    this.domElement.removeEventListener('mousedown', mousedown, false); 
    this.domElement.removeEventListener('wheel', mousewheel, false); 

    this.domElement.removeEventListener('touchstart', touchstart, false); 
    this.domElement.removeEventListener('touchend', touchend, false); 
    this.domElement.removeEventListener('touchmove', touchmove, false); 

    document.removeEventListener('mousemove', mousemove, false); 
    document.removeEventListener('mouseup', mouseup, false); 

    window.removeEventListener('keydown', keydown, false); 
    window.removeEventListener('keyup', keyup, false); 

    }; 

    this.domElement.addEventListener('contextmenu', contextmenu, false); 
    this.domElement.addEventListener('mousedown', mousedown, false); 
    this.domElement.addEventListener('wheel', mousewheel, false); 

    this.domElement.addEventListener('touchstart', touchstart, false); 
    this.domElement.addEventListener('touchend', touchend, false); 
    this.domElement.addEventListener('touchmove', touchmove, false); 

    window.addEventListener('keydown', keydown, false); 
    window.addEventListener('keyup', keyup, false); 

    this.handleResize(); 

    // force an update at start 
    this.update(); 

    document.addEventListener('mousemove', mousemove, false); 
    document.addEventListener('mouseup', mouseup, false); 
}; 

THREE.MyTrackballControls.prototype = Object.create(THREE.EventDispatcher.prototype); 
THREE.MyTrackballControls.prototype.constructor = THREE.MyTrackballControls; 


if (! Detector.webgl) Detector.addGetWebGLMessage(); 

var container, stats; 

var camera, controls, scene, renderer; 

var cross; 

init(); 
animate(); 

function init() { 

    camera = new THREE.PerspectiveCamera(60, window.innerWidth/window.innerHeight, 1, 1000); 
    camera.position.z = 500; 

    controls = new THREE.MyTrackballControls(camera); 

    controls.rotateSpeed = 2.0; 
    controls.zoomSpeed = 1.2; 
    controls.panSpeed = 0.8; 


    controls.noPan = false; 

    controls.staticMoving = false; 
    controls.dynamicDampingFactor = 0.3; 

    controls.keys = [ 65, 83, 68 ]; 

    controls.addEventListener( 'change', render); 

    // world 

    scene = new THREE.Scene(); 
    scene.fog = new THREE.FogExp2(0xcccccc, 0.002); 

    var geometry = new THREE.CylinderGeometry(0, 10, 100, 16, 1); 
    var material = new THREE.MeshPhongMaterial({ color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.SmoothShading }); 



    for (var i = 0; i < 200; i ++) { 

    var mesh = new THREE.Mesh(geometry, material); 
    mesh.position.x = (Math.random() - 0.5) * 500; 
    mesh.position.y = (Math.random() - 0.5) * 500; 
    mesh.position.z = (Math.random() - 0.5) * 500; 
    mesh.updateMatrix(); 
    mesh.matrixAutoUpdate = false; 
    scene.add(mesh); 

    } 


    // lights 

    light = new THREE.DirectionalLight(0xffffff); 
    light.position.set(1, 1, 1); 
    scene.add(light); 

    light = new THREE.DirectionalLight(0x002288); 
    light.position.set(-1, -1, -1); 
    scene.add(light); 

    light = new THREE.AmbientLight(0x222222); 
    scene.add(light); 


    renderer = new THREE.WebGLRenderer({ antialias: false }); 
    renderer.setClearColor(scene.fog.color); 
    renderer.setPixelRatio(window.devicePixelRatio); 
    renderer.setSize(window.innerWidth, window.innerHeight); 

    container = document.getElementById('container'); 
    container.appendChild(renderer.domElement); 

    stats = new Stats(); 
    stats.domElement.style.position = 'absolute'; 
    stats.domElement.style.top = '0px'; 
    stats.domElement.style.zIndex = 100; 
    container.appendChild(stats.domElement); 

    // 

    window.addEventListener('resize', onWindowResize, false); 
    // 

    render(); 

} 

function onWindowResize() { 

    camera.aspect = window.innerWidth/window.innerHeight; 
    camera.updateProjectionMatrix(); 

    renderer.setSize(window.innerWidth, window.innerHeight); 

    controls.handleResize(); 

    render(); 

} 

function animate() { 

    requestAnimationFrame(animate); 
    controls.update(); 


} 

function render() { 

    renderer.render(scene, camera); 
    stats.update(); 
} 
+0

我尝试此代码,我不断收到错误信息是说“无法读取的财产‘更新’:THREE.MyTrackballControls.render THREE.MyTrackballControls.dispatchEvent THREE.MyTrackballControls.update” –

+0

的工作活生生的例子是在我创建的codepen链接中提供的......不仅如此,这很难做到:https://codepen.io/leefsmp/pen/zEvaBK –