Three.js: побочный эффект Пеппера с OrbitControls: проблема с перемещением / вращением камеры

Я хотел бы иметь эффект, подобный Призрачному эффекту Пеппера, как здесь: https://threejs.org/examples/webgl_effects_peppersghost.html но с возможностью вращать и масштабировать куб с помощью мыши (то есть с помощью OrbitControl). Но куб не вращается так, как это происходит вокруг некоторых осей.

Я установил jsfiddle: https://jsfiddle.net/vesx5y8j/7/

'use strict';
var container;
  var camera, scene, renderer, effect, cubetest, _controls;
  var group;

  init();
  animate();

  function init() {

   container = document.createElement( 'div' );
   document.body.appendChild( container );
   
   scene = new THREE.Scene();
    
   camera = new THREE.PerspectiveCamera(  );
      camera.position.set( 0, 0, 6 );
    camera.up.set(0,1,0);
    camera.lookAt( new THREE.Vector3(0,0,0) );
 
   _controls = new THREE.OrbitControls(camera);
    _controls.autoRotate = false;
    _controls.autoRotateSpeed = 1.0;
      _controls.noPan = true;
      _controls.enabled = true;  
     _controls.update();
    
   
var axisHelper = new THREE.AxisHelper(100);
scene.add(axisHelper);
  
var cubeMaterials = [ 
    new THREE.MeshBasicMaterial({color:0xff0000, transparent:true, opacity:0.8, side: THREE.DoubleSide}),
    new THREE.MeshBasicMaterial({color:0x00ff00, transparent:true, opacity:0.8, side: THREE.DoubleSide}), 
    new THREE.MeshBasicMaterial({color:0x0000ff, transparent:true, opacity:0.8, side: THREE.DoubleSide}),
    new THREE.MeshBasicMaterial({color:0xffff00, transparent:true, opacity:0.8, side: THREE.DoubleSide}), 
    new THREE.MeshBasicMaterial({color:0xff00ff, transparent:true, opacity:0.8, side: THREE.DoubleSide}), 
    new THREE.MeshBasicMaterial({color:0x00ffff, transparent:true, opacity:0.8, side: THREE.DoubleSide}), 
]; 
// Create a MeshFaceMaterial, which allows the cube to have different materials on each face 
var cubeMaterial = new THREE.MeshFaceMaterial(cubeMaterials); 

cubetest = new THREE.Mesh( new THREE.CubeGeometry( 1, 2, 0.5), cubeMaterial  );
cubetest.position.set( 0, 0, 0 );
scene.add( cubetest );

renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
container.appendChild( renderer.domElement );

effect = new THREE.PeppersGhostEffect( renderer );
effect.setSize( window.innerWidth, window.innerHeight );
effect.cameraDistance = 6;
            
   
window.addEventListener( 'resize', onWindowResize, false );

}

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

   effect.setSize( window.innerWidth, window.innerHeight );
}

function animate() {
      requestAnimationFrame( animate );
      render();
  }

