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]);
元のポイントを消去してしまうため、アトリビュートの保存が必要な場合は手当てが必要。