Houdini Fun

2025-12-07 0 405

CGWiki DLC

Various Houdini tips and tricks I use a bunch. Hope someone finds this helpful!

Rabbit Hole

These articles grew too long to fit here. They\’re the most interesting in my opinion, so be sure to check them out!

  • Vertex Block Descent in Houdini
  • 3D Signed Distance Functions
  • Lerp and Fit
  • Waveforms
  • Easings
  • Normalized Device Coordinates
  • 4D Geometry
  • Time Smoothing (WIP, interactive!)
  • Vexember 2023 (WIP)
  • Sound Effects (WIP)

HDA: Fast Straight Skeleton 3D

They added a new Laplacian node to Houdini 20.5. You can do cool frequency-based tricks with it.

One example is calculating a straight skeleton. You can do this with a Laplacian node followed by a Linear Solver set to \”SymEigsShiftSolver\”. This gives you a bunch of Laplacian eigenvectors, which are like frequencies making up a mesh.

The second lowest frequency (or eigenvector) is called the Fiedler vector. It follows the general flow of the geometry, which is great for straight skeletons. Also it\’s orders of magnitude faster than Labs Straight Skeleton 3D!

Thanks to White Dog for letting me share this and suggesting improvements! It\’s based on his Curve Skeleton example.

Download the HDA! Download the HIP file!

HDA: Rigid Piece Preroll

Most preroll nodes use position difference only. This is fine for translation but not rotation.

Extract Transform can be used to estimate the rotation difference too. This gives preroll for both rotation and translation.

This HDA works on single and multiple pieces, either packed or unpacked. For packed pieces, it uses their intrinsic transforms.

Download the HDA! Download the HIP file!

Simple spring solver

Need to overshoot an animation or smooth it over time to reduce bumps? Introducing the simple spring solver!

Recursive Version

I stole this from an article on 2D wave simulation by Michael Hoffman. The idea is to set a target position and set the acceleration towards the target. This causes a natural overshoot when the object flies past the target, since the velocity takes time to flip. Next you apply damping to stop it going too crazy.

First add a target position to your geometry:

v@targetP = v@P;

Next add a solver. Inside the solver, add a point wrangle with this VEX:

float freq = 100.0;
float damping = 5.0;

// Dampen velocity to prevent infinite overshoot (done first to avoid distorting the acceleration)
v@v /= 1.0 + damping * f@TimeInc;

// Find direction towards target
vector dir = v@targetP - v@P;

// Accelerate towards it (@TimeInc to handle substeps)
v@accel = dir * freq;
v@v += v@accel * f@TimeInc;
v@P += v@v * f@TimeInc;

To adjust motion over time, plug the current geometry into the second input and use it instead of v@targetP:

// Find direction towards target
vector dir = v@opinput1_P - v@P;

UPDATE: The spring solver in MOPs uses Hooke\’s law.

This is more physically accurate, but I don\’t know how to make it substep independent.

float mass = 1.0;
float k = 0.4;
float damping = 0.9;

// Find direction towards target
vector dir = v@targetP - v@P;

// Accelerate towards it
vector force = k * dir;
v@v += force / mass;

// Dampen velocity to prevent infinite overshoot
v@v *= damping;
v@P += v@v * f@TimeInc;

Non-Recursive Version

An easy approximation is an oscillator with an exponential falloff. This is basically damped harmonic motion.

Note how it travels from 1 to 0. This makes it perfect to use as a mix factor, for example with lerp.

float spring(float time; float frequency; float damping) {
    return cos(frequency * time) * exp(-damping * time);
}

// Example usage, spring to targetP
v@P = lerp(v@targetP, v@P, spring(f@Time, 10.0, 5.0));

Overshoot occurs since cos ranges between -1 and 1. To fix this, remap cos between 0 and 1 instead.

float spring_less(float time; float frequency; float damping) {
    return (cos(frequency * time) * 0.5 + 0.5) * exp(-damping * time); // Or fit11(..., 0, 1)
}

// Example usage, spring to targetP
v@P = lerp(v@targetP, v@P, spring_less(f@Time, 10.0, 5.0));

Make an aimbot (find velocity to hit a target)

Want to prepare for the next war but can\’t solve projectile motion? Never fear, the Ballistic Path node is all you need.

Video Tutorial

Hit a static target

  1. Connect your projectile to a Ballistic Path node.
  2. Set the Launch Method to \”Targeted\” and disable drag.
  3. Add a @targetP attribute to your projectile. Set it to the centroid of the target object.
v@targetP = getbbox_center(1);
  1. You should see an arc. Transfer the velocity of the first point of the arc to your projectile.
