2

I have created a Mesh Loader to convert .obj files to a binary file so i can load them directly into my VertexBuffer without parsing them first. My code was working fine for the particular model i used for testing. But after testing some models i downloaded from the internet i noticed that those are not getting converted completely.

This is how i convert the .obj files (this is taken straight from the obj2vbo.cpp file Microsoft provided in a example, with some minor changes):

ifstream objFile(this->fileName.toStdString().c_str(), ifstream::in);
    if (!objFile.is_open()) {
        ui.statusBar->showMessage("Could not open obj file!");
        return false;
    }

    vector<XMFLOAT3> positions;
    vector<XMFLOAT3> normals;
    vector<XMFLOAT2> texcoords;
    vector<vector<IndexTriplet>> faces;

    unsigned int lineNum = 1;

    while (objFile.good()) {
        string line;
        getline(objFile, line);
        istringstream lineStream(line);

        if (lineStream.peek() != '#') {
            string tag;
            lineStream >> tag;

            if (
                tag.compare("mtllib") == 0 ||
                tag.compare("o") == 0 ||
                tag.compare("g") == 0 ||
                tag.compare("usemtl") == 0 ||
                tag.compare("s") == 0
                ) {
                cout << "(" << lineNum << "): Warning: Does not support tag \"" << tag << "\"" << endl;
            }
            else if (tag.compare("v") == 0) {
                XMFLOAT3 pos;
                lineStream >> pos.x >> pos.y >> pos.z;
                positions.push_back(pos);
            }
            else if (tag.compare("vn") == 0) {
                XMFLOAT3 normal;
                lineStream >> normal.x >> normal.y >> normal.z;
                normals.push_back(normal);
            }
            else if (tag.compare("vt") == 0) {
                XMFLOAT2 texcoord;
                lineStream >> texcoord.x >> texcoord.y;
                texcoords.push_back(texcoord);
            }
            else if (tag.compare("f") == 0) {
                vector<IndexTriplet> face;
                while (lineStream.good()) {
                    string tripletString;
                    lineStream >> tripletString;
                    if (tripletString.size() > 0) {
                        istringstream tripletStream(tripletString);

                        IndexTriplet triplet;
                        triplet.pos = 0;
                        triplet.norm = 0;
                        triplet.tex = 0;

                        tripletStream >> triplet.pos;
                        if (tripletStream.get() == '/') {
                            if (tripletStream.peek() != '/') {
                                tripletStream >> triplet.tex;
                            }
                            if (tripletStream.get() == '/') {
                                tripletStream >> triplet.norm;
                            }
                        }
                        face.push_back(triplet);
                    }
                }
                faces.push_back(face);
            }
            else if (tag.size() > 0) {
                // unsupported tag
            }
        }
        lineNum++;
    }

    objFile.close();

    if (positions.size() == 0 || faces.size() == 0) {
        ui.statusBar->showMessage("Error: File contains no geometry!");
        return false;
    }

    // Validate Mesh
    for (auto face = faces.begin(); face != faces.end(); face++) {
        if (face->size() < 3) {
            ui.statusBar->showMessage("Error: Face size < 3 invalid!");
            return false;
        }
        for (auto triplet = face->begin(); triplet != face->end(); triplet++) {
            if (triplet->pos > positions.size() || triplet->pos < 1) {
                ui.statusBar->showMessage("Error: Position index out of range");
                return false;
            }
            if (triplet->norm > normals.size() || triplet->norm < 1) {
                ui.statusBar->showMessage("Error: Normal index out of range");
                return false;
            }
            if (triplet->tex > texcoords.size() || triplet->tex < 1) {
                ui.statusBar->showMessage("Error: Texcoord index out of range");
                return false;
            }
        }
    }

    XMFLOAT3 boxMin = positions[faces[0][0].pos - 1];
    XMFLOAT3 boxMax = boxMin;
    for (auto face = faces.begin(); face != faces.end(); face++)
    {
        for (auto triplet = face->begin(); triplet != face->end(); triplet++)
        {
            XMFLOAT3 pos = positions[triplet->pos - 1];
            boxMin.x = min(boxMin.x, pos.x);
            boxMin.y = min(boxMin.y, pos.y);
            boxMin.z = min(boxMin.z, pos.z);
            boxMax.x = max(boxMax.x, pos.x);
            boxMax.y = max(boxMax.y, pos.y);
            boxMax.z = max(boxMax.z, pos.z);
        }
    }
    XMFLOAT3 boxCenter;
    XMStoreFloat3(&boxCenter, ((XMLoadFloat3(&boxMax) + XMLoadFloat3(&boxMin)) / 2.0f));

    // If specified in the arguments, normalize geometry to fit within a unit cube

    if (true) // Bool variable later...
    {
        float maxAxis = max(max(boxMax.x - boxMin.x, boxMax.y - boxMin.y), boxMax.z - boxMin.z);
        for (auto pos = positions.begin(); pos != positions.end(); pos++)
        {
            XMStoreFloat3(&(*pos), ((XMLoadFloat3(&(*pos)) - XMLoadFloat3(&boxCenter)) / maxAxis));
        }
    }


    // Generate missing normals
    for (auto face = faces.begin(); face != faces.end(); face++)
    {
        XMFLOAT3 normal(0, 0, 0);
        bool normalGenerated = false;
        for (auto triplet = face->begin(); triplet != face->end(); triplet++)
        {
            if (!normalGenerated && triplet->norm == 0)
            {
                for (auto triplet = face->begin(); triplet != face->end(); triplet++)
                {
                    XMFLOAT3 posThis = positions[triplet->pos - 1];
                    XMFLOAT3 posPrev = positions[(triplet == face->begin() ? (face->end() - 1)->pos : (triplet - 1)->pos) - 1];
                    XMFLOAT3 posNext = positions[(triplet == face->end() - 1 ? (face->begin())->pos : (triplet + 1)->pos) - 1];
                    XMStoreFloat3(
                                &normal, 
                                XMVectorAdd(
                                    XMLoadFloat3(&normal),
                                    XMVector3Cross(XMVectorSubtract(XMLoadFloat3(&posNext), XMLoadFloat3(&posThis)), XMVectorSubtract(XMLoadFloat3(&posPrev), XMLoadFloat3(&posThis)))
                                )
                            );
                    triplet->norm = normals.size() + 1;
                }
                normals.push_back(normal);
                normalGenerated = true;
            }
        }
    }

    // Fill in missing texture coordinates with (0, 0)

    bool missingTexcoordCreated = false;
    unsigned int missingTexcoordIndex = 0;
    for (auto face = faces.begin(); face != faces.end(); face++)
    {
        for (auto triplet = face->begin(); triplet != face->end(); triplet++)
        {
            if (triplet->tex == 0)
            {
                if (!missingTexcoordCreated)
                {
                    texcoords.push_back(XMFLOAT2(0.0f, 0.0f));
                    missingTexcoordIndex = texcoords.size();
                    missingTexcoordCreated = true;
                }
                triplet->tex = missingTexcoordIndex;
            }
        }
    }

    // Generate unique vertices and convert counter-clockwise faces to clockwise triangles

    vector<Vertex> vertices;
    vector<unsigned short> indices;
    map<IndexTriplet, unsigned short> tripletIndices;
    for (auto face = faces.begin(); face != faces.end(); face++)
    {
        for (auto triplet = face->begin(); triplet != face->end(); triplet++)
        {
            if (tripletIndices.find(*triplet) == tripletIndices.end())
            {
                tripletIndices[*triplet] = static_cast<unsigned short>(vertices.size());
                Vertex vertex;
                vertex.position = positions[triplet->pos - 1];
                vertex.normals = normals[triplet->norm - 1];
                vertex.uv = texcoords[triplet->tex - 1];
                vertices.push_back(vertex);
            }
            if (triplet >= face->begin() + 2)
            {
                indices.push_back(tripletIndices[*face->begin()]);
                indices.push_back(tripletIndices[*triplet]);
                indices.push_back(tripletIndices[*(triplet - 1)]);
            }
        }
    }

    // Dump vertex and index data to the output VBO file

    ofstream vboFile("binaryMesh.bin", ofstream::out | ofstream::binary);
    if (!vboFile.is_open())
    {
        ui.statusBar->showMessage("Could not open file for writing!");
        return false;
    }

    unsigned int numVertices = vertices.size();
    unsigned int numIndices = indices.size();
    vboFile.write(reinterpret_cast<char*>(&numVertices), sizeof(unsigned int));
    vboFile.write(reinterpret_cast<char*>(&numIndices), sizeof(unsigned int));
    vboFile.write(reinterpret_cast<char*>(&vertices[0]), sizeof(Vertex)* vertices.size());
    vboFile.write(reinterpret_cast<char*>(&indices[0]), sizeof(unsigned short)* indices.size());

    vboFile.close();

