2

モデルをMayaから非常に単純なiOSOpenGLESセットアップにエクスポートしてロードしようとしています。そのために、基本的に頂点と法線を取得し、それらを単純に含めるCヘッダーに計算するrubyobjパーサーを作成しました。単純に三角形分割された単位立方体の出力は、次の構造です。

Vertex3D cubeVertices[] = {
   {{-0.500000f, -0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{0,1,2},{0,6,7},{0,7,1},{0,6,4},{0,4,2}},5},
   {{0.500000f, -0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{1,0,2},{1,2,3},{1,0,7},{1,7,3}},4},
   {{-0.500000f, 0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{2,0,1},{2,1,3},{2,3,4},{2,4,0}},4},
   {{0.500000f, 0.500000f, 0.500000f},{0.000000f, 0.000000f, 1.000000f},{0.5f, 0.5f, 0.5f, 1},{{3,2,1},{3,2,4},{3,4,5},{3,1,7},{3,7,5}},5},
   {{-0.500000f, 0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{4,2,3},{4,3,5},{4,5,6},{4,6,0},{4,0,2}},5},
   {{0.500000f, 0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{5,4,3},{5,4,6},{5,6,7},{5,3,7}},4},
   {{-0.500000f, -0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{6,4,5},{6,5,7},{6,7,0},{6,0,4}},4},
   {{0.500000f, -0.500000f, -0.500000f},{0.000000f, 1.000000f, 0.000000f},{0.5f, 0.5f, 0.5f, 1},{{7,6,5},{7,6,0},{7,0,1},{7,1,3},{7,3,5}},5}
};

GLubyte cubeFaceIndices[] = {
   0, 1, 2,
   2, 1, 3,
   2, 3, 4,
   4, 3, 5,
   4, 5, 6,
   6, 5, 7,
   6, 7, 0,
   0, 7, 1,
   1, 7, 3,
   3, 7, 5,
   6, 0, 4,
   4, 0, 2
};

Vertex3Dの定義は次のとおりです。

struct Vertex3D {
   vec3 position;
   vec3 normal;
   vec4 color;
   Index3D connected_faces[100];
   int connectedFaceCount;
};
typedef struct Vertex3D Vertex3D;

ここで、いくつかの頂点の動きをアニメートしたいので、頂点法線を再計算する必要があります。このために、接続されているすべての頂点インデックスをすべての頂点に追加しました。これが、connected_facesインデックス配列の目的です。

計算では、外積を使用してすべての面法線を単純に計算します。そのためには、Index3Dに格納されている3つの頂点を使用し、位置をロードし、最初の頂点を減算してベクトルを取得し、外積を計算するだけです。次に、この頂点に属するすべての外積を合計し、ベクトルを正規化します。これが私の最終的な頂点法線です。

私が遭遇している問題は、同じ面の法線を持つ2つの面が発生することです。たとえば、三角形の立方体には常に4つの三角形を分割する2つの三角形があり、その面は反対方向に法線になります。後で計算するためにそれらを追加すると、もちろんそれらの合計はヌルベクトルになります。これが発生するのは、2つの頂点の順序が正しくない場合があるためです。つまり、AをBに置き換える必要がありますが、どちらを反転する必要があるのか​​わかりません。

法線がどちらの方向に進むか、そしてAxBとBxAのどちらを計算するかを推定する数学的な方法はありますか?Mayaで法線を再確認しましたが、ここでは完璧です。

編集:私は今、接続された面を注文しましたが、これは問題なく機能します。私は次のように法線を計算しています:

