3

曲面の視覚的地平線の2点を見つける必要があります。

私は持っている:

  • 4 つのコーナー ポイントの XYZ
  • 2 つの曲線エッジのベジェ ポイントの XYZ

そして、次のいずれかを計算する必要があります。

  • 水平点の XY
  • 水平点の XYZ
4

1 に答える 1

4

まず、3D ベジエを 2D に変換する必要があります。私の記憶が正しければ、レンダリングのために 3D ポイントを投影するのと同じように、曲線を投影するだけで十分です。

その後、曲線の極値を見つける必要があります。

ちょっとしたハウツー:

ベジェ曲線をベジェ表現から次の形式の多項式に変換します

  x(t) = a*t^3 + b*t^2 + c*t + d
  y(t) = e*t^3 + f*t^2 + g*t + g

  Here t is your interpolation variable that goes from 0 to 1.
  a to d are the coefficients for the curve along the x-axis
  e to g are the coefficients for the curve along the y-axis.

ここで、曲線の最初の導関数を作成します (ポリノメールなので簡単です)。これにより、二次方程式が得られます。根についてこれらを解き、0..1 の範囲外にあるすべての根を破棄します。2 次多項式であるため、根を求めるのは簡単です。

あなたはどのようにたくさんの根を持っていますか。これらすべてを元のベジエ曲線に差し込み、それらの位置を評価すると、多数のポイントが得られます。極値 (存在する場合) は、これらの点の中にあります。

あとは、y 座標が最も高い (または最も低い - 座標系がどのように見えるかはわかりません) ものを検索するだけです。

極値がまったく得られない場合があることに注意してください。これは、ベジエがたとえば直線である場合に発生します。このような場合、最初と最後のベジエ制御点も極値検索に含めることができます。


編集:

ベジエを多項式に変換する方法を尋ねました。さて、通常のベジエ曲線の式から始めます。

 x(t) = x0 * (1-t)³ + 3*x1*(1-t)²*t + 3*x2*(1-t)*t² +x3*t³

(x0 から x3 は、曲線の 4 つの制御点の x 値です)。

次に、すべての項を 1 つずつ乗算し、t のべき乗で並べ替えます。残念ながら、私が書いているコンピューターで数学パッケージを実行していません。紙でそれを行うのが面倒です:-)誰かが数学実験室を実行している場合は、この回答を編集して拡張を追加してくださいバージョン?

とにかく、あなたは多項式にはあまり興味がなく、その導関数だけに興味があるので、物事は少し簡単です。係数を直接取得できます (ここでは x のみを示しています)。

A = 3.0f*(x[1] - x[0]);
B = 6.0f*(x[2] - 2.0f*x[1] + x[0]);
C = 3.0f*(x[3] - 3.0f*x[2] + 3.0f *x[1] - x[0]);

これら 3 つの値 (A、B、C) を使用すると、最初の導関数の多項式は次のようになります。

  x(t) = A*t^2 + B*t + C

A、B、C を 2 次多項式のルート ソルバーに接続すれば完了です。参考までに、以下のソルバー C コードを使用します。

int GetQuadraticRoots (float A, float B, float C, float *roots)
{
  if ((C < -FLT_EPSILON) || (C > FLT_EPSILON))
  {
    float d,p;
    // it is a cubic:
    p = B*B - 4.0f * C*A;
    d = 0.5f / C;
    if (p>=0)
    {
      p = (float) sqrt(p);
      if ((p < -FLT_EPSILON) || (p > FLT_EPSILON))
      {
        // two single roots:
        roots[0] = (-B + p)*d;
        roots[1] = (-B - p)*d;
        return 2;
      } 
      // one double root:
      roots[0] = -B*d;
      return 1;
    } else {
      // no roots:
      return 0;
    }
  } 
  // it is linear:
  if ((B < -FLT_EPSILON) || (B > FLT_EPSILON))
  {
    // one single root:
    roots[0] = -A/B;
    return 1;
  }
  // it is constant, so .. no roots.
  return 0;
}
于 2009-02-21T18:00:08.097 に答える