Volumes: smoke, fire and liquids
A volume is a box of voxels rather than a surface: a smoke plume, a flame,
an explosion, water. Pixor reads .vdb files from Blender, EmberGen and
Houdini, and has a few of its own for when you have no simulation tool.
A volume has no geometry. It is drawn by walking a ray through it for every pixel, on the processor, and what comes out goes into the same picture the model does — so a flame sits in front of a hand, a character stands inside smoke, and the bands, lines and cleanup treat it exactly as they treat anything else.
Adding one
In the Scene step, the Outliner’s + menu, under A volume:
| Puff | a round puff of smoke |
| Flame | hot and narrow below, cool and wide above |
| Cloud | wide, flat underneath, lumpy on top |
| Mist | thin, low and even |
| From a .vdb file… | a simulation from Blender, EmberGen or Houdini |
A volume is a Volume node of the Scene graph, and
its row in the Outliner is the same node: a Row after it is a row of
volumes, each placed by its copy, and one wired into nothing is not in the
scene. Its settings are on the node too (pxr project scene game.pixor --set flame.voxels=48, by the volume’s name).
On the command line: --volume flame:0.5,0.8,0.5:0,0.55,0, where the
numbers are the size and then the position, in metres. A path to a .vdb
works in the same place: --volume smoke.vdb:1.2.
Carried by a bone, a volume goes where the bone goes in every clip —
a torch’s flame in a hand — and stays upright, as fire does; its position
is then measured from the bone. On the command line, @BONE at the end:
--volume flame:0.25:0,0.05,0@hand.r.
Carried by an effect’s emitter, a volume is part of that effect: it is
drawn on the effect’s own rows, from the effect’s first frame, wherever the
emitter is — on its bone, or where a clip’s keys move it — and on no other
row. The smoke of an explosion, the fire of a spell. Its position is then
measured from the emitter. On the command line, @effect:N for the
project’s Nth effect: --effect explosion --volume puff:1.5@effect:1.
How it is drawn
These are under How it is drawn in the volume’s Inspector.
- Thickness is how much volume a pixel needs before it is drawn at all. Higher gives a tighter, harder shape; lower a wispier one.
- Soft edge is how wide the fraying edge is. The edge is dithered away in an ordered pattern anchored to the volume itself, never blended, so every pixel stays on the palette and the pattern does not crawl as the volume turns.
- Self-shadow is how much the volume darkens where the light has to come through it.
- Colour is the volume’s own, and its ramp is built from it. Hot colour is the colour of the part that burns; setting it to the same as the colour means nothing burns, which is what smoke wants. Glows over says how hot a part has to be before it takes the hot colour whatever the light.
- Voxels is how finely the volume is cut up along its longest side. A sprite pixel wants one or two voxels: more only shimmers, because a different voxel wins the pixel every frame. A 256³ simulation is cut down to this on load, which is why a plume at 32 px stays still.
- Samples is how many points on a ray are looked at per voxel. Two is enough at sprite sizes; more is smoother and slower.
Volumes take no glint: a cloud has none, and the density they are shaded from is bumpy enough to sparkle if they were allowed one.
Sequences: making it move
One .vdb is one still volume. A simulation writes a file a frame —
fire_0001.vdb, fire_0002.vdb, and so on — and pointing Pixor at the
first of them plays the rest.
In the volume’s Sequence section:
| Frames | how many files to play, counting on from the one you opened |
| Every | take one file in N: a simulation is usually written at more frames than a sprite wants |
| Close the loop over | cross-fade this many frames from the end back into the start, so the sprite plays round and round without a jump. Those files become the fade and do not play: five files with a fade of one are four frames |
On the command line the sequence follows the size and the place:
--volume fire_0001.vdb:1.5::24,2,4 — 24 files, every second one, the last
four faded back into the first.
A sequence plays along with whatever motion the sheet already has: put a fire beside a walk cycle and the fire’s frames are the walk’s frames. When there is nothing else moving, the sequence is the motion and gets an action of its own, called volume.
Every frame is placed by the same transform, taken from the box the whole sequence fills, so a plume that grows does not shrink the picture back each frame. That also means Size is the size of the whole sequence, not of its first frame.
A sequence is never in memory whole: each file is read once to find that box, and then again when the sheet or the preview reaches its frame, with the last three kept. A long simulation costs time to read, not memory.
What Pixor reads
.vdb files holding float or vector grids in the usual tree, with values
stored plainly, zipped, or packed with Blosc-LZ4 (split into a stream per
byte or not, as Blosc 1.14 and later write it), all of them or only the
active ones — which is what Blender, EmberGen, Houdini and OpenVDB’s own
tools write. Pixelates for a grid named density,
smoke, fog or d, then temperature, flame, heat or fire for
the hot part, then velocity for the motion the anti-flicker pass uses. A
liquid’s surface (a level set) is read as a thickness with a hard edge,
solid all the way through.
Anything Pixor cannot read says so by name rather than coming out wrong:
another compressor, another kind of tree, a sheared transform.
pxr inspect fire.vdb prints a file’s grids, their size and their voxel
size.
What is not there yet
- Liquids are read and drawn as a volume, with no foam and no reflection. A sheet of water with both is the world’s Water node (Worlds).
What this page describes is in the full version; the free browser demo keeps to the default look and the PNG sheet.
Try in browser Get Pixor