// every vertex
GLsizei vertexCount = sizeof(cubeVertices) / sizeof(Vertex3D);
for (int i = 0; i < vertexCount; i++) {
    vec3 newNormal = {0.0f, 0.0f, 0.0f};

    // every vertex connected to the current vertex
    GLsizei faceCount = cubeVertices[i].connectedFaceCount;
    for(int j = 0; j < faceCount; j++){

        Index3D index = cubeVertices[i].connected_faces[j];

        vec3 vectorA = cubeVertices[index.a].position;
        vec3 vectorB = cubeVertices[index.b].position;
        vec3 vectorC = cubeVertices[index.c].position;
        vec3 vectorNormal = {0.0f, 0.0f, 0.0f};

        substractVectors(&vectorB, &vectorA);
        substractVectors(&vectorC, &vectorA);

        makeNormal(&vectorB, &vectorC, &vectorNormal);
        addVectors(&newNormal, &vectorNormal);
    }

    // set normal for current vertex
    normalize(&newNormal);
    cubeVertices[i].normal = newNormal;
}

しかし、三角形分割によって、まったく同じ方向を指す2つの法線が存在することがあるという問題があります。これは、期待される{0.33f、0.33f、0.33f}頂点法線にはなりません。それは正しい動作ですか、それともそれを計算する他の方法はありますか?

ご助力ありがとうございます!

4

1 に答える 1

1

これは、面の頂点の順序によって異なります。それらが反時計回りに並べられている場合(外側から顔を見た場合)、顔の法線をAxB、とA = (v1-v0)として計算しB = (v2-v0)ます。時計回りに並べられている場合は、AとBを切り替える必要があります。

しかし、これをすべての顔に対して一貫して行う限り、それは機能するはずです。そうしないと、立方体の面の向きが一貫していないため、四角形を三角形などに変換するときに、誰か(エクスポータ?)が向きを台無しにした可能性があります。

ちなみに、配列なしでそれらを計算するにはconnected_faces、面/インデックス配列を1回トラバースし、各面の面法線を計算し、これをそれぞれの3つの頂点の法線に追加してから、正規化するための単一の頂点配列トラバーサルを実行します。法線。

編集:前面または背面のいずれかをカリングして(とを使用してglCullFace(GL_BACK)) OpenGLでレンダリングを試みることができますglEnable(GL_CULL_FACE)。内側(またはカリングモードによっては外側)の一部の三角形がカリングされ、一部がカリングされていない場合、三角形の方向が一貫しておらず、キューブデータが壊れています。

編集:あなたの更新された質問から、少なくともあなたはもう0法線を持っていないと思います。コードも問題ないようです。すべての法線が3つの類似した座標を持っているわけではないという事実(ところで、0.33ではなく1 / sqrt(3)ですが、私はあなたが何を意味するかを知っています)は三角形から構築された立方体にとって自然です。極端な場合、頂点が6つまたは3つの三角形に接続されることがあります。他のすべての場合(そしてこれが起こるはずです)、あなたは完璧なコーナーを正常に得ることができません。

これは、立方体の三角形分割によるものです。立方体(6つの面と8つの頂点がそれぞれ正確に3つの面に接続されている)は表示されませんが、頂点が3〜6個の三角形に接続された三角形メッシュが表示されます。プログラムロジックは、いくつかの三角形が一緒に属し、クワッドを形成していることを認識していません。これは、一般的なメッシュの一般的な問題でもあります。たとえば、四角形のメッシュ(四角形から構築)で細分割アルゴリズムを実行すると、そのメッシュの三角形分割で同じ細分割を実行した場合とは異なるジオメトリになります(四角形ごとに2つの三角形があります)。

本当にクワッドで作業する必要がある場合は、クワッドレイヤーを表すために、より高いレベルの抽象化が必要です(おそらく、上部にある別のデータ構造、または三角形の特別な順序、たとえば、連続するすべてのトリスのペアがクワッドを形成します)。それ以外の場合は、OpenGLがクワッドを直接レンダリングできるため、クワッドを完全に操作することもできます(ただし、非推奨でないGLまたは少なくともESがクワッドのサポートを終了したかどうかはわかりません)。

編集:あなたの場合、あなたはそれを注文することができるので、2つの三角形ごとにクワッドを形成します。次に、法線計算では、常に2つの三角形を処理し、そのうちの1つの法線を計算してから、4つの異なる頂点の頂点法線のみを更新します。

于 2011-08-04T20:54:35.283 に答える