It Follows – VFX Work

Featured

Here’s my last work on “It Follows”, a Horror Movie presented at Cannes 2014 in the Critics Week section.

 

Project : It Follows (2014)
Role : FX, Modeling, Rendering, Lighting, Tracking, Compositing, Compositor

Production companies: Northern Lights Films, Animal Kingdom, Two Flints
Cast: Maika Monroe, Keir Gilchrist, Daniel Zovatto, Jake Weary, Olivia Luccardi, Lili Sepe
Director-screenwriter: David Robert Mitchell
Producers: Rebecca Green, Laura D. Smith, David Robert Mitchell, David Kaplan, Erik Rommesmo
Executive producers: Frederick W. Green, Joshua Astrachan, P. Jennifer Dana, Jeff Schlossman, Bill Wallwork, Alan Pao, Corey Large, Mia Chang
Director of photography: Michael Gioulakis
Production designer: Michael T. Perry
Costume designer: Kimberly Leitz-McCauley
Editor: Julio C. Perez IV
Music: Disasterpeace
Sales: Cinetic/Visit Films

Related articles:
Variety
Indiewire
Yahoo Movies
TheWrap
The Hollywood Reporter

7up – Commercial

Client : 7up
Studio : Framestore LA

Work : CG Crowd.
In this project I had to create and place a crowd (3.000 to 2.000.000 depending on the shot camera position). Each agent was wearing a wristband that would emit light of different colors according to animated patterns. The pattern had to be clearly visible from a distance, but at the same time, the crowd had to be believable from a relatively short distance (~40 m). The Director wanted to see light interaction on the crowd for the light generated by the wrist bands.

In order to be able to work quickly and allow the compers to test different wrist band patterns in Nuke without re-rendering from Houdini, I choose the route of re-lighting the crowd in Nuke, rendering every necessary AOV from Houdini.

I was provided with a library of dancing CG characters and a set of textures for the clothing.
The system was subdivided in 3 steps:

  • Crowd generation : generation of about 50 characters, procedurally dressed using the textures provided (Houdini OTL). Additionally for each character I was generating data that would later help me to render AOV passes related to the wrist band position and light interaction range.
  • Crowd render per Shot : in each shot I was positioning the crowd painting points over a surface. Later I was using copy SOP (with Packed primitives packing option enabled) to instance the characters on the crowd. For each shot the crowd was rendered with several AOVs.
  • Nuke Relighting Setup per Shot : I set up a key Nuke setup in which the crowd could be relighted using P and N AOVs. Using additional AOVs containing the wrist band data, compers were able to replace the wrist band pattern procedurally in Nuke.

Target – Commercial

Client : Target
Studio : Framestore LA

Work : characters and tablet pixelization for each shot.


Work: Icecream Mountain FX. I’ve used FLIP to generate the data necessary to model the interaction of the box with the ice cream mountain (yep, it’s not snow, it’s ice cream !!). I’ve converted every element of the sim (mountain, kicks, box, borders) into VDB and used VDB combing tools to model the final mountain.


Work: Procedural Maze FX. The look of the maze was not final till pretty much the very last moment. So I developed a procedural system in Houdini that would take care of creating the maze, starting from curves dropped on the ground plane. The system initially was analyzing the curves to identify wall corners, ends, single and double intersections (respectively L, I, T and X intersection topology). Subsequently it was instancing pre-modeled elements (procedurally non-uniformly scaled where necessary) and creating the (curved and straight) walls including the white , crescent moon shaped decorations. The final geometry was converted into Alembic and delivered to lighting for rendering in Arnold (Maya).

Python SOP vs VOP SOP – and the winner is …

I’ve played a bit with Python Sops , Vex sops, and Vop Sops.
Python sops are a really powerful tool cause they allow using Python !! Which is a way more complete scripting language than VEX. And yes, I am talking above all about….recursion !

Now, the power of Python comes to a big price compared to VEX: performance.

In order to quantify how slower a python script might get, compared to the identical Vex version I created a simple Python Sop to calculate the closest point on a surface , given a bunch of points in the world space (a very dense grid in the example), and an SDF (this can be a volume or a vdb sdf, it doesn’t make much difference).

Check it out yourself:

Don’t forget to install ths OTL in your favorite otl scan path.

OTL   |   HIP

In case you’re one of those who have no patience…in this specific case the winner is VEX because it’s like 20 times faster, as you can see from the hip file.

Why VEX is it faster ?

  • it allows multithreading
  • it’s a SIMD (single instruction multiple data , scripting language)
  • it doesn’t have the overhead loading times of importing Python libraries

Why sometimes Python is better ?

  • because of the same reason anyone might use Python as a scripting language
  • because differently from VEX, it allows recursion
  • you have much more freedom than VEX since vex is just a huge point loop and has many restrictions that come with it.

