Knowledge Garden

Search

Search IconIcon to open search

Catenary Curves Houdini Vex

Last updated Mar 1, 2024 Edit Source

Better curve code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Parameter to control the shape of the catenary
float a = chf("a");

// Retrieve the start and end points in global space
vector pos_start = point(0, "P", 0);
vector pos_end = point(0, "P", npoints(0) - 1);

// Calculate the line direction and length
vector line_dir = normalize(pos_end - pos_start);
float line_length = length(pos_end - pos_start);

// The distance between the lowest point of the catenary (vertex) and the endpoints along the line
float half_length = line_length * 0.5;
float y_offset = a * cosh(half_length / a);

// Adjust each point along the line
for (int i = 0; i < npoints(0); i++) {
    // Get the original position of the point
    vector pos = point(0, "P", i);
    
    // Calculate the parameter t along the line's length
    float t = float(i) / (float(npoints(0)) - 1);
    
    // Find the point's projection along the line's length
    float proj_length = lerp(-half_length, half_length, t);
    
    // Apply the catenary formula to calculate the sag in Y
    float sag = a * cosh(proj_length / a) - y_offset;
    
    // Apply the sag to the Y-coordinate
    pos.y -= sag;
    
    // Update the point position
    setpointattrib(0, "P", i, pos, "set");
}

// Ensure the endpoints remain at their original positions
setpointattrib(0, "P", 0, pos_start, "set");
setpointattrib(0, "P", npoints(0) - 1, pos_end, "set");
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <math.h>

void
getFrameOfReference(vector Z, X, Y)
{
    Y = {0,1,0};
    if (abs(dot(Z, Y)) == 1)
        Y = {1,0,0};
    X = normalize(cross(Y, Z));
    Y = cross(Z, X);
}

// Used for slope calculation
#define DELTA   0.001

vector
getNoise(float tt; vector nscale; float nfreq, noff, ntime, nclamp0, nclamp1;
                vector up, side)
{
    vector      nval;
    nval = nscale * (vector(noise(tt*nfreq + noff, ntime)) - .5);
    nval *= smooth(0.0, nclamp0, tt);
    nval *= 1.0-smooth(nclamp1, 1.0, tt);
    return nval.y*up + nval.x*side;
}

sop
springy(vector gravity={0,-1,0}; float stretch=1; float camp=0, cperiod=20;
            vector nscale=0; float nfreq=4, noff=0, ntime=0;
            float nclamp0=.25, nclamp1=.75)
{
    vector      p0, p1, P1;
    vector      u0, u1;
    vector      g;
    float       ss, t0, t1;
    float       cat0, cat1;
    vector      axis;
    vector      up, side;

    if (!import("P", p0, 1, 0)) p0 = 0;
    if (!import("P", p1, 1, 1)) p1 = 0;
    if (!import("up", u0, 1, 0)) u0 = {0,1,0};
    if (!import("up", u1, 1, 1)) u1 = {0,1,0};

    t0 = (float)ptnum / (float)Npt;
    if (t0 > 0.5)
         t1 = t0 + DELTA;
    else t1 = t0 - DELTA;

    // Compute catenary displacement
    g = normalize(gravity);
    cat0 = stretch*((exp(t0-.5) + exp(-t0+.5)) - (exp(0.5) + exp(-.5)));
    cat1 = stretch*((exp(t1-.5) + exp(-t1+.5)) - (exp(0.5) + exp(-.5)));
    P  = lerp(p0, p1, t0) - cat0*g;
    P1 = lerp(p0, p1, t1) - cat1*g;
    if (length2(nscale) > 0)
    {
        if (t0 > 0.5)
             axis = P1 - P;
        else axis = P - P1;
        getFrameOfReference(normalize(axis), up, side);
        P  += getNoise(t0, nscale, nfreq, noff, ntime, nclamp0, nclamp1,
                            up, side);
        P1 += getNoise(t0, nscale, nfreq, noff, ntime, nclamp0, nclamp1,
                            up, side);
    }
    if (camp != 0)
    {
        if (t0 > 0.5)
             axis = P1 - P;
        else axis = P - P1;
        getFrameOfReference(normalize(axis), up, side);

        ss = (2.0*M_PI)*cperiod*t0;
        P += camp * sin(ss) * side;
        P += camp * cos(ss) * up;
    }
}

# More Catenary

1
2
3
4
5
6
int iteration = detail(1,"iteration");
int seed = chi("seed");
float random = fit01(rand(iteration + seed),1,3);


@P.y -= ch("amount") * @restlength *random;