Resampling curves using VEX part 3: Adaptive root to tip

Generally, uneven segment lengths on hair curves are unusual for groom assets. But it could be helpful to resample a curve adaptively from root to tip to optimize some creature grooms, especially the ones with layers of down, awn, and guard hairs. Technically, you only need a few points toward the roots of the curves hidden underneath the fur. Simulating this kind of groom is another story. Some simulation pipelines have severe limitations regarding the curves' segment count. Before getting all hacky with curves segment count, it's good to check your restrictions with CFX. Resampling curves adaptively can also be helpful for many procedural modeling setups, and procedural modeling tasks generally have more freedom for creative solutions.

So, how do we calculate adaptive segment lengths for adaptive resample? If we look at our previous resample scripts, we need to add something that allows us to shift the sampled barycentric UV coordinates toward the root or the tip. This can be done using the chramp() vex function. This function takes values from 0 to 1 and modifies the value according to the ramp curve. All we need to do is add this line to the script:

uv.x = chramp("resample_bias",uv.x);

Now, the resample positions shift to the new values evaluated by the ramp parameter.

Constant segment count:

//primitive wrangle

int count = chi("count");

int new_prim = addprim(0,"polyline"); 
vector uv = {0,0};

for ( int i=0; i<=count; i++ ){

    uv.x = i/float(count);

    uv.x = chramp("resample_bias",uv.x);
    
    vector pos = primuv(0,"P",i@primnum,uv);
    int new_pnt = addpoint(0,pos);
    
    addvertex(0,new_prim,new_pnt);
}

removeprim(0,i@primnum,1);

Maximum segment length:

Note: Remember to calculate the curve length first and assign it to f@length primitive attribute. Example: Measure Hair Length (VEX).

//primitive wrangle

float max_seg_length = chf("maximum_segment_length");

float length = f@length;
float count = rint(length/max_seg_length);

int new_prim = addprim(0,"polyline");
vector uv = {0,0};

for ( int i=0; i<=count+1; i++ ){
    
    uv.x = i/count;
    
    uv.x = chramp("resample_bias",uv.x);
    
    vector pos = primuv(0,"P",i@primnum,uv);

    int new_pnt = addpoint(0,pos);
    addvertex(0,new_prim,new_pnt);
}
removeprim(0,i@primnum,1);
Next
Next

Resampling curves using VEX part 2: Maximum segment length