Drawing vertices with glDrawElements - opengl

I want to draw some indexed vertices with glDrawElements. Their positions are stored inside an array. Also, I've got an array with an uncertainty value that is associated with each vertex. Originally, this array was not sorted, so the first uncertainty value of this array corresponded to the first position in my vertex positions array. I then had to sort the uncertainty array, so the values are stored in descending order. I also have an index array, which containts the orignal indices from the uncertainty array. My arrays are set up like this:
vertexPositionArray = {(0,0,0,1), (0,0,1,1), ..., (dimX, dimY, dimZ, 1)}
uncertaintyArray = {1000.00, 989.20, 945.01, ...};
indexArray = {76504, 65024, 3424, 3, 30491, 59123, ...};
Now...I would like to draw the vertices inside my positionsArray in a way, that the order is determined by the indexArray. So the first vertex to render would be the one with the position at index 76504 in the vertexPositionsArray and with an uncertainty value at index 76504 in my uncertaintyArray.
I hope you get the point, it's pretty hard to describe what I'm trying to do. My current code isn't producing the expected output. I guess I'm not really sure which array the glDrawElements method works on.
// Enable user defined "IN"-variables
glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBufferObject);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vertexUncertaintyBufferObject);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexIndexBufferObject);
// Draw vertices
glDrawElements(GL_POINTS, dimensionX * dimensionY * dimensionZ, GL_UNSIGNED_INT, 0);

Related

How come no cube is drawn on my screen with this code in a GLFW window?

