Assimp loader with a cube of 8 vertices - opengl

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...

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.

Related

OpenGL Index Buffer Object element order incorrectly drawn

Notice how my program draws a single triangle, but instead what I am trying to express in code is to draw a square. My tri_indicies index buffer object I believe correctly orders these elements such that a square should be drawn, but when executing the program the draw order I have defined in the tri_indicies is not reflected in the window. Not sure if the error is rooted in tri_indicies, despite my changes to the element order not effecting my rendered output I want to believe it is here, but is it most likely somewhere else.
My program uses abstractions to notably the VertexBuffer, VertexArray, and IndexBuffer all detailed below.
const int buffer_object_size = 8;
const int index_buffer_object_size = 6;
float tri_verticies[buffer_object_size] = {
-0.7f, -0.7f, // 0
0.7f, -0.7f, // 1
0.7f, 0.7f, // 2
-0.7f, 0.7f // 3
};
unsigned int tri_indicies[index_buffer_object_size] = {
0, 1, 2,
2, 3, 0
};
VertexArray vertexArray;
VertexBuffer vertexBuffer(tri_verticies, buffer_object_size * sizeof(float)); // no call vertexBuffer.bind() constructor does it
VertexBufferLayout vertexBufferLayout;
vertexBufferLayout.push<float>(3);
vertexArray.add_buffer(vertexBuffer, vertexBufferLayout);
IndexBuffer indexBuffer(tri_indicies, index_buffer_object_size);
ShaderManager shaderManager;
ShaderSource shaderSource = shaderManager.parse_shader("BasicUniform.shader"); // ensure debug working dir is relative to $(ProjectDir)
unsigned int shader = shaderManager.create_shader(shaderSource.vertex_source, shaderSource.fragment_source);
MyGLCall(glUseProgram(shader));
Later in main I have a loop that is supposed to draw my square to the screen and fade the blue color value between 1.0f and 0.0f.
while (!glfwWindowShouldClose(window))
{
MyGLCall(glClear(GL_COLOR_BUFFER_BIT));
vertexArray.bind();
indexBuffer.bind();
MyGLCall(glDrawElements(GL_TRIANGLES, index_buffer_object_size, GL_UNSIGNED_INT, nullptr)); // nullptr since we bind buffers using glGenBuffers
if (blue > 1.0f) {
increment_color = -0.05f;
}
else if (blue < 0.0f) {
increment_color = 0.05f;
}
blue += increment_color;
glfwSwapBuffers(window);
glfwPollEvents();
}
The array tri_verticies consists of vertex coordinates with 2 components (x, y). So the tuple size for the specification of the array of generic vertex attribute data has to be 2 rather than 3:
vertexBufferLayout.push<float>(3);
vertexBufferLayout.push<float>(2);
What you actually do, is to specify an array with the following coordinates:
-0.7, -0.7, 0.7 // 0
-0.7, 0.7, 0.7 // 1
???, ???, ??? // 2
???, ???, ??? // 3
In general out-of-bound access to buffer objects has undefined results.
See OpenGL 4.6 API Core Profile Specification - 6.4 Effects of Accessing Outside Buffer Bounds, page 79

How to convert large arrays of quad primitives to triangle primitives?

