Umm.. I wrote this code to print mesh (var m), and it's running well
glBegin(GL_TRIANGLES);
for (unsigned i : m.vtIndex)
{
const aiVector3D *pv = &m.pMesh->mVertices[i];
const aiVector3D *pvn = &m.pMesh->mNormals[i];
glNormal3fv((const GLfloat *)pvn);
glVertex3fv((const GLfloat *)pv);
}
glEnd();
And here is other one
glVertexPointer(3, GL_FLOAT, 0, m.pMesh->mVertices);
glNormalPointer(GL_FLOAT, 0, m.pMesh->mNormals);
glDrawElements(GL_TRIANGLES, m.vtIndex.size(), GL_UNSIGNED_INT, &m.vtIndex[0]);
But second one occured access violation
Could you give me an opinion?
You are using deprecated OpenGL in this example and using client memory to store vertex data. In deprecated OpenGL, you need to enable the appropriate client states:
glEnableClientState (GL_VERTEX_ARRAY);
glEnableClientState (GL_NORMAL_ARRAY);
If you add this to your code before your draw call, it ought to fix your crash.
You can safely leave GL_VERTEX_ARRAY enabled for the entire time your program runs, but you may need to enable/disable other arrays such as GL_NORMAL_ARRAY depending on which vertex pointers your meshes actually use.
I figure out.
glEnableClientState(GL_INDEX_ARRAY); // Oops!!
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
haha....
Related
I am trying to draw a simple triangle and set the buffers as follows;
triangle t;
point3f vertices[] = { t.p1(), t.p2(), t.p3() };
GLushort indices[] = { 0, 1, 2 };
gl_vertex_array vao{ 3 };
vao.bind_vertex_array();
gl_vertex_buffer position_vbo{ buffer_type::array_buf };
position_vbo.bind_vertex_buffer();
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0],
GL_STATIC_DRAW);
position_vbo.unbind_vertex_buffer();
gl_vertex_buffer index_vbo{ buffer_type::element_array_buf };
index_vbo.bind_vertex_buffer();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices[0],
GL_STATIC_DRAW);
index_vbo.unbind_vertex_buffer();
vao.unbind_vertex_array();
Setting up of buffers and VAOs are fine I think, I checked with glGetError at each stage and everything seems to be working. On my render function, I do the following:
glClearColor(0.4f, 0.3f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
o.vao.bind_vertex_array();
o.sp.use_program();
GLenum error = glGetError();
assert(error == GL_NO_ERROR);
//glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
error = glGetError();
assert(error == GL_NO_ERROR);
o.sp.unuse_program();
o.vao.unbind_vertex_array();
This rendering call with glDrawArrays works just fine but when I try to render with glDrawElements, I get an exception thrown. Moreover, this is hard exception. I can't go to the next line to see the error code. I didn't know that OpenGl calls could throw. I am stuck here. What might be the problem?
Here is a similar discussion
nvoglv32.dll throws the exception
The problem lies in the VAO setup code. The index buffer gets unbound before the VAO is unbound:
index_vbo.unbind_vertex_buffer();
vao.unbind_vertex_array();
Since the VAO always stores the last state of the bound GL_ELEMENT_ARRAY_BUFFER, this is effectively unbinding the index buffer. The exception happens then because you try to read from a not bound index buffer. The solution should be to exchange these two lines and unbind the VAO first:
vao.unbind_vertex_array();
index_vbo.unbind_vertex_buffer();
As Nicol Bolas mentioned in the comments: You can actually leave away the unbinding of the element buffer completely. When the VAO gets unbound, there is no element buffer bound anymore.
I implemented simple OBJ-parser and using parallelepiped as example model. I added rotation feature based on quaternions. Next goal - adding light. I parsed normals and decided drawing normals as "debug" feature (for further better understanding light). But I stuck after that:
Here my parallelepiped with small rotation.
Look at the right further bottom vertice and normal. I can't understand why it rendered through my parallelepiped. It should be hidden.
I use depth buffer (because without it parallelepiped looking weird while I rotate it). So I initialize it:
glGenRenderbuffers(1, &_depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _frameBufferWidth, _frameBufferHeight);
and enable it:
glEnable(GL_DEPTH_TEST);
I generate 4 VBOs: vertex and index buffers for parallelepiped, vertex and index buffers for lines(normals).
I use one simple shader for both models(if it will be needed - I can add code later but I think everything is ok with it).
At first I draw parallelepiped, after that - normals.
Here my code:
// _field variable - parallelepiped
glClearColor(0.3, 0.3, 0.4, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int vertexSize = Vertex::size();
int colorSize = Color::size();
int normalSize = Normal::size();
int totalSize = vertexSize + colorSize + normalSize;
GLvoid *offset = (GLvoid *)(sizeof(Vertex));
glBindBuffer(GL_ARRAY_BUFFER, _geomBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indicesBufferID);
glVertexAttribPointer(_shaderAtributePosition, vertexSize, GL_FLOAT, GL_FALSE, sizeof(Vertex::oneElement()) * totalSize, 0);
glVertexAttribPointer(_shaderAttributeColor, colorSize, GL_FLOAT, GL_FALSE, sizeof(Color::oneElement()) * totalSize, offset);
glDrawElements(GL_TRIANGLES, _field->getIndicesCount(), GL_UNSIGNED_SHORT, 0);
#ifdef NORMALS_DEBUG_DRAWING
glBindBuffer(GL_ARRAY_BUFFER, _normalGeomBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _normalIndexBufferID);
totalSize = vertexSize + colorSize;
glVertexAttribPointer(_shaderAtributePosition, vertexSize, GL_FLOAT, GL_FALSE, sizeof(Vertex::oneElement()) * totalSize, 0);
glVertexAttribPointer(_shaderAttributeColor, colorSize, GL_FLOAT, GL_FALSE, sizeof(Color::oneElement()) * totalSize, offset);
glDrawElements(GL_LINES, 2 * _field->getVertexCount(), GL_UNSIGNED_SHORT, 0);
#endif
I understand for example if I merge this two draw calls in one (And use same VBOs for parallelepiped and normals - everything will be fine).
But it will be uncomfortable because I use lines and triangles.
There are should be another way for fixing Z order. I can't believe that complex scene (for example sky, land and buildings) draws via one draw call.
So, what I am missing?
Thanks in advance.
If you are rendering into a window surface you need to request depth as part of your EGL configuration request. The depth renderbuffer you have allocated is only useful if you attach it to a Framebuffer Object (FBO) for off-screen rendering.
I have a model i want to render with glMultiDrawElements. Preparing the data and rendering it using simple vectors works fine, but fails when i use vertex buffers. Apparently i make some kind of mistake when calculating the buffer offsets. First the working code:
I a first step i prepare the data for later use (contains pseudo code to make it easier to read):
for(each face in the model){
const Face &f = *face;
drawSizes.push_back(3);
for(int i=0;i<f.numberVertices;++i){
const Vertex &v = vertices[f.vertices[i]]]; // points to vertex array
vertexArray.push_back(v.x);
indexArray.push_back(vertexArray.size() - 1);
vertexArray.push_back(v.y);
indexArray.push_back(vertexArray.size() - 1);
vertexArray.push_back(v.z);
indexArray.push_back(vertexArray.size() - 1);
normalArray.push_back(f.normalx);
normalArray.push_back(f.normaly);
normalArray.push_back(f.normalz);
}
}
int counter = 0;
for(each face in the model){
vertexIndexStart.push_back(&indexArray[counter*3]);
offsetIndexArray.push_back(static_cast<void*>(0) + counter*3);
counter++;
}
drawSizes is a vector<Glint>
vertexArray is a vector<GLfloat>
indexArray is a vector<GLint>
vertexIndexStart is a vector<Glvoid *>
offsetIndexArray is a vector<GLvoid *>
I now draw this with the glMultiDrawElements-function in the following way:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3,GL_FLOAT,3*sizeof(GLfloat),&vertexArray[0]);
glNormalPointer(GL_FLOAT,0,&normalArray[0]);
glMultiDrawElements(GL_POLYGON,&drawSizes[0],GL_UNSIGNED_INT,&vertexIndexStart[0],vertexIndexStart.size());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
and it draws the model just as it should, altough the performance is not that much better than the immediate mode.
When i now try to buffer the created data and render the model using buffers it apparently does not work. Again in a first step i preprocess the already processed data:
glGenBuffers(2,buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertexArray),&vertexArray[0],GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexArray),&indexArray[0],GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
buffers is a GLuint[]
Then i try to render the data:
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glVertexPointer(3,GL_FLOAT,3*sizeof(GLfloat),0);
glMultiDrawElements(GL_POLYGON,&drawSizes[0],GL_UNSIGNED_INT,&offsetIndexArray[0],vertexIndexStart.size());
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
glDisableClientState(GL_VERTEX_ARRAY);
which leads to an empty screen. Any ideas?
Edit: I now use the correct indices as suggested but i still don't get the desired result.
This is wrong:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexIndexStart),&vertexIndexStart[0],GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
The element array buffer should contain the index array, which means the indices into the vertex arrays, not the indices into the index array.
Please also note that your code is using lots of deprecated GL features (builtin attributes, probably even the fixed-function pipeline, drawing without VAOs), and will not work in a core profile of modern OpenGL.
Speaking of modern GL: That further level of indirection, where the parameter array for glMultiDrawElements itself comes from a buffer object, is even supported in modern GL via glMultiDrawElemetnsIndirect.
I read this tutorial arc synthesis, vertex attributes, chapter 2 playing with colors and decided to play around with the code. To sum up, this tutorial explain how to pass vertices colors and coordinates to vertex and fragment shaders to put some color on a triangle.
Here is a code of the display function (from the tutorial with some changes) that works as expected :
void display()
{
// cleaning screen
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
//using expected program and binding to expected buffer
glUseProgram(theProgram);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
//setting data to attrib 0
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
//glDisableVertexAttribArray(0); // if uncommenting this out, it does not work anymore
//setting data to attrib 1
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)48);
//cleaning and rendering
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
glfwSwapBuffers();
}
Now if uncommenting the line
//glDisableVertexAttribArray(0);
before setting data to attribute 1 this does not work anymore. Why is that ? Plus, I don't get it why attribute 0 can be set without 1 enabled and not the contrary. By the way, what is the usefulness of enabling/disabling vertices attributes ? I mean you (at least I) will probably end up enabling all vertices attributes so why they are off by default ?
It's at the glDrawArrays call that currently enabled attributes are read and passed to the renderer. If you disable them before that then they won't get passed from your buffer.
There can be a lot of potential attributes available (up to glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &result); at least 16) and most applications don't need that many.
The position attribute in the shader is set to index 0 and if it doesn't get assigned then the shader gets all points with the same location (typically 0,0,0,1). Whereas index 1 is the color data and if that is missing it's not a big deal.
I am trying to convert the following piece of code into one that uses a vertex buffer:
glBegin (GL_QUADS);
glTexCoord2fv (&_vertex[ci->index_list[7]].uv.x);
glVertex3fv (&_vertex[ci->index_list[7]].position.x);
glVertex3fv (&_vertex[ci->index_list[5]].position.x);
glVertex3fv (&_vertex[ci->index_list[3]].position.x);
glVertex3fv (&_vertex[ci->index_list[1]].position.x);
glEnd ();
My faulty code partly looks like this:
GLfloat * p = (GLfloat *) malloc(sizeof(GLfloat)*14);
//Memcopies vertices into p pointer
memcpy(&p[counter+0], &_vertex[ci->index_list[7]].uv.x, sizeof(GLfloat)*2);
memcpy(&p[counter+2], &_vertex[ci->index_list[7]].position.x, sizeof(GLfloat)*3);
memcpy(&p[counter+5], &_vertex[ci->index_list[5]].position.x, sizeof(GLfloat)*3);
memcpy(&p[counter+8], &_vertex[ci->index_list[3]].position.x, sizeof(GLfloat)*3);
memcpy(&p[counter+11], &_vertex[ci->index_list[1]].position.x, sizeof(GLfloat)*3);
glGenBuffers(1, &vboId1);
glBindBuffer(GL_ARRAY_BUFFER, vboId1);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*14, p, GL_STATIC_DRAW_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*14, (GLfloat*)0);
glVertexPointer(3, GL_FLOAT, 0, 2+(GLfloat*)0);
glDrawArrays(GL_QUADS, 0, 1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
However, I get an "Access violation reading location" error on the glDrawArrays line. Any ideas what could be wrong here? I am very new to OpenGL/graphics and pretty sure I'm messing up something obvious.
This is not going to work. Immediate mode allowed you to omit respecifying unchanged attributes between vertices. But with vertex arrays, you cannot do that. What you currently do is telling the GL that it finds the TexCoords of the i-th vertex at byte offset 14*sizeof(GLfloat)*i in the buffer. For the first vertex, it will work, but for the second, you try to access data beyond the end of the buffer.
You have to duplicate that data, so that every vertex has exactly the same attributes, in the same layout. Basically, you need one vertex array per attribute, with one entry for every vertex, no matter it the value did change or not.
Better view a vertex as not just the position (specified by the glVertex command), but the complete n-tupel of relevant attributes. If any single component of any attribute differs, it is not to be considered the same vertex anymore.