4

私はopenGl用の.objローダーを書いています。ジオメトリは正常に読み込まれますが、法線は常にめちゃくちゃです。2 つの異なるプログラムでモデルをエクスポートしようとしましたが、何も機能していないようです。私の知る限り、これはGL_TRIANGLESに法線を入れる方法です

     glNormal3fv(norm1);   
     glVertex3fv(vert1);
     glNormal3fv(norm2);
     glVertex3fv(vert2);
     glNormal3fv(norm3);
     glVertex3fv(vert3);

(法線はコードの残りの部分で GLfloats を参照しています。)

編集: これは法線が壊れた等面体の写真ですここに画像の説明を入力

これは完全な obj ローダー コードとファイルです。

    void loadOBJFromFile(NSString *path,float movex,float movey)
{
    NSString *contentns = [[NSString alloc]initWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];
    NSArray *pieces = [contentns componentsSeparatedByString:@"#"];
    //creating the arrays to read the vertecies and normals from.
    NSArray *normals = [[pieces objectAtIndex:3]componentsSeparatedByString:@"\n"];
    NSArray *vertecies = [[pieces objectAtIndex:2]componentsSeparatedByString:@"\n"];
    //The +1 is to make sure we ignore the texture/ material definition that vomes before the faces.
    int normalCount = [[normals objectAtIndex:0]intValue]+2;
    int faceCount = [[normals objectAtIndex:normalCount]intValue];
    //glTranslatef(movex, 0, movey);

glBegin(GL_TRIANGLES);
{
for (int i = 0; i < faceCount;i++)
{
    //aquires all the numbers in thye current face.
    NSArray *currentFace = [[normals objectAtIndex:normalCount+i+1]componentsSeparatedByString:@" "];
    NSArray *v1 = [[currentFace objectAtIndex:1]componentsSeparatedByString:@"//"];
    NSArray *v2 = [[currentFace objectAtIndex:2]componentsSeparatedByString:@"//"];
    NSArray *v3 = [[currentFace objectAtIndex:3]componentsSeparatedByString:@"//"];

    //crewatres the arrays to contain the vertecies
    NSArray *vertex1 = [[vertecies objectAtIndex:[[v1 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
    NSArray *vertex2 = [[vertecies objectAtIndex:[[v2 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
    NSArray *vertex3 = [[vertecies objectAtIndex:[[v3 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
    //creates all the arrays for the normals
    NSArray *normal1 = [[normals objectAtIndex:[[v1 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
    NSArray *normal2 = [[normals objectAtIndex:[[v2 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
    NSArray *normal3 = [[normals objectAtIndex:[[v3 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];

    //creates the vertecies coordinates
    GLfloat vert1[] = {[[vertex1 objectAtIndex:1]floatValue],[[vertex1 objectAtIndex:2]floatValue],[[vertex1 objectAtIndex:3]floatValue]};
    GLfloat vert2[] = {[[vertex2 objectAtIndex:1]floatValue],[[vertex2 objectAtIndex:2]floatValue],[[vertex2 objectAtIndex:3]floatValue]};
    GLfloat vert3[] = {[[vertex3 objectAtIndex:1]floatValue],[[vertex3 objectAtIndex:2]floatValue],[[vertex3 objectAtIndex:3]floatValue]};
    //creates the normals coordinates

    GLfloat norm1[] = {[[normal1 objectAtIndex:1]floatValue],[[normal1 objectAtIndex:2]floatValue],[[normal1 objectAtIndex:3]floatValue]};
    GLfloat norm2[] = {[[normal2 objectAtIndex:1]floatValue],[[normal2 objectAtIndex:2]floatValue],[[normal2 objectAtIndex:3]floatValue]};
    GLfloat norm3[] = {[[normal3 objectAtIndex:1]floatValue],[[normal3 objectAtIndex:2]floatValue],[[normal3 objectAtIndex:3]floatValue]};

     glNormal3fv(norm1);   
     glVertex3fv(vert1);
     glNormal3fv(norm2);
     glVertex3fv(vert2);
     glNormal3fv(norm3);
     glVertex3fv(vert3);
}}
glEnd();

}

obj ファイル:

#Wavefront OBJ file created by Hexagon 2 
mtllib object.mtl
g Form0
usemtl def_surf_mat
# 12 
v -12.533 4.78719 0 
v -12.533 20.2788 0 
v -7.74583 12.533 -12.533 
v -7.74583 12.533 12.533 
v 0 0 -7.74583 
v 0 0 7.74583 
v 0 25.066 -7.74583 
v 0 25.066 7.74583 
v 7.74583 12.533 -12.533 
v 7.74583 12.533 12.533 
v 12.533 4.78719 0 
v 12.533 20.2788 0 
# 12 
vn -0.850651 -0.525731 0 
vn -0.850651 0.525731 1.50014e-08 
vn -0.525731 -1.50014e-08 -0.850651 
vn -0.525731 0 0.850651 
vn 1.50014e-08 -0.850651 -0.525731 
vn -1.50014e-08 -0.850651 0.525731 
vn -1.50014e-08 0.850651 -0.525731 
vn 1.50014e-08 0.850651 0.525731 
vn 0.525731 0 -0.850651 
vn 0.525731 7.5007e-09 0.850651 
vn 0.850651 -0.525731 1.50014e-08 
vn 0.850651 0.525731 -1.50014e-08 
usemtl def_surf_mat
20
f 7//7 8//8 12//12 
f 7//7 2//2 8//8 
f 8//8 4//4 10//10 
f 6//6 10//10 4//4 
f 7//7 9//9 3//3 
f 5//5 3//3 9//9 
f 6//6 5//5 11//11 
f 6//6 1//1 5//5 
f 1//1 4//4 2//2 
f 1//1 2//2 3//3 
f 12//12 11//11 9//9 
f 12//12 10//10 11//11 
f 2//2 4//4 8//8 
f 10//10 12//12 8//8 
f 12//12 9//9 7//7 
f 3//3 2//2 7//7 
f 3//3 5//5 1//1 
f 4//4 1//1 6//6 
f 9//9 11//11 5//5 
f 11//11 10//10 6//6 
4

4 に答える 4

1

OBJファイルは有効であり、OBJパーサーは頂点の位置と法線を正しく読み取ります。ですから、レンダリングの問題は別の理由から来ていると思います。

画像の視覚的なアーティファクトは、不適切な深度テストのように見えます。(三角形の半分だけを描画します)IB(Interface Builder)でNSOpenGLViewのサブクラスを使用していると思います。IB Attribute InspectorでNSOpenGLViewの 深度バッファーが有効になっていることを確認してください(デフォルトでは、なしです)。デプスバッファの一般的な値は24ビットで、ステンシルバッファの場合は8ビットです。


そして、ここにあなたのプログラムを改善するためのいくつかの提案があります。

  • 描画と解析は別々の機能で実行する必要があります。ファイルをロードする必要があるのは1回だけですが、モデルを複数回描画する可能性があるためです。

  • 頂点、法線、面にはNSMutableArrayを使用します。

  • OBJローダーはコメント行(#で始まる)に依存するため、OBJファイルを解析するための最良の方法ではありません。私はします:

    1. 行ごとに読み取り、行の配列に格納します。
    2. 各行をループして、以下をテストします。
    3. #で始まる場合は、スキップして行を解析します。
    4. 「v」で始まる場合は、頂点配列の同じ行に次の3つの数字を追加します。
    5. 「vn」で始まる場合は、その行の次の3つの数字を通常の配列に追加します。
    6. 「f」で始まる場合は、顔の配列に3つの顔のインデックスを追加します。
于 2012-06-29T05:23:32.033 に答える
1

tl;dr but--- check that the sign of your normals is correct. It is easy in the calculation to have normals pointing in the opposite direction than you intended. E.g. they are along the correct line, but point inside rather than outside. You image is consistent with that kind or error.

As far as I can remember when computing normals you have to take the vector cross product of two edges. The order in which you do the computation determines if the normal points in or out. So make sure you do the computation in the right order.

于 2012-06-27T16:24:03.680 に答える
1

あなたが質問に追加した追加情報で、私はアイデアが不足しています。私も実際には Objective-C を読むことはできませんが、配列のインデックス作成と行カウントのコードをすべて再確認することをお勧めします (おそらく、すべてを印刷して、それらが本当に期待どおりかどうかを確認してください)。単一のエクスポーターが作成するのは非常に毛むくじゃらです。

元の答え:

ローダー コードも .obj ファイルも表示されない場合は、次の点を確認してください。

  • どのようにめちゃくちゃ?完全に間違っていますか、それともスムーズ シェーディングではなくフラット シェーディングですか?
  • それらの norm1、norm2 などは 3 つの GLfloat の配列ですか?
  • 通常の配列には正常な値が含まれていますか (ファイルからの読み取りは機能しますか)?
  • 法線は長さ 1 に正規化されていますか?
  • 法線は正しくインデックス付けされていますか?つまり、正しい頂点に対して正しい法線がありますか?
于 2012-06-27T15:21:11.837 に答える
0

答えはとても簡単です。オブジェクトは、オブジェクト ファイルから正しくロードされていました。ローダー コードはさらに最適化できます。電話した後、

glEnable(GL_CULL_FACE | GL_CULL_FACE_MODE);

編集 当時、私がそのような初心者の間違いを犯したとは信じられません。カリングフェイスは役に立ちましたが、ほんの少しだけです。本当の問題は、深度バッファをクリアするのを忘れていたことです。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

他の誰かが同じようなことを経験している場合、それは問題を解決するはずです.

問題の一部は修正されました。実際には、別のバッファをクリアするか、マトリックスをポップする必要がありました。これで、ライティング ジオメトリが、エディタやモデリング プログラムでの表示とまったく同じように読み込まれます。ご協力ありがとうございました。

于 2012-07-01T12:32:29.610 に答える