2

I'm loading a .obj model of a cube currently using those flags :

const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals | aiProcess_JoinIdenticalVertices);

The model only contains 8 vertices (each sommet of the cube) and thus no duplicate vertices to specify assimp to draw all of the triangles needed. As a result, I only get 3 triangles of my box drawn.

I believe this is because I use :

glDrawArrays(GL_TRIANGLES, 0, vertices.size());

Where vertices.size() is equal to 22 (it's the return of mesh->mNumVertices).

I don't get this 22, to me it should either be 8 or 6*2*3 = 36 (6 faces with 2 triangles each). Can anyone explain where it comes from ?

I though of using GL_TRIANGLE_STRIP but the vertices are not in the right order (I don't even know if they can be). I get more triangles but not the right ones.

So my main question is : is there a flag I could add to ReadFile -or something else- to write a copy of the vertices for each triangle to be drawn in the .obj file.

PS : I exported the Wavefront model from Blender, maybe it's on Blender that I can set something to export redondant vertices.

My .obj file : o 1

  # Vertex list

  v -0.5 -0.5 0.5
  v -0.5 -0.5 -0.5
  v -0.5 0.5 -0.5
  v -0.5 0.5 0.5
  v 0.5 -0.5 0.5
  v 0.5 -0.5 -0.5
  v 0.5 0.5 -0.5
  v 0.5 0.5 0.5

  usemtl Default
  f 4 3 2 1
  f 2 6 5 1
  f 3 7 6 2
  f 8 7 3 4
  f 5 8 4 1
  f 6 7 8 5

EDIT : How I set up the mesh with Qt OpenGL types (and now with EBO):

   void setupMesh(QOpenGLShaderProgram* program)
    {
    // Create Vertex Array Object
    if (!VAO->isCreated()) {
        VAO->create();
    }
    VAO->bind();

    VBO.create();
    VBO.bind();

    VBO.setUsagePattern(QOpenGLBuffer::StaticDraw);

    construct_sg_vertex();

    VBO.allocate(this->m_vec.constData(), this->m_vec.size() * sizeof(m_vec.at(0)));


    EBO.create();
    EBO.bind(); //glBindBuffer(GL_ARRAY_BUFFER, ebo);
    EBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
    EBO.allocate(indices.data(),indices.size()*sizeof(GLuint)); 

    // 0 : positions
    program->enableAttributeArray(0);
    program->setAttributeBuffer(0, GL_FLOAT, Vertex::positionOffset(), Vertex::PositionTupleSize, Vertex::stride());

    //1: colors
    program->enableAttributeArray(1);
    program->setAttributeBuffer(1, GL_FLOAT, Vertex::colorOffset(), Vertex::ColorTupleSize, Vertex::stride());

    VBO.release();
    EBO.release();
}

private:

QOpenGLBuffer VBO ;
QOpenGLVertexArrayObject* VAO = new QOpenGLVertexArrayObject();
QOpenGLBuffer EBO ; //New Element Buffer
};

With this added indices buffer I changed the way I draw to : VAO->bind() ; glDrawElements(GL_TRIANGLES, indices.size(),GL_UNSIGNED_INT,0);

As a result, nothing is rendered at all...

Lauriane.C
  • 100
  • 10
  • You are leaving out some essential information here, e.g how do you setup your buffer (glBindBuffer, glEnableVertexAttribArray, glVertexAttribPointer). What does your .obj look like? Is backface culling enabled? – Andreas Sep 01 '16 at 10:39
  • Backface culling is enabled. I'm using Qt for shaders and VAO actually. I'm editing so that you can see how I set them up. – Lauriane.C Sep 01 '16 at 11:27
  • Only taking the vertices into account is not enough. You also need the faces to know how the vertices are assembled. – BDL Sep 01 '16 at 12:07
  • Yes but the f x y z t does the assembling in the obj file I believe, doesn't it ? – Lauriane.C Sep 01 '16 at 12:09
  • Yes, this line is for assembly. But you don't take that into account. This information is stored in `mFaces`. You have to build a index buffer from that. – BDL Sep 01 '16 at 12:20
  • Ok but if I build and index buffer and then use glDrawElements() to render my model, I believe this code won't work anymode for my main model which is not the cube but a drone that is renderer fine now and does not include faces. I'm saying that because at first I used an index buffer and then had to delete this step. – Lauriane.C Sep 01 '16 at 12:37
  • What do you mean by: "Does not include faces?" When the obj file does not have face information, then it is simply incomplete. Nevertheless, for this example you will need an index buffer. – BDL Sep 01 '16 at 12:50
  • When you call `EBO.release()` before unbinding the vao, the index buffer binding gets removed from the vao. – BDL Sep 01 '16 at 16:05
  • Ok I deleted EBO but still no result. I don't get it because my indices vector is filled with 36 good values, so is my vertices vector that is filled with relevant Vertex_Struct values (only position and color for now). Is there a debug method I could use to catch what I'm doing wrong ? – Lauriane.C Sep 02 '16 at 09:10

1 Answers1

1

From the flags you provide I would expect 24 vertices to be generated: A cube consists of 6 faces, each composed of 2 triangles. When now normals are generated (as requested by aiProcess_GenNormals), each side of the cube has 4 unique vertices. Note, that vertex refers here to a combination of position and normal. 4 unique vertices and six sides are in total 24 vertices.

Now to the drawing problem: Since aiProcess_JoinIdenticalVertices is request, assimp will join together all identical vertices, leaving only these unique vertices in the aiMesh->mVertices array. Alone, this information is not sufficient to draw anything. What is needed in addition, is the information about how these vertices have to be assembled in triangles, which is given by aiMesh->mFaces. From these faces, one either has to generate an index buffer, or assembly the vertices into a new array by duplicating them in the correct order. The next code shows how the data for the index buffer can be constructed:

std::vector<unsigned int> indices;
indices.reserve(aimesh->mNumFaces * 3);
for (unsigned int fid = 0; fid < aimesh->mNumFaces; fid++)
{
    auto& face = aimesh->mFaces[fid];
    for (size_t iid = 0; iid < 3; iid++)
        indices.push_back(face.mIndices[iid]);
}

The indices data can than be used by OpenGL.

BDL
  • 21,052
  • 22
  • 49
  • 55