v@v = point(1, \"v\", 0);
  1. Connect everything to a RBD Solver.

  2. Use \”Life\” to set the height of the path, and lower the \”FPS\” to reduce unneeded points.

Hit a moving target

Use the same method as before, but sample the target\’s position forwards in time.

  1. On the Ballistic Path node, set the Targeting Method to \”Life\”.
  2. Copy the \”Life\” attribute. It\’s the number of seconds until we hit the target. We need to find where the target is at that time.
  3. Add a Time Shift node to the target (before the centroid is calculated). Set it to the current time plus the \”Life\” attribute.
Download the HIP file!

Hit multiple targets

Extract multiple centroids and transfer v from each arc. Enable \”Path Point Index\” on Ballistic Path, blast non-zero indices, then Attribute Copy v.

If your \”Life\” changes per target, set a life attribute on each point.

Copernicus: Radial Blur

Simple radial blur shader I made for Balthazar on the CGWiki Discord.

#bind layer src? val=0
#bind layer !&dst

#bind parm quality int val=10
#bind parm center float2 val=0
#bind parm scale float val=0.2
#bind parm rotation float val=0

@KERNEL
{
    float2 offset = @P - @center;
    float4 result = 0.;
    float scale = 1;
    
    for (int i = 0; i <= @quality; ++i) {
        result += @src.imageSample(offset * scale + @center) / (@quality + 1);
        offset = rotate2D(offset, @rotation / @quality);
        scale -= @scale / @quality;
    }
    
    @dst.set(result);
}
Download the HIP file!

Copernicus to Heightfield

Copernicus stores images in 2D volumes. Guess what else is stored in 2D volumes? Heightfields!

Video Tutorial

Complex Growth in 2 nodes

You can get cool and organic looking shapes using opposing forces, like Relax and Attribute Blur.

Download the HIP file! Video Tutorial

Smooth steps

Smoothstep\’s evil uncle, smooth steps. This helps for staggering animations, like points moving along lines.

Start with regular steps. This is the integer component:

Use modulo to form a line per step, then clamp it below 1. This is the fractional component:

Add them together to achieve smooth steps:

float x = f@Time; // Replace with whatever you want to step
float width = 2; // Size of each step
float steepness = 1; // Gradient of each step

int int_step = floor(x / width); // Integer component, steps
float frac_step = min(1, x % width * steepness); // Fractional component, lines
float smooth_steps = int_step + frac_step; // Both combined, smooth steps

Remove points by time after simulation

Sometimes POP sims take ages to run, especially FLIP sims. This makes it annoying to get notes about timing changes.

I found a decent approach to avoid resimulation:

  1. Simulate tons of points, way more than you need.
  2. After simulating, get the birth time of each point using f@Time - f@age.
  3. Cull points based on the birth time. There\’s 2 main ways to do it.

Keyframes over time

chf() lets you fetch values over time using chf(\"channel\", time). Use the birth time and you\’re good to go!

float birth_time = f@Time - f@age;
if (chf(\"keep_percent\", birth_time) < rand(i@id)) {
    removepoint(0, i@ptnum, 0);
}

Ramp over time

I used to remap time using a ramp instead. It\’s not as controllable as keyframes, but helps in some cases.

float birth_time = f@Time - f@age;
float time_factor = invlerp(birth_time, $TSTART, $TEND);
if (chramp(\"keep_percent\", time_factor) < rand(i@id)) {
    removepoint(0, i@ptnum, 0);
}
Original Sim Post-Sim Removal

I used this ramp for the demo above:

Download the HIP file!

Generating circles

Sometimes you need to generate circles without relying on built-in nodes, like to know the phase.

Luckily it\’s easy, just use sin() on one axis and cos() on the other:

float theta = chf(\"theta\");
float radius = chf(\"radius\");
v@P = set(cos(theta), 0, sin(theta)) * radius;

See Waveforms for more about sine and cosine.

To draw a circle, add points while moving between 0 and 2*PI:

int num_points = chi(\"point_count\");
float radius = chf(\"radius\");

for (int i = 0; i < num_points; ++i) {
    // Sin/cos range from 0 to 2*PI, so remap from 0-1 to 0-2*PI
    float theta = float(i) / num_points * 2 * PI;
    // Use sin and cos on either axis to form a circle
    vector pos = set(cos(theta), 0, sin(theta)) * radius;
    addpoint(0, pos);
}

To connect the points, you can use addprim():

int num_points = chi(\"point_count\");
float radius = chf(\"radius\");
int points[];

for (int i = 0; i < num_points; ++i) {
    // Sin/cos range from 0 to 2*PI, so remap from 0-1 to 0-2*PI
    float theta = float(i) / num_points * 2 * PI;
    // Use sin and cos on either axis to form a circle
    vector pos = set(cos(theta), 0, sin(theta)) * radius;
    // Add the point to the array for polyline
    int id = addpoint(0, pos);
    append(points, id);
}
// Connect all the points with a polygon
addprim(0, \"poly\", points);

Download the HIP file!

Extract Transform in VEX

Ever wondered how Extract Transform works? Turns out it uses a popular matrix solving technique called singular value decomposition.

Align Translation

Aligning the translation is easy. The best translation happens when you align the center of mass (average) of each point cloud.

You don\’t even need VEX for this, just use Extract Centroid set to \”Center of Mass\”, then offset the position by that amount.

// Detail Wrangle: Solves translation only
// Input 1: Source
// Input 2: Target

// 1. Calculate centroids
float n = npoints(1);
vector source_centroid = 0, target_centroid = 0;
for (int i = 0; i < n; ++i) {
    source_centroid += point(1, \"P\", i);
    target_centroid += point(2, \"P\", i);
}

// 2. Turn translation into 4x4 matrix
matrix transform = ident();
translate(transform, (target_centroid - source_centroid) / n);

// 3. Add point for Transform Pieces to use
setpointattrib(0, \"transform\", addpoint(0, {0, 0, 0}), transform);

Align Translation + Rotation

Aligning the rotation is harder. You need to build a covariance matrix, then solve it with SVD.

Luckily we don\’t need to leave VEX! Houdini has a SVD solver called svddecomp().

// Detail Wrangle: Solves translation and rotation only
// Input 1: Source
// Input 2: Target

// 1. Calculate centroids
float n = npoints(1);
vector source_centroid = 0, target_centroid = 0;
for (int i = 0; i < n; ++i) {
    source_centroid += point(1, \"P\", i);
    target_centroid += point(2, \"P\", i);
}
target_centroid /= n;
source_centroid /= n;

// 2. Build covariance matrix
matrix3 covariance = ident();
for (int i = 0; i < n; ++i) {
    vector source_diff = point(1, \"P\", i) - source_centroid;
    vector target_diff = point(2, \"P\", i) - target_centroid;
    covariance += outerproduct(target_diff, source_diff);
}

// 3. Solve rotation with SVD
matrix3 U;
vector S;
matrix3 V;
svddecomp(covariance, U, S, V);
matrix3 R = V * transpose(U);

// 4. Flip if determinant is negative (this causes negative scales to screw up)
if (determinant(R) < 0) {
    R = V * diag({1, 1, -1}) * transpose(U);
}

// 5. Combine translation and rotation into 4x4 matrix
matrix transform = set(R);
translate(transform, target_centroid - source_centroid);

// 6. Add point for Transform Pieces to use
setpointattrib(0, \"transform\", addpoint(0, {0, 0, 0}), transform);

Align Translation + Rotation + Scale

Aligning the scale is even harder. One popular way is the Umeyama algorithm.

Sadly it only solves uniform scale, and breaks on negative scales. This happens when you flip the sign of the 2nd column of the rotation matrix.

Extract Transform set to \”Uniform Scale\” also breaks with negative scales, so it probably uses this method!

// Detail Wrangle: Solves translation, rotation, uniform scale (like Eigen::umeyama)
// Input 1: Source
// Input 2: Target

// 1. Calculate centroids
float n = npoints(1);
vector source_centroid = 0, target_centroid = 0;
for (int i = 0; i < n; ++i) {
    source_centroid += point(1, \"P\", i);
    target_centroid += point(2, \"P\", i);
}
target_centroid /= n;
source_centroid /= n;

// 2. Build covariance matrix
float deviation = 0;
matrix3 covariance = ident();
for (int i = 0; i < n; ++i) {
    vector source_diff = point(1, \"P\", i) - source_centroid;
    vector target_diff = point(2, \"P\", i) - target_centroid;
    deviation += length2(source_diff);
    covariance += outerproduct(target_diff, source_diff);
}

// 3. Solve rotation with SVD
matrix3 U;
vector S;
matrix3 V;
svddecomp(covariance, U, S, V);
matrix3 R = V * transpose(U);

// 4. Flip if determinant is negative (this causes negative scales to screw up)
float det = determinant(R);
vector e = set(1, 1, det < 0 ? -1 : 1);
if (det < 0) {
    R = V * diag(e) * transpose(U);
}

// 5. Solve scale using standard deviation
R *= dot(S, e) / deviation;

// 6. Combine translation rotation and scale into 4x4 matrix
matrix transform = set(R);
translate(transform, target_centroid - (R * source_centroid));

// 7. Add point for Transform Pieces to use
setpointattrib(0, \"transform\", addpoint(0, {0, 0, 0}), transform);
Download the HIP file!

Attribute Interpolate / Primuv in VEX

Ever wondered how primuv works? It doesn\’t exist in OpenCL, so I had to remake it:

vector primuv_diy(int geo; string attr; int prim; vector</span

下载源码

通过命令行克隆项目:

git clone https://github.com/MysteryPancake/Houdini-Fun.git

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 开发教程 Houdini Fun https://www.zuozi.net/31479.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务