運用 vex 將 curve 轉換成片條狀

雖然 Houdini 本身有 PolyWire 這個節點,但其功能是將 curve 轉成管狀而不是片狀,當在做 mograph 之類需要片條狀的特殊情況便不能派上用場。

大概翻了一下所有節點,貌似沒有節點在做這類事情,乾脆直接寫一個。

  • 每根 curve 都是一個 primitive。
  • primitive 上每個 point 都有 width 屬性代表寬度。
  • primitive 最後一個點可以收縮成三角形。
  • 旋轉方向目前是隨機,當然改寫一下也可以照特定角度去旋轉。
  • 最後用 Attribute WrangleRun Over Primitives 處理。
//參數設定
int pts[] = primpoints(0, i@primnum);
int new_pts[];
int new_prim = -1;
int new_prims[];

int ways[] = array(1, -1);

float rot_seed = 123;
float rot = radians(rand(i@primnum * rot_seed) * 360);
matrix3 m_rot = ident();
rotate(m_rot, rot, {0, 0, 1});
vector up = {0, 1, 0} * m_rot;

for (int i = 0; i < len(pts); i++){
    int pt = pts[i];
    if (i == len(pts) -1){
        vector pos = point(0, "P", pt);
        int new_pt = addpoint(0, pos);
        push(new_pts, new_pt);
        int pr = addprim(0, "poly", new_pts[-3], new_pts[-2], new_pts[-1]);
        push(new_prims, pr);
        continue;
    }

    vector cur_pos = point(0, "P", pt);
    vector next_pos = point(0, "P", pt + 1);
    vector cur_N = normalize(next_pos - cur_pos);
    matrix3 m_N = dihedral({0, 0, 1}, cur_N);
    vector cur_up = up * m_N;

    float width = point(0, "width", pt);

    foreach(int way; ways){
        vector pos = cur_pos + cur_up * way * width / 2.0;
        int new_pt = addpoint(0, pos);
        push(new_pts, new_pt);
    }

    if (i > 0){
        int pr = addprim(0, "poly", new_pts[-4], new_pts[-3], new_pts[-1], new_pts[-2]);
        push(new_prims, pr);
    }
}

int vcount = nvertices(0);
float step = 1/(float)len(new_prims);

float x_width = ch("x_width");
float uvx = fit01(rand(i@primnum*779), 0, 1 - x_width);

removeprim(0, i@primnum, 1); // 移除原本的curve

// 上UV

for (int p = 0; p < len(new_prims); p++){
    setprimattrib(0, "source_pt", new_prims[p], i@source_pt);
    int vtxs = p == len(new_prims) - 1 ? 3 : 4;
    int startv = vcount + p * 4;
    for (int i = 0; i < vtxs; i++){
        int vt = startv + i;
        vector uv = {0, 0, 0};
        if (i != 0 && i != vtxs - 1){
            uv.x = 1;
        }
        if (i > 1){
            uv.y = 1;
        }
        if (i == vtxs - 1 && vtxs == 3){
            uv.x = 0.5;
        }
        uv.x *= x_width;
        uv.x += uvx;
        uv.y *= step;
        uv.y += step * p;
        setvertexattrib(0, "uv", vt, -1, uv);
    }
}