I have an existing system, which provides 3D meshes. The provided data are an array of vertex coordinates with 3 components (x, y, z) and an index list.
The issue is that the index list is a consecutive array of quad primitives.
The system has to be make runnable with a core profile OpenGL Context first, and later with OpenGL ES 3.x, too.
I know that all the quads have all the same winding order (counter clockwise), but I have no further information about the quads. I don't know anything about their relation or adjacencies.
Since I want to use core profile Context for rendering, I cannot use the GL_QUAD primitive type. I have to convert the quads to triangles.
Of course the array of quad indices can easily be converted to an array of triangle indices:
std::vector<unsigned int> triangles;
triangles.reserve( no_of_indices * 6 / 4 );
for ( int i = 0; i < no_of_indices; i += 4 )
{
int tri[] = { quad[i], quad[i+1], quad[i+2], quad[i], quad[i+2], quad[i+3] };
triangles.insert(triangles.end(), tri, tri+6 );
}
If that has to be done only once, then that would be the solution. But the mesh data are not static. The data can change dynamically.
The data do not change continuously and every time, but the data change unpredictably and randomly.
An other simple solution would be to create an vertex array object, which directly refers to an element array buffer with the quads and draw them in a loop with the GL_TRIANGLE_FAN primitive type:
for ( int i = 0; i < no_of_indices; i += 4 )
glDrawElements( GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, (void*)(sizeof(unsigned int) * 4) );
But I hope there is a better solution. I'm searching for a possibility to draw the quads with one single draw call, or to transform the quads to triangles on the GPU.
If that has to be done only once, then that would be the solution. But the mesh data are not static.
The mesh data may be dynamic, but the topology of that list is the same. Every 4 vertices is a quad, so every 4 vertices represents the triangles (0, 1, 2) and (0, 2, 3).
So you can build an arbitrarily large static index buffer containing an ever increasing series of these numbers (0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, etc). You can even use baseVertex rendering to offset them to render different serieses of quads using the same index buffer.
My suggestion would be to make the index buffer use GLushort as the index type. This way, your index data only takes up 12 bytes per quad. Using shorts gives you a limit of 16384 quads in a single drawing command, but you can reuse the same index buffer to draw multiple serieses of quads with baseVertex rendering:
constexpr GLushort batchSize = 16384;
constexpr unsigned int vertsPerQuad = 6;
void drawQuads(GLuint quadCount)
{
//Assume VAO is set up.
int baseVertex = 0;
while(quadCount > batchSize)
{
glDrawElementsBaseVertex(GL_TRIANGLES​, batchSize * vertsPerQuad, GL_UNSIGNED_SHORT, 0, baseVertex​ * 4);
baseVertex += batchSize;
quadCount -= batchSize;
}
glDrawElementsBaseVertex(GL_TRIANGLES​, quadCount * vertsPerQuad, GL_UNSIGNED_SHORT, 0, baseVertex​ * 4);
}
If you want slightly less index data, you can use primitive restart indices. This allows you to designate an index to mean "restart the primitive". This allows you to use a GL_TRIANGLE_STRIP primitive and break the primitive up into pieces while still only having a single draw call. So instead of 6 indices per quad, you have 5, with the 5th being the restart index. So now your GLushort indices only take up 10 bytes per quad. However, the batchSize now must be 16383, since the index 0xFFFF is reserved for restarting. And vertsPerQuad must be 5.
Of course, baseVertex rendering works just fine with primitive restarting, so the above code works too.
First I want to mention that this is not a question which I want to answer myself, but I want to provide my current solution to this issue.
This means, that I'm still looking for "the" solution, the perfectly acceptable solution.
In my solution, I decided to use Tessellation. I draw patches with a size of 4:
glPatchParameteri( GL_PATCH_VERTICES, self.__patch_vertices )
glDrawElements( GL_PATCHES, no_of_indices, GL_UNSIGNED_INT, 0 )
The Tessellation Control Shader has a default behavior. The patch data is passed directly from the Vertex Shader invocations to the tessellation primitive generation. Because of that it can be omitted completely.
The Tessellation Evaluation Shader uses a quadrilateral patch (quads) to create 2 triangles:
#version 450
layout(quads, ccw) in;
in TInOut
{
vec3 pos;
} inData[];
out TInOut
{
vec3 pos;
} outData;
uniform mat4 u_projectionMat44;
void main()
{
const int inx_map[4] = int[4](0, 1, 3, 2);
float i_quad = dot( vec2(1.0, 2.0), gl_TessCoord.xy );
int inx = inx_map[int(round(i_quad))];
outData.pos = inData[inx].pos;
gl_Position = u_projectionMat44 * vec4( outData.pos, 1.0 );
}
An alternative solution would be to use a Geometry Shader. The input primitive type lines_adjacency provides 4 vertices, which can be mapped to 2 triangles (triangle_strip). Of course this seems to be a hack, since a lines adjacency is something completely different than a quad, but it works anyway.
glDrawElements( GL_LINES_ADJACENCY, no_of_indices, GL_UNSIGNED_INT, 0 );
Geometry Shader:
#version 450
layout( lines_adjacency ) in;
layout( triangle_strip, max_vertices = 4 ) out;
in TInOut
{
vec3 pos;
} inData[];
out TInOut
{
vec3 col;
} outData;
uniform mat4 u_projectionMat44;
void main()
{
const int inx_map[4] = int[4](0, 1, 3, 2);
for ( int i=0; i < 4; ++i )
{
outData.pos = inData[inx_map[i]].pos;
gl_Position = u_projectionMat44 * vec4( outData.pos, 1.0 );
EmitVertex();
}
EndPrimitive();
}
An improvement would be to use Transform Feedback to capture new buffers, containing triangle primitives.

How to correctly populate vertex array

