« C4D 方向を示す複数のベクトルの平均? | トップページ | C4D C.O.F.F.E.E.前回の四角ポリゴンの法線を求める関数を結果から比較してみる。 »

C4D C.O.F.F.E.E.で四角ポリゴンの法線を求める方法を考える。

三角ポリゴンの法線は、深く考えなくても求めることができました。
では四角ポリゴンは、どうするのだろうか。

2個の三角ポリゴンに分解して求めるのか?

四角ポリゴンが平面なら、どのポリゴンのエッジを使って法線を取得しても同じベクトルが求める事ができ、何の問題ありません。

ただし、四角ポリゴンは平面とは限らないのだ…

webで調べても、明確なものはヒットしません。

四角ポリゴンを2つの三角ポリゴンに分割して、2つの法線を取得し、このベクトルから法線を求めるのか?。

単純に考えると…
ポリゴンの面積を求めたときのように、四角ポリゴンを2個の三角ポリゴンに分割して、2個の法線ベクトルを取得し、この2つの方向ベクトルの平均的な方向を算出してみます。

Normal_04

そうすると、四角ポリゴンの法線を求める関数は、こんな具合になります。

//四角ポリゴンの法線を求める
GetPolygonNormal(p0 , p1 , p2 , p3)
{
  var v1 , v2;

  v1 = vnorm(vcross(p2 - p1 , p0 - p1));
  v2 = vnorm(vcross(p0 - p3 , p2 - p3));

  return vnorm(v1 + v2);
}

p1、p3を基準にベクトルを求めvcross()で直交ベクトルを算出していますが…
どのポイントを基準にvcross()を計算させるかは、問題ではありません。

vcross()関数のv1かv2どちらかがvector(0.0 , 0.0 , 0.0)の場合は、vector(0.0 , 0.0 , 0.0)を返すので、この四角ポリゴンの法線を取得する関数は、C4Dのポリゴンデータ上、三角ポリゴンでも、問題なく法線を求める事だろう。

この方法には、問題があります。

問題点を考えて見ます。
2個の三角ポリゴンに分割したときに、片方が45°になる四角ポリゴンで確認します。

ベースになるポリゴンの構成です。

x y z
p0 0.0 0.0 -100.0
p1 -100.0 100.0 0.0
p2 0.0 0.0 100.0
p3 100.0 0.0 0.0

これで、p0、p1、p2がつくる三角ポリゴンの角度が45°になります。

Normal_13

2個の黄色い線は、三角ポリゴンの法線です。長さは50倍。
オレンジ色の線は、全体の四角ポリゴンの法線です。長さは100倍。

次のように、p1の座標を変えます。

p1を(-50.0 , 50.0 , 0.0)へ移動しました。四角ポリゴンの法線は変化していませんね。

Normal_14

更に、p1を(-20.0 , 20.0 , 0.0)へ移動させます。

Normal_15

四角ポリゴンは平面に近づいているのに、法線は変化しません。

当然ですね。
単純に、2つに分割した三角形の法線を足したものから法線を得ているわけですから、2つの角度が変わらなければ、四角ポリゴンの法線は変化しません。

この2つに分割した三角ポリゴンの法線から四角ポリゴンの法線を取得するのであれば、何らかの方法で、各二枚の三角ポリゴンの法線に重み付けをしないといけないですね。

例えば、2枚の三角ポリゴンの面積比に対して、2つの法線の合成する割合を決めるなど…
第一の三角形をp0,p1,p2として、第二の三角形をp2,p3,p0とします。

(第一の三角形の法線)×(第一の三角形の面積 ÷ 四角ポリゴンの面積)
(第二の三角形の法線)×(第二の三角形の面積 ÷ 四角ポリゴンの面積)

この2個のベクトルから、四角ポリゴンの法線を求めます。

2枚の三角形の面積比からベクトルを求める

三角形の面積を求める関数と、法線を求める関数です。

//三角形p0,p1,p2の面積
GetArea(p0 , p1 , p2)
{
  var s;  //面積
  var half;  //三辺の総和の1/2
  var a , b , c;  //各三辺の長さ

  a = vlen(p1 - p0);
  b = vlen(p2 - p1);
  c = vlen(p0 - p2);
  half = (a + b + c) / 2.0;
  s = sqrt(half * (half - a) * (half - b) * (half - c));

  return s;
}


