I typically bundle these snippets as presets in a wrangle node as I get to use most of these functions from day to day. This generally gives me a good head start for similar wrangle tasks and also aids my efficiency.
#SPIRAL FROM LINE
//SPIRAL FROM LINE
//CIRCLE OF REFERENCE AND LINE MUST LIE IN THE SAME PLANE
//(ZX) PLANE IS SUGGESTED
//RADIUS OF CIRCLE SHOULD IDEALLY BE THE SAME AS LENGTH OF LINE
//Use uvtexture node to compute uv attrib on points
//Texture type is set to Row & Columns
//Get velocity vector along line
int total = npoints(0)-1; //last point
int after = total-1;//penultimate point
int ntm = @ptnum+1;
vector npos = point(0,"P",ntm);
v@v = @P-npos;
//get vel of last point
if(@ptnum==total){
v@v = point(0,"P",after)-point(0,"P",total);
}
v@v = normalize(v@v);
v@up = chv("up"); //set to {0,1,0} if on ZX plane, must be perpendicular to plane
v@side = cross(v@v,v@up);
//Matrices
matrix3 xform = ident();
float freq = chf("frequency");//controls number of spirals
float angle = @uv.x * freq;
vector axis = v@up;
rotate(xform,angle,axis);
@P*=xform;
#LIMIT THE VELOCITY OF CROWD AGENTS
//Modifying the 'v_agent' array vector attribute //Use inside a SOP Solver vector myvel[] = v[]@v_agent; float mult = chf("mult"); foreach(int i; vector k; myvel) { if(length(k)!=0.0) { if(length(k)>chf("max_speed")) continue; else myvel[i] = myvel[i] * mult; } } v[]@v_agent = myvel;
#FLOW VECTOR ALONG GEO (CROSS PRODUCT)
vector up = set(0,1,0);
vector side = normalize(v@N);
vector flew = cross(side,up);
vector flow = cross(side,flew);
v@side = flow; //visualize flow vector
#FLOW VECTOR ALONG GEO
i[]@nbrs = neighbours(geoself(),@ptnum); f[]@dot; v[]@dir; vector down = chv("down"); //resize(@dot,3); //resize(@nbrs,3); //resize(@dir,3); int nlen = len(@nbrs); //Calculate direction vector for(int i=0; i<nlen;i++) { @dir[i] = point(0,"P",@nbrs[i]) - point(0,"P",@ptnum); } //Get dot product for(int i=0; i<nlen;i++) { @dot[i] = dot( normalize(@dir[i]) , normalize(down)); } //Get maximum value of dot product i[]@argdot = argsort(@dot); //Index of sorted array in increasing order //Get direction using lowest index //Loop though argdot // if value of argdot is 0, get value of dir foreach(int c;int d;@argdot) { if(@argdot[c] == 0) v@flow = @dir[c]; } v@v = v@flow; //Flip vector if facing up float dd = dot(normalize(v@v),set(0,1,0)); if(dd>chf("dot_threshold"))v@v*=-1; //-0.1
#ATTRIBUTE TRANSFER COLOR FROM SECOND INPUT
int handle = pcopen(@OpInput2, "P", @P, chf("rad"), chi("num")); vector lookup_P = pcfilter(handle, "P"); //Average P from second input vector lookup_Cd = pcfilter(handle, "Cd"); //Average Cd from second input i@many = pcnumfound(handle); if(i@many>0){ @Cd = lookup_Cd; v@P = lerp(v@P, lookup_P, chf("mix")); }
#CALCULATE VOLUME BASED ON BOUNDING BOX
//calculate_volume_based_on_bbox vector two = point(0,"P",2); vector one = point(0,"P",1); vector three = point(0,"P",3); vector six = point(0,"P",6); float l = length(two-one); float b = length(two-three); float h = length(two-six); f@vol = l * b * h * chf("scale"); // scale if values are too small f@vol = abs(f@vol);
#REST POSITION FROM (ARRAY) NAME ATTRIBUTE
Often times when making RBD simulations, we receive notes to prune some pieces. This code makes isolating the pieces to be pruned to be easily selected in the viewport.
You don’t need to select all the polygons in the primitives to be pruned. A single polygon face for each piece(primitive) to be pruned is sufficient for as long as the polygon contains a valid name attribute. This code iterates through every isolated packed primitive (Input2) and adds their corresponding name attribute to an array stored on a single point at origin(Input1).
//Set rest position from array //This two part code uses two attrib wrangle nodes //It generates an array that contains the name attribs //of selected pieces and stores this array attrib on a single point //steps: isolate points to not deform //attrib promote name to prim //pack and transfer name attrib to packed pts //Input 1 is a single pt to store array of blasted geo on //Input two is the packed pts i[]@pts = pcfind(1, "P", @P, chf("rad"), chi("num")); string nnme[]; s[]@nme= nnme; string tok; foreach(int a;@pts){ tok = prim(1,"name",a); push(@nme,tok); } //The following code goes into another attrib wrangle node //That sets the rest position in name attrib is in our array //Input 1 is our complete sim //Input 2 is the single pt that contains array attrib string names[] = point(1,"nme",0); foreach(string nme; names){ if(s@name==nme)@P = v@rest; }
#ISOLATE MULTIPLE PRIMS
i[]@prims = {0,1,2}; //primitives to keep foreach(int i;@prims){ if(i==@primnum)@group_del=1; }
#PRUNE BY STRING MATCH
string aa[] = split(chs("str")); foreach(string i;aa) { string word = "*" + i + "*"; if(match(word,s@AssemblyPath))removepoint(geoself(),@ptnum); }
#AVERAGING STUFF
vector accum_p = set(0,0,0); vector pos; int count=0; vector avg_p; float vlen = length(v@v); int handle = pcopen(@OpInput1, "P", @P, chf("rad"), chi("num")); while(pciterate(handle)){ pcimport(handle,"P",pos); accum_p+=pos; count+=1; }; avg_p = accum_p/count; v@P = lerp(v@P,avg_p,chf("mix"));
#CULL BASED ON RAY DIRECTION
int handle = pcopen(@OpInput1, "P", @P, chf("rad"), chi("num")); vector up = {0,1,0}; vector dir,pos; float angle; i@many = pcnumfound(handle); while(pciterate(handle)){ if(i@many>1){ pcimport(handle,"P",pos); dir = pos - @P; angle = dot(normalize(dir),up); if(angle>chf("mix"))removepoint(geoself(),@ptnum); }; }; pcclose(handle);
#REFLECT DOWN FACING VEL ATTRIBUTE ABOUT AN AXIS
vector ref = set(chf("refx"),chf("refy"),chf("refz")); float dot = dot(normalize(v@v),ref); vector axis = set(0,1,0); if(dot<chf("thres"))v@v = reflect(v@v,axis);
#ASSIGN ROTATION MATRIX COMPONENTS TO ATTRIBUTES
assign(v@N.x, v@N.y, v@N.z, v@up.x, v@up.y, v@up.z, v@side.x, v@side.y, v@side.z,3@xform); //Get Rotation Matrix components
#EXTRACT MATRIX COMPONENTS FROM PACKED POINT
v@up=set(0,1,0); v@v=normalize(v@v); v@side = cross(v@up,v@v); 3@xform = set(v@v.x, v@v.y, v@v.z, v@up.x, v@up.y, v@up.z, v@side.x, v@side.y, v@side.z); //3D Rotation Matrix 4@from = set(1 , v@v.x, v@v.y, v@v.z, v@up.x, 1 , v@up.y, v@up.z, v@side.x, v@side.y, 1 , v@side.z,v@P.x, v@P.y, v@P.z, 1 ); //3D Transformation matrix
#GET CENTROID
float cex, cey, cez; vector min, max; getbbox(0, min, max); cex = (max.x + min.x) * 0.5; cey = (max.y + min.y) * 0.5; cez = (max.z + min.z) * 0.5; vector centroid = set(cex, cey, cez);
#APPLY SOME NOISE TO THE POSITION ATTRIBUTE
int turb = chi("turb"); float rough = chf("rough"); float atten = chf("atten"); vector mynoise = anoise(@P, turb, rough, atten); v@P+=mynoise;
#BLACK AND WHITE MASK AFTER PAINTING WITH THE PAINT SOP
if(@Cd.y<1)@Cd = set(1,1,1); else (@Cd = set(0,0,0));
#GENERAL POINT CLOUD OPEN FUNCTION
int handle = pcopen(@OpInput2, "P", @P, chf("rad"), chi("num")); vector lookup_P = pcfilter(handle, "P"); i@many = pcnumfound(handle);
#QUATERNION ROTATE
v@N = set(0,1,0); matrix3 xform = ident(); float amt = chf("amt"); vector axis = set(chf("axisx"),chf("axisy"),chf("axisz")); rotate(xform, amt, axis); p@roti = normalize(quaternion(xform)); v@up= qrotate(p@roti,v@N); v@N*=xform;
#A RANDOM ROTATION MATRIX
matrix3 myrot = ident(); float amt = fit(rand(@id+chf("seed")),0,1,chf("minamt"),chf("maxamt")); vector axis = sample_direction_uniform(rand(@id)); rotate(myrot, amt, axis); @P*=myrot;
#REDUCE POINTS
if(rand(@id)<ch("kill")) removepoint(geoself(), @ptnum);
#SHRINK WRAP
int handle = pcopen(@OpInput2, "P", @P, chf("rad"), chi("num")); vector lookup_P = pcfilter(handle, "P"); i@many = pcnumfound(handle); if(i@many>=1)v@N = @P-lookup_P; else v@N = set(0,0,0); @P-=v@N;
#GENERAL THRESHOLD OPERATION
if(@Cd.x<chf("thres"))removepoint(geoself(),@ptnum);
#TIGHTEN POINTS
int handle = pcopen(@OpInput1, "P", @P, chf("rad"), chi("num")); vector lookUp_P = pcfilter(handle, "P"); v@P = lerp(v@P,lookUp_P,chf("mix"));
#BLEND GEO BETWEEN SUBFRAMES
v@N = v@N; //set normals vector pp = point(@OpInput2,"P",@ptnum); float dp = dot(normalize(v@v),normalize(v@N)); float mix = fit(dp,chf("mindot"), chf("maxdot"), chf("min"), chf("max")); @P = lerp(@P,pp,mix);
#CULL BY VOLUME (chi(“inv”)) is a check box.
float vsample = volumesample(1,0,@P); if(chi("inv")==1){ if(vsample==0) removepoint(geoself(), @ptnum); } else{ if(vsample!=0) removepoint(geoself(), @ptnum); }
#DELETE LONE POINTS
int handle = pcopen(@OpInput1, "P", @P, chf("rad"), chi("num")); i@many = pcnumfound(handle); if(i@many<chi("num"))removepoint(geoself(),@ptnum);
#DOT PRODUCT CULLING
vector ref = set(chf("refx"),chf("refy"),chf("refz")); float dot = dot(normalize(v@v),ref); if(dot<chf("thres")) @Cd = set(1,0,0); //Visualize if(dot<chf("thres")) removepoint(geoself(),@ptnum); //Delete
#GET LENGTH, BREADTH AND HEIGHT
//get length, breadth and height vector sz = getbbox_size(geoself()); assign(f@l,f@b,f@h,sz);
#GROUP ROOTS AND TIPS OF CURVES
i@root = (vertexprimindex(0, @vtxnum) == 0); i@tip = (vertexprimindex(0, @vtxnum) == (@numvtx-1)); setpointgroup(0, "roots", @ptnum, @root, "set"); setpointgroup(0, "tips", @ptnum, @tip, "set");
#MATCH BY ID
//create a point cloud //add an enumerate SOP //Group type - points //Attribue - id //delete a subset of the points and add to input 2 //Full point cloud goes into input 1 int match = findattribval(1,"point","id",@id,0); if(match!=-1)removepoint(geoself(),@ptnum);
#CULL BY RELATIVE BOUNDING BOX
vector bbox = relbbox(0,@P); if(bbox.xchf("xmax"))removepoint(geoself(),@ptnum); if(bbox.ychf("ymax"))removepoint(geoself(),@ptnum); if(bbox.zchf("zmax"))removepoint(geoself(),@ptnum);
#LINEAR INTERPOLATIONS
//Interpolate between point positions vector p1 = point(1,"P",@ptnum); v@P = lerp(v@P, p1, chf("mix")); //Interpolate between velocities vector v1 = point(0,"v",@ptnum); vector v2 = point(1,"v",@ptnum); v@v = lerp(v1, v2, chf("mix"));
#ROTATE BY MATRIX
float xrotamt = radians(chf("xrotamt")); float yrotamt = radians(chf("yrotamt")); float zrotamt = radians(chf("zrotamt")); float cex, cey, cez; vector min, max,centroid; vector xrotaxis = set(1,0,0); vector yrotaxis = set(0,1,0); vector zrotaxis = set(0,0,1); //Calculate the Centroid here getbbox(0, min, max); cex = (max.x + min.x) * 0.5; cey = (max.y + min.y) * 0.5; cez = (max.z + min.z) * 0.5; centroid = set(cex, cey, cez); //Declare identity matrix here. 3@xform = ident(); //Rotation order is x y z rotate(3@xform , xrotamt, xrotaxis); rotate(3@xform , yrotamt, yrotaxis); rotate(3@xform , zrotamt, zrotaxis); v@P-=centroid; //move points to origin @P = @P * 3@xform; //Apply Rotation v@P+=centroid; //move back to original position
#TRANSFORM BY PRIMITIVE INTRINSIC
matrix xform = primintrinsic(@OpInput2, "packedfulltransform", 0); @P*=xform;
#VOLUME FRUSTRUM CULL
vector pndc = toNDC(chs("camera_name"), @P); // padding float pad = .2; if(pndc.x1+pad || pndc.y1+pad || pndc.z>=0 ){ @density=0; }
#VELOCITY ALONG PATH
int total = npoints(0)-1; //last point int after = total-1;//penultimate point int ntm = @ptnum+1; vector npos = point(0,"P",ntm); v@v = @P-npos; //get vel of last point if(@ptnum==total){ v@v = point(0,"P",after)-point(0,"P",total); }
#MOVE POINTS TO GROUND SURFACE (GEO)
int handle = pcopen(@OpInput2, "P", @P, chf("rad"), chi("num")); vector lp = pcfilter(handle, "P"); i@npt = nearpoint(1,@P); vector npos = point(1,"P",i@npt); vector off = set(0,chf("yoffset"),0); if(@P.y<npos.y){ vector disp = @P-lp; @P-=disp; @P+=off; }
#ROTATE LINE ALONG SELF (TWISTER)
//uvtexture node to compute uv attrib on points //Texture type is set to Row & Columns //Get velocity vector along line int total = npoints(0)-1; //last point int after = total-1;//penultimate point int ntm = @ptnum+1; vector npos = point(0,"P",ntm); v@v = @P-npos; //get vel of last point if(@ptnum==total){ v@v = point(0,"P",after)-point(0,"P",total); } //Make orthogonal frame vectors v, up and side v@up = set(1,0,0); v@side = cross(normalize(v@v),normalize(v@up)); v@up = cross(normalize(v@side),normalize(v@v)); v@v = cross(normalize(v@side),normalize(v@up)); //Matrices /*'offset' is scaled with up vector or side vector so the offset position is usually perpendicular to the angle of rotation, in the event that the line is rotatated before applying the twist */ float offset = chf("offset_multiplier"); float freq = chf("frequency"); float angle = @uv.x * freq; vector offset_pos = (v@side*offset) + @P; vector axis = v@v; matrix3 xform = ident(); rotate(xform,angle,axis); //EXTRACTING TRANSFORMS //Depending on the value of c, //returns the translate (c=0), rotate (c=1), or scale (c=2) //component of the transform (xform) #define XFORM_SRT 0 // Scale Rotate Translate #define XFORM_XYZ 0 // Rx Ry Rz int trs = XFORM_XYZ; //Transform Order int xyz = XFORM_SRT; //Rotation Order vector p = set(0,0,0); //pivot for crack/extracting transforms vector translate = cracktransform(trs, xyz, 0 , p, xform); vector rotate = cracktransform(trs, xyz, 1 , p, xform); vector scale = set(1,1,1); vector pivot = @P; //pivot for rotations //MAKE TRANSFORM matrix newTrans = maketransform(trs, xyz, translate, rotate, scale, pivot); @P=offset_pos*newTrans;
#MOVE POINTS TO GEOMETRY SURFACE IF INSIDE SDF
//Input 2 is Geo //Input3 is SDF representation of Geo int handle = pcopen(@OpInput2, "P", @P, chf("rad"), chi("num")); vector lp = pcfilter(handle, "P"); i@npt = nearpoint(1,@P); vector npos = point(1,"P",i@npt); vector off = set(0,chf("yoffset"),0); vector disp = @P-lp; float vsample = volumesample(2,0,@P); if(vsample<0)@P-=disp;
#APPLY RANDOM ROTATION TO VECTOR ON ALL AXIS (AXES)
float amt = 0; float randx, randy, randz; vector axis = set(0,0,0); int npts2 = npoints(1); //Number of points in second input int lidx2 = npts2-1; //Index of penultimate point vector stemdir = point(1,"P",lidx2) - point(1,"P",0); //Main stem direction amt = fit(rand(@id+chf("rotation amt_seed")),0,1,chf("min_rotation_amt"),chf("max_rotation_amt")); randx = fit(rand(@id+chf("x_axis_seed")),0,1,chf("x_lower_limit"),chf("x_uppper_limit")); randy = fit(rand(@id+chf("y_axis_seed")),0,1,chf("y_lower_limit"),chf("y_uppper_limit")); randz = fit(rand(@id+chf("z_axis_seed")),0,1,chf("z_lower_limit"),chf("z_uppper_limit")); axis = set(randx,randy,randz); //create identity matrix to use for rotatating stem dir matrix3 idm = ident(); rotate(idm,amt,axis); //Rotate the matrix v@N = stemdir; //visualize through normal @N*=idm; //Apply transformation
#MOVE POINTS TO SURFACE (SDF)
float vsample = volumesample(1,0,@P); vector dirtosurf = volumegradient(1, 0, @P); @P -= normalize(dirtosurf) * (vsample - chf("offset"));
#QUANTIZE POSITION – CUBIFY
float ps = chf("scale"); @P.x = rint(@P.x/ps) * ps; @P.y = rint(@P.y/ps) * ps; @P.z = rint(@P.z/ps) * ps;
#SINK PUMP BEHAVIOR – VELOCITY FIELD
//Plug in a point cloud into input 1 //Visualize the velocity attrib vector pp = getbbox_center(geoself()); //ORIGIN OR SINK/PUMP v@v = normalize(pp-@P); //v@v.y*=0; vector a = normalize(chv("ref")); vector b = normalize(v@v); float dd = dot(a,b); f@theta = degrees(acos(dd)); matrix3 mm = lookat(v@v,a); v@v*=mm;
#INTERPOLATE LINE INTO CIRCLE
//Input is a line //Resample line for more points //UV texture SOP on line as point attrib //Set to rows and column //Interpreted from: https://darioseyb.com/post/curvy-lines/ int num = npoints(0); vector lineStart = point(0,"P",0); vector lineEnd = point(0,"P",num-1); vector lineDir = lineStart-lineEnd; //Calculate vector perpendicular to lineDir float l = length(lineDir); vector up = set(0,1,0); vector side = cross(normalize(lineDir),normalize(up)); //Flip up if lineDir is in the same direction as up vector if(dot(up,normalize(lineDir))<0)up=set(1,0,0); float t = @uv.x; float pivot = chf("pivot"); //Normalized pivot float lineLength = length(lineDir); //line length float bendFactor = chf("bend_Factor"); //bend factor float circleRad = lineLength / (2 * PI); //vector circleCenter = lineStart + lineDir * (pivot + up * circleRad); vector circleCenter = lineStart + (-lineDir * pivot); //Make Circle tangle to line circleCenter+=up*circleRad; float angle = PI + bendFactor * (1.0 - (t+pivot)) * 2 * PI; vector posOnCircle = circleCenter + set(cos(angle),sin(angle),0) * circleRad; @P = lerp(@P,posOnCircle,bendFactor);
#BEND CURVE
//Input is a line //Resample SOP on line for more points //Activate curveu attrib in resample SOP //Remap curveu to shape of bend @curveu=chramp("ramp",@curveu); float bamt = chf("bend_amt"); //bend amount vector benddir = chv("bend_dir"); //bend direction @P+= benddir * bamt * @curveu;
#LOOK AT: GENERATE RADIAL VELOCITIES
//Input 1 is a point cloud v@v = set(1,0,1); vector pp = getbbox_center(geoself());//point to look at matrix3 mm = lookat(pp,@P); @v*=mm;
#LOOK AT: GENERATE LINEAR VELOCITIES
//Input 1 is a point cloud v@v = set(0,0,1); vector pp = getbbox_center(geoself());//point to look at matrix3 mm = lookat(pp,@P); @v*=mm;
#LOOK AT TARGET
vector pp = point(1,"P",0);//point to look at matrix3 mm = lookat(@P,pp); @P*=mm;
#MEDIAN POINT NUMBER
int npt = npoints(0); //Even if(npt%2==0) i@midpt = (npt/2) -1; else i@midpt = (int(ceil(float(npt)/2))) -1;
#ADD A POINT AT CENTER OF OBJECT
//Run Over Detail //Object whose centroid is to be computed goes into input 2 vector cent = getbbox_center(1); addpoint(0,cent);
#CALCULATE/VISUALIZE POINT CLOUD DENSITY
//POINT DENSITY float rad = chf("rad"); int num = chi("num"); int handle = pcopen(@OpInput1, "P", @P, rad, num); vector lookup_P = pcfilter(handle, "P"); int many = pcnumfound(handle); i@many = many; f@viz = float(many)/float(num); //point cloud density @Cd = vector(f@viz);
#SCALE BY MATRIX
vector p = getbbox_center(0); //pivot float sx, sy, sz; sx = sy = sz = chf("scale"); matrix idan = maketransform(0,0,{ 0, 0, 0 },{ 0, 0, 0 },set(sx,sy,sz),{ 0, 0, 0 }); //Move to origin, scale, then move back @P-=p; @P*=idan; @P+=p;
#RANDOM ATTRIB ON POINTS BASED ON PARENT PRIM NUM
/*HINT: use the 'rnd' attrib to sort points by attributes in a sort SOP*/ //Run over Primitives int points[] = primpoints(0,@primnum); int ll = len(points); for(int i=0; i<ll;i++) { setpointattrib(geoself(),"rnd",points[i],@primnum, "set"); }
#CULL POINTS BASED ON SPEED (VELOCITY THRESHOLD)
float vlen = length(v@v);
if(vlen<chf("speed"))removepoint(geoself(),@ptnum);
#ORIENT ATTRIBUTE FROM NORMAL ATTRIBUTE
matrix3 m = dihedral({0,0,1},@N); @orient = quaternion(m);
#SIMPLEX NOISE ON VELOCITY ATTRIBUTE
v@v*=chf("vel_scale"); vector freq = chv("freq"); vector offset = chv("offset"); float amp = chf("amp"); vector nn = xnoise(@P * freq + offset); nn = fit(nn,{0,0,0},{1,1,1},{-1,-1,-1},{1,1,1}); nn*=amp; v@v+=nn;
#CONNECT POINTS
//Run over detail int num = npoints(geoself()); int vtx_limit = num-1; //We dont want to add an extra vertex to the last point for(int i=0;i<vtx_limit;i++) { int prim = addprim(0,"polyline"); addvertex(0,prim,i); addvertex(0,prim,i+1); }
This guide is simply awesome! Thank you Tosin, glad that I had found this site.
Hope you are doing great!
You’re very welcome Leo. Glad you find it relevant. 🙂
Pingback: VEX: Bend Wrangle | gareth bell | cg bod
Thank you! Yours snippets help me a lot!
Thank you very much. Very helpful
This is a gold mine! Thank you for sharing this information! Appreciate your time on this 🙂
Thank you, you’re welcome!
Would you be able to guide me as to how I can achieve the geo culling using bbox intersection in houdini python?
This can be done in VEX, but you are saying you will like to do it Python instead?
I sadly do not know VEX and wish to learn.
That’s why I was wondering about python.
Thanks you so much, bookmarked!