I am confused with how to populate my vertex array for it to be correctly drawn. The OpenGL code that I am using is:
float vertices[size];
//Here I have a method to populate the array with my values from a 2D matrix
glGenVertexArrays(1, &vaoID[0]); // Create our Vertex Array Object
glBindVertexArray(vaoID[0]); // Bind our Vertex Array Object so we can use it
glGenBuffers(1, vboID); // Generate our Vertex Buffer Object
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // Bind our Vertex Buffer Object
glBufferData(GL_ARRAY_BUFFER, (size) * sizeof(GLfloat), vertices, GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // Set up our vertex attributes pointer
glEnableVertexAttribArray(0); // Disable our Vertex Array Object
glBindVertexArray(0); // Disable our Vertex Buffer Object
glBindVertexArray(vaoID[0]); // Bind our Vertex Array Object
glDrawArrays(GL_TRIANGLES, 0, size/3); // Draw
glBindVertexArray(0); // Unbind our Vertex Array Object
Hopefully the image makes this easier to understand. In image 'A' the 3x3 matrix on the left shows what I am currently getting when I draw triangles, the matrix on the right is what I am trying to achieve.
Currently when I create the array of vertices to draw from, I populate it in the order shown in image 'B'. I add values to the array as I work along a row, then step down a column and repeat. So for example:
vertexArray[0] = matrixElement[0].x
vertexArray[1] = matrixElement[0].y
vertexArray[2] = matrixElement[0].z
vertexArray[3] = matrixElement[1].x
vertexArray[4] = matrixElement[1].y
vertexArray[5] = matrixElement[1].z
This order of input into the vertexArray gives results that can be seen in image 'C', where the wrong triangles are created.
My question is: what is the sensible way of populating a vertex array, in an order that is going to create triangles on a large matrix of vertices in a way that looks like the right hand diagram in image 'A'.
If you want to avoid any redundancy, and draw the whole mesh with a single draw call, one option is to use a combination of:
GL_TRIANGLE_STRIP as the primitive type.
Indexed drawing.
Primitive restart (requires OpenGL 3.1 or later).
The primitive restart feature is needed because you can't easily represent this mesh with a single triangle strip. Using the numbering from your sketch, you can for example describe the topology with two triangle strips using these two index sequences:
0 3 1 4 2 5
3 6 4 7 5 8
Setting up and enabling primitive restart can be done with these calls:
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(0xFFFF);
You can chose the index, but the common policy (and only option supported in OpenGL ES) is to use the largest possible value, which is 0xFFFF if you use GLushort as the type of the indices.
Once primitive restart is enabled, the "special" index will then start a new triangle strip. So the two triangle strips above can now be given by a single index sequence:
0 3 1 4 2 5 0xFFFF 3 6 4 7 5 8
You should be able to find plenty of examples that show how to set up an index buffer (you can recognize them by their use of GL_ELEMENT_ARRAY_BUFFER), so I'll skip that part. The draw call is then:
glDrawElements(GL_TRIANGLE_STRIP, 0, 13, GL_UNSIGNED_SHORT, 0);
where 13 is the number of indices used.
There are alternatives to using primitive restart:
Use repeated vertices. This was a common trick before primitive restart was widely available. I wouldn't recommend it anymore. Just for illustration, the index sequence in this case would be:
0 3 1 4 2 5 5 3 3 6 4 7 5 8
The two repeated indices will result in a degenerate (0 pixel) triangle that "connects" the two triangle strips.
Use glMultiDrawElements() to draw multiple triangle strips with a single draw call.
You're using GL_TRIANGLES and glDrawArrays() so you'll need to append 3 vertexes for each triangle you want:
// first vertex
vertexArray.push_back( matrixElement[0].x );
vertexArray.push_back( matrixElement[0].y );
vertexArray.push_back( matrixElement[0].z );
// second vertex
vertexArray.push_back( matrixElement[3].x );
vertexArray.push_back( matrixElement[3].y );
vertexArray.push_back( matrixElement[3].z );
// third vertex
vertexArray.push_back( matrixElement[1].x );
vertexArray.push_back( matrixElement[1].y );
vertexArray.push_back( matrixElement[1].z );
...
For what you are looking for, GL_TRIANGLE_STRIP would be a better choice than GL_TRIANGLES. For an example on how to arrange vertices, see here

How Can I use glClipPlane more than 6 times in OPENGL?

I have a Sphere . I would like to clip some planes like below picture. I need more than 10 clipping plane but maximum glClipPlane limit is 6. How can I solve this problem.
My Sample Code below;
double[] eqn = { 0.0, 1.0, 0.0, 0.72};
double[] eqn2 = { -1.0, 0.0, -0.5, 0.80 };
double[] eqnK = { 0.0, 0.0, 1.0, 0.40 };
/* */
Gl.glClipPlane(Gl.GL_CLIP_PLANE0, eqn);
Gl.glEnable(Gl.GL_CLIP_PLANE0);
/* */
Gl.glClipPlane(Gl.GL_CLIP_PLANE1, eqn2);
Gl.glEnable(Gl.GL_CLIP_PLANE1);
Gl.glClipPlane(Gl.GL_CLIP_PLANE2, eqnK);
Gl.glEnable(Gl.GL_CLIP_PLANE2);
//// draw sphere
Gl.glColor3f(0.5f, .5f, 0.5f);
Glu.gluSphere(quadratic, 0.8f, 50, 50);
Glu.gluDeleteQuadric(quadratic);
Gl.glDisable(Gl.GL_CLIP_PLANE0);
Gl.glDisable(Gl.GL_CLIP_PLANE1);
Gl.glDisable(Gl.GL_CLIP_PLANE2);
You should consider multi-pass rendering and the stencil buffer.
Say you need 10 user clip-planes and you are limited to 6, you can setup the first 6, render the scene into the stencil buffer and then do a second pass with the remaining 4 clip planes. You would then use the stencil buffer to reject parts of the screen that were clipped on the prior pass. So this way you get the effect of 10 user clip planes when the implementation only supports 6.
// In this example you want 10 clip planes but you can only do 6 per-pass,
// so you need 1 extra pass.
const int num_extra_clip_passes = 1;
glClear (GL_STENCIL_BUFFER_BIT);
// Disable color and depth writes for the extra clipping passes
glDepthMask (GL_FALSE);
glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
// Increment the stencil buffer value by 1 for every part of the sphere
// that is not clipped.
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
glStencilFunc (GL_ALWAYS, 1, 0xFFFF);
// Setup Clip Planes: 0 through 5
// Draw Sphere
// Reject any part of the sphere that did not pass _all_ of the clipping passes
glStencilFunc (GL_EQUAL, num_extra_clip_passes, 0xFFFF);
// Re-enable color and depth writes
glDepthMask (GL_TRUE);
glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Setup Leftover Clip Planes
// DrawSphere
It is not perfect, it is quite fill-rate intensive and limits you to a total of 1536 clip planes (given an 8-bit stencil buffer), but it will get the job done without resorting to features present only in GLSL 130+ (namely gl_ClipDistance []).
You can just reuse "Gl.glEnable(Gl.GL_CLIP_PLANE1);" because you was disabled it later ...

How does a 3ds Max store normals in a Mesh class?

I'm writing a 3ds Max exporter and I need to get mesh normals computed by the application. I have a Mesh instance and I can get vertex positions, UVs, colors, etc. but the normals seem to be not so easy... BTW: I know how to compute face/vertex normals, but I need the exact data from 3ds Max, with smoothing groups and material index taken into account.
For this case I've created a simple box and looked into resulting Mesh instance after calling the buildNormals() method. Here is what I've found after some debugging and digging into documentation, all mentioned data are inside of a Mesh class:
I have simple vertex/face numbers:
int numVerts = 8;
int numFaces = 12;
And verices/faces data:
Point3* verts; // contains 8 vectors with positions (x,y,z)
Face* faces; // contains 12 faces, each with 3 indexes into *verts - [0-7]
So far so good... Now I have computed normals data:
int normalCount = 24; // 6 sides * 4 vertices each, no reuse of normal data
Point3* gfxNormals; // contains 24 normal vectors
At this point I have almost all the data I need but I can't assign one normal to one rendered vertex. There is one more interesting table:
Tab<ulong> norInd; // contains 8 indexes - {0,3,6,9,12,15,18,21}
It seems to be somehow connected to previous fields (I have 8 verts, each has 3 normals) but I have no idea how to use it in more complex situations.
What I need to get:
I need an index of normal for particular vertex in particular face, or in other words - if I wanted to render 0'th face in OpenGl I could use:
glVertex3f( verts[ faces[0].v[0] ].x, verts[ faces[0].v[0] ].y, verts[ faces[0].v[0] ].z );
glVertex3f( verts[ faces[0].v[1] ].x, verts[ faces[0].v[1] ].y, verts[ faces[0].v[1] ].z );
glVertex3f( verts[ faces[0].v[2] ].x, verts[ faces[0].v[2] ].y, verts[ faces[0].v[2] ].z );
But what to pass to glNormal3f()?
The way I get them is this:
for(int f = 0; f < mesh->numFaces; ++f)
{
Point3 normal;
Face* face = &mesh->faces[f];
for(int v = 0; v < 3; ++v)
{
DWORD vi = face->v[v];
Point3 normal;
if(mesh->getRVertPtr(vi))
normal = GetVertexNormal(mesh, f, mesh->getRVertPtr(vi));
else
normal = Point3(0, 0, 1);
fprintf(file, "\t\t\t<normal x=\"%f\" y=\"%f\" z=\"%f\" />\n", normal.x, normal.y, normal.z);
}
}