And this is how i read it again:

void createMeshData(_In_ byte* meshData, _Out_ VertexBuffer** vertexBuffer, _Out_ uint32* vertexCount)
{
    *vertexCount = *reinterpret_cast<uint32*>(meshData);
    BasicVertex* vertices = reinterpret_cast<BasicVertex*>(meshData + sizeof(uint32)* 2);
    *vertexBuffer = this->m_renderer->createVertexBuffer(vertices, sizeof(BasicVertex) * (*vertexCount), false);
}

I already made sure that both structs BasicVertex and Vertex are the same. This is a example model (Hulk) and how it looks rendered:

enter image description here

It seems that not only the vertices are wrong but the texture coordinates are aswell, but this is another problem.. If you need any more information, please let me know. Thanks for any tip

puelo
  • 5,464
  • 2
  • 34
  • 62
  • The data also contains indices. It seems you're just ignoring them. – Nico Schertler Jun 14 '14 at 15:58
  • 1
    Uh wow. Never thought about that. This actually makes perfect sense. My model i used for testing did have exactly as much indices as vertices so the rendering worked fine, but for the other models it is obviously wrong... i will test it and report back. THANKS a lot – puelo Jun 14 '14 at 16:01
  • As expected: This was the solution! You can add your comment as an answer and i will accept it. Thanks again! – puelo Jun 14 '14 at 18:46
  • The texture is still wrong. Do you see something obvious wrong? @NicoSchertler – puelo Jun 14 '14 at 19:36

0 Answers0