頂点を特定平面上に投影(整列)する

投稿者: | 2016/05/05

通常、特定の軸に沿った平面上への投影は、単にその軸の座標を均一にするだけで実現出来ます。
例えば、全てのX座標を0.0に揃えれば、それはX平面上に投影された事になります。

しかし、これが単純な軸平面上ではない場合、もしくは任意の移動方向に制限して投影する場合、話が一気に難しくなります。
今回はそういった高度な平面投影の計算方法を説明します。

投影関数

以下は指定した座標を、任意の平面上に任意の方向から投影する関数です。

fn projToPlane plnNrm plnOfs pos direc threshold:0.0001 =
(
    local vecAng = dot plnNrm direc  -- 1
    if (abs vecAng) > threshold then  -- 2
    (
        local closestDist = dot plnNrm (plnOfs - pos)  -- 3
        local dist = closestDist / vecAng  -- 4
        direc * dist + pos  -- 5
    )
    else
        pos  -- 引数posをそのまま返す
)

引数説明

引数名
plnNrm 投影平面の法線です。
法線というのは面から垂直に伸びているベクトルの事で、例えば完全に上を向いている平面であれば、法線はZ軸の方向を向いているので [0.0, 0.0, 1.0] になります。
ベクトルは長さが1.0になるように、normalize関数で正規化する必要があります。(単位ベクトル)
plnOfs 投影平面の座標です。
平面上にある任意の一点を指定します。この一点は平面上に有りさえすれば何処を指定していてもかまいません。
pos 投影を行う頂点座標です。
direc 投影方向を表す単位ベクトルです。
面と垂直に投影する場合は、plnNrmと同じ値を指定します。また、このベクトルが面と完全に平行だった場合、投影は行われません。
threshold オプション引数。面方向と投影方向が極めて並行に近かった時の許容値です。
1.0を完全に垂直、0.0を完全に水平とし、0.0以外の値を指定する事が出来ます。

処理内容解説

  1. 面と投影方向の並行度を内積で計算しています。 この戻り値は-1から1の間になり、0だと完全に並行となります。
  2. 並行度が許容値か判定しています。
    許容値以下だった場合、計算せずに引数posをそのまま返します。
  3. 初めにposからplnOfsへ向かうベクトルを計算しています。このベクトルと、平面法線のベクトルで内積を取ると、posから平面までの垂直距離が分かります。
  4. 垂直距離を並行度で割ると実際の移動距離が分かります。
    thresholdを0.0にしてしまうと、ここでエラーが出る可能性があります。
  5. 最終的な投影座標を計算し、そのまま関数の戻り値として返しています。

実際の使用

以下は選択ポリゴンの全頂点を平面に投影しています。

投影面はZ座標10.0を通っており、ややX方向に傾いた上向きの面です。
投影方向は今回はZ方向としますが、実際にはどんな向きでも投影出来ます。

thePoly = selection[1]
plnNrm = normalize [0.5, 0, 1]
plnOfs = [0, 0, 10]
direc = z_axis

in coordsys #world
(
    for vi = 1 to (polyop.getNumVerts thePoly) do
    (
        local v = polyop.getVert thePoly vi
        polyop.setVert thePoly vi (projToPlane plnNrm plnOfs v direc)
    )
)

処理結果は以下のようになります。

どうでしょうか?
傾いた面上に整列しているのが分かるかと思います。
また面は原点を通っておらず、Z方向にオフセットされている事も確認出来ます。

本来であればもっと画像を多用して解説すべき記事ですが、管理人の体力が限界なのでこの辺で。

コメントを残す

メールアドレスが公開されることはありません。