My life has improved with the wrangle SOP and VEX. I don't know why i did shy away from that the first years I used Houdini, probably because it can look a bit intimidating. As a matter of fact, it is often actually more straightforward as the SOP equivalents. It's especially useful inside a solver sop, too.
Global / external attributes:
@Frame //current frame
@Time //current time, second-wise
@ptnum //this point's id
@primnum //this prim's id
@numprim //total prim number
@numpt //total point number
@P //point position
@N //normal
Setting attributes
//will just create a float attribute.
@myattrib;
//vector attribute
v@vectValue = {1,1,1};
//float attribute
f@floatValue = 0.2;
//int attribute
i@intValue = 2;
Get user input
Believe it or not, Houdini will auto-create user input for you in a wrangle SOP:
//Create a float slider mapped to myfloat
f@myfloat = ch('float');
//Same with a vector
v@myvec = chv('vec');
//Int
i@myint = chi('int');
//Float ramp. Grab the value at the position ramppos.
float ramppos = 0.5;
f@otherfloat = chramp('ramp', ramppos);
Some snippets
Set point attribute by point id. Useful in loops.
setpointattrib(0, "attribute", @ptnum, val);
Refer to geometry in the second input
point(@OpInput2, "Cd", @ptnum);
Some examples
Randomize normal direction
v@N = normalize(@N + (ch('random_factor')* sample_direction_uniform(random(@P))));
Blur attribute
int pchandle = pcopen(0, 'P', @P, 1, chi('pts_to_average'));
@attrib = pcfilter(pchandle, 'attrib');
Iterate through prim's verts
for (int i=0; i < primvertexcount(0, @primnum) ; i++) {
vector myP = vertex(0, "P", i);
}
Poor man's uvlayout
Following an uvtexture's face option, you might want to 'fit' uvs proportionally into 0-1 space. You could use uvlayout but that might rotate or such and is very slow depending on your setup.
vector minP = {100000, 100000, 100000};
vector maxP = {-100000, -100000, -100000};
// iterate once, get extents
for (int i=0; i < primvertexcount(0, @primnum) ; i++) {
vector currentUV = vertex(0, "uv", @primnum, i);
minP.x = min(minP.x, currentUV.x);
maxP.x = max(maxP.x, currentUV.x);
minP.y = min(minP.y, currentUV.y);
maxP.y = max(maxP.y, currentUV.y);
}
// calculate sizes
float xSize = maxP.x - minP.x;
float ySize = maxP.y - minP.y;
float largestSize = max(ySize, xSize);
for (int i=0; i < primvertexcount(0, @primnum) ; i++) {
vector origUV = vertex(0, "uv", @primnum, i);
// transform to 0,0
vector correctedUV = set(origUV.x + (minP.x*-1), origUV.y + (minP.y*-1), 0);
// stretch / shrink to bounds
correctedUV.x *= 1/largestSize;
correctedUV.y *= 1/largestSize;
// set the thing
setvertexattrib(0, "uv", @primnum, i, correctedUV);
}
Packed prims: Add randomness
vector scale = {1,1,1};
scale = scale * rand(@P);
matrix3 m_trans = primintrinsic(0, "transform", @ptnum);
matrix scalem = maketransform(0, 0, {0,0,0}, {0,0,0}, scale, @P);
m_trans *= matrix3(scalem);
//overall randomness: 20 deg around Y
float roat_rand = radians(fit(rand(@P),0,1,-20,20));
rotate(m_trans, roat_rand, {0,1,0});
setprimintrinsic(0, "transform", @ptnum, m_trans);
Create points at primitive centers (primitive wrangle)
int pt = addpoint(0, @P);
removeprim(0, @primnum, 1);
setpointattrib(0, "N", pt, @N);
Rotate stuff:
@P = qrotate( quaternion( {0,90,0}, 0 ), @P );
See:
http://www.tokeru.com/cgwiki/?title=HoudiniVex
https://sites.google.com/site/fujitarium/Houdini/sop/wrangle
Some animations:
Infection-style wrangle:
if (@tagged == 0) {
float maxdist = ch('maxdist');
int maxpoints = 8;
int pts[] = nearpoints(0,@P, maxdist, maxpoints);
int pt ;
foreach (pt;pts) {
if (point(0,'tagged',pt)==1) {
@tagged=1;
v@Cd = {1,0,0};
//int prim = addprim(0,'polyline');
//addvertex(0,prim,@ptnum);
//addvertex(0,prim,pt);
@age = @Frame;
return;
}
}
}
else{
@P.y = @P.y-0.1;
}
Crashing trees:
Each point stores a direction to the next untagged point, then vectors are interpolated
v@N2;
f@lifetime;
v@dir;
if (@tagged == 0) {
@N2 = @N;
float maxdist = ch('maxdist');
int maxpoints = 3;
int pts[] = nearpoints(0, @P, maxdist, maxpoints);
int pt ;
foreach (pt;pts) {
if (point(0,'tagged', pt)==1) {
@tagged=1;
@dir = @P - point(0, 'P', pt);
@dir.y -= 0.0001;
return;
}
}
}
else{
@lifetime += 0.006;
@lifetime = clamp(@lifetime, 0, 1);
float anim_scale = chramp('anim', @lifetime);
@N = lerp(@N2, @dir, anim_scale);
}
random links:
http://pepefx.blogspot.de/2015/06/h14-point-wrangle-vs-creep-sop.html
https://sites.google.com/site/fujitarium/Houdini/sop/wrangle
http://www.tokeru.com/cgwiki/?title=HoudiniVex