GroomLab

Other renderers

Rendering GroomLab hair with the RenderMan procedural (and in prman from any Maya or the app), in V-Ray Standalone from Maya or from a V-Ray scene export, or in RenderMan, Redshift and V-Ray from Alembic and USD exports - file layout, units, attributes and hair shader setup.

GroomLab renders natively in Arnold (Rendering) and in RenderMan 27 (below), where a procedural evaluates the groom file at render time; Render > RenderMan (prman) renders the scene in RenderMan from any Maya version and from the standalone app. For V-Ray, GroomLab writes a V-Ray scene with the hair and its shader, and renders it in V-Ray Standalone from any Maya version (below). For Redshift and other renderers, export the strands as Alembic or USD curves. For quick previews with no renderer at all, Render > Maya Hardware 2.0 renders with Maya's own viewport renderer (Maya Hardware 2.0).

What we have tested

The contents of the exported files (File contents), the RenderMan procedural and Render > RenderMan (prman) (in RenderMan Pro Server 27.3, from Maya 2022 and the app), the V-Ray scene export and Render > V-Ray Standalone (in V-Ray Standalone 7, from Maya 2022) are tested. The V-Ray for Maya hook and Load as VRayScene are experimental and untested. The Alembic and USD import steps for each renderer below follow that renderer's documentation, linked in each section; they have not been tested in Redshift or V-Ray yet. If a step does not work, contact support@getgroomlab.com.

Export

Set the frame range

The menu exports the playback range. For a still, set a one-frame range.

Export

Select the groom and choose GroomLab > Export > Alembic... (.abc) or USD... (.usda). From Python:

import groomlab

groomlab.export_alembic(groom, "C:/shots/010/hair.abc", start=1, end=48)
groomlab.export_usd(groom, "C:/shots/010/hair.usda", start=1, end=48,
                    render_overrides=True)  # renderDensity, renderWidthScale, renderLengthScale
  • Density: exports contain every strand (density=1.0), regardless of previewDensity. Pass a lower density for a lighter file, or render_overrides=True to export the groom with its render overrides applied. The menu exports without the overrides.
  • No render-time LOD: distance thinning and camera culling only apply in Arnold at render time. Exports do not apply them.
  • Alembic or USD: prefer USD. Only USD carries per-point attributes (opacity, a tip color or bands, wetness); Alembic carries per-strand attributes only.

File contents

Both formats are written from the same strand data, so their contents match except where the table says otherwise. For the full list of attributes and their names, see Strand attributes; for every prim and primvar of the USD file, its types and its version marker, see USD layout.

Alembic (.abc)USD (.usda)
Layout/<groom>/<groom>Shape, an ICurves object/<groom> (Xform, the default prim) with strands, a BasisCurves prim
CurvesLinear, non-periodic (no basis)type = "linear", wrap = "nonperiodic"
PointsThe strands' own points (a Resample node sets how many)Same
Widthswidth, one per point (vertex scope): the strand diameterwidths, one per point (vertex interpolation): the diameter
Strand IDstrandId (uint64, uniform scope)primvars:strandId (int64, uniform)
Root UVThe curves' uvs, one per curve (with scalp UVs)primvars:st (texCoord2f, uniform)
ColorCd (linear RGB, uniform scope)primvars:displayColor (linear RGB, uniform)
Per-strand attributesEach as a float arbGeomParam, uniform scope, by its nameEach as primvars:<name> (float, uniform)
Per-point attributesNot writtenEach as primvars:<name> (float, vertex)
UnitsScene units: centimeters in Maya. Alembic has no unit metadataCentimeters, with metersPerUnit = 0.01
Up axisMaya's (Y unless the scene is Z-up), not taggedupAxis metadata, from Maya's preference
AnimationOne sample per exported frameOne time sample per exported frame (timeCodesPerSecond = the scene frame rate)
VelocitiesNoneNone
  • Space: points are in the groom node's object space. The file's root transform is identity, so if the groom's transform was moved in Maya, parent the imported cache under the same transform.
  • Color: Cd / displayColor is one color per strand. Color that varies along a strand (a tip color, bands) is only carried by USD's per-point attributes colorR_2, colorG_2, colorB_2 (renamed because the per-strand colorR, colorG, colorB already use the names).
  • Scales and instances: the Scales node's scales are exported next to the strands as a mesh, and USD also writes Instance nodes' instances as a PointInstancer (Scales).
  • Inspecting a file: groomlab-cli abc-info hair.abc lists an Alembic file's frames and strands; .usda files are plain text.

