Scientific visualisation with POV-Ray
This skill packages a set of POV-Ray building blocks and conventions developed for a real hero figure (four magnetic ground-state renders plus five concept-icon widgets for a grant proposal), refined over several rounds of visual review. Reach for it any time the deliverable is a standalone diagram or icon meant to sit in a document someone else will read - not a UI, not a web page, a rendered image.
Why POV-Ray, and what this buys you
POV-Ray scenes are plain text, which means: they're easy to parameterise (loop over N atoms, generate a lattice, sweep a parameter), easy to compose from reusable macros, and easy to re-render at a different resolution without redoing any work. The output is a flat, precisely-controlled raster image (not an interactive 3D scene) - exactly the format papers, slides, and grant PDFs actually want.
Quick start
#include "common.inc"first - sets up the camera, a soft 3-point light rig, background/transparency, and shared finish presets. Look at it once; the comments explain the why behind each choice (matters if you need to deviate from it).- Pull in whichever of these you need:
molecule.inc- atoms (sv_atom), bonds (sv_bond), vector arrows (sv_arrow)wave.inc- oscillating tubes: propagating waves and fuzzy "abstract interaction" connectors are the same macro (sv_wave_tube) with different parametersglow.inc- the layered-halo trick for anything that should read as glowing/hot/energetic (sv_glow_sphere)orientation_color.inc- map a direction/angle to a perceptually distinct colour (sv_orientation_colour/sv_colour_wheel), for when direction itself is the data (spin angle, flow direction, phase)
- Render with
scripts/render.sh <scene.pov> [W] [H] [out.png]rather than callingpovraydirectly - it sets+UA(real alpha channel), sensible antialiasing, points POV-Ray at this skill'sassets/so your#includes resolve without copying files around, and it will warn you if the alpha channel came out wrong (see the gotcha below - this has bitten a real session before, silently). - Look at the result before calling it done. Read the PNG back
(
Readtool) and actually look - POV-Ray will happily render something subtly wrong (clipped by the camera frame, wrong colour, arrows overlapping) with zero errors.
The five widget templates
assets/widgets/ has five ready-to-adapt scenes, each a worked example of
the building blocks above:
| File | What it shows | Built from |
|---|---|---|
laser.pov | A propagating oscillating wave + direction arrow (light, sound, any signal) | sv_wave_tube (open, no taper) |
particle_current.pov | A row of N particles each carrying a vector property, drifting in a flow direction | sv_atom + sv_arrow + a flow arrow |
thermal_grid.pov | An NxN lattice with small positional jitter, glowing hot-to-cool by distance from centre | sv_glow_sphere + a jittered grid loop |
interaction_triangle.pov | N objects joined by fuzzy, glowing, non-rigid "interaction" lines (distinct from a physical bond) | sv_atom + sv_wave_tube (tapered, jittered, glowing) |
Copy the one closest to what you need and change the declared parameters at the top (colours, counts, spacing, amplitude) before touching the geometry itself - all four are written so the "knobs" are up top.
For a real molecule/crystal structure (not a concept icon), skip the
widgets and go straight to molecule.inc: loop over your atom
coordinates calling sv_atom and sv_bond, using sv_arrow for any
per-atom vector (spin, dipole, displacement) and sv_orientation_colour
if that vector's direction is itself meaningful data worth colour-coding.
Design conventions worth keeping
These aren't arbitrary - each came out of a real visual-review round:
- White background, real alpha channel (
+UA). Renders drop straight onto a slide/page/figure without a visible box, and compose cleanly next to other panels regardless of what's behind them. - The 3-point light rig in
common.inc, not a single point light. One hard light reads as a rendered 3D object ("clip art"); the soft key+fill+fill rig reads as a polished, matte, printed illustration. Keep the same rig across every panel of a multi-panel figure so they read as one family - a panel lit differently from its neighbours looks like a mismatched sticker even when the geometry style matches. - Bonds/rigid connectors get a small away-from-camera z-offset
(
sv_bond'sZOffsetparam) whenever a bond and an arrow might run near-parallel through the same region - otherwise they z-fight, or the bond visibly slices into an arrowhead. Small enough (0.15-0.25 units on a typical scene scale) that no one will consciously notice it's there. - Arrows are 10-20% shorter than "touching." If two vector arrows
meet at a shared point, shrink
Scaleuntil their tips clear each other - touching tips read as a rendering glitch, not as data. - Abstract vs. physical connections get different visual language.
A real bond (
sv_bond): rigid, crisp, matte. An abstract coupling/force/correlation (sv_wave_tubewithGlow=true): wavy, soft-edged, glowing. Don't draw an interaction you can't point to a literal atom-atom orbital overlap for as if it were a physical rod. - Slightly distort "generic" arrangements. A perfect equilateral
triangle or perfectly regular grid reads as clip art. A small, deliberate
irregularity (see
interaction_triangle.pov's triangle, orthermal_grid.pov's jitter) reads as "a real system," even in a schematic icon that isn't simulation output.
When you're rendering real simulation data, not an icon
If atom positions/vectors come from an actual simulation (DFT, molecular
dynamics, micromagnetics, whatever), the icon-widget conventions above
still apply, but you're populating sv_atom/sv_bond/sv_arrow calls
from real coordinate data rather than hand-picking values. Practical
notes:
- Generate bonds by a distance cutoff between atom pairs, not by hand.
- If you want to show a real, physically periodic tiled patch (a bigger region than one simulation cell) without re-running an expensive simulation, and the property tiles uniformly (true for most simple ordered ground states), it's often valid to replicate the already- converged small-cell result geometrically rather than resimulating a larger system - just verify first that the property genuinely doesn't vary from cell to cell in your case.
- Crop to a physically meaningful boundary (e.g. one full coordination shell/unit motif), not an arbitrary rectangle - the crop itself should say something true about the structure.
Troubleshooting
Read references/troubleshooting.md before spending time debugging a
POV-Ray parse error or a render that looks wrong - it lists the specific
gotchas already hit while building this skill (reserved SDL words that
look like ordinary variable names, the silent-alpha-transparency bug,
POV-Ray's camera handedness, sphere_sweep/array scoping quirks). Most
POV-Ray error messages are honest about the syntax problem but unhelpful
about why it looks that way from a normal-programmer's expectations;
that file exists so you don't have to rediscover the same handful of traps.
For fuller worked explanations of each macro's parameters and design
rationale (with more example calls than fit here), see
references/techniques.md.