Introduction: Reflective Prism

This display system uses a technique that is often referred to as Pepper's Ghost. It was first invented by Giambattista della Porta in 1584 and has been commonly used in theatre. Some of its famous uses include Alexander McQueen's performance with Kate Moss, Tupac's CG concert cameo, and numerous Hatsune Miku concert performances. Although "hologram" is often found in the title of these display systems - they have no holographic qualities. A hologram refers to a specific medium that stores image data through a laser, a holographic substrait and interference pattern. Pepper's Ghost uses a much simpler technique that merely reflects an image off of a surface to create an illusion of a 3D object floating in physical space.

Step 1: Materials

In order to create a Pepper's Ghost effect, there are two types of materials commonly used. The first is a transparent material that has a reflective surface. Glass would work for this, but a cheaper, lighter, and easier to use material is acrylic plexiglass. When using a transparent acrylic sheet, take a look a both sides as one side is always more reflective. The more reflective side should be facing the image source. Another material that can be used is a scrim or semi-transparent piece of cloth (most commonly being black). Although a scrim won't reflect the image off of it, it can indeed catch an image as a movie screen might. A mirror or semi-transparent mirror would also work in order to reflect an image off of it, but you would lose the illusion that the object is floating mid-air.

Step 2: One Sided

Pepper's Ghost was originally designed with one reflective surface in mind. Below you'll find an experiment I made using a transparent piece of acrylic (reflecting an image generating on a iPhone5). Please note, that the acrylic is angled at 45 degrees in relation to the display, the viewer is looking at it straight on (0 degree viewing angle) and that the black pixels from the phone are showing up as transparent.

The reflective surface is often placed at a 45 degrees from the image to allow for the source image to be hidden. Creating a steeper or shorter angle can change the sweet spot for the viewing angle and can linearly distort the image if the viewing angle does not change. If you tilt the reflective surface to be 70 degrees while keeping a straight on viewing angle, you'll achieve a larger display surface, but the image will be distorted from a horizontal viewing angle. To compensate for this, it is possible to reverse distort the image that's projected in order to have a clear image that takes up a larger surface area.

Before jumping to a four sided prism, it's good to test out what the one sided effect looks like and play around with different reflective angles along with different viewing angles.

Step 3: Four Sided

The same principles are taken into account when breaking it out to have four sides. The advantage of having four sides is that you can show an object from four unique angles. By placing four cameras in 45 degree intervals it gives the illusion that you can walk around the display and multiple people can view the same object from different vantage points. It also greatly enhances the illusion that an object is sitting in physical space. Above is a diagram for the placement of the four cameras in your 3D scene.

It's important to note that along with the position of the camera within the circumference of a circle - you'll need to rotate the Z-Axis of your camera to match the base-line of each panel. Your resulting program should look something like this and this (with 3D model).

These 3D scenes are generated using three.js (a webGL library using javascript). You could however create this scene using any software that supports 3D (After Effects, OpenGL, Maya, 3ds Max, ect.). The code used to create the multiple cameras is as follows:

//create views

var views = [
		{ 
			left: 0,
			bottom: 0.5,
			width: 0.5,
			height: 0.5,
			background: { r: 0.0, g: 0.0, b: 0.0, a: 1 },
			eye: [ 0, 300, 1800 ],
			up: [ 0, 1, 0 ],
			fov: 30,
			angle : 0,
			rotation: 33.75
		},
		{ 
			left: 0,
			bottom: 0,
			width: 0.5,
			height: 0.5,
			background: { r: 0.0, g: 0.0, b: 0.0, a: 1 },
			eye: [ 0, 300, 1800 ],
			up: [ 0, 1, 0 ],
			fov: 30,
			angle: 90,
			rotation: 101.25
		},
		{ 
			left: 0.5,
			bottom: 0,
			width: 0.5,
			height: 0.5,
			background: { r: 0.0, g: 0.0, b: 0.0, a: 1 },
			eye: [ 0, 300, 1800 ],
			up: [ 0, 1, 0 ],
			fov: 30,
			angle: 180,
			rotation: -101.25
		},
		{ 
			left: 0.5,
			bottom: 0.5,
			width: 0.5,
			height: 0.5,
			background: { r: 0.0, g: 0.0, b: 0.0, a: 1 },
			eye: [ 0, 300, 1800 ],
			up: [ 0, 1, 0 ],
			fov: 30,
			angle: 270,
			rotation: 101.25
		}
	];//add cameras
	for (var i =  0; i < views.length; i++ ) {
		var view = views[i];
		var camera = new THREE.PerspectiveCamera( view.fov, windowWidth / windowHeight, 1, 10000 );
		camera.position.x = view.eye[ 0 ];
		camera.position.y = view.eye[ 1 ];
		camera.position.z = view.eye[ 2 ];
		camera.up.x = view.up[ 0 ];
		camera.up.y = view.up[ 1 ];
		camera.up.z = view.up[ 2 ];
		view.camera = camera;
	}

