Saturday, December 19, 2015

Hologram Projector

Problem:

With this personal project, I wanted to take an image sequence and convert it to a holographic projected image, much like those seen in Sci-Fi movies such as TRON.

TRON Legacy scene that served as inspiration for the effect
Image © Walt Disney Studios

Solution:

The first challenge was importing the image sequence into Houdini. The easiest way to do that was using a COP network.

Initial Image
From here, I was able to crop the image to a square shape to match a grid of points and scale the image down so that one pixel in the image would map to one point in the grid. I also adjusted to color to achieve the blue hue I desired in the final hologram.

Image after COP network editing
From there, I imported the image sequence to a CHOP network in order to convert the image data into a format that could be read by geometry in the SOP context. Using the Image Node in the CHOP network, which splits up the color data of the image sequence into one channel per pixel row.

The challenge then becomes importing all of these channels in an efficient manner. To do this I set up the following network in the SOP context.

SOP network
First, I create a grid of points to copy the color data to. I used VEX code to generate the grid, but a Grid SOP outputting only points would have worked just as well. From there I applied a color attribute to receive the color data from the image sequence.

Initial Point Grid
Then the challenge was copying each row onto their matching row in the grid. To do this, I used a Partition SOP to procedural generate a group for each row using the Y position of each point to separate the groups.

With each row in its own group, I used a ForEach SOP to loop over each of these groups. The Channel SOP imports channels just the way I need them to, but by default the Channel SOP only allows for channels to be explicitly listed, which would copy only a single row of data to all the rows. To resolve this, I wrote a simple python script to define the channels to be copied from by their row number:

Python expression to dynamically assign a channel to each row as they are iterated over
When evaluated, this ForEach SOP takes the color of each pixel and sets it as the color attribute on each point in the grid.

Point Grid with color data
From there, I could use the luminosity of the color on each point to drive a displacement function that created a very appealing parallax effect.

Point Grid displaced by luminosity factor
From there, I simply set the grid to rotate to show off the parallax effect and make it appear as a projection.

To give the hologram a "surface" to project onto, I generated a volume from similar geometry and advected the volume by a velocity that I had traced from the points using the Trail SOP.

Using VEX, I procedurally modeled and animated several rings below to act as the projection source and projector "user interface".

From there, I created a surrogate geometry for the objects in the live plate and captured the reflections seen. Then, I used Nuke to adjust the reflections to make the plate in the background leading us to the final sequence.