UNPKG

three

Version:

JavaScript 3D library

175 lines (119 loc) 4.25 kB
import { PerspectiveCamera, Quaternion, Vector3 } from 'three'; /** * A class that implements a peppers ghost effect. * * Reference: [Reflective Prism]{@link http://www.instructables.com/id/Reflective-Prism/?ALLSTEPS} * * @three_import import { PeppersGhostEffect } from 'three/addons/effects/PeppersGhostEffect.js'; */ class PeppersGhostEffect { /** * Constructs a new peppers ghost effect. * * @param {(WebGPURenderer|WebGLRenderer)} renderer - The renderer. */ constructor( renderer ) { const scope = this; scope.cameraDistance = 15; scope.reflectFromAbove = false; // Internals let _halfWidth, _width, _height; const _cameraF = new PerspectiveCamera(); //front const _cameraB = new PerspectiveCamera(); //back const _cameraL = new PerspectiveCamera(); //left const _cameraR = new PerspectiveCamera(); //right const _position = new Vector3(); const _quaternion = new Quaternion(); const _scale = new Vector3(); // Initialization renderer.autoClear = false; /** * Resizes the effect. * * @param {number} width - The width of the effect in logical pixels. * @param {number} height - The height of the effect in logical pixels. */ 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 ); }; /** * When using this effect, this method should be called instead of the * default {@link WebGLRenderer#render}. * * @param {Object3D} scene - The scene to render. * @param {Camera} camera - The camera. */ this.render = function ( scene, camera ) { if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); camera.matrixWorld.decompose( _position, _quaternion, _scale ); // front _cameraF.position.copy( _position ); _cameraF.quaternion.copy( _quaternion ); _cameraF.translateZ( scope.cameraDistance ); _cameraF.lookAt( scene.position ); // back _cameraB.position.copy( _position ); _cameraB.quaternion.copy( _quaternion ); _cameraB.translateZ( - ( scope.cameraDistance ) ); _cameraB.lookAt( scene.position ); _cameraB.rotation.z += 180 * ( Math.PI / 180 ); // left _cameraL.position.copy( _position ); _cameraL.quaternion.copy( _quaternion ); _cameraL.translateX( - ( scope.cameraDistance ) ); _cameraL.lookAt( scene.position ); _cameraL.rotation.x += 90 * ( Math.PI / 180 ); // right _cameraR.position.copy( _position ); _cameraR.quaternion.copy( _quaternion ); _cameraR.translateX( scope.cameraDistance ); _cameraR.lookAt( scene.position ); _cameraR.rotation.x += 90 * ( Math.PI / 180 ); renderer.clear(); renderer.setScissorTest( true ); renderer.setScissor( _halfWidth - ( _width / 2 ), ( _height * 2 ), _width, _height ); renderer.setViewport( _halfWidth - ( _width / 2 ), ( _height * 2 ), _width, _height ); if ( scope.reflectFromAbove ) { renderer.render( scene, _cameraB ); } else { renderer.render( scene, _cameraF ); } renderer.setScissor( _halfWidth - ( _width / 2 ), 0, _width, _height ); renderer.setViewport( _halfWidth - ( _width / 2 ), 0, _width, _height ); if ( scope.reflectFromAbove ) { renderer.render( scene, _cameraF ); } else { renderer.render( scene, _cameraB ); } renderer.setScissor( _halfWidth - ( _width / 2 ) - _width, _height, _width, _height ); renderer.setViewport( _halfWidth - ( _width / 2 ) - _width, _height, _width, _height ); if ( scope.reflectFromAbove ) { renderer.render( scene, _cameraR ); } else { renderer.render( scene, _cameraL ); } renderer.setScissor( _halfWidth + ( _width / 2 ), _height, _width, _height ); renderer.setViewport( _halfWidth + ( _width / 2 ), _height, _width, _height ); if ( scope.reflectFromAbove ) { renderer.render( scene, _cameraL ); } else { renderer.render( scene, _cameraR ); } renderer.setScissorTest( false ); }; } } export { PeppersGhostEffect };