//四角ポリゴンの法線を求める
GetPolygonNormal(p0 , p1 , p2 , p3)
{
  var v;
  var s1 = GetArea(p0 , p1 , p2);
  var s2 = GetArea(p2 , p3 , p0);
  var ssum = s1 + s2;

  v  = vnorm(vcross(p2 - p1 , p0 - p1)) * (s1 / ssum);
  v += vnorm(vcross(p0 - p3 , p2 - p3)) * (s2 / ssum);

  return vnorm(v);
}

これで問題は解決するのか?

とりあえず、分割した三角形の面積比が変わると法線の方向がかわります。

同じ四角ポリゴンでも分割の向きが変わると、結果がどう変わるのか…

例えばp0の座標から始まっていますが、p1から始まると三角形の分割は(p1、p2、p3)と(p3、p0、p1)の三角形になります。

Normal_16

ならば、上の図の三角形2枚と、下の図の三角形2枚の面積も合わせた面積比で求めて見ましょう。

Normal_21_2

4枚の三角形の面積比からベクトルを求めてみる

//三角形p0,p1,p2の面積
GetArea(p0 , p1 , p2)
{
  var s;  //面積
  var half;  //三辺の総和の1/2
  var a , b , c;  //各三辺の長さ

  a = vlen(p1 - p0);
  b = vlen(p2 - p1);
  c = vlen(p0 - p2);
  half = (a + b + c) / 2.0;
  s = sqrt(half * (half - a) * (half - b) * (half - c));

  return s;
}


//四角ポリゴンの法線を求める
GetPolygonNormal(p0 , p1 , p2 , p3)
{
  var v;
  var s1 = GetArea(p0 , p1 , p2);
  var s2 = GetArea(p2 , p3 , p0);
  var s3 = GetArea(p0 , p1 , p3);
  var s4 = GetArea(p1 , p2 , p3);
  var ssum = s1 + s2 + s3 + s4;

  v  = vnorm(vcross(p2 - p1 , p0 - p1)) * (s1 / ssum);
  v += vnorm(vcross(p0 - p3 , p2 - p3)) * (s2 / ssum);
  v += vnorm(vcross(p1 - p0 , p3 - p0)) * (s3 / ssum);
  v += vnorm(vcross(p3 - p2 , p1 - p2)) * (s4 / ssum);

  return vnorm(v);
}

ポリゴンに対しての、各頂点付近の法線の合計から法線を取得してみる。

Normal_17

4つの頂点を挟むエッジから、法線を求める関数です。

//ポリゴンの法線
GetPolygonNormal(p0 , p1 , p2 , p3)
{
  var v;
 
  v  = vnorm(vcross(p1 - p0 , p3 - p0));//三角ポリゴンの場合、下と同じになります
  v += vnorm(vcross(p2 - p1 , p0 - p1));//三角ポリゴンの場合、上と同じになります
  v += vnorm(vcross(p3 - p2 , p1 - p2));//三角ポリゴンの場合(0.0 , 0.0 , 0.0)になります
  v += vnorm(vcross(p0 - p3 , p2 - p3));//三角ポリゴンの場合(0.0 , 0.0 , 0.0)になります

  return vnorm(v);
}

この関数は、次の図の4つの法線を合成した単位ベクトルと同じですね。

Normal_18 Normal_19

四角ポリゴンの対角線から法線を求める。

2本の対角線に垂直に交わるベクトルの単位ベクトルです。

Normal_20

2つの対角線に直角に交わる、と言っても交点を算出するわけではなく、単純に2つの対角線をvcross()関数に渡して、その垂直に交わるベクトルです。

//四角ポリゴンの法線を求める
GetPolygonNormal(p0 , p1 , p2 , p3)
{
  return vnorm(vcross(p0 - p2 , p1 - p3));
}

この方法だと、分割の向きの影響がありません。
おまけに三角ポリゴンにも、特別何もしなくても対応ができます。

実際、四角ポリゴンの法線を求めるには、この対角ベクトルを使います。

四角ポリゴンの法線を取得する関数を、3種類をあげてみました。

次回は…
今回の数種類の「法線を求める関数」で、実際にポリゴンの法線を取得してみます。

|

« C4D 方向を示す複数のベクトルの平均? | トップページ | C4D C.O.F.F.E.E.前回の四角ポリゴンの法線を求める関数を結果から比較してみる。 »