-1

以下のコードを考えます。http://pastie.org/pastes/764327/textから取得

    void CreateSphere(int PointRows, int PointsPerRow)
{
    NumVertices = (PointRows-2)*PointsPerRow + 2;
    Vertices = new SVertex[NumVertices];
    IndexVect.clear();  //to be sure it is empty
    float x,y,z;
    int i,j;
    double r;
    for (i = 1; i < (PointRows-1); i++)
    {
        for (j = 0; j < PointsPerRow; j++)
        {
            y = 1.0 - float(i) / float(PointRows-1)*2.0;
            r = sin (acos(y));  //radius of the row
            x = r * sin(float(j) / float(PointsPerRow)*PI*2.0);     
            z = r * cos(float(j) / float(PointsPerRow)*PI*2.0);
        Vertices[(i-1)*PointsPerRow+j].x = x;
        Vertices[(i-1)*PointsPerRow+j].y = y;
        Vertices[(i-1)*PointsPerRow+j].z = z;
        Vertices[(i-1)*PointsPerRow+j].r = (float)(i) / float(PointRows);
        Vertices[(i-1)*PointsPerRow+j].g = 0.7;
        Vertices[(i-1)*PointsPerRow+j].b = (float)(j) / float(PointsPerRow);
    }

}
//The highest and deepest vertices:
Vertices[(PointRows-2)*PointsPerRow].x = 0.0;
Vertices[(PointRows-2)*PointsPerRow].y = 1.0;
Vertices[(PointRows-2)*PointsPerRow].z = 0.0;
Vertices[(PointRows-2)*PointsPerRow].r = 1.0;
Vertices[(PointRows-2)*PointsPerRow].g = 0.7;
Vertices[(PointRows-2)*PointsPerRow].b = 1.0;
Vertices[(PointRows-2)*PointsPerRow+1].x = 0.0;
Vertices[(PointRows-2)*PointsPerRow+1].y = -1.0;
Vertices[(PointRows-2)*PointsPerRow+1].z = 0.0;
Vertices[(PointRows-2)*PointsPerRow+1].r = 1.0;
Vertices[(PointRows-2)*PointsPerRow+1].g = 0.7;
Vertices[(PointRows-2)*PointsPerRow+1].b = 1.0;

for (i = 1; i < (PointRows-2); i++)
{
    for (j = 0; j < (PointsPerRow-1); j++)
    {
        IndexVect.push_back((i-1)*PointsPerRow+j);
        IndexVect.push_back((i-1)*PointsPerRow+j+1);
        IndexVect.push_back((i)*PointsPerRow+j);

        IndexVect.push_back((i-1)*PointsPerRow+j+1);
        IndexVect.push_back((i)*PointsPerRow+j+1);
        IndexVect.push_back((i)*PointsPerRow+j);
    }

    IndexVect.push_back((i-1)*PointsPerRow+PointsPerRow-1);
    IndexVect.push_back((i-1)*PointsPerRow);
    IndexVect.push_back((i)*PointsPerRow+j);

    IndexVect.push_back((i)*PointsPerRow);
    IndexVect.push_back((i-1)*PointsPerRow);
    IndexVect.push_back((i)*PointsPerRow+j);
}       

//The triangles to the highest and deepest vertices:
for (j = 0; j< (PointsPerRow-1); j++)
{
    IndexVect.push_back(j);
    IndexVect.push_back(j+1);
    IndexVect.push_back((PointRows-2)*PointsPerRow);
}
IndexVect.push_back(j);
IndexVect.push_back(0);
IndexVect.push_back((PointRows-2)*PointsPerRow);

for (j = 0; j< (PointsPerRow-1); j++)
{
    IndexVect.push_back((PointRows-3)*PointsPerRow+j);
    IndexVect.push_back((PointRows-3)*PointsPerRow+j+1);
    IndexVect.push_back((PointRows-2)*PointsPerRow+1);
}
IndexVect.push_back((PointRows-3)*PointsPerRow+j);
IndexVect.push_back((PointRows-3)*PointsPerRow);
IndexVect.push_back((PointRows-2)*PointsPerRow+1);
Indices = new GLuint[IndexVect.size()];  //allocate the required memory
for (i = 0; i < IndexVect.size(); i++)
{
    Indices[i] = IndexVect[i];
}
NumIndices = IndexVect.size();
IndexVect.clear();  //no longer needed, takes only memory

}

結果の頂点を使用してどのように法線を計算しますか?