Shading

GroomLab describes hair color with the same parameters as aiStandardHair. To reproduce a look in another renderer:

  1. Read the values. On the HairColor node: melanin, redness (melaninRedness in the file) and dye, and under Highlight: specular (default 0.3), roughness (0.5) and tilt (3 degrees). Opacity is on the RenderData node. From Python: groomlab.hair_color_params(groom), groomlab.hair_look(groom) and groomlab.render_data_params(groom).
  2. Set the hair shader's base values using the table below.
  3. Connect the per-strand values where they vary: HairColor varies melanin and redness per strand and per clump, so read the melanin and melaninRedness attributes rather than a constant, and disable the shader's own melanin randomization.

The V-Ray scene export sets V-Ray's shader up itself (V-Ray); the V-Ray column is for Alembic and USD imports.

GroomLab's melanin and redness are aiStandardHair's 0-1 parameters. The other renderers use 0-1 parameters for similar melanin models, but each converts them to fiber absorption differently. Use the same values as a starting point, then match against the GroomLab viewport or an Arnold render.

GroomLabArnold (create_hair_shader)RenderMan: PxrHairColor + PxrMarschnerHairRedshift: Principled HairV-Ray: VRayHairNextMtl
melanin (0-1)melaninMelanin (Physical mode)MelaninMelanin
redness / melaninRedness (0-1)melanin_rednessRedness (the eumelanin/pheomelanin balance)Melanin RednessPheomelanin (redness as a share of the melanin)
dye (RGB, white: none)base_colorDyeTintDye Color
RGB color (Cd / displayColor)base_color from hair_color, melanin 0Color (Artistic mode)Albedo, with Albedo Mix 1Dye Color, with Melanin 0
specular (0-1)specular_tint = min(1, specular / 0.3)Primary specular color/gain: keep white for physical hairNo direct controlPrimary Tint
roughness (0-1)roughness = 0.1 + 0.4 x roughnessSpecular cone angles: match visuallyRoughness: start at 0.1 + 0.4 x roughnessGlossiness (higher is sharper): match visually
opacity (per point, USD only)opacitySee RenderMan's documentationSee Redshift's documentationTransparency (white is opaque): use 1 - opacity
Melanin randomizationmelaninRandomize offMelanin Randomize 0Melanin Var. 0Random Melanin 0
  • Wet hair: GroomLab's wet look (darker, more saturated, glossier) is built for Arnold by create_hair_shader. Elsewhere, use the wetness attribute to build it: more melanin and lower roughness where it is high.
  • Iridescence: FeatherColor's iridescence network exists for Arnold only. The iridescence attribute (USD) gives the mask.

RenderMan

RenderMan procedural

The Maya download includes GroomLab/procedurals/renderman/groomlab_renderman.dll, a RenderMan 27 procedural: prman evaluates the groom from a .groom file at render time and emits linear RiCurves with the strands' color, highlight, opacity and wetness as primvars for a PxrHairColor + PxrMarschnerHair network. groom.rib next to it is a complete example scene, shading network included. The primvars are listed in Strand attributes.

  • In a RIB or on a farm:

    Procedural2 "DynamicLoad" "DSOBound" "string dsoname" ["groomlab_renderman"]
        "string filename" ["C:/shots/010/hair.groom"] "float frame" [12]

    Parameters: filename, frame, fps, density, widthScale, lengthScale, motionStart, motionEnd, motionKeys (motion blur), searchPaths, name, and debug (prints every primvar). Instances and scales are not rendered by this procedural.

  • In RenderMan for Maya (Maya 2024 to 2026), experimental: load RenderMan for Maya, select the groom and choose GroomLab > Render > RenderMan Procedural (experimental). It creates a RenderMan Procedural node that renders the groom, exporting the groom file each frame, and can build the hair shading network. It is tested through prman but has not yet been run inside Maya; please report results.

  • Color: GroomLab's melanin and redness are converted to PxrHairColor's (the rman_melanin and rman_redness primvars). Under a strong key light, light hair can render darker than in Arnold, because PxrMarschnerHair transmits less light through many hairs.