function render() {
    //cubetest.rotation.x += 0.01;
    _controls.update();
  
  effect.render( scene, camera );
}
    
   
body {
      background: #777;
      padding: 0;
      margin: 0;
      font-weight: bold;
      overflow: hidden;
    }

    #info {
      position: absolute;
      top: 0px;
      width: 100%;
      color: #ffffff;
      padding: 5px;
      font-family: Monospace;
      font-size: 13px;
      text-align: center;
      z-index: 1000;
    }

    a {
      color: #ffffff;
    }

    #webglmessage a {
      color: #da0
    }
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script data-name="PeppersGhostEffect.js">
 THREE.PeppersGhostEffect = function ( renderer ) {

 var scope = this;

 // Internals
 var _halfWidth, _width, _height;

 var _cameraF = new THREE.PerspectiveCamera(); //front
 var _cameraB = new THREE.PerspectiveCamera(); //back
  var _cameraL = new THREE.PerspectiveCamera(); //left
 var _cameraR = new THREE.PerspectiveCamera(); //right
 
 var _position = new THREE.Vector3();
 var _quaternion = new THREE.Quaternion();
 var _scale = new THREE.Vector3();

 // Initialization
 renderer.autoClear = false;

 this.setSize = function ( width, height ) {

  _halfWidth = width / 2;
  if ( width < height ) {

   _width = width / 3;
   _height = width / 3;

  } else {

   _width = height / 3;
   _height = height / 3;

  }
  renderer.setSize( width, height );
 };

 this.render = function ( scene, camera ) {
  
  scene.updateMatrixWorld();

  if ( camera.parent === null ) camera.updateMatrixWorld();

  camera.matrixWorld.decompose( _position, _quaternion, _scale );
  
  renderer.clear();
  renderer.enableScissorTest( true );
  
    //front camera
  _cameraF.position.copy( _position );
  _cameraF.quaternion.copy( _quaternion );
  _cameraF.lookAt( new THREE.Vector3(0,0,0)  );
  
    // back camera
  _cameraB.position.copy( _position );
  _cameraB.quaternion.copy( _quaternion );
   _cameraB.translateZ( -2.*scope.cameraDistance);
   //  _cameraB.translateZ( -2.*_position.z);
  _cameraB.up.set(0,-1,0);
  _cameraB.lookAt( new THREE.Vector3(0,0,0)  );
  
  // left camera
  _cameraL.position.copy( _position );
  _cameraL.quaternion.copy( _quaternion );
  _cameraL.translateZ( - scope.cameraDistance);
  _cameraL.translateX( - scope.cameraDistance);
   // _cameraL.translateZ( -_position.z);
 // _cameraL.translateX( - _position.x);
  _cameraL.up.set(0,0,-1);
  _cameraL.lookAt( new THREE.Vector3(0,0,0));
 
  
    //right camera
  _cameraR.position.copy( _position );
  _cameraR.quaternion.copy( _quaternion );
  _cameraR.translateZ( - scope.cameraDistance);
  _cameraR.translateX( scope.cameraDistance);
  _cameraR.up.set(0,0,-1);
  _cameraR.lookAt( new THREE.Vector3(0,0,0) );
  
  
  renderer.setScissor( _halfWidth - ( _width / 2 ), 0, _width, _height );
  renderer.setViewport( _halfWidth - ( _width / 2 ), 0, _width, _height );
  renderer.render( scene, _cameraF );
  
  renderer.setScissor( _halfWidth - ( _width / 2 ), ( _height * 2 ), _width, _height );
  renderer.setViewport( _halfWidth - ( _width / 2 ), ( _height * 2 ), _width, _height);
  renderer.render( scene, _cameraB);
  
  renderer.setScissor( _halfWidth - ( _width / 2 ) - _width, _height, _width, _height);
  renderer.setViewport( _halfWidth - ( _width / 2 ) - _width, _height, _width,_height);
  renderer.render( scene, _cameraL);

  renderer.setScissor( _halfWidth + ( _width / 2 ), _height, _width, _height );
  renderer.setViewport( _halfWidth + ( _width / 2 ), _height, _width, _height );
  renderer.render( scene, _cameraR );
  

  renderer.enableScissorTest( false );

 };


};
</script>

Фронтальная камера (внизу экрана) - это камера в исходном положении. Прежде чем начать вращение или масштабирование, кубы показывают, как ожидалось.

Относительно задней камеры: она работает, как и ожидалось, когда я вращаюсь, но масштабирование инвертируется (оно увеличивается, когда уменьшается передний куб) Когда я помещаю строку 60 в html: _cameraB.translateZ( -2.*_ Position.z); вместо _cameraB.translateZ( -2.*scope.cameraDistance); тогда масштабирование работает нормально, но вращение дает странные результаты.

Что касается левой и правой камер: вращение работает нормально, когда я вращаюсь вокруг зеленой оси, но не когда я поворачиваюсь вокруг красной оси (тогда левый и правый кубы не двигаются; они должны повернуться на 90 градусов).

Я не знаю, пропускаю ли я что-то (возможно, из-за того, что я использую кватернионы, не зная, как они работают), или, возможно, просто невозможно объединить движение камеры с OrbitControls?

Альтернативой может быть вместо вращения камеры с помощью OrbitControls вращение куба. Но я не нашел ничего похожего на OrbitControls (с возможностью поворота и масштабирования), которое можно было бы применить к объекту.

Большое спасибо за любую помощь!

0 ответов

Другие вопросы по тегам