Final Project: Aurora

For my project, I wanted to build a hologram after being shown a particular method used in the project Light Barrier by the group Kimchi and Chips. For my project I wanted to reproduce this effect in a smaller scale using lenses rather than mirrors and with much less funding.

Light Box (8)

For hardware, I made a wooden box with a mirror inside it and a platform on which a projector can be placed. On the top of the box is a hole in which wide-angle (concave) Fresnel lenses are placed. I also created a clear acrylic box which is placed on top of the first box to hold fog in place over the lenses. I purchased a fog machine from Guitar Center for the production of the fog.

Aurora Setup

For software, I made a C++ program which minimally utilizes Cinder. In this program I implemented methods which calculate the scene from the perspective of each lens. I do this using the thin lens formula.



Here is the relevant code for drawing the view.

void GhostApp::draw()
	// clear out the window with black	
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

	float camToLensDist = 1000.0f;
	float lensWidth = 35.0f; //number in mm
	float lensHeight = 35.0f; //number in mm
	float lensFocal = -40.0f/2.0f; // number in mm
	int numXLenses = 10;
	int numYLenses = 5;
	for (int x = 0; x < numXLenses; x++){
		for (int y = 0; y < numYLenses; y++){
			// set the viewport
			glViewport(config.offsetX + x*(config.viewWidth / numXLenses), config.offsetY + y*(config.viewHeight / numYLenses), config.viewWidth / numXLenses, config.viewHeight / numYLenses);
			// lens, object and image positions
			float lensCenterX = lensWidth*0.5f + (lensWidth*x) - (lensWidth*numXLenses*0.5);
			float lensCenterY = lensHeight*0.5f + (lensHeight*y) - (lensHeight*numYLenses*0.5);
			//distance to projector on xy plane
			float Ho = sqrtf(lensCenterX*lensCenterX + lensCenterY*lensCenterY);
			//distance to projector on z axis
			float Do = camToLensDist;
			//focal point
			float f = lensFocal;
			// 1/f = 1/di + 1/do
			float Di = 1.0f / ((1.0f / f) - (1.0f / Do));
			// -Di/Do = Hi/Ho
			float Hi = (-Di*Ho) / Do;

			float camX = (Hi == 0.0f) ? 0.0f : lensCenterX*(1.0f - (Hi / Ho));
			float camY = (Hi == 0.0f) ? 0.0f : lensCenterY*(1.0f - (Hi / Ho));
			float nearZ = camToLensDist*(-Di / Do);
			float camZ = -(camToLensDist - nearZ);
			float farZ = 10000.0f;

			float left = (x*lensWidth - (numXLenses*lensWidth*0.5f)) - camX;
			float right = ((x + 1)*lensWidth - (numXLenses*lensWidth*0.5f)) - camX;
			float top = (y*lensHeight - (numYLenses*lensHeight*0.5)) - camY;
			float bottom = ((y + 1)*lensHeight - (numYLenses*lensHeight*0.5)) - camY;

			glFrustum(left, right, top, bottom, nearZ, farZ);
			gl::translate(-camX, -camY, -camZ - camToLensDist);
			gl::scale(1.0f, 1.0f, -1.0f);
			switch (scene){
			case 0:
			case 1:
			case 2:
				scene = 0;
	// draw guide grids to help lens placement
	if (grids){
		glViewport(config.offsetX, config.offsetY, config.viewWidth, config.viewHeight);
		glOrtho(0, config.viewWidth, 0, config.viewHeight, -10, 10);
		for (int x = 1; x < numXLenses; x++){
			gl::drawSolidRect(Rectf(x*(config.viewWidth / numXLenses) - 4.0f, 0, x*(config.viewWidth / numXLenses) + 4.0f, config.viewHeight));
		for (int y = 1; y < numYLenses; y++){
			gl::drawSolidRect(Rectf(0, y*(config.viewHeight / numYLenses) - 4.0f, config.viewWidth, y*(config.viewHeight / numYLenses) + 4.0f));

I’m proud of the software and the math that went into the system. I felt the build quality of the box could have been better had I planned the system more before building. The outcome and final visual is blurry and less defined than I had expected. I attribute this to a lack of clarity from the lenses and a lack of precision in the lens setup. All in all, I appreciate the project and feel that I have made something pleasing to look at.


Comments are closed.