Render in RenderMan (any Maya, tested)

GroomLab > Render > RenderMan (prman)... (also in the Groom Tools' Output section) renders what the scene shows in RenderMan's prman, through the procedural above, so any Maya version renders the groom in RenderMan, Maya 2022 too: RenderMan for Maya is not needed, only RenderMan Pro Server (RenderMan is free for non-commercial use; a commercial license otherwise). Pick the frames (the current frame, the playback range or the render range: a turntable is a sequence), the size, the quality (Draft, Preview, Final), the meshes and motion blur; prman then renders in the background, Maya stays free, a progress window counts the frames (Stop cancels), and the image opens in Maya's Render View. The images, the RIB, the groom file and prman's log are kept in the scene's groomlab/<scene>/renders/prman_<date> folder.

What goes to RenderMan, as one RIB with a frame block per frame:

  • Grooms: every visible groom, written to a .groom file the procedural evaluates at each frame (with its scalp's animation cached when the scalp moves; a groom set to Render from Groom File uses its own file), its render density and overrides, and the hair network above with the groom's cuticle tilt. With Motion blur, the procedural writes deformation keys over half a frame.
  • Meshes: every visible mesh (or the selection and the grooms' scalps and colliders) with a PxrSurface from its shader's plain values (aiStandardSurface's base color, specular and roughness; a Lambert's or Blinn's color; textures are not followed), subdivided when Arnold's subdivision or Maya's smooth mesh preview is on. Meshes that cast no shadow, and Maya's light links, carry over.
  • Camera: the studio's camera when there is a studio, else the viewport's, with the field of view the render resolution gives it (film fit).
  • Lights: Arnold and Maya area lights as PxrRectLight (exposure and normalize as in Arnold; a spread below 1 becomes emissionFocus), sky domes as PxrDomeLight (their color; an HDR texture is not carried) and directional lights as PxrDistantLight (Arnold's intensity is the irradiance). Point, spot, mesh and photometric lights are left out; a scene without any of these gets a soft grey dome and a key light from above the camera. Each studio light alone renders within about 5% of Arnold on the backdrop (in linear sRGB); the hair and head within about 10%, light hair a little darker and more saturated in its rims (PxrMarschnerHair's).

GroomLab looks for prman where you set it (the dialog's Browse..., or groomlab.set_prman_path(path)), then in the GROOMLAB_PRMAN and RMANTREE environment variables, the default install folder (C:\Program Files\Pixar\RenderManProServer-*\bin) and the PATH, and says so when it finds none.

import groomlab

job = groomlab.render_prman()                                     # this frame
job = groomlab.render_prman(start=1, end=120, quality="final",    # a sequence, 1280 x 720
                            width=1280, height=720, motion_blur=True)
job.wait()                                                        # or job.poll() / job.cancel()
print(job.images())                                               # the PNGs

From Alembic or USD

Links: PxrHairColor, PxrPrimvar, Alembic workflows in RenderMan for Maya, hdPrman (RenderMan's USD plugin). These are the RenderMan 25 pages; check the RenderMan 27 pages on rmanwiki.pixar.com for changes.

Export (verified)

groomlab.export_alembic(groom, "C:/shots/010/hair.abc", start=1, end=48) for Maya, or groomlab.export_usd(...) for a USD pipeline (Solaris, or another Hydra host).

Load it in the renderer

In Maya, load the Alembic file in a gpuCache node (Cache > GPU Cache > Import...) and enable its Render Alembic Cache; RenderMan for Maya renders gpuCache archives at full quality. RenderMan renders linear curves, so no conversion is needed.

For USD, reference the layer into a stage that RenderMan renders through hdPrman, its Hydra delegate (for example Houdini's Solaris with RenderMan for Houdini).

Assign the hair shader

Create a PxrMarschnerHair fed by a PxrHairColor in Physical mode, connected as RenderMan's documentation shows. Set Melanin from the HairColor node, Redness from its redness (PxrHairColor's Redness is the eumelanin/pheomelanin balance, as GroomLab's is), Dye from its dye, and keep the primary specular color white. PxrHairColor's Stray settings (density, melanin) correspond to GroomLab's greys, and its randomization options need Hair ID Primvar set. RenderMan's melanin scale may not match Arnold's exactly; compare on a test frame.

Read the per-strand values

Add a PxrPrimvar with Variable Name melanin and Variable Type float, and connect its result (resultR in Maya) to PxrHairColor's Melanin. Leave Melanin Randomize at 0, since GroomLab already varies melanin per strand. For an RGB color, a PxrPrimvar of type color reading Cd (Alembic) or displayColor (USD) feeds Artistic mode's Color.

  • PxrHairColor's randomization options need a per-curve Hair ID Primvar. The Alembic and USD exports write strandId as a 64-bit integer, which RenderMan may not accept as an ID; reading melanin per strand, as above, gives the same variation. (The RenderMan procedural writes hair_index, a uniform float, for this purpose.)
  • RenderMan's documentation recommends Alembic archives written by RenderMan's own exporter for gpuCache renders, so check a GroomLab archive on a test frame first.

Redshift

Links: Principled Hair, Alembic Procedural, USD Procedural, Scalar User Data, Color User Data.

Export (verified)

groomlab.export_alembic(...) or groomlab.export_usd(...), as above.

Load it in a Redshift Proxy

From the Redshift shelf, create a Redshift Proxy and set its File Type to Alembic (Redshift 2025.4 and later in Maya) or USD, then pick the file. The proxy loads it at render time. Redshift's documentation does not state whether the proxy renders Alembic or USD curves as hair in Maya; check on a test frame.

Assign the hair shader

Create a Principled Hair material and assign it to the proxy's placeholder (for USD, set Material Mode to From Scene (assigned to placeholder)). Set Melanin and Melanin Redness from the HairColor node, leave Tint white unless the hair is dyed, and set Roughness from the HairColor node.

Read the per-strand values

A Scalar User Data node with Attribute Name melanin feeds Melanin, another with melaninRedness feeds Melanin Redness; set Melanin Var. and Melanin Redness Var. to 0. For an RGB color, a Color User Data node reading Cd (Alembic) or displayColor (USD) feeds Albedo, with Albedo Mix at 1.

  • Redshift's documentation says hair reads per-vertex color and scalar attributes from Redshift 2025.4 on. GroomLab's melanin and color are per curve, so check that they reach the shader. If they don't, use a single value for the whole groom.

V-Ray

GroomLab writes a groom as a V-Ray scene (.vrscene, V-Ray's own scene format): the strands as V-Ray hair, each strand's color on them, and a VRayHairNextMtl shader set up from the groom's look so it renders close to Arnold. No Alembic or USD import and no shader setup are needed.

Links: VRayHairNextMtl, V-Ray Proxy.

Which route:

RouteMayaUse it for
Render > V-Ray Standalone... (tested)Every version GroomLab supports (2022 to 2027); V-Ray for Maya not neededGroom renders and lookdev: the grooms, the visible meshes, the camera and the lights rendered by V-Ray Standalone in the background, the image in the Render View
Render > V-Ray for Maya Hook (2024+, experimental)2024 and later, with V-Ray for MayaThe grooms inside your full V-Ray for Maya scene renders (your shaders, lights, render elements and farm)
Render > Load as VRayScene (2024+, experimental)2024 and later, with V-Ray for MayaThe same without a script: a VRayScene node pointing at an exported .vrscene
Export > V-Ray Scene... (tested)Every version, and BlenderA .vrscene of the groom to #include in your own V-Ray scenes

Render in V-Ray Standalone (any Maya, tested)

GroomLab > Render > V-Ray Standalone... (also in the Groom Tools' Output section) renders what the scene shows in V-Ray Standalone, so any Maya version renders the groom in V-Ray, Maya 2022 too. Pick the frames (the current frame, the playback range or the render range: a turntable is a sequence), the size (the render settings', half or a quarter), the quality (Draft, Preview, Final) and the meshes; vray.exe then renders in the background, Maya stays free, a progress window counts the frames (Stop cancels), and the image opens in Maya's Render View. The images, the .vrscene files and V-Ray's log are kept in the scene's groomlab/<scene>/renders/vray_<date> folder.

What goes to V-Ray:

  • Grooms: every visible groom, exported as below with its render density and overrides.
  • Meshes: every visible mesh (or the selection and the grooms' scalps and colliders), with a simple V-Ray material from its shader's plain values: aiStandardSurface's base color, specular and roughness (the studio's mannequin and backdrop greys), or a Lambert's or Blinn's color. Textures are not followed. Meshes that cast no shadow, and Maya's light links, carry over.
  • Camera: the studio's camera when there is a studio, else the viewport's, with the field of view the render resolution gives it (film fit).
  • Lights: Arnold and Maya area lights (exposure, normalize and spread as in Arnold: a spread below 1 becomes V-Ray's Directional), sky domes (their color; an HDR texture is not carried) and directional lights. Point, spot, mesh and photometric lights are left out. A scene without any of these gets a soft grey dome and a key light from above the camera. The studio presets render within about 15% of Arnold in V-Ray (in linear sRGB).
  • Animation: over a frame range, a moving camera or light (the Turntable preset orbits them) and a deforming mesh are keyed per frame.

GroomLab looks for vray.exe where you set it (the dialog's Browse..., or groomlab.set_vray_path(path)), then in the GROOMLAB_VRAY and VRAY_PATH environment variables, the default install folder (C:\Program Files\Chaos\V-Ray\Standalone for x64\bin) and the PATH, and says so when it finds none. V-Ray Standalone needs a V-Ray license of its own.

import groomlab

job = groomlab.render_vray()                                      # this frame
job = groomlab.render_vray(start=1, end=120, quality="final",     # a sequence, 1280 x 720
                           width=1280, height=720)
job.wait()                                                        # or job.poll() / job.cancel()
print(job.images())                                               # the PNGs

V-Ray for Maya hook (Maya 2024+, experimental)

Experimental, untested

V-Ray for Maya supports Maya 2024 and later only, and these two items have not been run inside V-Ray for Maya yet. They are written from Chaos's documented Python API; please report results to support@getgroomlab.com. In Maya 2022, or without V-Ray for Maya loaded, they say "V-Ray for Maya 2024+ required" and change nothing.

Render > V-Ray for Maya Hook (2024+, experimental) adds one line to V-Ray's Post Translate Python Script (Render Settings > Common > MEL/Python callbacks: the vraySettings.postTranslatePython attribute; your own lines stay). After V-Ray has translated the scene, for each visible groom it writes the frame (with V-Ray's camera motion blur on: the shutter's interval, in its geometry samples) to a .vrscene in the scene's groomlab/<scene>/caches/vray folder, and adds a VRayScene plugin pointing at it through V-Ray's vray.utils module. The file carries the groom's world matrix, so the plugin adds none. Pick the item again to take the line out.

import groomlab.vray_hook as hook
hook.enable_hook()     # hook.disable_hook() takes it out

Render > Load as VRayScene (2024+, experimental) exports the selected groom over the playback range to the scene's exports folder and makes a VRayScene node pointing at it (its transform is locked at the origin: the file has the groom's world matrix). Run it again after changing the groom.

Export (tested in V-Ray Standalone 7)

Select the groom and choose GroomLab > Export > V-Ray Scene... (in Maya or Blender). It exports the playback range; for a still, set a one-frame range. From Python or the command line:

import groomlab

groomlab.export_vrscene(groom, "C:/shots/010/hair.vrscene", start=1, end=48,
                        render_overrides=True)  # renderDensity, renderWidthScale, renderLengthScale
groomlab-cli eval hair.groom -o hair.vrscene -f 1-48

Render it

V-Ray Standalone: the file holds the groom only (no camera, lights or render settings), so #include it in a scene that has them, then render:

#include "C:/shots/010/hair.vrscene"
// ... your camera (RenderView), lights, settings and other objects
vray -sceneFile=shot.vrscene -imgFile=hair.png -frames=12

V-Ray for Maya: load the file in a V-Ray Scene node (VRayScene) and render, or use Render > Load as VRayScene (above). The hair keeps the file's shader. This step has not been run inside Maya yet; please report results.

V-Ray for Blender and the GroomLab app need no export: a final render in V-Ray for Blender renders the groom this way on its own (Blender), and the app's Render > Render Frame in V-Ray renders it in V-Ray Standalone with the viewport's camera and lights (the app).

What the file holds (plugin names start with the groom's name):

PluginWhat it is
GeomMayaHair <name>@hairThe strands in the groom's object space: points per strand, widths per point (V-Ray's hair width is the radius, so it holds half GroomLab's width), the color per point, root UVs (strand_uvw), opacity as transparency when the groom has any
BRDFHair4 <name>@hairBrdfVRayHairNextMtl's shader: Melanin 0 and Dye Color from each strand's color (a TexHairSampler reads it), the highlight from HairColor's specular, roughness and tilt; glints, glitter and V-Ray's random variation off (GroomLab varies each strand already)
MtlSingleBRDF <name>@hairMtlThe material
Node <name>@nodeThe hair with its material and transform: the groom's world matrix in Maya (so it lands where the groom is; its scale goes into the strands), the identity from Blender, the app and the CLI (groom space)
SettingsUnitsInfo <name>@unitsCentimeters (meters_scale 0.01), the up axis (Y unless the Maya scene or groom file is Z-up) and the frame rate
  • Color: every color reaches the shader per point: HairColor's pigment (melanin and redness, varied per strand and clump), its RGB mode, tips, Bands and FeatherColor. Wet hair (a Wet node) is darker as in Arnold; its glossier highlight is not carried (the highlight is one for the groom).
  • Look: V-Ray's hair shader differs from aiStandardHair, so GroomLab converts its values to V-Ray's (Glossiness 0.46 and Softness 0.35 for the default look, IOR 1.7, 40 bounces). Against Arnold on a test head, brown and black hair come within about 5-10%, blonde and light RGB colors render 10-15% darker, and red hair about 25% brighter in V-Ray.
  • Highlight per strand: HairColor's specularRandom and roughnessRandom, and specular or roughness maps, are not carried: V-Ray uses the groom's values for every strand.
  • Animation and motion blur: a frame range is one file. Values that change between frames (the points of a moving groom) are written as V-Ray keys, one per frame; values that don't are written once. Turn on V-Ray's motion blur and it blurs between the keys: to blur frame 12, export frames 12 to 13 (or subframes with step=0.5). As for Alembic and USD, give a groom on a deforming scalp a rest mesh so every frame has the same strands.
  • Not written: instances and scales (use USD for those), FeatherColor's iridescence, and the render-time LOD that Arnold's procedural applies.
  • Size: the long lists are compressed, about 22 bytes per point per frame.
  • Scale: V-Ray does not scale hair widths with a transform, so a scaled groom's scale goes into the strands themselves and the Node keeps its rotation and position. Don't scale the file again with a V-Ray Scene node's transform: the strands would render too thick or too thin. Render it in the file's units (GroomLab's own V-Ray renders in Blender write the strands in the scene's units for this reason).

From Alembic or USD

The .vrscene export is the recommended route. Alembic (in a V-Ray Proxy, with Tessellate Hair) and USD (through MayaUSD) also load, untested: assign a VRayHairNextMtl yourself and read the per-strand melanin with a VRayUserScalar into Melanin (or Cd with a VRayUserColor into Dye Color, Melanin 0), with Random Melanin at 0.

Animation, motion blur and farms

  • Animated grooms: export the frame range; each frame is one sample in the same file. Give a groom on a deforming scalp a rest mesh, so every frame has the same strands and point counts (Motion and simulation). Renderers only compute deformation blur for curves when the samples have matching topology.
  • Motion blur: the files carry no velocities. The renderer interpolates between samples, so for fast motion export subframes: step=0.5 (or 0.25) writes samples between frames.
  • Without Maya: save a groom file (GroomLab > Groom Files > Save Groom File As...) with its scalp cache, and groomlab-cli writes the Alembic, USD or V-Ray scene on any machine:
groomlab-cli eval hair.groom -o hair.abc -f 1-48
groomlab-cli eval hair.groom -o hair.usda -f 1-48 --step 0.5 --density 1

The CLI names the root groom and writes USD in the groom file's own up axis and units. It has no render-overrides option; pass --density instead.

  • Size: .usda is text, about 60 bytes per point per frame. Convert large files to binary with USD's usdcat (usdcat hair.usda -o hair.usdc).
  • Arnold farms don't need any of this: the Arnold procedural evaluates the groom file at render time (Farm renders).

On this page