I have a bunch of code (copied from various tutorials) that is supposed to draw a random color-changing cube that the camera shifts around every second or so (with a variable, not using timers yet). It worked in the past before I moved my code into distinctive classes and shoved it all into my main function, but now I can't see anything on the main window other than a blank background. I cannot pinpoint any particular issue here as I am getting no errors or exceptions, and my own personally defined code checks out; when I debugged, every variable had a value I expected, and the shaders I used (in string form) worked in the past before I re-organized my code. I can print out the vertices of the cube in the same scope as the glDrawArrays() function as well, and they have the correct values too. Basically, I have no idea what's wrong with my code that is causing nothing to be drawn.
My best guess is that I called - or forgot to call - some opengl function improperly with the wrong data in one of the three methods of my Model class. In my program, I create a Model object (after glfw and glad are initialized, which then calls the Model constructor), update it every once and a while (time doesn't matter) through the update() function, then draw it to my screen every time my main loop is run through the draw() function.
Possible locations of code faults:
Model::Model(std::vector<GLfloat> vertexBufferData, std::vector<GLfloat> colorBufferData) {
mVertexBufferData = vertexBufferData;
mColorBufferData = colorBufferData;
// Generate 1 buffer, put the resulting identifier in vertexbuffer
glGenBuffers(1, &VBO);
// The following commands will talk about our 'vertexbuffer' buffer
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// Give our vertices to OpenGL.
glBufferData(GL_ARRAY_BUFFER, sizeof(mVertexBufferData), &mVertexBufferData.front(), GL_STATIC_DRAW);
glGenBuffers(1, &CBO);
glBindBuffer(GL_ARRAY_BUFFER, CBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(mColorBufferData), &mColorBufferData.front(), GL_STATIC_DRAW);
// Create and compile our GLSL program from the shaders
programID = loadShaders(zachos::DATA_DEF);
glUseProgram(programID);
}
void Model::update() {
for (int v = 0; v < 12 * 3; v++) {
mColorBufferData[3 * v + 0] = (float)std::rand() / RAND_MAX;
mColorBufferData[3 * v + 1] = (float)std::rand() / RAND_MAX;
mColorBufferData[3 * v + 2] = (float)std::rand() / RAND_MAX;
}
glBufferData(GL_ARRAY_BUFFER, sizeof(mColorBufferData), &mColorBufferData.front(), GL_STATIC_DRAW);
}
void Model::draw() {
// Setup some 3D stuff
glm::mat4 mvp = Mainframe::projection * Mainframe::view * model;
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &mvp[0][0]);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, CBO);
glVertexAttribPointer(
1, // attribute. No particular reason for 1, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the array
glDrawArrays(GL_TRIANGLES, 0, mVertexBufferData.size() / 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
};
My question is simple, how come my program won't draw a cube on my screen? Is the issue within these three functions or elsewhere? I can provide more general information about the drawing process if needed, though I believe the code I provided is enough, since I literally just call model.draw().
sizeof(std::vector) will usually just be 24bytes (since the struct contains 3 pointers typically). So basically both of your buffers have 6 floats loaded in them, which is not enough verts for a single triangle, lets alone a cube!
You should instead be calling size() on the vector when loading the data into the vertex buffers.
glBufferData(GL_ARRAY_BUFFER,
mVertexBufferData.size() * sizeof(float), ///< this!
mVertexBufferData.data(), ///< prefer calling data() here!
GL_STATIC_DRAW);

array vertex_buffer_object must be bound to call this method

Does anyone know why this error is being thrown?
I thought I am binding to VBO when I use glEnableVertexAttribArray?
com.jogamp.opengl.GLException: array vertex_buffer_object must be bound to call this method
at jogamp.opengl.gl4.GL4bcImpl.checkBufferObject(GL4bcImpl.java:39146)
at jogamp.opengl.gl4.GL4bcImpl.checkArrayVBOBound(GL4bcImpl.java:39178)
at jogamp.opengl.gl4.GL4bcImpl.glVertexAttribPointer(GL4bcImpl.java:37371)
This is my code to draw ..
public void draw(final GL2ES2 gl, Matrix4f projectionMatrix, Matrix4f viewMatrix, int shaderProgram, final Vec3 position, final float angle) {
// enable glsl
gl.glUseProgram(shaderProgram);
// enable alpha
gl.glEnable(GL2ES2.GL_BLEND);
gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA);
// get handle to glsl variables
mPositionHandle = gl.glGetAttribLocation(shaderProgram, "vPosition");
setmColorHandle(gl.glGetUniformLocation(shaderProgram, "vColor"));
mProj = gl.glGetUniformLocation(shaderProgram, "mProj");
mView = gl.glGetUniformLocation(shaderProgram, "mView");
mModel = gl.glGetUniformLocation(shaderProgram, "mModel");
// perform translations
getModelMatrix().loadIdentity();
getModelMatrix().translate(new Vec3(position.x * 60.0f, position.y * 60.0f, position.z * 60.0f));
getModelMatrix().rotate(angle, 0, 0, 1);
// set glsl variables
gl.glUniform4fv(getmColorHandle(), 1, getColorArray(), 0);
gl.glUniformMatrix4fv(mProj, 1, true, projectionMatrix.getValues(), 0);
gl.glUniformMatrix4fv(mView, 1, true, viewMatrix.getValues(), 0);
gl.glUniformMatrix4fv(mModel, 1, true, getModelMatrix().getValues(), 0);
// Enable a handle to the triangle vertices
gl.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
gl.glVertexAttribPointer(
getmPositionHandle(),
COORDS_PER_VERTEX,
GL2ES2.GL_FLOAT,
false,
vertexStride, 0L); // This is the line that throws error
// Draw the square
gl.glDrawElements(
GL2ES2.GL_TRIANGLES,
drawOrder.length,
GL2ES2.GL_UNSIGNED_SHORT,
0L);
// Disable vertex array
gl.glDisableVertexAttribArray(mPositionHandle);
gl.glDisable(GL2ES2.GL_BLEND);
gl.glUseProgram(0);
}
(I've never used OpenGL with Java, so I'll use C/C++ code, but I hope it will come across well)
You do not create or bind a Vertex Buffer Object.
First, use glGenBuffers to create a buffer, as so:
GLuint bufferID;
glGenBuffers(1, &bufferID);
This allocates a handle and stores it in bufferID.
Then, bind the buffer:
glBindBuffers(GL_ARRAY_BUFFER, bufferID);
This makes it the "current" buffer to use.
Next, fill the buffer with data. Assuming vertices is an array that stores your vertex coordinates, in flat format, with three floats per vertex:
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
This actually puts the data in GPU memory.
Then enable the attribute array and set the pointer:
glEnableVertexAttribArray(mPositionHandle);
glVertexAttribPointer(mPositionHandle, 3, GL_FLOAT, 0, 0, 0);
This will make the data in vertices available for shader programs under the vertex attribute location of mPositionHandle.
The second-to-last parameter of glVertexAttribPointer is stride. In this example, it is 0, because the buffer contains only vertex position data. If you want to pack both vertex position data and color data in the same buffer, as so:
v1.positionX v1.positionY v1.positionZ v1.colorR v1.colorG v1.colorB
v2.positionX ...
you will need to use a non-zero stride. stride specifies the offset between one attribute and the next of the same type; with stride of 0, they are assumed to be tightly packed. In this case, you'll want to set a stride of sizeof(GLfloat) * 6, so that after reading one vertex's position, it will skip the color data to arrive at the next vertex, and similarily for colors.
// (create, bind and fill vertex buffer here)
glEnableVertexAttribArray(location_handle_of_position_data);
glVertexAttribPointer(location_handle_of_position_data, 3, GL_FLOAT, 0, sizeof(GLfloat) * 6, 0);
glEnableVertexAttribArray(location_handle_of_color_data);
glVertexAttribPointer(location_handle_of_color_data, 3, GL_FLOAT, 0, sizeof(GLfloat) * 6, sizeof(GLfloat) * 3);
The last parameter is the offset to the first attribute - the first color attribute starts after the third float.
Other considerations:
You should look into using Vertex Array Objects. It might or might not work without them, but by standard they are required, and they simplify the code in any case.
For the sake of simplicity, this example code stores color data in floats, but for real use bytes are preferable.
glVertexAttribPointer() specifies that data for the attribute should be pulled from the currently bound vertex buffer, using the parameters specified. So you need to call:
gl.glBindBuffer(GL_VERTEX_ARRAY, ...);
before you call glVertexAttribPointer().
glEnableVertexAttribArray() specifies that an array should be used for the vertex attribute. Otherwise, a constant value, specified with calls like glVertexAttrib4f() is used. But it does not specify that the array is in a buffer. And even more importantly, there's no way glVertexAttribPointer() would know which buffer to use for the attribute unless you bind a specific buffer.

