Mapping
Problem: Why Mapping Exists
Natsura needed a way to control growth that wasn't just “add more sliders to every node”.
For scalars, Mappings solve this: they turn attributes (and other data) into parameter values, so you can build your own behaviours on top of the simulation instead of waiting for new hard-coded parameters.
What Mapping Enables
Mapping lets a single parameter:
- Vary along the plant (per point / per segment).
- Change with time/age, distance, or depth in the structure.
- React to world-space information (via effectors and attributes).
- Contain controlled randomness instead of noise everywhere.
- Switch modes based on conditions (age, generation, region, etc.).
Examples of what that means artistically:
- Taper branches or trunks along their length.
- Make forks more likely near the top of the tree than near the base.
- Bend growth toward light or with wind.
- Turn decorations on only after certain ages or generations.
- Blend between “forms” (e.g. young vs old profile) smoothly.
Mapping doesn’t change the simulation itself.
It decides what numbers nodes see when they ask “what is my pitch/width/fork probability/etc. here?”.
How to Use Mapping (Artist View)
- Pick a parameter to drive
- On a node like Grow, choose a parameter (e.g. Pitch, Width, Fork Probability).
- Promote it to a mapping
- Instead of typing a single number, attach a map chain to that parameter’s socket.
- Add map nodes to the chain
- Use nodes like Map, Map Attribute, Map Random, Map If, Map Blend, Map Constant.
- Each node contributes part of the logic: read some data, remap it, blend it into the result.
- Preview the effect
- Run the simulation. The parameter is now a per-point value that changes according to your chain.
You can always drop back to “just a number” if you don’t need mapping.
Mapping is there when a single slider stops being enough.
How Mapping Works (Broadly)
At a high level:
- A map chain is a definition of how to compute one scalar value per point for a parameter.
- Each map node adds one step: read an attribute, apply a ramp, add randomness, blend with the previous value, and so on.
- Internally, this becomes a small VEX program plus data that is evaluated later during simulation.
If you know Houdini:
- Think of mapping as a mini VOP/VEX graph aimed at a single parameter.
- You work with map nodes instead of wiring VOP nodes directly, but the idea is the same: data flows in, code transforms it, you get a value out.
You don’t need to know any of the internals to use mapping.
All of the “program assembly” is hidden behind the map nodes.
Where Mapping Is Used Now
Today, mapping is mainly used on Grow to drive:
- Length and width over repeats.
- Pitch, roll, yaw, bending and spirals.
- Fork probability and related branching behaviour.
- Noise/variation strengths and other scalar controls.
Where Mapping Will Be Used
Mapping is being extended to:
- Other core nodes that control structure and flow.
- Decoration and scattering nodes (surface, cluster, selection).
The goal is that anywhere you see “this could be more interesting than a constant slider”, you can plug in a map chain.
Current Mapping Options and Combinations
Core map node types and how they combine:
- Map Constant
- Set a base value (e.g. default pitch or width).
- Often the first node in a chain.
- Map Attribute
- Read an attribute such as
u,age,root_distance,branch_id, or a custom one. - Remap it through ranges or ramps (classic taper along
ulives here).
- Read an attribute such as
- Map Random
- Add controlled randomness.
- Seeded by branch ID, point ID, or other attributes for stable variation.
- Map If
- Condition-based logic (e.g. “if age > 2, use this profile, otherwise use that one”).
- Good for “only after this stage” or “different behaviour per generation”.
- Map Blend
- Blend between two map sub-chains.
- Useful for mixing shapes (e.g. “between young and old taper” or “between calm and windy response”).
- Map (general)
- A more flexible building block that can act like a combination of the above behaviours depending on settings.
Interesting artistic combinations:
- Attribute + Random
- Taper width by
uand then add small random variation → natural, non-uniform branches.
- Taper width by
- Effector + Attribute
- Use an effector (e.g. light direction reduced to a scalar) multiplied by a ramp along
u→ branches that bend more toward light at the tips than at the base.
- Use an effector (e.g. light direction reduced to a scalar) multiplied by a ramp along
- Map If + Random
- Use Map If on
generationto make higher generations more random and lower generations more stable.
- Use Map If on
- Map Blend for style mixing
- Two fully different map chains blended with a slider → smoothly interpolate between two “tree styles” without rebuilding the graph.
Advanced Topics (for Technical Users)
The rest of this section is aimed at tech artists, TDs, and developers.
If you only care about artistic control, you can stop reading here.
Internal Mental Model
Internally, a map chain is:
- A structure: map nodes that each contribute a small VEX snippet and an optional primitive.
- A skeleton program: assembled from all those snippets, with a placeholder output called
<parm>. - A data store: primitives holding UI parameters (ramps, ranges, etc.) in a separate geometry stream.
At this stage, the chain does not know which concrete attribute it will write; <parm> is just “whatever this parameter will be”.
Discrete Stages: From Map Chain to Running Code
There are several distinct steps between “artist builds a map chain” and “code runs per point”:
- User builds the chain
- Each map node contributes:
- A VEX snippet that uses
<parm>as its output symbol. - A primitive (in another stream) containing its UI data if needed.
- A VEX snippet that uses
- Result: a chain that defines how to compute a value, but not where to store it.
- Each map node contributes:
- Binding
<parm>to a real attribute- When a node ingests the chain for a specific parameter, it decides what
<parm>actually means. - Example: for Grow’s Pitch on a given Grow,
<parm>becomes@cluster_pitch. - All snippets in the chain are rewritten so
<parm>is replaced by that attribute name.
- When a node ingests the chain for a specific parameter, it decides what
- Program assembly
- A code processor concatenates snippets from the chain (in order) into a single VEX block.
- This block is now a complete program for computing that attribute.
- Compilation and APEX graph
- The assembled VEX is fed into an Attrib VOP.
- That VOP is compiled and wired into an APEX Invoke graph.
- From this point on, the Grow node can call that graph to evaluate the mapping.
Each Grow with mapped parameters ends up with its own unique program per mapped parameter (or per group of parameters), but:
- The VEX is compiled once per Grow.
- Subsequent evaluations reuse the compiled program.
Primitives, Streams, and primuv
To avoid recompiling whenever a slider or ramp changes:
- Mapping splits code and data.
Code:
- Lives in the assembled VEX program constructed from snippets.
Data:
- Lives on primitives in a separate geometry stream (typically stream 1).
- Each map node’s point has a path attribute that points to its corresponding primitive.
At evaluation time:
- The program runs over stream 0 (the simulated plant geometry).
- It uses the path attribute and
primuv()(and related calls) on stream 1 to read its parameters from primitives.
Typical pattern:
- Treat an attribute (like
u) as a UV (or a 1D parameter). - Use
primuv()on stream 1 to sample@P.y(or other components) on a ramp curve primitive. - Use that value as part of the scalar being written to
<parm>.
Because primitives can hold arbitrary data, this mechanism can support more complex map behaviours over time without changing the program structure.
Re-evaluation vs Re-compilation
This separation has a key consequence:
- Changing map UI values (ramps, ranges, toggles) only changes the primitive data.
- The compiled VEX program remains the same.
- The APEX graph does not need to be rebuilt; it is simply re-evaluated with new primitive values.
You only pay the cost of rebuilding/compiling when:
- The map chain structure changes (nodes added/removed/wired differently), or
- You change the advanced VEX snippets themselves.
Customising and Extending Mapping
For advanced users:
- Each map node’s VEX snippet is exposed under an Advanced section.
- You can modify those snippets directly if you follow the
<parm>convention and the expected inputs. - You can create new mapping behaviours by:
- Writing new snippets,
- Defining how they are combined in the chain, and
- Creating primitives to store any additional parameters.
Beyond per-node customisation:
- You can build compound map HDAs that internally contain multiple core map nodes wired together to express higher-level plant behaviours.
- Artists then see one higher-level node, built from familiar low-level map components.
One-Line Mental Model
Mappings are deferred scalar programs:
- Artists build them from map nodes.
- Nodes bind them to real attributes and compile them once.
- The compiled code is reused to fill per-point parameter values during simulation, driven by attributes, effectors, and primitives.