To render the cameras, I used the following code:

//for each view
for (var i = 0; i < views.length; i++ ) { //grab each view var view = views[i]//grab each camera var camera = view.camera; //Adjust camera within 3D spherical coordinates camera.position.x = earth.position.x + cameraRadius * Math.sin(rotateY * Math.PI/180) * Math.cos(view.angle * Math.PI/180); camera.position.z = earth.position.y + cameraRadius * Math.sin(rotateY * Math.PI/180) * Math.sin(view.angle * Math.PI/180); camera.position.y = earth.position.z + cameraRadius * Math.cos(rotateY * Math.PI/180); camera.lookAt(scene.position);//Set rotation of camera on Z-Axis camera.rotation.z= view.rotation - Math.PI; //Grab view ports var left = Math.floor( windowWidth * view.left ); var bottom = Math.floor( windowHeight * view.bottom ); var width = Math.floor( windowWidth * view.width ); var height = Math.floor( windowHeight * view.height );//Render renderer.setViewport( left, bottom, width, height ); renderer.setScissor( left, bottom, width, height ); renderer.enableScissorTest ( true ); renderer.setClearColor( view.background, view.background.a ); renderer.render(scene, camera) }

For this experiment, I used a laser cutter to cut each side of the prism from 12x12" transparent acrylic plexiglass panels. When glued together (using a solvent), it creates a prism where each side is 45 degrees from the horizontal plane. I placed the image source on the bottom in this example, but this design could easily be flipped upside-down. Doing this would make the image source less viewable and allow the user to better focus on the content reflected off of the prism.

Step 4: Leap Motion

In order to allow users to directly manipulate the content that they are viewing, I connected the display system to a Leap Motion. The Leap is a small 3D sensor that specializes in reading hands. If you have a Leap Motion, include leapjs in your <head> and then use your finger or hand position to manipulate the object:

        //Create a mapping function
function map(value, inputMin, inputMax, outputMin, outputMax){ outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin); if(outVal > outputMax){ outVal = outputMax; } if(outVal < outputMin){ outVal = outputMin; } return outVal; } //Set the rotation of your object based on your finger position x yourObject.rotation.x = map(t[1], -300, 300, 0, 10); //Set the rotation of your object based on your finger position y yourObject.rotation.y = map(t[0], -300, 300, 0, 10);

If you have a Leap Motion connected - feel free to view a demo of the program here or download the attached zip.

Step 5: Content Generation

When designing content for this display system it's important to be aware of window violations. A window violation is the appearance of an object cut off due to the window size (or in our case the reflective surface size). When this occurs, the image looks like a slice has been cut off of it and the viewer loses their suspension of disbelief. Due to this, using objects that are self contained work well. Examples of self-contained objects include a tree, car, watch, planet, among many others. Objects that work less well would include something like a hand/arm. To display a hand at decent scale, the arm would likely fall off the displays edges and it would no longer look like a solid object floating in space. Scale is also important to consider. Projecting small objects like a key work very well because they can be seen at real scale and are self-contained in a way that it would be difficult to receive a window violation.

If an object appears beyond the bounds of the prism, it breaks the illusion being created. Due to this, it's best to use self contained objects that fit within the center area of the display panels. It's also important to be aware that any light in the room will both enhance the illusion that the content is appear mid-air, but also wash out the colors presented on the display. I'd advise you to find a balance the meets your particular needs.

Working with your surrounding environment can also enhance the illusion further. When designing content for a display that sits within your environment, it can be beneficial to think about the forces that may affect the content. From wind, gravity, sound, lighting touch, to temperature - adding more input mechanisms helps to support the illusion. Along with this, it's key to consider the lighting in the room. Since we're dealing with projected light, the darker the room is, the crisper the image appears. In the same respect, if the room is too dark, you can lose the background and the "floating" image no longer as a reference point to allow it to be floating in-front of. Due to this, you'll likely want to adjust lighting to find a fit that you're happy with.


Lastly, since the reflection of the image source happens on the outside of the reflection surface - any light that shines on the inside of the reflection surface will not effect the image. It seems unintuitive, but this allows you to add lighting inside the prism if you would like to present your object sitting on a surface that's lit underneath or above it like a spotlight.

Step 6: Can You Have More Than Four Sides?

The most common question I've received is if this display system could have more than four sides. The answer to this is both yes and no. The principles of it remain the same and you can have as few or as many sides as you would like. However, if you have more sides - lets say 8 for this examples purpose - you'll have image issues if your 3D object isn't very very very small. The reason for this is that your camera for each slice will diminish in horizontal width as you add more sides. As its width gets smaller - the object your display will likely get horizontally cut off unless shrunk in size. Due to this, you'll lose the illusion of the 3D object and create window violations. If your creating something more abstract (like a single 3D cylinder vertically positioned with a thin diameter) perhaps you'll be happy with the result. However, it's important to keep in mind that your content will exponentially need to be scaled down as you add more sides.