I have a list of QVector3D, which is a list of points, I want to draw a list of points with glDrawArrays.
initializeGLFunctions();
glGenBuffers(2, vbo);
//the vertices
QVector3D *vertices = &data[0];
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(QVector3D), vertices, GL_STATIC_DRAW);
glDrawArrays(GL_POINTS,??);
or what other method I can use to deal with this?
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(QVector3D), vertices, GL_STATIC_DRAW);
This is correct, but I would suggest to use more intelligent containers like QVector outside an then constData as follows:
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(QVector3D), myVector.constData(), GL_STATIC_DRAW);
Here is another official example how to use glBufferData in the context of QVector3D:
geometryengine.cpp Example File
Here can you find another third-party example following the official example:
FabScan100
Then, you could write:
glDrawArrays(GL_POINTS, 0, data.size());
Related
I am trying to render multiple models sharing the same VAO and vertex format (following top answer on this post Render one VAO containing two VBOs), however I cannot get it to work with GL_ELEMENT_ARRAY_BUFFER nor can I find any resource/example to help me. Is it even possible to do that or does the element array buffer work in a way that is incompatible with glVertexAttribFormat/glBindVertexBuffer and sharing VAOs? or am I missing the ELEMENT_ARRAY_BUFFER equivalent of glBindVertexBuffer?
My VAO is first created this way:
glCreateVertexArrays(1, &sharedVao);
glBindVertexArray(sharedVao);
glEnableVertexAttribArray(0);
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(0, 0);
// (just 1 for the example but there is more)
glBindVertexArray(0);
Then my model buffers are created as follow:
glBindVertexArray(sharedVao); // tried with and without binding vao first, no success
glCreateBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), vertices.data(), GL_STATIC_DRAW);
// (just 1 for the example but there is more)
glCreateBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangles.size() * sizeof(triangle), triangles.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
And finally I render as follow:
glBindVertexArray(sharedVao);
for (auto const& model : models)
{
glBindVertexBuffer(0, model.vbo, sizeof(vertex));
// (just 1 for the example but there is more)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.ebo);
// also tried glVertexArrayElementBuffer(sharedVao, model.ebo);
glDrawElements(GL_TRIANGLES, model.triangleCount * 3, GL_UNSIGNED_INT, nullptr);
}
Note that it does work if I start rendering the same VAO with glDrawArray (so without element array buffer).
This C++ GLSL Multiple IBO in VAO may be of valuable use, but still not sure what it means for sharing VAO formats for multiple models... (also realized that calling it IBO gives me more results than EBO...).
EDIT: this question was originally closed as supposedly a duplicate of Rendering meshes with multiple indices but it is not. Unlike this other question I am not talking about having different indices for different data (ex: indices for positions, indices for normals, indices for texture coords, etc.) but to have different indices per draw calls, while still using the same VAO format (the same way it is done with VBO and glBindVertexBuffer in Render one VAO containing two VBOs).
Multiple draw calls with shared Vertex Array Object
The purpose of this method is to avoid the cost of changing VAO format (see glVertexAttribPointer and glVertexAttribFormat: What's the difference? or https://www.youtube.com/watch?v=-bCeNzgiJ8I&t=1860) by sharing VAO and only rebinding buffers for every draw.
A clear example that doesn't make use of Element Buffer Array can be seen here: Render one VAO containing two VBOs
Create shared VAO (could be only once per program):
GLuint sharedVao = 0;
glCreateVertexArray(1, &sharedVao);
glBindVertexArray(sharedVao);
glEnableVertexAttribArray(0);
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
// binding each attribute from its own buffer so attrib_index == buffer_index
glVertexAttribBinding(0, 0);
glEnableVertexAttribArray(1);
glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(1, 1);
Create mesh buffers (would be only once per mesh):
struct Mesh
{
GLuint m_ebo = 0;
std::array<GLuint, 2> m_vbos = 0;
GLuint m_triangleCount = 0;
};
// Binding shared VAO here is mandatory as operations accessing or modifying EBO's
// state are not guaranteed to succeed if it wasn't bound to a VAO.
// However, for every new model, binding the EBO will unbind the previous, and we
// will need to rebind EBO to shared VAO for every draw call.
glBindVertexArray(sharedVao);
glCreateBuffer(1, &mesh.m_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.m_ebo);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
triangles.size() * sizeof(Triangle),
triangles.data(),
GL_STATIC_DRAW);
glBindVertexArray(0);
mesh.m_triangleCount = triangles.size();
glCreateBuffers(2, mesh.m_vbos.data());
glBindBuffer(GL_ARRAY_BUFFER, mesh.m_vbos[0]);
glBufferData(
GL_ARRAY_BUFFER,
positions.size() * sizeof(glm::vec3),
positions.data(),
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, mesh.m_vbos[1]);
glBufferData(
GL_ARRAY_BUFFER,
textureCoords.size() * sizeof(glm::vec2),
textureCoords.data(),
GL_STATIC_DRAW);
Render loop:
// Bind shared VAO only once
// If drawing with different set of vertex data bound, use glEnableVertexAttribArray
// or glDisableVertexAttribArray before draw calls
glBindVertexArray(sharedVao);
for (auto const& mesh : meshes)
{
glBindVertexBuffer(0, mesh.m_vbos[0], 0, sizeof(glm::vec3));
glBindVertexBuffer(1, mesh.m_vbos[1], 0, sizeof(glm::vec2));
// This is the key difference with existing example on sharing VAO:
// EBO must be rebound for every draw (unless 2 draws share the same primitive indices)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.m_ebo);
glDrawElements(GL_TRIANGLES, mesh.m_triangleCount * 3, GL_UNSIGNED_INT, nullptr);
}
Here is a sample code :-
unsigned int instanceVBO;
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBindVertexArray(VAO);
...
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * 100,
&translations[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
... ... ...
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribDivisor(2, 1); //<--- who own this setting?
//^ mostly copied from https://learnopengl.com/Advanced-OpenGL/Instancing
Who own the glVertexAttribDivisor setting? (VAO / instanceVBO / global state)
A comment in https://gamedev.stackexchange.com/questions/99236/what-state-is-stored-in-an-opengl-vertex-array-object-vao-and-how-do-i-use-the#comment174555_99238 suggests that it is stored in VBO.
However, the comment contradicts (?) to the above code which calls glVertexAttribDivisor(2, 1) after unbinds glBindBuffer(GL_ARRAY_BUFFER, 0); .
I would be appreciate if you are also kind to provide reference that I can read more about :
which settings/states owned by which one of Opengl's thingy (VAO/VBO/etc).
The vertex array divisor (VERTEX BINDING DIVISOR) is stored in the Vertex Array Objects state vector, separately for each vertex attribute (like enable state, offset, stride etc.).
The states which are stored in the VAO are listed in the specification in Table 23.3: Vertex Array Object State.
VAOs are specified in OpenGL 4.6 API Core Profile Specification - 10.3.1 Vertex Array Objects.
See also Vertex Specification - Instanced arrays
I have been implementing a small opengl application that I based off of this tutorial:
http://openglbook.com/the-book/chapter-4-entering-the-third-dimension/
I understand most of the code but I am really confused about this line:
glGenBuffers(2, &BufferIds[1]);
Which is then followed by
glBindBuffer(GL_ARRAY_BUFFER, BufferIds[1]);
glBufferData(GL_ARRAY_BUFFER, size, &theModel->theMesh.pos[0], GL_STATIC_DRAW);
I assume I only need one free name/id to bind my buffer data to, but if I change
glGenBuffers(2,
to
glGenBuffers(1,
The buffer fails to bind and nothing works.
BufferIds is 3 in size (GLuint BufferIds[3]). I would like to make it BufferIds[2] using the first slot for the VAO & the second for the VBO.
glGenVertexArrays(1, &BufferIds[0]);
ExitOnGLError("ERROR: Could not generate the VAO");
glBindVertexArray(BufferIds[0]);
ExitOnGLError("ERROR: Could not bind the VAO");
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
ExitOnGLError("ERROR: Could not enable vertex attributes");
glGenBuffers(2, &BufferIds[1]); //if this gets from changed 2 to 1 ...
ExitOnGLError("ERROR: Could not generate the buffer objects");
int size = theModel->theMesh.pos.size() * sizeof(theModel->theMesh.pos[0]) ;
glBindBuffer(GL_ARRAY_BUFFER, BufferIds[1]);
ExitOnGLError("ERROR: Could not bind the VBO to the VAO"); // ...this error triggers
glBufferData(GL_ARRAY_BUFFER, size, &theModel->theMesh.pos[0], GL_STATIC_DRAW);
That is because you pass BufferIds[1] to glBindBuffer. Index 1 is actually the second element, so your code crashes when you only create one buffer.
Try that:
glGenBuffers(1, &BufferIds[0]);
glBindBuffer(GL_ARRAY_BUFFER, BufferIds[0]);
I have the following class to represent a Mesh;
OpenGLMesh::OpenGLMesh(const std::vector<float>& vertexData, const std::vector<float>& normalData, const std::vector<float>& texCoords, const std::vector<uint32_t>& indexData) : mIndices(indexData.size())
{
glGenBuffers(1, &mVBO);
glGenBuffers(1, &mIndexBuffer);
glGenVertexArrays(1, &mVAO);
// buffer vertex, normals and index data
size_t vertexDataSize = vertexData.size() * sizeof(float);
size_t normalDataSize = normalData.size() * sizeof(float);
size_t texCoordDataSize = texCoords.size() * sizeof(float);
size_t indexDataSize = indexData.size() * sizeof(uint32_t);
glBindVertexArray(mVAO);
glBindBuffer(GL_ARRAY_BUFFER, mVBO);
glBufferData(GL_ARRAY_BUFFER, vertexDataSize + normalDataSize + texCoordDataSize, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, NULL, vertexDataSize, &vertexData[0]);
glBufferSubData(GL_ARRAY_BUFFER, vertexDataSize, normalDataSize, &normalData[0]);
glBufferSubData(GL_ARRAY_BUFFER, vertexDataSize + normalDataSize, texCoordDataSize, &texCoords[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataSize, &indexData[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(vertexDataSize));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(vertexDataSize + normalDataSize));
// unbind array buffer and VAO
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
And then a method to draw the mesh;
void OpenGLMesh::Render()
{
glBindVertexArray(mVAO);
glDrawElements(GL_TRIANGLES, mIndices, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
I am using GLFW3 where you can create a new window and use the same context as the previous window (link), however as I understand it you still need to reset the OpenGL states even though the buffer objects and their contents are still saved - correct?
I tried reading on the manual but I cannot find out what parts of the code I posted is treated as part of OpenGL state and needs to be reset?
create a new window and use the same context
Not quite. GLFW will create a new context that shares some of the other contexts' objects. Namely ever object that holds some data (textures, buffer objects, shaders and programs, etc) will be shared, i.e. accessible from both contexts. Container objects, which reference other objects, are not shared (framebuffer objects, vertex array objects).
however as I understand it you still need to reset the OpenGL states
Technically the newly created contexts start in a reset default state, with some objects already preallocated and initialized.
However like any state machine you should never assume OpenGL to be in a certain state when you're about to use it. Always make sure you set all the required state right before you need it when you need it. Which boils down, that you should set each and every state you require at the beginning of your drawing code.
I generated model (Suzie) in blender and exported it to .obj file with normals. During loading mode to my app i noticed that numbers of vertices and normals are diffrent (2012 and 1967).
I try to implement simple cell shading. The problem is in passing normals to shader. For storing vertex data i use vectors from glm.
std::vector<unsigned int> face_indices;
std::vector<unsigned int> normal_indices;
std::vector<glm::vec3> geometry;
std::vector<glm::vec3> normals;
Result i've got so far
Buffers Layout
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBufferData(GL_ARRAY_BUFFER, geometry.size() * sizeof(glm::vec3), &geometry[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, NormalVBOID);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_DYNAMIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VIndexVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, face_indices.size() * sizeof(unsigned int), &face_indices[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
Rendering fragment
glBindVertexArray(VAO);
glPolygonMode(GL_FRONT_AND_BACK, GL_QUADS);
glDrawElements(GL_QUADS, face_indices.size(), GL_UNSIGNED_INT, (void*)0);
glBindVertexArray(0);
The reason that had such wierd problem was that some normals were used more than once to preserve disk space so i had to rearrange them in a proper order. So the solution is pretty trival.
geometry.clear();
normals.clear();
geometry.resize(vv.size());
normals.resize(vv.size());
for (unsigned int i = 0; i < face_indices.size(); i++)
{
int vi = face_indices[i];
int ni = normal_indices[i];
glm::vec3 v = vv [vi];
glm::vec3 n = vn [ni];
geometry[vi] = v ;
normals[vi] = n ;
indices.push_back(vi);
}
You should also keep in mind that using the smooth modifier in Blender before export will in some cases help ensure that you have 1 normal per vertex (you may or may not need to also set per-vert normal view instead of face-normal view...can't rem so you'll have to test). This is because by default, blender uses per-face normals. The smooth modifier ("w" hotkey menu)
will switch it to per-vertex norms. Then when you export, you export verts and norms as usual, and the number should match. It doesn't always, but this has worked for me in the past.
This could possibly mean less unnecessary juggling of your data during import.