曲率によってカーブの分割数を増減する

Resample SOP等で事前にポイントの間隔を均等にしておく。

Resample SOPのLength項目に以下のように記述した。

prim(0,0,"intrinsic:measuredperimeter",0)/npoints(0)

step:直線時に進む長さ
divRatio:0~
stepScale:1.0~

divRatioは分割する係数。大きい数字ほど分割数が増える。stepScaleはstepに対する倍率。比較する範囲を広くしている。

//
// 曲率の高いエリアほど分割数を増やしたカーブを生成する
// Run Over: Primitives
// input0: 元にするカーブ
//
float step = 10;      // 直線での間隔の長さ
float divRatio = 12;  // この値を高くするほど、コーナーの分割数が多くなる。0だと何も影響を与えない。
float stepScale = 1;  // stepに対する倍率。比較するポイント幅を広くする。

float curveLength = primintrinsic(0, "measuredperimeter", @primnum);
float length = 0; // 1次元座標(実際の長さ)

// 元のプリミティブのポイント情報
int pts[] = primpoints(0, @primnum);
// 頂点を全部消す
int vertices[] = primvertices(0, @primnum);
for(int i = 0; i < len(vertices); i++)
    removevertex(0, vertices[i]);

int flag = -1;
while(flag < 0)
{
    // Prev Pos
    float l_prev = length - (step * stepScale);  
    float p_prev = l_prev / curveLength; // パラメトリック空間(0-1)へ
    vector prev = primuv(0, "P", @primnum, set(p_prev, 0));
    
    // 始端より前なら延長して補正する
    if(p_prev < 0)
    {
        vector p0 = primuv(0, "P", @primnum, set(0, 0));
        vector p1 = primuv(0, "P", @primnum, set(0.001, 0));
        vector v0 = normalize(p1 - p0) * curveLength * p_prev;
        prev = p0 + v0;
    }
    
    // Next Pos
    float l_next = length + (step * stepScale);
    float p_next = l_next / curveLength;
    vector next = primuv(0, "P", @primnum, set(p_next, 0));
    
    // 終端より後なら延長して補正する
    if(p_next > 1.0)
    {
        vector p0 = primuv(0, "P", @primnum, set(1 - 0.001, 0));
        vector p1 = primuv(0, "P", @primnum, set(1.0, 0));    
        vector v0 = normalize(p1 - p0) * curveLength * (p_next - 1.0);
        next = p0 + v0;
    }
    
    // prev,next両端の真ん中の座標
    vector center = (prev + next) * 0.5;
    
    vector pt = primuv(0, "P", @primnum, set(length/curveLength, 0));
    
    //        ---pt---
    //     ---    |r  ----
    // prev----center-----next
    //
    // 折れているほどptとcenterの差rが大きくなる
    // divideRatio=0の時、r=0になるので影響は全くない状態になる
    // また直線の時もr=0になる
    
    float r = length(center - pt) * divRatio / (step * stepScale);
 
    int point = addpoint(0, pt);
    addvertex(0, @primnum, point);
    
    // 次のポイント
    if(r < 0) r = 0;
        
    length += step / (1.0 + r);
    
    // 最後のポイントを打って終了
    if(length >= curveLength)
    {
        pt = primuv(0, "P", @primnum, set(1.0, 0));
        point = addpoint(0, pt);
        addvertex(0, @primnum, point);
        flag = 1;
    }
}

// 元のポイントを消去する
for(int i = 0; i < len(pts); i++)
    removepoint(0, pts[i]);

元のポイントを消去してしまうため、アトリビュートの保存が必要な場合は手当てが必要。

タイトルとURLをコピーしました