3

DirectX 11 の OBJ ローダーに取り組んでいます。OBJ 形式では、正方形 (2 つの三角形) は次のようになります。

v 0 0 0
v 0 1 0
v 1 1 0
v 1 0 0

f 1 2 3
f 1 3 4

したがって、最初に頂点データが で与えられv、次に面が で与えられfます。したがって、頂点を頂点バッファーに読み込み、インデックスをインデックス バッファーに読み込むだけです。しかし、今度はピクセル シェーダーの法線を計算する必要があります。インデックス付きレンダリングを使用しているときに、どうにかして FACES の通常のデータを保存できますか? または、インデックスなしで頂点バッファーを作成する必要がありますか? (各頂点は1つの面でのみ使用されるため、各頂点の法線データを保存できるため)

4

1 に答える 1

4

通常の方法は、面の 3 つの頂点すべてに同じ法線ベクトルを格納することです。このようなもの:

Vertex
{
    Vector3 position;
    Vector3 normal;
}

std::vector<Vertex>  vertices;
std::vector<uint32_t>  indices;

for(each face f)
{
    Vector3 faceNormal = CalculateFaceNormalFromPositions(f); // Generate normal for given face number `f`;
    for(each vertex v)
    {
        Vertex vertex;
        vertex.position = LoadPosition(f, v); // Load position from OBJ based on face index (f) and vertex index (v);
        vertex.normal = faceNormal;
        vertices.push_back(vertex);

        indices.push_back(GetPosIndex()); // only position index from OBJ file needed
    }
}

注:通常、面法線の代わりに頂点法線を使用することをお勧めします。これは、頂点法線を使用すると、見栄えの良いライティング アルゴリズムを適用できるためです (ピクセル単位のライティング)。

for(each face f)
{
    for(each vertex v)
    {
        Vertex vertex;
        vertex.position = LoadPosition(f, v);
        vertex.normal = ...precalculated somewhere...
        vertices.push_back(vertex);
    }
}

注 2:通常、実行時に計算するのではなく、事前に計算された法線をアセット ファイルから読み取る必要があります。

for(each face f)
{
    for(each vertex v)
    {
        Vertex vertex;
        vertex.position = LoadPosition(f, v);
        vertex.normal = LoadNormal(f, v);
        vertices.push_back(vertex);
    }
}

.obj 形式では、頂点ごとの法線を保存できます)。グーグルからの例:

# cube.obj
#

g cube

# positions
v  0.0  0.0  0.0
v  0.0  0.0  1.0
v  0.0  1.0  0.0
v  0.0  1.0  1.0
v  1.0  0.0  0.0
v  1.0  0.0  1.0
v  1.0  1.0  0.0
v  1.0  1.0  1.0

# normals
vn  0.0  0.0  1.0
vn  0.0  0.0 -1.0
vn  0.0  1.0  0.0
vn  0.0 -1.0  0.0
vn  1.0  0.0  0.0
vn -1.0  0.0  0.0

# faces: indices of position / texcoord(empty) / normal 
f  1//2  7//2  5//2
f  1//2  3//2  7//2 
f  1//6  4//6  3//6 
f  1//6  2//6  4//6 
f  3//3  8//3  7//3 
f  3//3  4//3  8//3 
f  5//5  7//5  8//5 
f  5//5  8//5  6//5 
f  1//4  5//4  6//4 
f  1//4  6//4  2//4 
f  2//1  6//1  8//1 
f  2//1  8//1  4//1 

C++ のサンプル コード (未テスト)

struct Vector3{ float x, y, z; };

struct Face
{
    uint32_t position_ids[3];
    uint32_t normal_ids[3];
};

struct Vertex
{
    Vector3 position;
    Vector3 normal;
};

std::vector<Vertex>  vertices; // Your future vertex buffer
std::vector<uint32_t>  indices;  // Your future index buffer

void ParseOBJ(std::vector<Vector3>& positions, std::vector <Vector3>& normals, std::vector<Face>& faces) {  /*TODO*/ }

void LoadOBJ(const std::wstring& filename, std::vector<Vertex>& vertices, std::vector<uint32_t>& indices)
{
    // after parsing obj file
    // you will have positions, normals 
    // and faces (which contains indices for positions and normals)
    std::vector<Vector3> positions;
    std::vector<Vector3> normals;
    std::vector<Face> faces;
    ParseOBJ(positions, normals, faces);

    for (auto itFace = faces.begin(); itFace != faces.end(); ++itFace) // for each face
    {
        for (uint32_t i = 0; i < 3; ++i) // for each face vertex
        {
            uint32_t position_id = itFace->position_ids[i]; // just for short writing later
            uint32_t normal_id = itFace->normal_ids[i];

            Vertex vertex;
            vertex.position = positions[position_id];
            vertex.normal = normals[normal_id];

            indices.push_back(position_id);     // Note: only position's indices
            vertices.push_back(vertex);
        }
    }
}

頂点内の法線のデータをマージした後は、法線のインデックスはもう必要ないことに注意してください。したがって、法線はインデックス化されません (また、2 つの等しい法線が異なる頂点に格納される可能性があり、これはスペースの無駄です)。ただし、位置にはインデックスが付けられているため、インデックス付きレンダリングを引き続き使用できます。

もちろん、最新の GPU のプログラム可能なパイプラインにより、よりトリッキーなことが可能になると言わざるを得ません。

  • それぞれのバッファを作成します: 位置、法線、pos_indices、nor_indices
  • 現在の vertex_id を使用して、シェーダーの現在の position_id と対応する位置、normal_id と対応する法線を読み取ります
  • シェーダーで法線を生成することもできます (したがって、normal_id と法線バッファーはまったく必要ありません)。
  • ジオメトリ シェーダーで顔を組み立てることができます
  • ...ここで別の悪いアイデア =) そのようなアルゴリズムでは、レンダリング システムがより複雑になり、ほとんど利益が得られません。
于 2013-07-09T14:03:34.933 に答える