次に、 glEnableClientState(GL_NORMAL_ARRAY) と glNormalPointer(GL_FLOAT,0, Normals) を glDrawElements と共に使用して、法線と一緒に結果のインデックスを描画したいと考えています。

試してみましたが、どうやら間違っているようです。照明は、球体の下ではなく左に表示されます。

申し訳ありません。ここでは全体像を示していません。基本的に、データにノイズを入力して、ランダムな形状を生成しようとしています。

最初のネストされたループの最後で次のコードを使用すると:

Normals[(i-1)*PointsPerRow+j].x = x;
Normals[(i-1)*PointsPerRow+j].y = y;
Normals[(i-1)*PointsPerRow+j].z = z;

球の正しい法線を生成することができ、すべて問題なく表示されます。

ただし、これを行うと:

x=x+(noise3(x,y,z));
y=y+(noise3(x,y,z));
z=z+(noise3(x,y,z));

そして、使用してみてください:

Normals[(i-1)*PointsPerRow+j].x = x;
Normals[(i-1)*PointsPerRow+j].y = y;
Normals[(i-1)*PointsPerRow+j].z = z;

一部の面では法線が正しく見えません。完全な形状が作成されたら、結果のインデックスをループしてから、各ポイントの法線を計算します。

OK、これが私が得たものです。それはおそらく完全に間違っているので、簡単に行ってください。

  for (j = 0; j < NumIndices-2; j=j+3)
   {

Ax = Vertices[Indices[j]].x;    Bx = Vertices[Indices[j+1]].x;   Cx = Vertices[Indices[j+2]].x;
Ay = Vertices[Indices[j]].y;   By = Vertices[Indices[j+1]].y;   Cy = Vertices[Indices[j+2]].y;
Az = Vertices[Indices[j]].z;   Bz = Vertices[Indices[j+1]].z;   Cz = Vertices[Indices[j+2]].z;

dms::Vector3 p1(Ax,Ay,Az);
dms::Vector3 p2(Bx,By,Bz);
dms::Vector3 p3(Cx,Cy,Cz);
dms::Vector3 V1= (p2 - p1);
dms::Vector3 V2 = (p3 - p1);
dms::Vector3 normal = V1.cross(V2);

Normals[j].x = normal[0];
Normals[j].y = normal[1];
Normals[j].z = normal[2];;

Normals[j+1].x = normal[0];
Normals[j+1].y = normal[1];
Normals[j+1].z = normal[2];;


Normals[j+2].x = normal[0];
Normals[j+2].y = normal[1];
Normals[j+2].z = normal[2];;

}

編集 - -

2 つのベクトルが計算されるセクションを再配置することで、より良い結果を得ることができました。以下を変更しました。

dms::Vector3 V1= (p2 - p1);
dms::Vector3 V2 = (p3 - p1);

に:

dms::Vector3 V1= (p2 - p1);
dms::Vector3 V2 = (p1 - p3);

球体の前面に沿って走る暗い帯があり、球体の上部が奇妙に見えます。

残りの問題を解決するために取り組むKaganarの優れた回答に感謝します。バートにも感謝します!

4

1 に答える 1

4

コメントに基づいて、これは1つの可能な答えです:

  • 手順1:すべての頂点法線をゼロベクトルに設定します。
  • ステップ2:各三角形の法線を計算し、それを各三角形のすべての頂点に追加します。
  • ステップ3:すべての頂点法線を正規化します。

この回答を書いている時点で投稿したコードについて:

  • 法線がゼロベクトルに初期化されているかどうかは明らかではありません。
  • 頂点法線に法線を追加するのではなく、割り当てます。(したがって、ステップ2は正しく機能していません。)さらに、頂点法線に追加する法線自体は正規化されていません。(外積は自動的に正規化されません。外積の結果を正規化する必要があります。)
  • ステップ3はまったく実行していません。

さらにもう1つの注意:正規化するときは、特にノイズの多い生成された形状を使用している場合は、正規化関数に渡される長さがゼロに近いベクトルに注意してください。正規化はベクトルの長さの成分を除算するだけなので、通常予想される除算を行う前に、この長さがゼロに近いかどうかを確認するのが一般的です。ゼロに近い場合、そのような正規化関数の出力は通常、アップベクトルになります(ゼロベクトルはほとんどのシェーディングモデルで偽りの暗い結果を引き起こすため)。

于 2012-06-07T13:33:14.293 に答える