HoudiniCops

From cgwiki

Mike Lyndon has done a great overview of Cops, definitely worth watching: https://vimeo.com/247302953

Cops and Vex

Cop vex screencap.gif

Download scene: File:cop_vex.hipnc

There's no Cops wrangle yet, boo.

Cops Vop with a snippet works though, yay!

It still feels a little crusty (why all capital letters? Why X Y R G B A as separate attributes rather than P and Cd?) , but still fun to play with.

If you're doing straight colour manipulation, that's simple enough, read the incoming rgba, modify, write it out.

If you're transforming pixels (say a rotate or a warp) the workflow is different; it's similar to a primuv call in that you request an xy position, it returns a value.

The vex functions to do this are cinput() binput() finput(), which return low/mid/high quality results. An easier way is to use the 'cop input' vop, which wraps all 3 and gives you a combo box to choose the quality.

So to do a sine ripple to an image, you put down a cop vop filter, dive inside, make a snippet, wire in X and Y, and modify X like:

vector2 pos = set(X,Y);
pos.x += sin(pos.y*60)*0.02;
X = pos.x;
Y = pos.y;


That then feeds the u and v inputs of a cop input, set the output signature to 4D vector (ie rgba), then split that vector back into individual floats, and wire to RGBA.

Latlong to cubemap

Latlong cubemap preview.gif

Download scene: File:latlong_to_cubemap_v04.hipnc

Cop vop latlong cubemap.jpg

Many thanks to Eetu for solving the last bit I was struggling with!

Been doing more and more pano experiments in Houdini lately, but I always have to keep Nuke open to do relatively simple things. A key thing is to be able to transform from a equirectangular/latlong panorama to a cubemap. Having recently worked out how to put a vex snippet in a cop vop, this seemed a good thing to try.

First, I did some intense research on polar maths and space conversion , which led me to this post:

http://stackoverflow.com/questions/29678510/convert-21-equirectangular-panorama-to-cube-map

The trickiest part here was taking the python answer, and translating it into vex. Not the language per se, but taking the sequential method of the python example ('for every pixel in the images do this...') and making a parallel processing version in vex. The python example also has lots of code for anti-aliasing, which wasn't a concern here as the cinput vop takes care of all that.

Anyway, got it all ported and... it was almost right. Could see the N/S/E/W planes were sort of working, but the top and bottom were skewed. At that point it was past midnight, so I posted my work in progress to the discord houdini chatroom.

In the morning, Eetu found the fix, amusingly using a technique similar to mine; try and understand the logic behind it, work out where the fix should be, find it didn't work, then randomly insert multipliers here and there until one started to move things in the right way, then playing with that number until its fixed. At some point I'll go back and try and understand why, but not right now.

To show-off, you can slide the pano horizontally (making sure wrap is enabled), and you get that cool cube tumble effect. I also show off that handy feature of houdini to use http paths to images. I'd planned to use the panos that ship with Houdini in $HFS/houdini/pic/, but annoyingly they're in a houdini cubemap format already, and to unpack those into a latlong, then back to cubemap, seemed more effort than it was worth.

The idea behind the code is to treat the image as a new blank cubemap, and work out where to lookup the corect values from the latlong. First it identifies the NSEW zones, which are every 1/4 across the image. Then it divides the image vertically into thirds, and defines the top third as top of the cube, and bottom third as bottom of the cube.

Now that it knows the regions, it calculates the uv position on the sphere using the previously defined outImgToXYZ function. This does a conversion from the 2d cubmap positions into 3d sphere positions. This is then used to get the polar coordinates (ie, the compass direction, or theta, then the up/down angle, or phi), to find the pixel we need on the latlong, which is in turn used to drive the copinput vop.

The top and bottom regions will cover the entire top and bottom strips, so I make a mask based on the regions to multiply the results against later to get a clean cubemap image. You can bypass the multiply1 node to see the effect of this.

80s stuff

This odforce post on wireframe rendering made me try a few things I've wanted to have a go at, which I'll sum up as 'retro kitsch'.

Scanlines are easy enough, vopcop filter, combine the R G B channels into a single Cd vector, and X and Y into a P vector, then run this in a snippet:

float scanline = clamp(sin(P.y*YRES),0,1);
scanline = fit(scanline,0,1,0.6,1);
Cd*=scanline;


At one point I wanted to test an effect, and needed a grid. Vopcop2 generator, snippet, thus:

float linewidth = 0.002;
float gridsize=0.04;
Cd  = P.x % gridsize < linewidth ?1:0;
Cd += P.y % gridsize < linewidth ?1:0;


Next was a chromatic aberration effect, which is basically a radial distort that is mostly 0 at the center, and increases at the edges, applied slightly differently to the r/g/b channels.

The core of the distort is this in a snippet:

float d  = distance({0.5,0.5},P);
d = smooth(0.2,2,d);
d*=0.05;
vector2 disp = set(d,d);
if (P.x<0.5) {
 disp.x*=-1;
}
if (P.y<0.5) {
 disp.y*=-1;
}
 
P +=disp;
P-=0.5;
P*=0.9;
P+=0.5;


That then drives 3 copinput vops as before (each beign run through an addconstant to slightly increase/decrease the effect for each channel, then combined.

That, plus some blurs, convolves, other hacky things, made something I was kinda happy with.