Are you wrestling with erratic particle paths or jittery simulations in Houdini when all you need is smooth control over Point Velocity? Do you find yourself hunting through shelf tools and SOP nodes without quite understanding how motion attributes work behind the scenes?
It’s easy to get frustrated when adjusting forces or tweaking velocity values yields unexpected results. You tweak one setting and everything goes haywire, or worse, nothing changes at all. Without a firm grasp of the underlying code, you’re left guessing.
In this guide, we’ll demystify the VEX approach to manipulating velocity at the point level. You’ll learn what the point velocity attribute really represents, how VEX reads and writes that data, and why it behaves the way it does in procedural contexts.
Along the way, you’ll see concise examples that show how to initialize, modify, and blend motion data directly in an Attribute Wrangle. We’ll explain key functions, common pitfalls, and best practices for clean, efficient code.
By the end, you’ll understand how to diagnose jitter, set up per-point forces, and optimize your Houdini scenes for robust, predictable motion. No more guesswork—just precise control over every vector in your simulation.
What exactly is point velocity in Houdini and how does VEX represent its data and coordinate spaces?
In Houdini, point velocity is a per-point vector attribute that defines motion direction and speed over time. It’s commonly named “v” or “vel” and stored as a three-component float vector. During SOP operations, velocity guides procedural deformations and particle advection. Inside DOP simulations, it drives rigid bodies, fluids, and smoke. VEX code reads and writes this attribute to control dynamic behaviors.
VEX exposes velocity as a native vector type. In an Attribute Wrangle you reference it with v@v or f@vel depending on naming. Access functions like getpointattrib() or @v allow you to sample and modify velocity at runtime. Since VEX is stateless per point, changes to @v persist through the cook, enabling chained effects like turbulence or drag. Data precision is float32 by default, ensuring both performance and accuracy.
Velocity vectors exist in specific coordinate spaces. Understanding these spaces is crucial when transforming or combining velocities:
- Local: Point coordinates relative to the SOP’s own origin. Default for most wrangles.
- Object: After object-level transforms (translate/rotate/scale) but before world transforms.
- World: Fully transformed by all parent nodes. Required when syncing with DOP nets or external engines.
To convert between spaces in VEX, apply matrix transforms: multiply by optransform(opinputpath(“.”, 0)) for local→object, or use invert() on an “.world” transform. For rigid simulations you might fetch the primitive transform with primintrinsic(0, “transform”, primnum) and apply qtransform() to align velocities under rotating frames.
By mastering how VEX represents and manipulates point velocity across these coordinate spaces, you gain precise control over motion — from nuanced particle swirls to large-scale smoke advection — all within Houdini’s procedural context.
How do I read, write and initialize point velocity attributes safely in VEX for SOP and DOP contexts?
VEX snippets: reading, writing and initializing @v in SOP wrangles (examples and edge cases)
In SOP wrangles, velocity is stored in the vector attribute v. To read it reliably, use getpointattrib(0, “v”, @ptnum, 0). If a point has no v, this returns {0,0,0}. To overwrite or initialize, use setpointattrib(0, “v”, @ptnum, newvel, “set”).
- Read: vector oldv = getpointattrib(0, “v”, @ptnum, 0);
- Initialize if empty: if(length(oldv)==0) oldv = set(0,1,0);
- Write: setpointattrib(0, “v”, @ptnum, oldv + accel * @TimeInc, “set”);
Edge case: when creating points via addpoint(), always call setpointattrib() immediately. Otherwise, accessing @v later yields zero without warning. Use addvariablename in the Wrangle to declare v explicitly and avoid silent fails.
Handling packed primitives, DOP-packed velocities and intrinsic velocity attributes
Packed primitives carry velocity in an intrinsic, typically “vel” or “v” inside the gameplan. To access packed velocities in SOPs, use pcfind to get points, then pointvelocity(0, @P, “set”, vel). For DOPs, use dopfield, e.g.:
- vector dvel = dopfield(“DOP_network”, “mysolver”, “vel”, @ptnum);
- setpointattrib(0, “v”, @ptnum, dvel, “set”);
For primintrinsic() on packed geometry:
- vector iv = primintrinsic(0, “velocity”, @primnum);
- primintrinsic(0, “velocity”, @primnum, iv + delta);
This approach ensures you never override solver-generated data blindly. Always query the correct context—SOP vs DOP—and use intrinsic calls for packed primitives to preserve transform hierarchies and avoid lost motion data.
How should I integrate and update point velocity per timestep to produce stable, physically plausible motion?
In procedural dynamics, integrating velocity each timestep ensures that motion responds naturally to forces. A robust method is the semi-implicit Euler integrator, which first updates velocity from acceleration and then applies that velocity to position. This order reduces energy gain and prevents numerical instability common in explicit schemes.
Within a Point Wrangle or SOP Solver, compute acceleration (a) by summing forces divided by mass. Multiply by the frame’s deltaTime (often accessed via @TimeStep) to advance velocity: vel += a * deltaTime. Next, move the point: pos += vel * deltaTime. This two-step update keeps velocity and position coherent, minimizing drift.
To avoid runaway speeds and jitter, introduce damping and clamping. Apply a damping factor (velocity *= 1 – damping * deltaTime) to simulate friction or air resistance. Optionally, enforce a maximum speed threshold: vel = clamp(vel, -maxSpeed, maxSpeed). These controls suppress high-frequency noise and maintain stability over long animations.
- Use small timesteps or enable substepping in SOP Solver settings for tight collision or fast-moving particles.
- Store and reuse previous velocity via attributes (e.g., v@oldv) when blending between solvers or custom constraints.
- Group forces logically—gravity, drag, custom attractors—so you can adjust each source without rewriting integration logic.
In practice, wrap this logic in a SOP Solver loop or POP wrangle node. Inside a SOP Solver, ensure you enable “Reset Simulation” off and reference the accumulating velocity attribute. This approach guarantees each frame builds on the last, yielding a stable, physically plausible result without relying on built-in POP forces.
How can I manipulate motion in VEX: adding forces, impulses, noise and constraints without breaking simulation coherence?
Maintaining simulation coherence means updating point velocity consistently across frames and respecting integration steps. In a SOP Solver or DOP Wrangle, read the timestep (f@TimeInc or f@dt) and use attributes like @v, @mass or custom density to scale effects uniformly. This prevents sudden jumps or energy leaks.
To add forces and use impulses, accumulate acceleration directly on @v: for a constant force, write @v += forceVector*f@dt/@mass. For instantaneous impulses, detect an event (trigger attribute or proximity) then @v += impulseVector; reset the trigger flag to avoid repetition. Always apply in a Solver context so time integration remains stable.
- Run VEX in a SOP Solver or POP Wrangle to access time step and geometry history.
- Store per-point impulse flags or magnitudes as attributes to control one-shot effects.
- Low-pass filter added velocities (lerp towards @v) to smooth abrupt changes.
- Use pcopen/pciterate to enforce neighborhood-based corrections or cohesion forces.
Introducing procedural noise enriches organic motion but can break momentum if over-scaled. Generate a curl noise field (curlNoise(@P*freq + time*speed)) and blend: @v = lerp(@v, @v + noiseAmp*noiseVec, noiseBlend). Adjust frequency, amplitude and blend in real time to avoid high-frequency jitter.
Constraints lock points or preserve distances without halting simulation. In SOP Solvers, use vellum constraints or write custom springs by sampling neighbor positions (pcopen) and applying a corrective force: dir = @P – target; @v += -stiffness * dir * f@dt. Bake constraint targets into attributes and tweak stiffness/damping to keep coherence.
How do I transfer, blend and retarget velocities between particles, meshes and packed geometry using VEX?
First, to transfer velocity from a mesh or packed primitive onto particles, use an Attribute Wrangle with point cloud lookups. For example, open a pc handle on the source geometry (input 1) via pcopen(1, “P”, @P, radius, 1), filter the velocity attribute via pcfilter(handle, “v”), then assign @v to the particle. This handles arbitrary point clouds or mesh vertices.
For mesh surfaces, use xyzdist() and primuv() to find the closest primitive and compute barycentric coordinates. Example: int prim; float u, v; xyzdist(1, @P, prim, u, v); vector vel = primuv(1, “v”, prim, set(u, v, 0)); assigns the interpolated surface velocity. This avoids radius-based lookups and ensures exact surface projection.
When blending between multiple velocity fields—particles carrying wind and animated mesh deformation—apply VEX interpolation functions like lerp() with per-point weights or smoothstep ramps based on age or proximity. Example: @v = lerp(@v, sampled_vel, smoothstep(0,1,@age/age_max)); achieves seamless transitions controlled by procedural attributes.
Retargeting velocities onto packed geometry requires transforming the sampled velocity into the packed prim’s local space. Retrieve the intrinsic transform via primintrinsic(1, “transform”, @primnum), compute its inverse with invert(), and apply cracktransform(). After sampling in world space, run cracktransform(inv_xform, sampled_vel) to align motion in object space, then apply the forward transform to move back to world space under the packed prim’s animation.
- pcopen + pcfilter: transfer velocities via point clouds
- xyzdist + primuv: precise mesh surface sampling
- lerp, smoothstep: weighted blending
- primintrinsic, cracktransform: retargeting for packed primitives
What practical debugging, visualization techniques and performance optimizations should advanced artists use when working with point velocity in VEX?
When troubleshooting point velocity in VEX, start by outputting values to the Geometry Spreadsheet or using printf inside a Point Wrangle. Printing velocity vectors per frame helps catch sign errors or unexpected zeroes. For real-time inspection, enable the Attribute Visualizer on the velocity attribute (v@v) to overlay arrows directly in the viewport.
To see motion trails and confirm integration over time, connect a Trail SOP after your simulation. Set it to “All Points” and view the path each point follows. You can also color-code velocities via a Color SOP driven by an expression like fit(length(v@v), 0, maxVel, 0, 1) to instantly highlight slow or overly fast particles.
- Attribute Visualizer: arrows scaled by speed
- Trail SOP: path length and direction checks
- Geometry Spreadsheet: batch inspect v@v components
Performance hinges on minimizing attribute lookups and branching in VEX. Access v@v directly rather than using point() calls. When iterating over neighbors, use pcopen/pciterate with setprimgroup or hash-based proximity rather than looping through all points. Encapsulate heavy operations in compile blocks to allow the compiler to optimize constant expressions.
Leverage multithreading by staying within a single Wrangle or using SOP Solver for time-dependent logic. Avoid nested Wrangles on the same geometry each frame, and prefer in-place updates (modify @v instead of creating a new attribute). This reduces disk thrashing when cooking large point sets and ensures Houdini’s scheduler can distribute work across cores efficiently.