Conclusions:
If you want speed, use VEX.
If you need recursion, use Python.

 

lsystem wrapper

In this nth experiment I wanted to create a way to wrap a growing geometry on the surface of another geometry without relying upon UVs on the target geometry.

The OTL I created takes 3 inputs:

  1. lsystem (this will be wrapped on top of 2)
  2. poly geometry
  3. one point

otl_screengrab

L-System (points and edges)

The L-System provided as first input can be any L-System where the root point of a new branch overlaps the point it generates from. In other words if you ‘window’ select the first point of a branch in your L-System you should end up selecting 2 points.
Inside the OTL the L-System is pre-processed adding point attributes (like an attr that specifies if a certain point is a branch root, or the direction of each segment) that will make traversing it’s hierarchy later on way faster.
Something like this:

Wrapped Geometry (any geometry)

The OTL wraps the original L-System around this geometry. It can be any geometry. This geometry will be converted into a VDB SDF in the OTL, sample and gradient volume vops are used to quickly find the closest point on this surface. Because of this approach, the OTL doesn’t require any UV coordinate to locate positions on this geometry and it’s super fast since the SDF is calculate only once at the beginning of the whole simulation and contains already all the info to calculate the closest point on the surface with just a couple of multiplications and sums.

Start Point (one point)

The closest point of the Start Point on the Wrapped Geometry is where the root of the ‘wrapped’ L-System will sit. This point must be as close as possible to the the Wrapped Geometry surface (in order to have it within the Wrapped Geometry SDF VDB voxels).

How it works

This is the interface to the OTL

otl_parameters

The original L-System is flattened on the XY plane before being processed.

The root (the first point calculated) of the wrapped L-System (WL) is the closest point of the Start Point (SP) on the Wrapped Geometry (WG). The initial direction is given by the vector specified in the OTL UI (see image above).
Every ‘next’ point position is calculated starting from the position of the previous point. For this reason I used a foreach loop making sure to uncheck the parameter “merge”, since I want the same data to be processed and provided to the next cycle after adding a new point.
To calculate the closest point on the surface from a certain point in the world space, I’ve used VDB SDF. SDF are already a blessing provided by Houdini but they’ve always had a certain level of imprecision. VDB SDF are way faster to calculate, and much more precise (thank you DreamWorks Animation for this gift !).
The following is the VOP SOP structure to calculate the closest point on surface, given an SDF volume and a sample location in world space:

cpos_vopsop

In this example I’ve created the wrapped L-System, and then used a Ray Sop to make sure each point really was on the surface, once per frame (Ray Sop is very fast).

I made sure to preserve the Width attribute calculated by default in the L-System Sop and I used it in the PolyWire Sop to drive the width of the Tubes as explained in the PolyWire documentation:

….This node works like the Wireframe node, but this node creates more complex tube geometry from curves, with smoother bends and intersections than Wireframe, especially for L-systems.

The four numerical parameters support all the local variables of the Point operation, plus the LSYSTEM specific variables of $WIDTH, $SEGS, $DIV, $LAGE, $GEN, and $ARC….

WL has been calculated on a static WG (I choose the first frame of the hand animation). Then I used a Lattice Sop to wrap WL on the animated version of WG. Before applying the Lattice Sop I’ve calculated and stored the density of the points on a point attribute on the animated WG via VOP SOP where I used Point Cloud vex nodes to access the same geometry and return the number of points within a certain radius. Then I’ve used the density attribute to drive the size of the metaballs internally used by Lattice Sop.

Note:
L-Systems are perfect to create intricate veins systems. Because L-Systems are a parallel rewriting systems, their size might get huge very fast. For instance in the previous example the original L-System had 95 generations and ~66k points. Nevertheless the generation of the L-System itself was very fast (less than 1s per frame for 95 generations).

OTL processing time to calculate the Wrapped L-System in this example:

Frames 1-84 (83 frames) : less than 2 minutes
Frames 85-91 (7 frames) : ~1 minute
Frames 92-96 (4 frames) : ~1 minute
Frames 97-99 (2 frames) : ~1 minute
Frames 100-102 (2 frames) : ~1 minute
Frames 103-104 (1 frame): ~1 minute

Frame 116 : ~2 minutes
Frame 122 : ~3 minutes
Frame 131 : ~5 minutes
Frame 138: ~10 minutes
Frame 145: ~21 minutes

Time to calculate 145 frames ~ 3h 40m.

On an Intel Core i7 3.0Ghz – 4 cores – 8 logical
All VOP SOPs are set to 1 thread per proc.

As you can see , processing times increase exponentially when the number of L-System generation starts getting crazy so if the idea is, for instance, to cover a full animated character with veins, the best approach is divide and conquer, instead of using one single massive L-System.

Now, I guess this is just a way to accomplish this effect, I am sure there are many others I’ve not thought about. So, feel free to comment and pitch ideas !

Alessandro