Lava Melt: Driving a Lava Look from FLIP Attributes in Houdini
A cracked rock sphere that melts and drains into a lava pool, where the whole look comes from two simulation attributes and a couple of wrangles.
A sphere of cold, cracked rock heats up, melts from the bottom and drains into a glowing pool, which skins over with crust again as it spreads and slows. 140 frames at 24 fps, simulated with FLIP and rendered in Karma XPU.
The goal of this test was to keep the shading procedural and driven by the simulation: no textures, no hand-painted masks. Everything you see comes from two attributes on the meshed FLIP surface — temperature and v — plus a pair of VEX wrangles.
The network
The look-dev side is a short, linear SOP chain on top of the cached FLIP surface:
filecache (FLIP surface) → subdivide → lava_look → normal → rock_disp → normal → OUT
- filecache – loads the meshed FLIP surface, which carries
temperatureand velocityv. - subdivide – one OpenSubdiv Catmull-Clark pass to remove the faceting from meshing.
- lava_look – turns sim attributes into colour, emission and roughness.
- rock_disp – adds geometric relief, but only where the lava has cooled.
Step 1 — How molten is it?
The first signal is simply temperature, remapped into a 0–1 "molten" value:
float temp = f@temperature;
float molten = smooth(chf("melt_lo"), chf("melt_hi"), temp);
Cold parts of the sphere stay rock, and as the temperature rises the surface turns molten and starts to flow. But real lava isn't uniformly glowing — the interesting part is where it stops glowing again.
Step 2 — Faking a cooling crust
Instead of simulating heat loss, I let the crust form where lava is slow and low — the pool spreading on the ground — and keep the falling stream clean:
float spd = length(v@v);
float slow = 1.0 - smooth(0.0, chf("crust_speed"), spd);
float low = 1.0 - smooth(0.0, chf("crust_height"), @P.y);
float crust = clamp(slow * low * chf("crust_amt"), 0.0, 1.0) * (1.0 - crack);
It's a cheap heuristic, but it reads correctly: the stream pouring off the sphere stays white-hot, and as the pool settles it darkens and skins over.
Step 3 — Plates and glowing cracks
The crust is broken into plates using a Worley pattern (wnoise, F2 − F1 gives the cell borders). Straight Voronoi edges look artificial, so the lookup position is domain-warped with two layers of noise, and an extra anoise term makes the cracks thicker and thinner along their length:
vector warp = (noise(P0 * warp_freq) - 0.5) * 2.0 * warp_amp
+ (noise(P0 * warp_freq * 3.1 + 7.3) - 0.5) * 2.0 * warp_amp * warp_detail;
wnoise((P0 + warp) * cell_freq, seed, f1, f2);
float edge = f2 - f1 + (anoise(P0 * edge_noise_freq) - 0.5) * edge_noise_amp;
float crack = 1.0 - smooth(0.0, crack_width, edge);
Crack width and glow are animated, so the crust visibly fractures as the pool spreads.
Step 4 — Heat colour and outputs
Glow is the molten amount minus crust, plus whatever shines through the cracks. Colour runs from a deep red to a yellow-hot core, and the wrangle writes everything the material needs:
float glow = max(molten * (1.0 - crust), crack * crack_glow);
vector hot = lerp(hot_red, hot_yellow, smooth(0.6, 1.0, temp) * (1.0 - crust));
v@basecolor = lerp(rock, hot * 0.3, glow);
v@emit = hot * glow * emit_intensity;
f@rough = lerp(0.85, 0.35, glow); // rough rock, glossier molten lava
f@glow = glow;
Step 5 — Relief only where it's cold
The rock_disp wrangle rebuilds the exact same warped cell pattern — it reads every pattern parameter from lava_look via chf("../lava_look/...") — so the relief always lines up with the colour. Plates are raised, cracks recessed, rims get a little chipping, and the whole thing is masked by the inverse of glow:
float rockmask = pow(clamp(1.0 - f@glow, 0.0, 1.0), chf("mask_falloff"));
@P += normalize(@N) * d * rockmask * chf("disp_amp");
Molten lava stays smooth and liquid; only cooled crust gets texture. Driving both wrangles from one set of parameters made iterating on the look much faster — change the cell size once and colour and displacement follow.
Rendering in Solaris
- Material: a single MaterialX Standard Surface that reads
Cd,emitandroughwithmtlxgeompropvaluenodes — all the look decisions live in SOPs. - Lighting: a cool key, a strong blue rim and a dim blue dome. The cold light against the orange emission is a big part of what makes the lava read as hot.
- Camera: 77.8 mm with depth of field.
- Karma XPU: 512 × 512, 128 path-traced samples, motion blur on, diffuse limit 1 (emission does most of the lighting work anyway). Around 2:45 per frame.
- Image filters: a warm wide glow on the brightest values, a subtle vignette and AI denoise.