環境:Houdini 20.5.584
ガウス関数を使い、ポリラインのポイントの値を重み付き平均で平滑化する。


アップベクトルを平滑化する場合
//
// upベクトルにブラーを掛ける
// カーブに沿った距離でガウスブラーをかける
// Run Over: Points
//
float blurRadius = `chs("../blurDist")`; // ブラーする距離(範囲)
int num = 10; // サンプルするポイント数
float step = blurRadius / (float)num;
int prim = pointprims(0, @ptnum)[0];
float curveLength = primintrinsic(0, "measuredperimeter", prim);
vector weighted_up = {0,0,0};
float total_weight = 0;
// ポイントのUV値を取得する
vector pos = point(0, "P", @ptnum);
int index;
vector uv;
xyzdist(0, pos, index, uv);
// マイナス方向
for(int i = 0; i < num; i++)
{
// 端はクランプする
float prev_u = clamp(uv.x - (step * i / curveLength), 0, 1);
vector pt_up = primuv(0, "up", index, set(prev_u, 0));
// 距離による重み(ガウシアン)
float dist = step * i;
float weight = exp(-pow(dist / blurRadius, 2));
weighted_up += pt_up * weight;
total_weight += weight;
}
// プラス方向
for(int i = 1; i < num; i++)
{
// 端はクランプする
float next_u = clamp(uv.x + (step * i / curveLength), 0, 1);
vector pt_up = primuv(0, "up", index, set(next_u, 0));
// 距離による重み(ガウシアン)
float dist = step * i;
float weight = exp(-pow(dist / blurRadius, 2));
weighted_up += pt_up * weight;
total_weight += weight;
}
if(total_weight > 0) {
v@up = normalize(weighted_up / total_weight);
}ガウスブラーの仕組み
float weight = exp(-pow(dist / blurRadius, 2));正規化された距離の二乗
dist / blurRadiusで距離を正規化する。pow(x, 2)で二乗することで距離が離れるほど値が急激に大きくなる。
例: blur_width = 1.0の場合
dist = 0.5 → 0.5^2 = 0.25
dist = 1.0 → 1.0^2 = 1.0
dist = 2.0 → 2.0^2 = 4.0
なぜ二乗するのか
二乗することで中心からの距離に対して「放射状に均等な減衰」が得られる。2D/3D空間でも距離の二乗は方向に依存しないので、綺麗な円形/球形の影響範囲になる。
マイナス記号の意味
二乗した値を負の値に反転している。
dist = 0.5 → -0.25
dist = 1.0 → -1.0
dist = 2.0 → -4.0
これにより距離が大きいほど、より大きな負の数になる。
指数関数による変換
exp(x)は自然対数の底e(2.718…)をx乗する関数。
負の値をexpに入れると
exp(0) = 1.0(距離ゼロ = 完全な重み)
exp(-0.25) ≒ 0.78
exp(-1) ≒ 0.37
exp(-4) ≒ 0.018(ほぼゼロ)
指数関数により「滑らかな減衰曲線」が作られる。
中心ではweight = 1.0
距離が離れるにつれ重みが滑らかにかつ素早くゼロに近づく
完全にゼロにはならないがblur_widthの2、3倍程度でほぼゼロになる
