PepperGhostEffect.js library question

Hey guys! I’ve recently been doing some interesting things with three.js and I stumbled upon a library called PeppersGhostEffect.js which serves as a way to create a Pepper Ghost Hologram effect based on any object. So I have an object here(just a random one that I designed in blender) and I used that PepperGhostEffect.js library on that object. The object was renderer 4 times on the screen as expected. On the top, the bottom, the left and the right side of the screen respectively. What I’ve come to realise is that if the object is slightly bigger and you want to apply some kind of rotation on it, the effect breaks. Essentially, that PepperGhostEffect.js library just creates 4 scissor regions and within these 4 regions, is renderer the object. And frankly, those 4 regions that it creates are quite small and so whenever I rotate my object, the object just gets cut somewhere in its rotation. I’ve been trying to modify the scissor regions within the PepperGhostEffect.js file itself, but I haven’t been successful. When the object rotates, it always gets cut. Here’s my current code below. I also attached a video to showcase what I mean.
Untitled video - Made with Clipchamp (1)

import * as THREE from ‘three’;
import { PeppersGhostEffect } from ‘three/examples/jsm/effects/PeppersGhostEffect.js’;
import { GLTFLoader } from ‘three/examples/jsm/loaders/GLTFLoader.js’;

let scene, earth, container, effect,mesh;

scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 100000 );
const renderer = new THREE.WebGLRenderer({antialias: true});
scene.background = new THREE.Color( 0x00ff0f );
renderer.setSize(window.innerWidth, window.innerHeight);
effect = new PeppersGhostEffect(renderer);
effect.setSize(window.innerWidth, window.innerHeight);
effect.cameraDistance = 47.5

container = document.createElement( ‘div’ );
document.body.appendChild( container );
container.appendChild( renderer.domElement );

const ambient = new THREE.AmbientLight(0x404040,3);
//scene.add(ambient);

// load model

let loader = new GLTFLoader();
loader.load(“./testing.gltf”, function(gltf) {
var scale = 4;
scene.add(gltf.scene);
console.log(gltf);
earth = gltf.scene.children[0];
earth.scale.set (scale,scale,scale);
});

function animate() {
requestAnimationFrame(animate);
earth.rotation.y += 0.01
effect.render(scene,camera);
}

animate();

If anyone knows how to make those scissor regions bigger, I’d really appreciate a hand. Many thanks!

i’m wondering, did three’s native peppersghost effect not perform as you require? if not the source PeppersGhostEffect.js file served with the above demo may give some insights into how to resize your renderers scissor test regions

Yep you’re absolutely right, its the one from three.js webgl - effects - peppers ghost. The important piece is right here :

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 );

So basically these parts require modifications( I messed with them myself, but never got something good looking):

                 renderer.setScissor( _halfWidth - ( _width / 2 ), ( _height * 2 ), _width, _height );
                    renderer.setViewport( _halfWidth - ( _width / 2 ), ( _height * 2 ), _width, _height );

renderer.setScissor( _halfWidth - ( _width / 2 ), 0, _width, _height );
renderer.setViewport( _halfWidth - ( _width / 2 ), 0, _width, _height );

renderer.setScissor( _halfWidth - ( _width / 2 ) - _width, _height, _width, _height );
renderer.setViewport( _halfWidth - ( _width / 2 ) - _width, _height, _width, _height );

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

No matter the modifications I did to the scissor regions, they would always be too small for the object’s rotation and the object would always get cut. The default regions look like this :

But I was hoping to make them look somewhat like this :

So I’ve done quite a bit of testing and yeah everything failed. I mean literally everything. I just don’t get it. I was able to make the scissor regions bigger, that was easy. But then whenever I would update the ViewPort, it would just stretch my entire scene and I still can’t figure out why. And it seems like updating the viewport is also necessary since otherwise the object gets cut whenever it rotates, regardless if the scissor region is big enough or not.

Nevermind I fixed my issue, turns out this line was messing me up : earth = gltf.scene.children[0];

This only works if the object you’re importing is just one single object meaning like a single mesh, so maybe something like a simble cube, or sphere, etc.

However, if like my object, your object is made of multiple parts, different geometries(cubes,spheres,etc), you would need to use : earth = gltf.scene instead. So the same thing, but without the : children[0] at the end.

Hope this helps someone in the future.