Houdini 21: Object-to-Object Instance/Particle Transformation Research¶
Procedural Workflow for Coin Morphing Effects¶
1. CORE WORKFLOW: Scatter Instances on Source Mesh → Morph to Target Mesh¶
Standard Procedural Pipeline¶
Step 1: Scatter points on both source and target meshes
- Use Scatter SOP (v2.0) on each mesh to generate point distributions
- Ensure both have the same point count (use Force Total Count or match densities)
- Enable Prim Num Attribute and Prim UVW Attribute output options for later interpolation
- For consistent point distributions across different meshes, consider scattering "In Texture Space" (if UVs are available and consistent)
Step 2: Match source points to target points
- Several matching strategies (see Section 3 below for details):
- Nearest-point matching: Use nearpoint() or nearpoints() in VEX
- Surface-distance matching: Use xyzdist() for closest surface location
- Random/staggered matching: Shuffle target point order for more organic transitions
- Attribute-driven matching: Sort both point clouds by spatial position and match by index
Step 3: Animate the morph with VEX
- Store both source (source_pos) and target (target_pos) positions on each point
- Use lerp() for position interpolation: P = lerp(source_pos, target_pos, blend)
- Use slerp() for quaternion orientation interpolation: orient = slerp(source_orient, target_orient, blend)
- Drive the blend parameter with a ramp or noise for staggered/particle-like timing
- Add intermediate "fly" positions using noise, curl noise, or offset paths
Step 4: Instance coins onto the morphing points
- Use Copy to Points SOP (v2.0) to stamp coin geometry onto the animated points
- For large point counts, use packed primitives or render-time instancing for performance
- Key instance attributes on points: orient, pscale, scale, N, up, v, pivot, transform
Step 5: Add secondary motion (optional)
- Point Jitter SOP (H21 now has mask parameter) for organic wobble
- Noise-based offsets during flight phase
- Spin/tumble via animated orient using dihedral() or qrotate()
VEX Code Example: Point Wrangle for Morphing¶
// Run over points - input 0 has both source_pos and target_pos attributes
// blend is driven by a ramp parameter or channel reference
float blend = chf("blend"); // 0 = source shape, 1 = target shape
// Per-point staggered timing using noise or ID
int ptid = @ptnum;
float stagger = noise(@ptnum * ch("stagger_freq")) * ch("stagger_amount");
float local_blend = clamp(blend - stagger, 0, 1);
// Smooth the blend curve
local_blend = chramp("blend_curve", local_blend);
// Position morph
vector src_P = v@source_pos;
vector tgt_P = v@target_pos;
// Optional: Add arc trajectory instead of straight line
vector mid_P = lerp(src_P, tgt_P, 0.5);
mid_P += curlnoise(@P * ch("curl_freq")) * ch("curl_amp") * sin(local_blend * M_PI);
@P = lerp(src_P, tgt_P, local_blend);
// With arc: @P = lerp(lerp(src_P, mid_P, local_blend), lerp(mid_P, tgt_P, local_blend), local_blend);
// Orientation morph
vector4 src_orient = p@source_orient;
vector4 tgt_orient = p@target_orient;
p@orient = slerp(src_orient, tgt_orient, local_blend);
// Scale pulse during flight
float scale_pulse = 1.0 + sin(local_blend * M_PI) * ch("scale_bulge");
f@pscale *= scale_pulse;
2. POINT MATCHING STRATEGIES (Critical for Quality)¶
Strategy A: Nearest Point (Simplest)¶
// Point Wrangle on source points, input 1 = target points
int target_pt = nearpoint(1, @P);
v@target_pos = point(1, "P", target_pt);
p@target_orient = point(1, "orient", target_pt);
Strategy B: Nearest Point with Exclusion (Better Distribution)¶
// Use nearpoints() to find multiple candidates, then use unique assignment
int targets[] = nearpoints(1, @P, ch("maxdist"), chi("maxpts"));
// Filter out already-assigned targets (requires tracking via attribute or array)
Strategy C: Sort-Based Matching¶
// Sort both source and target points by spatial position (e.g., by distance from centroid)
// Then match by index (ptnum)
// Use Attribute Sort SOP (new in Houdini 21!) or Sort SOP
Strategy D: xyzdist Surface Matching¶
// For each source point, find closest surface location on target
int target_prim;
vector target_uv;
float dist = xyzdist(1, @P, target_prim, target_uv);
v@target_pos = primuv(1, "P", target_prim, target_uv);
Strategy E: VDB/Volume-Based Transfer¶
- Convert both meshes to SDF volumes (VDB from Polygons)
- Scatter points on the target SDF surface using VDB analysis
- Match using closest point in volume space
- Best for very different topologies
3. KEY Houdini 21 NODES FOR THIS WORKFLOW¶
Scatter SOP (v2.0)¶
- Scatters points across surfaces or through volumes
- Critical feature: "Stick on deforming geometry" workflow using Attribute Interpolate
- Scatter once on rest geometry → Attribute Interpolate deforms points with animated mesh
- Output
Prim Num AttributeandPrim UVW Attributefor tracking - Density can be controlled by attributes or texture maps
- "In Texture Space" mode for consistent scattering across different meshes with same UVs
Copy to Points SOP (v2.0)¶
- Copies geometry onto points with full instance attribute support
- Piece Attribute: Copy different source geometry to different points
- Supports
orient,pscale,scale,N,up,v,rot,trans,pivot,transformattributes - For large counts: use packed primitives or render-time instancing
Attribute Interpolate SOP¶
- Interpolates attributes between geometries using:
- Primitive number + UVW weights
- Point numbers + weights (array attributes)
- Vertex numbers + weights
- Key for scatter-to-deform workflows: Keep scattered points consistent on deforming geometry
- Can compute weights from primitive UVW for reuse
Blend Shapes SOP (v2.0)¶
- Computes 3D metamorphosis between shapes WITH THE SAME TOPOLOGY
- Supports painted masks and per-blend mask options
- Limitation: Requires matching topology — NOT suitable for different mesh shapes
- Only useful if source and target have identical point/prim counts
Ray SOP¶
- Projects points from one surface onto another
- Houdini 21 addition: Bidirectional option (closest or farthest hit)
- Methods: Ray projection along normals OR Minimum Distance (shrinkwrap)
- Useful for initial target point placement
New Houdini 21 SOPs with Mask Support¶
- Peak SOP, Soft Peak SOP, Inflate SOP, Flatten SOP, Point Jitter SOP — all now have mask parameters
- Point Jitter with mask = great for adding organic variation to coin positions
Separate Pieces SOP (New in H21)¶
- Offsets individual pieces of geometry by unique attribute
- Useful for exploding/separating coins before reforming
4. APEX CAPABILITIES IN HOUDINI 21 FOR THIS WORKFLOW¶
APEX Overview¶
APEX is Houdini 21's rigging and character animation graph framework, deeply integrated with KineFX. It is designed for: - Building character rigs procedurally - Managing transform hierarchies (skeletons, controls) - Channel/animation manipulation - Procedural rigging via Autorig Builder/Components
APEX Nodes Available¶
Key APEX nodes include: - RunVex: Executes custom VEX snippets within APEX graphs — this is the bridge for custom geometry manipulation - TransformObject: Manages transform hierarchies, animation-friendly TRS inputs, constraints - Lerp/NLerp/Slerp: Built-in interpolation nodes (position/orientation blending) - Noise: Perlin-style noise for procedural variation - Math nodes: Add, Subtract, Multiply, Clamp, Fit, etc. - For/ForEach loops: Iteration within APEX graphs - If/Else: Conditional logic - RampLookup: Ramp evaluation for blend curves - Switch/SwitchByName: Conditional value selection
Can APEX Be Used for This Workflow?¶
Short answer: Not recommended as the primary approach.
Reasoning: 1. APEX is designed for character rig transforms, not point-cloud-level operations. APEX TransformObject manages a hierarchy of transforms (like skeleton joints), not thousands of scattered particle positions.
-
APEX operates on a different abstraction level: It works with named transform objects (controls, joints) in a hierarchy, not with arbitrary point clouds. You would need one TransformObject per coin, which is impractical for thousands of instances.
-
The RunVex node CAN execute custom VEX within an APEX graph, so technically you could implement point morphing logic there. But this essentially bypasses APEX's purpose — you'd just be writing VEX inside an APEX wrapper.
-
No native point cloud or scatter operations exist in APEX. There are no equivalents of
nearpoint(),xyzdist(),pcfind(), or Scatter SOP functionality. -
Where APEX could be useful: If you want to rig a single coin with articulation (bending, tumbling), or if you want to drive a small number of "hero" coins with rig-like controls, APEX could add value for those specific elements.
Recommendation: Use SOPs + VEX wrangles for the main coin morphing effect. APEX is the wrong tool for this specific job. Reserve APEX for character rigging tasks it was designed for.
5. BEST PRACTICES FOR POINT-BASED MORPHING¶
Point Count Management¶
- Always match point counts between source and target scatter distributions
- Use Scatter SOP's "Force Total Count" to ensure identical counts
- Alternative: Scatter extra points, then use Point Generate SOP or Wrangle to add/remove to match
Staggered/Timed Transitions (Avoids "Boring" Uniform Morph)¶
// Per-point delay based on spatial position
float delay = fit(length(v@source_pos - getbbox_center(0)), ch("min_dist"), ch("max_dist"), 0, ch("max_delay"));
float local_time = max(0, @Time - delay);
float blend = chramp("transition", fit(local_time, 0, ch("duration"), 0, 1));
rand(@ptnum)
Orientation Handling¶
- Always use
orient(quaternion) attribute — NOT N/up vectors for animated instances slerp()for quaternion interpolation preserves shortest path- For tumbling coins: add incremental rotation during flight:
Arc Trajectories (Coins Should Fly, Not Slide)¶
- Simple arc: Use quadratic bezier between source → apex → target
- More complex: Use curl noise or custom curve paths
- Alternative: Use POP VOP/POP Wrangle in a DOP network for physics-based flight
Scale and "Pop" Effects¶
- Coins can scale down to 0 at departure, fly as small, scale up at arrival
- Or pulse scale during flight for energy feel
pscaleattribute drives this per-point
Performance Tips¶
- Render-time instancing for >10K coins (create packed primitives, not real geometry)
- Use
instancefileorinstanceattribute for disk-based instances - If real geometry needed (for collisions/sim): limit coin count or use LOD
- VEX Wrangles are significantly faster than VOPs for this kind of per-point logic
- Cache the scatter points to disk if geometry is static
6. COMPLETE RECOMMENDED NODE FLOW¶
[Source Mesh] → Scatter SOP → [Source Points]
↓
[Target Mesh] → Scatter SOP → [Target Points]
↓
Point Wrangle (match + store target_pos/target_orient)
↓
Point Wrangle (animated morph with lerp/slerp + stagger)
↓
[Coin Geometry] ────────→ Copy to Points SOP → [Output]
↑
(or Instance SOP for render-time)
Alternative with POP Solvers for Physics¶
[Source Mesh] → Scatter SOP → [Source Points]
[Target Mesh] → Scatter SOP → [Target Points]
↓
Attribute Create (v = target_pos - source_pos)
↓
POP VOP / POP Wrangle in DOP Network
(use v@v as attraction force toward target)
↓
Copy to Points / Instance
Alternative with Vellum for Coin Physics¶
Same scatter setup → Vellum Grains (with target attraction)
→ Pin to Target with stiffness
→ Add wind/turbulence for flight path variation
7. KEY VEX FUNCTIONS REFERENCE¶
| Function | Purpose | Usage |
|---|---|---|
lerp(a, b, t) |
Linear interpolation of positions/vectors | P = lerp(src, tgt, blend) |
slerp(q1, q2, t) |
Spherical interpolation of quaternions/matrices | orient = slerp(src_q, tgt_q, blend) |
nearpoint(geo, pos) |
Find closest point index | Point matching |
nearpoints(geo, pos, rad, max) |
Find N closest points | Better point matching |
pcfind(geo, channel, pos, rad, max) |
Find close points in radius | Proximity queries |
xyzdist(geo, pos, prim, uv) |
Closest surface location + prim/UV | Surface matching |
primuv(geo, attr, prim, uvw) |
Sample attribute at parametric UV | Attribute transfer |
dihedral(v1, v2) |
Quaternion rotating v1 to v2 | Orientation alignment |
qrotate(angle, axis) |
Quaternion from axis-angle | Coin tumbling |
qmultiply(q1, q2) |
Quaternion multiplication | Combine rotations |
pointtransform(geo, ptnum) |
Get instance transform matrix from point attributes | Read instance transforms |
curlnoise(pos) |
Curl noise for organic displacement | Flight path variation |
rand(seed) |
Random number generation | Per-point variation |
fit(val, src_min, src_max, dst_min, dst_max) |
Remap values | Timing/spatial remapping |
8. INSTANCING POINT ATTRIBUTES (Complete Reference)¶
These attributes on points control Copy to Points / instance behavior:
| Attribute | Type | Description |
|---|---|---|
orient |
float4 (quaternion) | Orientation of the copy |
pscale |
float | Uniform scale |
scale |
float3 | Non-uniform scale |
N |
vector | Normal (+Z axis if no orient) |
up |
vector | Up vector (+Y axis if no orient) |
v |
vector | Velocity (motion blur, +Z if no orient/N) |
rot |
float4 (quaternion) | Additional rotation after orient |
P |
vector | Translation of the copy |
trans |
vector | Additional translation |
pivot |
vector | Local pivot point |
transform |
3×3 or 4×4 matrix | Override transform (except P/pivot/trans) |
Priority order: If transform exists, it overrides orient/scale/rot. If orient exists, it overrides N/up alignment. If neither, N and up define orientation.
SOURCES¶
- SideFX Houdini 21.0 Official Documentation (sidefx.com/docs/houdini21.0/)
- Scatter SOP 2.0 docs (sidefx.com/docs/houdini/nodes/sop/scatter.html)
- Copy to Points SOP 2.0 docs (sidefx.com/docs/houdini/nodes/sop/copytoanchors.html)
- Attribute Interpolate SOP docs
- Blend Shapes SOP 2.0 docs
- Ray SOP docs (with new H21 bidirectional feature)
- APEX nodes index (sidefx.com/docs/houdini/nodes/apex/index.html)
- RunVex APEX node docs
- TransformObject APEX node docs
- Copying and Instancing point attributes docs
- VEX functions: lerp, slerp, nearpoint, xyzdist, primuv, pcfind, pointtransform
- Houdini 21 What's New - Modeling, Geometry, and Terrains
- Houdini 21 What's New - APEX, KineFX, and Animation
- Houdini 21 What's New - VEX and OpenCL