Tags

, ,

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);
    
}