Three.js: побочный эффект Пеппера с OrbitControls: проблема с перемещением / вращением камеры - PullRequest
0 голосов
/ 23 мая 2019

Я хотел бы иметь эффект, похожий на Призрачный эффект Пеппера, как здесь: 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 (с возможностью вращения и масштабирования), которое можно было бы применить к объекту.

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

...