曲率とは
曲率半径
曲線を局所的な円弧と見た場合の半径。
曲率
曲率半径の逆数になる。
パラメトリックUVで計算する
ポリラインの各ポイントの曲率を計算する。円弧から曲率半径を求める。Resample SOPで均等なポイント配置になっている必要あり。
//
// ポリラインの角ポイントの曲率を計算する
// Run Over: Primitives
//
float step = 10.0; // 曲率を計算する幅(片側)
float curveLength = primintrinsic(0, "measuredperimeter", @primnum);
int pts[] = primpoints(0, @primnum);
for(int i = 0; i < len(pts); i++)
{
vector pos = point(0, "P", pts[i]);
int index;
vector uv;
xyzdist(0, pos, index, uv);
// 端はクランプする
float prevU = clamp(uv.x - (step / curveLength), 0, 1);
float nextU = clamp(uv.x + (step / curveLength), 0, 1);
vector p0 = primuv(0, "P", index, set(prevU, 0));
vector p1 = point(0, "P", pts[i]);
vector p2 = primuv(0, "P", index, set(nextU, 0));
// XZ平面で計算する場合はこのチェックを外す
p0.y = 0;
p1.y = 0;
p2.y = 0;
// 弧長
float c = length(p2 - p0);
// p1から一番近いP0-P2上の点
vector p = p0 + dot((p1 - p0), normalize(p2 - p0)) * normalize(p2 - p0);
// 矢高
float h = length(p - p1);
// ほとんど矢向が0に近い場合はほぼ直線とみなす
if(h < 0.0001)
{
// 無限は(-1)として条件分岐させる
setpointattrib(0, "__radius", pts[i], -1);
setpointattrib(0, "__theta", pts[i], PI);
setpointattrib(0, "__curvature", pts[i], 0.0);
}
else
{
// 半径
float radius = (c * c / 4 + h * h) / (2 * h);
// 中心角
float theta = 2 * asin(c / (2 * radius));
if(theta > radians(0.0))
{
setpointattrib(0, "__radius", pts[i], radius);
setpointattrib(0, "__theta", pts[i], theta);
setpointattrib(0, "__curvature", pts[i], 1.0/radius);
}
}
}
曲率を視覚化する
曲率を彩度のグラデーションにする。
//
// ポリラインの曲率を視覚化する
// Run Over: Primitives
//
float minRadius = chf("radius"); // 上限の最小曲率半径(m)(赤く表示される値)
float maxCurvature = 1.0/minRadius; // 上限の曲率
float step = 1.0; // 曲率を計算する幅(片側)
float curveLength = primintrinsic(0, "measuredperimeter", @primnum);
int pts[] = primpoints(0, @primnum);
for(int i = 0; i < len(pts); i++)
{
vector pos = point(0, "P", pts[i]);
int index;
vector uv;
xyzdist(0, pos, index, uv);
// 端はクランプする
float prevU = clamp(uv.x - (step / curveLength), 0, 1);
float nextU = clamp(uv.x + (step / curveLength), 0, 1);
vector p0 = primuv(0, "P", index, set(prevU, 0));
vector p1 = point(0, "P", pts[i]);
vector p2 = primuv(0, "P", index, set(nextU, 0));
// 弧長
float c = length(p2 - p0);
// p1から一番近いP0-P2上の点
vector p = p0 + dot((p1 - p0), normalize(p2 - p0)) * normalize(p2 - p0);
// 矢高
float h = length(p - p1);
// ほとんど矢向が0に近い場合は無限半径(=0)とする
if(h < 0.0001)
{
setpointattrib(0, "__radius", pts[i], -1.0); // 曲率半径
setpointattrib(0, "__theta", pts[i], PI); // 中心角
setpointattrib(0, "__curvature", pts[i], 0.0); // 曲率
vector color = hsvtorgb(0.5, 1.0, 1.0);
setpointattrib(0, "Cd", pts[i], color);
}
else
{
// 半径
float radius = (c * c / 4 + h * h) / (2 * h);
float curvature = 1.0/radius;
// 中心角
float theta = 2 * asin(c / (2 * radius));
if(theta > radians(0.0))
{
setpointattrib(0, "__radius", pts[i], radius); // 曲率半径
setpointattrib(0, "__theta", pts[i], theta); // 中心角
setpointattrib(0, "__curvature", pts[i], curvature); // 曲率
float hue = clamp(curvature/maxCurvature, 0, 1.0) * 0.5 * -1 + 0.5;
vector color = hsvtorgb(hue, 1.0, 1.0);
setpointattrib(0, "Cd", pts[i], color);
}
}
}
環境:Houdini 19.5.752