1

私の問題はOpenGLとNormalsに関するもので、その背後にある数学を理解しており、ある程度の成功を収めています。

以下に添付した関数は、インターリーブされた頂点配列を受け入れ、4つの頂点ごとに法線を計算します。これらは、同じ方向を持つQUADSを表します。私の理解では、これらの4つの頂点は同じ法線を共有するはずです。彼らが同じように直面している限り。

私が抱えている問題は、QUADSが次のように斜めのグラデーションでレンダリングしていることです。光の効果-影が中央にあり、光が隅にあることを除いて。

私は一貫した方法でQUADSを描きます。TopLeft、TopRight、BottomRight、BottomLeft、および法線の計算に使用する頂点は、TopRight-TopLeft、およびBottomRight-TopLeftです。

誰かが私が失敗したものを見ることができるといいのですが、私は何時間もこれに取り組んできました。

記録のために、私は立方体をレンダリングし、オブジェクトの横にティーポットを置いて照明が機能していることを確認しているので、ライトの位置に問題はないと確信しています。

void CalculateNormals(point8 toCalc[], int toCalcLength)
{
    GLfloat N[3], U[3], V[3];//N will be our final calculated normal, U and V will be the subjects of cross-product
    float length;

for (int i = 0; i < toCalcLength; i+=4) //Starting with every first corner QUAD vertice
{
    U[0] = toCalc[i+1][5] - toCalc[i][5]; U[1] = toCalc[i+1][6] - toCalc[i][6]; U[2] = toCalc[i+1][7] - toCalc[i][7]; //Calculate Ux Uy Uz 
    V[0] = toCalc[i+3][5] - toCalc[i][5]; V[1] = toCalc[i+3][6] - toCalc[i][6]; V[2] = toCalc[i+3][7] - toCalc[i][7]; //Calculate Vx Vy Vz

    N[0] = (U[1]*V[2]) - (U[2] * V[1]);
    N[1] = (U[2]*V[0]) - (U[0] * V[2]);
    N[2] = (U[0]*V[1]) - (U[1] * V[0]);

    //Calculate length for normalising
    length = (float)sqrt((pow(N[0],2)) + (pow(N[1],2)) + (pow(N[2],2)));

    for (int a = 0; a < 3; a++)
    {
        N[a]/=length;
    }

    for (int j = 0; i < 4; i++)
    {
                    //Apply normals to QUAD vertices (3,4,5 index position of normals in interleaved array)
        toCalc[i+j][3] = N[0]; toCalc[i+j][4] = N[1]; toCalc[i+j][5] = N[2];
    }
}
}
4

3 に答える 3

2

インデックス5、6、および7から計算に使用する頂点位置の値を取得し、インデックス3、4、および5で法線を書き出すようです。両方でインデックス5がどのように使用されているかに注意してください。そのうちの1つが正しくないと思います。

于 2012-01-17T16:45:40.690 に答える
2

あなたがあなたfor-loopsを噛んでいるようです。

for (int i = 0; i < toCalcLength; i+=4) //Starting with every first corner QUAD vertice
{
  ...
  for (int j = 0; i < 4; i++)
  { //            ^      ^
    // Should you be using 'j' instead of 'i' here?
    // j will never increment
    // This loop won't be called at all after the first time through the outer loop
    ...
  }
}
于 2012-01-17T16:46:04.570 に答える
2

通常の格納には、インデックス3、4、および5を使用します。

toCalc[i+j][3] = N[0]; toCalc[i+j][4] = N[1]; toCalc[i+j][5] = N[2];

また、インデックス5、6 、および7を使用して、ポイント座標を取得します。

U[0] = toCalc[i+1][5] - toCalc[i][5]; U[1] = toCalc[i+1][6] - toCalc[i][6]; U[2] = toCalc[i+1][7] - toCalc[i][7];

これらのインデックスは重複しています(normal.xはposition.zと同じインデックスを共有しています)。これは発生しないはずです。


推奨事項:

  1. すべてを構造に入れます。
  2. また:
    1. 数学ライブラリを使用します。
    2. または、ベクトル演算を適切な名前の個別のサブルーチンに入れます。
  3. インデックスの代わりに名前付き変数を使用します。

そうすることで、コード内のバグの数を減らすことができます。a.position.xよりも読みやすくquad[0][5]、コードがコピーペーストされていない場合のベクトル演算のタイプミスを修正する方が簡単です。


ユニオンを使用して、インデックスと名前の両方でベクトルコンポーネントにアクセスできます。

struct Vector3{
    union{
        struct{
            float x, y, z;
        };
        float v[3];
    };
};    

クワッドABCDで法線を計算するため

A--B
|  |
C--D

式を使用します:

normal = normalize((B.position-A.position)X(C.position-A.position))。

また

normal = normalize((D.position-A.position)X(C.position-B.position))。

ここで、「X」は「外積」を意味します。

どちらの方法でも問題なく動作します。

于 2012-01-17T16:47:52.057 に答える