Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm writing a simple model loader just to learn how models are loaded. I wrote a program to convert .OBJ files in a custom format. (It's virtually exactly the same as .OBJ, I wrote it once again just for learning). I can load all the data into std::vectors but I don't know how to put it into an array of vertices and indices, so it's rendering wrong. Here's how it turns out with no culling and wireframe enabled (it's supposed to be a sphere, and that L shape in the middle isn't part of the model):

http://i.imgur.com/eMK4I.png

When I tell it to render a point list, all the vertices are there in the right places. However, they don't seem to form faces correctly...

This is the code that renders them:

    //=========================================================
    // CONVERT THE DATA INTO SOMETHING USABLE
    //=========================================================

    bool isDuplicate;
    for(int i = 0; i < polygonCount; i++)
    {
        for(int i2 = 0; i2 < 3; i2++)
        {
            isDuplicate = false;
            isCreated = false;
            selectedVertex = faceDefinitions[i].vertexIndexes[i2];

            for(int i3 = 0; i3 < vertexCount; i3++)
            {
                if(modelData->vertices[i3].position == vertexPositions[selectedVertex])
                {
                    if(modelData->vertices[i3].texture == D3DXVECTOR2(0,0))
                    {
                        indices[selectedVertex] = i3; 
                        isDuplicate = true;
                        break;
                    }
                }
            }

            if(isDuplicate)
                continue;

            indices[selectedVertex] = selectedVertex;

            modelData->vertices[selectedVertex].position = vertexPositions[selectedVertex];
            modelData->vertices[selectedVertex].normal = vertexNormals[faceDefinitions[i].normalIndexes[i2]];
            modelData->vertices[selectedVertex].texture = D3DXVECTOR2(0,0);
        }
    }

    modelData->indices = indices;

I know there's a way to do it but I can't seem to wrap my head around it. I've rewritten it probably 5 times, but I always get the same result.

Here's the ModelData structure:

struct ModelData
{
    int vertexCount;
    int normalCount;
    int faceCount;
    unsigned long* indices;
    EntityBase::VertexType* vertices;
    int errorCode;
};

The FaceDefinition structure contains the the indices of the vertices positions, normals, and texture coords. I haven't implemented texture coords yet, though.

struct FaceDefinition
{
    int vertexIndexes[3];
    int textureIndexes[3];
    int normalIndexes[3];
};

Here is the entire function, just for clarity:

ModelData* CModelLoader::LoadModel(WCHAR* modelName)
{
    ifstream loaderStream(Application::FileSystem::GetFileLocation(FILE_TYPE_MODEL,modelName));

    ModelData* modelData = new ModelData;

    vector<D3DXVECTOR3> vertexPositions;
    vector<D3DXVECTOR3> vertexNormals;
    vector<D3DXVECTOR3> vertexTextureCoords;
    vector<int> setVertices;
    vector<FaceDefinition> faceDefinitions;
    vector<string> tokens;
    vector<string> faceToken;
    int vertexCount = 0, normalCount = 0, polygonCount = 0;
    unsigned long *indices;
    int selectedVertex;
    bool isCreated;

    string input;
    string currentToken;
    string currentFaceToken;
    std::istringstream streamReader;
    std::istringstream faceReader;
    D3DXVECTOR3 tempVector;
    FaceDefinition tempFace;

    modelData->errorCode = ERR_NO_ERROR;

    if(!loaderStream)
        modelData->errorCode = ERR_COULD_NOT_OPEN;
    else
    {
        while(std::getline(loaderStream, input))
        {
            streamReader.clear();
            streamReader.str(input);
            tokens.clear();
            while(std::getline(streamReader, currentToken, ' '))
            {
                tokens.push_back(currentToken);
            }
            if(tokens.size() < 1)
                continue;

            if(tokens[0] == "VERTEX")
            {
                vertexCount++;
                if(tokens.size() >= 4)
                {
                    tempVector = D3DXVECTOR3(0,0,0);
                    tempVector.x = (float) atof(tokens[1].c_str());
                    tempVector.y = (float) atof(tokens[2].c_str());
                    tempVector.z = (float) atof(tokens[3].c_str());
                    vertexPositions.push_back(tempVector);
                    continue;
                }
                else
                {
                    vertexPositions.push_back(D3DXVECTOR3(0,0,0)); //give it a bad vertex, because we received a bad vertex
                }
            }
            if(tokens[0] == "VERTEX_NORMAL")
            {
                normalCount++;
                if(tokens.size() >= 4)
                {
                    tempVector = D3DXVECTOR3(0,0,0);
                    tempVector.x = (float) atof(tokens[1].c_str());
                    tempVector.y = (float) atof(tokens[2].c_str());
                    tempVector.z = (float) atof(tokens[3].c_str());
                    vertexNormals.push_back(tempVector);
                    continue;
                }
                else
                {
                    vertexNormals.push_back(D3DXVECTOR3(0,0,0)); //give it a bad normal, because we received a bad normal
                }
            }
            if(tokens[0] == "FACE")
            {
                polygonCount++;
                if(tokens.size() == 4) //sorry, but non triangles aren't worth the time
                {
                    tempFace = FaceDefinition();

                    //vertex 1
                    faceReader.clear();
                    faceReader.str(tokens[1]);
                    faceToken.clear();
                    while(std::getline(faceReader, currentFaceToken, ','))
                    {
                        faceToken.push_back(currentFaceToken);
                    }
                    if(faceToken.size() == 3) //should have all the info, or, same as above, its not worth the time
                    {
                        tempFace.vertexIndexes[0]  = atoi(faceToken[0].c_str()) - 1;
                        tempFace.textureIndexes[0] = atoi(faceToken[1].c_str()) - 1;
                        tempFace.normalIndexes[0]  = atoi(faceToken[2].c_str()) - 1;
                    }

                    //vertex 2
                    faceReader.clear();
                    faceReader.str(tokens[2]);
                    faceToken.clear();
                    while(std::getline(faceReader, currentFaceToken, ','))
                    {
                        faceToken.push_back(currentFaceToken);
                    }
                    if(faceToken.size() == 3) //should have all the info, or, same as above, its not worth the time
                    {
                        tempFace.vertexIndexes[1]  = atoi(faceToken[0].c_str()) - 1;
                        tempFace.textureIndexes[1] = atoi(faceToken[1].c_str()) - 1;
                        tempFace.normalIndexes[1]  = atoi(faceToken[2].c_str()) - 1;
                    }

                    //vertex 3
                    faceReader.clear();
                    faceReader.str(tokens[3]);
                    faceToken.clear();
                    while(std::getline(faceReader, currentFaceToken, ','))
                    {
                        faceToken.push_back(currentFaceToken);
                    }
                    if(faceToken.size() == 3) //should have all the info, or, same as above, its not worth the time
                    {
                        tempFace.vertexIndexes[2]  = atoi(faceToken[0].c_str()) - 1;
                        tempFace.textureIndexes[2] = atoi(faceToken[1].c_str()) - 1;
                        tempFace.normalIndexes[2]  = atoi(faceToken[2].c_str()) - 1;
                    }

                    faceDefinitions.push_back(tempFace);
                }
                //if we receive a bad face, we just wont read it
            }
        }
    }

    indices = new unsigned long[vertexCount];

    modelData->faceCount = polygonCount;
    modelData->normalCount = normalCount;
    modelData->vertexCount = vertexCount;
    modelData->vertices = new EntityBase::VertexType[vertexCount];

    //< ^^everything up here works^^ >
    //=========================================================
    // CONVERT THE DATA INTO SOMETHING USABLE
    //=========================================================

    //now is the boring part, creating the vertex list...

    bool isDuplicate;
    for(int i = 0; i < polygonCount; i++)
    {
        for(int i2 = 0; i2 < 3; i2++)
        {
            isDuplicate = false;
            isCreated = false;
            selectedVertex = faceDefinitions[i].vertexIndexes[i2];

            for(int i3 = 0; i3 < vertexCount; i3++)
            {
                if(modelData->vertices[i3].position == vertexPositions[selectedVertex])
                {
                    if(modelData->vertices[i3].texture == D3DXVECTOR2(0,0))
                    {
                        indices[selectedVertex] = i3; 
                        isDuplicate = true;
                        break;
                    }
                }
            }

            if(isDuplicate)
                continue;

            indices[selectedVertex] = selectedVertex;

            modelData->vertices[selectedVertex].position = vertexPositions[selectedVertex];
            modelData->vertices[selectedVertex].normal = vertexNormals[faceDefinitions[i].normalIndexes[i2]];
            modelData->vertices[selectedVertex].texture = D3DXVECTOR2(0,0);
        }
    }

    modelData->indices = indices;

    return modelData;
}

This is there sphere models file:

#Vertex Info

VERTEX_COUNT:62
NORMAL_COUNT:62
FACE_COUNT:120

VERTEX 0 19.5 0
VERTEX 0 -19.5 0
VERTEX 9.75 -16.887495 0
VERTEX 8.443748 -16.887495 4.875
VERTEX 4.875 -16.887495 8.443748
VERTEX 0 -16.887495 9.75
VERTEX -4.875 -16.887495 8.443748
VERTEX -8.443748 -16.887495 4.875
VERTEX -9.75 -16.887495 0
VERTEX -8.443748 -16.887495 -4.875
VERTEX -4.875 -16.887495 -8.443748
VERTEX 0 -16.887495 -9.75
VERTEX 4.875 -16.887495 -8.443748
VERTEX 8.443748 -16.887495 -4.875
VERTEX 16.887497 -9.75 0
VERTEX 14.625001 -9.75 8.443748
VERTEX 8.443748 -9.75 14.625
VERTEX 0 -9.75 16.887497
VERTEX -8.443748 -9.75 14.625
VERTEX -14.625001 -9.75 8.443748
VERTEX -16.887497 -9.75 0
VERTEX -14.625001 -9.75 -8.443748
VERTEX -8.443748 -9.75 -14.625
VERTEX 0 -9.75 -16.887497
VERTEX 8.443748 -9.75 -14.625
VERTEX 14.625001 -9.75 -8.443748
VERTEX 19.5 1E-06 0
VERTEX 16.887495 1E-06 9.75
VERTEX 9.75 1E-06 16.887495
VERTEX 0 1E-06 19.5
VERTEX -9.75 1E-06 16.887495
VERTEX -16.887495 1E-06 9.75
VERTEX -19.5 1E-06 0
VERTEX -16.887495 1E-06 -9.75
VERTEX -9.75 1E-06 -16.887497
VERTEX 0 1E-06 -19.5
VERTEX 9.75 1E-06 -16.887497
VERTEX 16.887495 1E-06 -9.75
VERTEX 16.887495 9.750001 0
VERTEX 14.624999 9.750001 8.443748
VERTEX 8.443748 9.750001 14.625
VERTEX 0 9.750001 16.887495
VERTEX -8.443748 9.750001 14.625
VERTEX -14.624999 9.750001 8.443748
VERTEX -16.887495 9.750001 0
VERTEX -14.624999 9.750001 -8.443748
VERTEX -8.443748 9.750001 -14.625
VERTEX 0 9.750001 -16.887497
VERTEX 8.443748 9.750001 -14.625
VERTEX 14.624999 9.750001 -8.443748
VERTEX 9.750001 16.887495 0
VERTEX 8.443748 16.887495 4.875
VERTEX 4.875 16.887495 8.443748
VERTEX 0 16.887495 9.750001
VERTEX -4.875 16.887495 8.443748
VERTEX -8.443748 16.887495 4.875
VERTEX -9.750001 16.887495 0
VERTEX -8.443748 16.887495 -4.875
VERTEX -4.875 16.887495 -8.443748
VERTEX 0 16.887495 -9.750002
VERTEX 4.875 16.887495 -8.443748
VERTEX 8.443748 16.887495 -4.875

# Vertex Normals!

VERTEX_NORMAL 0 -1 0
VERTEX_NORMAL 0.573584 -0.819147 0
VERTEX_NORMAL 0.431481 -0.867044 0.249116
VERTEX_NORMAL 0 1 0
VERTEX_NORMAL 0.431481 0.867044 0.249116
VERTEX_NORMAL 0.573584 0.819147 0
VERTEX_NORMAL 0.286792 -0.819147 0.496738
VERTEX_NORMAL 0.286792 0.819147 0.496738
VERTEX_NORMAL 0 -0.867044 0.498231
VERTEX_NORMAL 0 0.867044 0.498231
VERTEX_NORMAL -0.286792 -0.819147 0.496738
VERTEX_NORMAL -0.286792 0.819147 0.496738
VERTEX_NORMAL -0.431481 -0.867044 0.249116
VERTEX_NORMAL -0.431481 0.867044 0.249116
VERTEX_NORMAL -0.573584 -0.819147 0
VERTEX_NORMAL -0.573584 0.819147 0
VERTEX_NORMAL -0.431481 -0.867044 -0.249116
VERTEX_NORMAL -0.431481 0.867044 -0.249116
VERTEX_NORMAL -0.286792 -0.819147 -0.496738
VERTEX_NORMAL -0.286792 0.819147 -0.496738
VERTEX_NORMAL 0 -0.867044 -0.498231
VERTEX_NORMAL 0 0.867044 -0.498231
VERTEX_NORMAL 0.286792 -0.819147 -0.496738
VERTEX_NORMAL 0.286792 0.819147 -0.496738
VERTEX_NORMAL 0.431481 -0.867044 -0.249116
VERTEX_NORMAL 0.431481 0.867044 -0.249116
VERTEX_NORMAL 0.865033 -0.501714 0
VERTEX_NORMAL 0.749141 -0.501714 0.432517
VERTEX_NORMAL 0.432517 -0.501714 0.749141
VERTEX_NORMAL 0 -0.501714 0.865033
VERTEX_NORMAL -0.432517 -0.501714 0.749141
VERTEX_NORMAL -0.749141 -0.501714 0.432517
VERTEX_NORMAL -0.865033 -0.501714 0
VERTEX_NORMAL -0.749141 -0.501714 -0.432517
VERTEX_NORMAL -0.432517 -0.501714 -0.749141
VERTEX_NORMAL 0 -0.501714 -0.865033
VERTEX_NORMAL 0.432517 -0.501714 -0.749141
VERTEX_NORMAL 0.749141 -0.501714 -0.432517
VERTEX_NORMAL 1 0 0
VERTEX_NORMAL 0.866025 0 0.5
VERTEX_NORMAL 0.5 0 0.866025
VERTEX_NORMAL 0 0 1
VERTEX_NORMAL -0.5 0 0.866025
VERTEX_NORMAL -0.866025 0 0.5
VERTEX_NORMAL -1 0 0
VERTEX_NORMAL -0.866025 0 -0.5
VERTEX_NORMAL -0.5 0 -0.866025
VERTEX_NORMAL 0 0 -1
VERTEX_NORMAL 0.5 0 -0.866025
VERTEX_NORMAL 0.866025 0 -0.5
VERTEX_NORMAL 0.865033 0.501714 0
VERTEX_NORMAL 0.749141 0.501714 0.432517
VERTEX_NORMAL 0.432517 0.501714 0.749141
VERTEX_NORMAL 0 0.501714 0.865033
VERTEX_NORMAL -0.432517 0.501714 0.749141
VERTEX_NORMAL -0.749141 0.501714 0.432517
VERTEX_NORMAL -0.865033 0.501714 0
VERTEX_NORMAL -0.749141 0.501714 -0.432517
VERTEX_NORMAL -0.432517 0.501715 -0.749141
VERTEX_NORMAL 0 0.501714 -0.865033
VERTEX_NORMAL 0.432517 0.501715 -0.749141
VERTEX_NORMAL 0.749141 0.501714 -0.432517

# Face Definitions!

FACE 2,1,1 3,2,2 4,3,3
FACE 1,4,4 52,5,5 51,6,6
FACE 2,7,1 4,3,3 5,8,7
FACE 1,9,4 53,10,8 52,5,5
FACE 2,11,1 5,8,7 6,12,9
FACE 1,13,4 54,14,10 53,10,8
FACE 2,15,1 6,12,9 7,16,11
FACE 1,17,4 55,18,12 54,14,10
FACE 2,19,1 7,16,11 8,20,13
FACE 1,21,4 56,22,14 55,18,12
FACE 2,23,1 8,20,13 9,24,15
FACE 1,25,4 57,26,16 56,22,14
FACE 2,27,1 9,24,15 10,28,17
FACE 1,29,4 58,30,18 57,26,16
FACE 2,31,1 10,28,17 11,32,19
FACE 1,33,4 59,34,20 58,30,18
FACE 2,35,1 11,32,19 12,36,21
FACE 1,37,4 60,38,22 59,34,20
FACE 2,39,1 12,36,21 13,40,23
FACE 1,41,4 61,42,24 60,38,22
FACE 2,43,1 13,40,23 14,44,25
FACE 1,45,4 62,46,26 61,42,24
FACE 2,47,1 14,44,25 3,48,2
FACE 1,49,4 51,50,6 62,46,26
FACE 3,2,2 15,51,27 16,52,28
FACE 3,2,2 16,52,28 4,3,3
FACE 4,3,3 16,52,28 5,8,7
FACE 16,52,28 17,53,29 5,8,7
FACE 5,8,7 17,53,29 18,54,30
FACE 5,8,7 18,54,30 6,12,9
FACE 6,12,9 18,54,30 7,16,11
FACE 18,54,30 19,55,31 7,16,11
FACE 7,16,11 19,55,31 20,56,32
FACE 7,16,11 20,56,32 8,20,13
FACE 8,20,13 20,56,32 9,24,15
FACE 20,56,32 21,57,33 9,24,15
FACE 9,24,15 21,57,33 22,58,34
FACE 9,24,15 22,58,34 10,28,17
FACE 10,28,17 22,58,34 11,32,19
FACE 22,58,34 23,59,35 11,32,19
FACE 11,32,19 23,59,35 24,60,36
FACE 11,32,19 24,60,36 12,36,21
FACE 12,36,21 24,60,36 13,40,23
FACE 24,60,36 25,61,37 13,40,23
FACE 13,40,23 25,61,37 26,62,38
FACE 13,40,23 26,62,38 14,44,25
FACE 14,44,25 26,62,38 3,48,2
FACE 26,62,38 15,63,27 3,48,2
FACE 15,51,27 27,64,39 16,52,28
FACE 27,64,39 28,65,40 16,52,28
FACE 16,52,28 28,65,40 29,66,41
FACE 16,52,28 29,66,41 17,53,29
FACE 17,53,29 29,66,41 18,54,30
FACE 29,66,41 30,67,42 18,54,30
FACE 18,54,30 30,67,42 31,68,43
FACE 18,54,30 31,68,43 19,55,31
FACE 19,55,31 31,68,43 20,56,32
FACE 31,68,43 32,69,44 20,56,32
FACE 20,56,32 32,69,44 33,70,45
FACE 20,56,32 33,70,45 21,57,33
FACE 21,57,33 33,70,45 22,58,34
FACE 33,70,45 34,71,46 22,58,34
FACE 22,58,34 34,71,46 35,72,47
FACE 22,58,34 35,72,47 23,59,35
FACE 23,59,35 35,72,47 24,60,36
FACE 35,72,47 36,73,48 24,60,36
FACE 24,60,36 36,73,48 37,74,49
FACE 24,60,36 37,74,49 25,61,37
FACE 25,61,37 37,74,49 26,62,38
FACE 37,74,49 38,75,50 26,62,38
FACE 26,62,38 38,75,50 27,76,39
FACE 26,62,38 27,76,39 15,63,27
FACE 27,64,39 39,77,51 40,78,52
FACE 27,64,39 40,78,52 28,65,40
FACE 28,65,40 40,78,52 29,66,41
FACE 40,78,52 41,79,53 29,66,41
FACE 29,66,41 41,79,53 42,80,54
FACE 29,66,41 42,80,54 30,67,42
FACE 30,67,42 42,80,54 31,68,43
FACE 42,80,54 43,81,55 31,68,43
FACE 31,68,43 43,81,55 44,82,56
FACE 31,68,43 44,82,56 32,69,44
FACE 32,69,44 44,82,56 33,70,45
FACE 44,82,56 45,83,57 33,70,45
FACE 33,70,45 45,83,57 46,84,58
FACE 33,70,45 46,84,58 34,71,46
FACE 34,71,46 46,84,58 35,72,47
FACE 46,84,58 47,85,59 35,72,47
FACE 35,72,47 47,85,59 48,86,60
FACE 35,72,47 48,86,60 36,73,48
FACE 36,73,48 48,86,60 37,74,49
FACE 48,86,60 49,87,61 37,74,49
FACE 37,74,49 49,87,61 50,88,62
FACE 37,74,49 50,88,62 38,75,50
FACE 38,75,50 50,88,62 27,76,39
FACE 50,88,62 39,89,51 27,76,39
FACE 39,77,51 51,6,6 40,78,52
FACE 51,6,6 52,5,5 40,78,52
FACE 40,78,52 52,5,5 53,10,8
FACE 40,78,52 53,10,8 41,79,53
FACE 41,79,53 53,10,8 42,80,54
FACE 53,10,8 54,14,10 42,80,54
FACE 42,80,54 54,14,10 55,18,12
FACE 42,80,54 55,18,12 43,81,55
FACE 43,81,55 55,18,12 44,82,56
FACE 55,18,12 56,22,14 44,82,56
FACE 44,82,56 56,22,14 57,26,16
FACE 44,82,56 57,26,16 45,83,57
FACE 45,83,57 57,26,16 46,84,58
FACE 57,26,16 58,30,18 46,84,58
FACE 46,84,58 58,30,18 59,34,20
FACE 46,84,58 59,34,20 47,85,59
FACE 47,85,59 59,34,20 48,86,60
FACE 59,34,20 60,38,22 48,86,60
FACE 48,86,60 60,38,22 61,42,24
FACE 48,86,60 61,42,24 49,87,61
FACE 49,87,61 61,42,24 50,88,62
FACE 61,42,24 62,46,26 50,88,62
FACE 50,88,62 62,46,26 51,50,6
FACE 50,88,62 51,50,6 39,89,51
share|improve this question
    
What happens when you try it on a very simple model. Like a single triangle or a flat plane? Also can you post a sample of what you're importing from? –  Byte56 Dec 20 '11 at 2:19
    
The object OP posted looks like it should be a sphere. –  sarahm Dec 20 '11 at 4:48
    
By the way, OP: Unless you triangulate your model before exporting it to .obj from your modelling app, your .obj can contain faces defined by more than three points, e.g. quads. But this looks like an indexing error. OP, you do know indices in .obj go from 1...max_vertice unlike array indices 0...[max_vertice - 1] ? –  sarahm Dec 20 '11 at 4:55
    
Yep, I know it's supposed to be a sphere. Perhaps trying it on a simple object will better reveal the issue at hand. Suppose the OP tries it on a plane and only a triangle gets rendered? Then it's likely as you said, an indexing error. Which was my suspicion as well. –  Byte56 Dec 20 '11 at 5:36
2  
I might be wrong, but why are you modifying positions of vertices ? You should end with a vertex list (in the order they appear in the file), and an index list (which refer to the vertices). You don't have to reorder vertices at all (doing so would actually be an error). –  Ravachol Dec 20 '11 at 13:29
show 1 more comment

2 Answers

up vote 0 down vote accepted

Ok, I solved it...

I simply had to change the code that fills the buffers to this:

    bool isDuplicate;
    indices.clear();
    for(int i = 0; i < polygonCount; i++)
    {
        for(int i2 = 0; i2 < 3; i2++)
        {
            indices.push_back(faceDefinitions[i].vertexIndexes[i2]);
        }
    }

    modelData->indices = new unsigned long[indices.size()];
    modelData->indexCount = indices.size();

    for(int i = 0; i < vertexCount; i++)
    {
        modelData->vertices[i].position = vertexPositions[i];
    }

    for(unsigned long i = 0; i < indices.size(); i++)
    {
        modelData->indices[i]  = indices[i];
    }

So it was an indexing error in the end...

share|improve this answer
1  
You might as well mark your answer as the correct one, to make this question answered. –  Jari Komppa Feb 15 '12 at 7:55
1  
You really should accept this. Else, the Community bot will keep bumping it to get more attention. –  DeadMG Mar 16 '12 at 1:33
    
@DeadMG Heh I forgot about this, sorry –  smoth190 Mar 16 '12 at 18:50
add comment

Here are two little c++ functions from my project. I tried to make them readable without knowledge of my code. Just know the ObjImporter class is a container for the information read from the obj file.

They essentially use a map to store every unique vertex generated by the face list. In order to do this, a hash value has to be generated from the position, texture, and normal indices. My implementation just uses two random constants that work for my obj files. If your files are larger, there is a chance that you may get hash collisions which will place incorrect vertices in your index buffer so adjust them as needed. The hash key is mapped to the index of the vertex in the vertex buffer.

Once you know how to hash your vertices from the indices, you can use this to check if a vertex already exist in your vertex buffer. If it does then you have it's index into the buffer from the map and if it isn't you know that you can append the vertex to the buffers.

The second function is dependent upon your vertex drawing type. My implementation below assumes you are using triangle list. (Two triangles for each quad)

// Description -
// Given an index to a vertex, that vertex is then checked using a map to determine if
// it is in the vertex buffer already. If it is then it's index is just appended to the index
// buffer, if it isn't than the vertex is appended to the map and both the index and vertex buffers
// Parameters -
// _vBuffer - Vector containing the vertex buffer you are building.
// _iBuffer - Vector containing the index buffer you are building.
// _vMap    - Map that uses a hash value to determine if a vertex is already in the buffer. <Key,Value> = <HashValue, vertexBufferIndex>
// _faceIndex   - Index into an array of faces containing position, normal, and texture value indices. Face list provided by obj file.
// _vertexIndex - Index into the face object.
// _import - Container object for the face and vertex array from the obj file. Class was responsible for reading and storing the obj file. 
void ImportVertex(std::vector<VERTEX> &_vBuffer, std::vector<unsigned int> &_iBuffer, std::map<unsigned int, unsigned int> &_vMap,
    const unsigned int _faceIndex, const unsigned int _vertexIndex, const ObjImporter &_import) {

    // Vertex that will be pushed onto the vertex buffer vector.
    static VERTEX _vTemp;

    // Get the indices from the face for the vertex.
    int _vPosIndex = _import.GetFaceIndexPtr(_faceIndex)->GetVertexPositionIndex(_vertexIndex);
    int _vNorIndex = _import.GetFaceIndexPtr(_faceIndex)->GetVertexNormalIndex(_vertexIndex);
    int _vTexIndex = _import.GetFaceIndexPtr(_faceIndex)->GetVertexTextureIndex(_vertexIndex);

    // Initially build the key from just the position.
    unsigned int _vKey = _vPosIndex;

    // Set the position using the index from the face.
    _vTemp.SetPosition(_import.GetVertexPositionPtr(_vPosIndex));

    // If you have a normal index and value.
    // My importer fills the indices with -1 if they don't exist.
    if (_vNorIndex >= 0) {
        _vTemp.SetNormal(_import.GetVertexNormalPtr(_vNorIndex));
        // Append the key value multiplied by a constant.
        // This constant is dependent upon the size of your obj file and it must be unique for
        // each different vertex. 
        _vKey += _vNorIndex * 1000;
    } else _vTemp.SetNormal(0.0f, 0.0f, 0.0f);

    if (_vTexIndex >= 0) {
        _vTemp.SetTexture(_import.GetVertexTexturePtr(_vTexIndex));
        // Append the key value with the texture index scaled by
        // a higher constant.
        _vKey += _vTexIndex * 1000000;
    } else _vTemp.SetTexture(0.0f, 0.0f, 0.0f);

    // Check to see if the map already contains the key generated.
    if (_vMap.count(_vKey) == 0) {
        // Since the vertex is new it will be at the end of the vector.
        // Map it's key to it's position.
        _vMap[_vKey] = _vBuffer.size();
        // Push back the vertex onto the vertex buffer vector.
        _iBuffer.push_back(_vBuffer.size());
        // Push back the index of this vertex onto the index buffer.
        _vBuffer.push_back(_vTemp);
    // If the vertex is already in the map and hence in the vertex buffer,
    // then just add it's index to the index buffer.                    
    } else _iBuffer.push_back(_vMap[_vKey]);
}

// Description -
// Given an obj file, the faces are iterated through and used to build a triangle list
// vertex buffer.
void Import(const ObjImporter &_import) {
    // Vectors are used to build the index and vertex buffers
    std::vector<RENDEROBJECT_DEFAULT_VERTEX>  _vAggregateBuffer; 
    std::vector<unsigned int> _iAggregateBuffer;
    std::map<unsigned int, unsigned int> _vMap;

    // Iterate through every face in the obj file.
    for (unsigned int i = 0; i < _import.GetFaceCount(); ++i) {
        // If it's a triangle.
        if (_import.GetFaceIndexPtr(i)->GetVertexCount() == 3)
            // Grab each vertex
            for (int k = 0; k < 3; ++k)
                ImportVertex(_vAggregateBuffer, _iAggregateBuffer, _vMap, i, k, _import);                   
        // Else assumes a quad was provided.
        else {
            // Grab each vertex. This is dependent upon vertex drawing type.
            // The order below assumes a triangle list.
            ImportVertex(_vAggregateBuffer, _iAggregateBuffer, _vMap, i, 0, _import);
            ImportVertex(_vAggregateBuffer, _iAggregateBuffer, _vMap, i, 1, _import);
            ImportVertex(_vAggregateBuffer, _iAggregateBuffer, _vMap, i, 2, _import);
            ImportVertex(_vAggregateBuffer, _iAggregateBuffer, _vMap, i, 2, _import);
            ImportVertex(_vAggregateBuffer, _iAggregateBuffer, _vMap, i, 3, _import);
            ImportVertex(_vAggregateBuffer, _iAggregateBuffer, _vMap, i, 0, _import);               
        }
    }
}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.