glDrawElements doesn't render all the points

In the first place, I'm rendering a point cloud with OpenGL.
// The object pointCloud wraps some raw data in different buffers.
// At this point, everything has been allocated, filled and enabled.
glDrawArrays(GL_POINTS, 0, pointCloud->count());
This works just fine.
However, I need to render a mesh instead of just points. To achieve that, the most obvious way seems to be using GL_TRIANGLE_STRIP and glDrawElements with the good array of indices.
So I start by transforming my current code by something that should render the exact same thing.
// Creates a set of indices of all the points, in their natural order
std::vector<GLuint> indices;
indices.resize(pointCloud->count());
for (GLuint i = 0; i < pointCloud->count(); i++)
indices[i] = i;
// Populates the element array buffer with the indices
GLuint ebo = -1;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size(), indices.data(), GL_STATIC_DRAW);
// Should draw the exact same thing as the previous example
glDrawElements(GL_POINTS, indices.size(), GL_UNSIGNED_INT, 0);
But it doesn't work right. It's rendering something that seems to be only the first quarter of the points.
If I mess with the indices range by making it 2 or 4 times smaller, the same points are displayed. If it's 8 times smaller, only the first half of them is.
If I fill it with only even indices, one half of the same set of points is shown.
If I start it at the half of the set, nothing is shown.
There's obviously something that I'm missing about how glDrawElement behaves in comparison to glDrawArrays.
Thanks in advance for your help.
The size passed as the second argument to glBufferData() is in bytes. The posted code passes the number of indices instead. The call needs to be:
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW);

LWJGL Indexed VBO, a lot of confusion

I cannot figure out how to use an Indexed VBO, IMHO there's a lack of information about it (for example the lwjgl site in which the indexed vbo page is missing ATM).
The structure i'm using in my vertex buffer is {pos.x, pos.y pos.z}, {tex.u, tex.v tex.W} and {norm.x, norm.y norm.z}, my index buffer structure is {posIndex, texIndex, normIndex}
I'm reading all this data from an .obj file, if tex or norm is missing i set it to{-1,-1,-1}.
Here's the code part in which i send data to the GPUs buffers:
this.VBOSize = Vertices.size();
FloatBuffer vbo = BufferUtils.createFloatBuffer(this.VBOSize);
for (int i = 0; i < this.VBOSize; i++) {
vbo.put(Vertices.get(i));
}
vbo.flip();
glBindBuffer(GL_ARRAY_BUFFER, VBOHandle);
glBufferData(GL_ARRAY_BUFFER, vbo, GL_STATIC_DRAW);
this.IBOSize = Indices.size();
IntBuffer ibo = BufferUtils.createIntBuffer(this.IBOSize);
for (int i = 0; i < this.IBOSize; i++) {
ibo.put(Indices.get(i));
}
ibo.flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOHandle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
and here's how i [incorrectly] render it:
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, Object3D.getVBOHandle());
glVertexAttribPointer(0, 3, GL_FLOAT, true, 12, 0);//3 floats * 4 sizeof(float)
glVertexAttribPointer(1, 3, GL_FLOAT, true, 12, 13);
glVertexAttribPointer(2, 3, GL_FLOAT, true, 12, 25);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Object3D.getIBOHandle());
glDrawElements(GL_TRIANGLES, Object3D.getIBOSize(), GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
THis is not how opengl works. In openGL, a vertex is a set of attributes like position, normal, color, textcoord, whatever. Indexed rendering just references vertices. You cannot have different indices for the various attributes, but just one index for the whole set. If you have the situation where two vertices share their position, but, not the texcoords, they are entirely _different_ vertices, as far as the GL is concerned. You cannot directly use the data from lightwave .obj files but have to preprocess the data to generate the vertex arrays OpenGL can work this.
There is the GL_AMD_interleaved_elements extension which somewhat implements the feature you want to use. It still uses 32-Bit indices, but allowes one to split them into 2 16-Bit or 4 8-Bit indices to use different indices for different attributes, but this extension is far from being in core GL, isn't widely supported and is still very limited.
Nowadays with the programmable pipeline, one could also do the index dereferencing manually in the shaders, basically (mis)using the vertex attributes and accessing the real attribute arrays via a texture buffer object, but that is quite advanced and the performance implications are not clear.

Drawing OpenGL Lines & Squares in 3.2 using VAO & VBO's

I've been experimenting with OpenGL 3.2+.
I can successfully render either a line to the screen, or a square made up of two triangles...
I think I'm using VAO and VBO's correctly, yet somehow I can not rending both of them... I experience strange renders.
Obviously, I've coded it wrong... but how are you supposed to use VAO and VBO's when rending multiple objects defined in different Arrays?
My code is far too long to post here, so I've linked a copy on Pastebin > Here <
When you have multiple objects to display, each in its own buffer array, each buffer needs its own vertex array object handle :
int curr_num_object = 0;
static const int vertex_array_object_fish = curr_num_object++;
static const int vertex_array_object_shark = curr_num_object++;
static const int vertex_array_object_doughnut = curr_num_object++;
GLuint array_vertex_array_object[curr_num_object]; // one for each drawn object
glGenVertexArrays(curr_num_object, &array_vertex_array_object[0]);
then for each buffer array you bind then load its data onto the GPU :
// ----------------- fish
glBindVertexArray(array_vertex_array_object[vertex_array_object_fish]); // fish VAO
GLuint vertex_buffer_fish;
glGenBuffers(1, & vertex_buffer_fish);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_fish);
glBufferData(GL_ARRAY_BUFFER, audio_model->get_sizeof_fish_array(), audio_model->get_address_fish_array(), GL_DYNAMIC_DRAW);
glVertexAttribPointer(
0, // attribute. No particular reason for 0, but must match the layout in the shader.
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(0);
above only deals with the first such buffer array, fish. Each subsequent object you wish to display wants a similar set of OpenGL calls. Above is called once outside of your windowing event loop (glfw, glut ...). Notice in the 2nd parm to glVertexAttribPointer its a 2D array ... here is its header entry :
float molecules_location_fish[max_fish][num_dimensions_2D_grid]; // X & Y per fish
Here is a second object I want to display (doughnut) with its similar calls to above fish :
// -----------
glBindVertexArray(array_vertex_array_object[vertex_array_object_doughnut]); // doughnut VAO
GLuint vertex_buffer_doughnut_box;
glGenBuffers(1, & vertex_buffer_doughnut_box);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_doughnut_box);
glBufferData(GL_ARRAY_BUFFER, audio_model->get_sizeof_doughnut_box_array(), audio_model->get_address_doughnut_box_array(), GL_DYNAMIC_DRAW);
glVertexAttribPointer(
0, // attribute. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(0);
// -----------
Now inside your windowing event loop, where perhaps you also make calls to update locations to data of your objects (lines, triangles, ...), you make these OpenGL calls for each object to display :
// ---------
glBindVertexArray(array_vertex_array_object[vertex_array_object_fish]);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_fish);
glBufferData(GL_ARRAY_BUFFER, audio_model->get_sizeof_fish_array(), audio_model->get_address_fish_array(), GL_DYNAMIC_DRAW);
glDrawArrays(GL_POINTS, 0, audio_model->get_curr_num_fish()); // 12*3 indices starting at 0 -> 12 triangles
And for completeness, here are the doughnut calls inside your event loop :
glBindVertexArray(array_vertex_array_object[vertex_array_object_doughnut]);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_doughnut_box);
glBufferData(GL_ARRAY_BUFFER,audio_model->get_sizeof_doughnut_box_array(),audio_model->get_address_doughnut_box_array(),GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, audio_model->get_curr_num_doughnut_boxes());
Notice in my fish I display its 2D as points, whereas the doughnut is 3D and displayed as a set of triangles (not indexed)
Let us know how you get on - this initial speed bump learning OpenGL is (^()&)(& Here is a really nice set of tutorials : http://www.opengl-tutorial.org