Recently I started to learn OpenGL and I am beginning to learn the newer assets of it. For a while now I've been trying to work with VBOs, to draw a simple cube from a vertex point array. I am having trouble rendering it and understanding some of the arguments in the functions. It throws no errors but nothing is in my view.
float cubeVertPoints[72]; //An array containing the vertex points
Here is my VBO init
void loadBufferData()
{
glGenBuffers(1, &cubeVBO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertPoints[0])*3, &cubeVertPoints[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(cubeVertPoints[0])*3, (void*)sizeof(GL_FLOAT));
}
Drawing
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(cubeVertPoints[0])*3, (void*)sizeof(GL_FLOAT));
glDrawArrays(GL_TRIANGLES, 0, 1);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
You are not transferring all your data into the vertex buffer. The 2nd parameter of glBufferData takes the size of all of your vertex data in bytes. You should set it to sizeof(vertex) * vertex_count.
Also, calling glEnableVertexAttribArray and glVertexAttribPointer in loadBufferData is redundant. You should call them only in your rendering function.
Your second problem is with glVertexAttribPointer. You are not passing the correct offset to your vertex position data in your vertex data "structure". Since your vertices only consist of positions, this offset should be 0. If you would have positions and colors for each vertex, these offset could be 0 (for position) and sizeof(float) * 3 (for color, because you have 3 coordinates).
Finally, you only draw a single vertex. You should draw 72/3=24 if your cube has 24 vertices.
I think you can make your life easier by defining an actual structure for your vertices, like so:
struct Vertex
{
float position[3];
};
Then, you can compute offsets for each of your vertex positions, colors, etc, with (GLvoid*)(&((Vertex*)NULL)->position).
Related
hi everyone I new to OPENGL and I want to update the vertices and indices when I translate the 3d object I make vertices vector and indices vector these vector hold all the data of the 3d object is this possible
the code I use :
// Create buffers/arrays
glGenVertexArrays(1, &this->VAO);
glGenBuffers(1, &this->VBO);
glGenBuffers(1, &this->EBO);
glBindVertexArray(this->VAO);
// Load data into vertex buffers
glBindBuffer(GL_ARRAY_BUFFER, this->VBO);
// A great thing about structs is that their memory layout is sequential for all its items.
// The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which
// again translates to 3/2 floats which translates to a byte array.
glBufferData(GL_ARRAY_BUFFER,this->vertices.size() * sizeof(vertex), &this->vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(int), &this->indices[0], GL_STATIC_DRAW);
// Set the vertex attribute pointers
// Vertex Positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)0);
// Vertex Normals
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, normal));
// Vertex Texture Coords
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, uv));
glBindVertexArray(0);
I do not know if this code make change to the vertices and indices or it just make copy of this two vector and render what I want is not make copy this vector and render I want to use this vector directly and make change to this vector is this possible
Usually on graphics we use what's called a transformation matrix for space operations such as translation / rotation / scale.
This allow us to avoid mixing data between model specific data (such as vertices, normals, etc..) and his state in the 3D world (transform).
So my advice here would be to use transformation matrix and update the model position in the vertex shader.
You can find more info here https://learnopengl.com/Getting-started/Transformations
I'm attempting to move a vertex by modifying it's positional vertex attribute. As a test, I have added the line vertices[0] = 0.4f; both before and after the creation of my VAO procedure, to see whether I am able to modify the vertices array after an initial render. When I add it before the VAO creation, it modifies the location of the vertex, and when it is added afterwards it does not. This leads me to believe my rendering procedure:
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
Somehow isn't actually updating the buffer with the current float[] in memory. However, I can then replace the line glBindVertexArray(VAO); with the whole rendering procedure:
// 2. copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
// 2. copy our vertex indices in a buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
// 3. then set our vertex attributes pointers:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); // Pos vec3
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3* sizeof(float))); // Col vec4
glEnableVertexAttribArray(1);
And with this as my rendering procedure, I can update the vertices array and this change is carried across to the GPU, updating the position of the vertex on-screen. Here is my VAO creation code:
// Generate a Vertex Array Object to store our rendering procedure.
unsigned int VAO;
glGenVertexArrays(1, &VAO);
// 1. bind Vertex Array Object, Element Buffer Object
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// 2. copy our vertices array in a buffer for OpenGL to use
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
// 2. copy our vertex indices in a buffer for OpenGL to use
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
// 3. then set our vertex attributes pointers:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); // Pos vec3
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3* sizeof(float))); // Col vec4
glEnableVertexAttribArray(1);
So it works when I express the rendering procedure explicitly, but not when I store it in a VAO? From what I understand, a VAO is a construct for storing a rendering procedure, and when we then run glBindVertexArray(VAO);, this rendering procedure is carried out. Am I understanding this wrong? Is there another line I need in either the creation of the VAO or when rendering?
Here is the full source in C++: https://pastebin.com/DgZuZt4K
And the same thing written in OpenTK, C#: https://pastebin.com/DHj9UN16
[...] From what I understand, a VAO is a construct for storing a rendering procedure, [...]
No it is not. A Vertex Array Object stores states.
When glBufferData/glBufferSubData is called, then the buffer object's data store is initialized respectively updated.
When glVertexAttribPointer is called, then states are set in the state vector of the VAO. The buffer object which is currently bound to the target GL_ARRAY_BUFFER is associated to the specified vertex attribute in the currently bound VAO.
The VAO stores the information about how to interpret the vertex information and the id of the VBO for each attribute.
But the VAO does not store a procedure or even a process. When you have changed the vertices, then you have to update the Vertex Buffer Object by either glBufferSubData or buffer mapping.
Related: What is the proper way to modify OpenGL vertex buffer?
If you want to specify and enable a vertex attribute (glVertexAttribPointer / glEnableVertexAttribArray), then you have to bind the VAO and the VBO. The VAO stores the specification and the id of the VBO is stored in the VAO.
If you want to update the vertex coordinates and attributes (e.g. glBufferSubData), then you have to bind the VBO.
If you want to draw the mesh (e.g. glDrawArrays), then it is sufficient to bind the VAO.
My goal is to render a list of segments using VBOs with different colors and if possible with different widths.
Each vertex is defined by:
class Vector2f {
public:
float x, y;
};
The list of segments consists in pairs of vertexes that define a segment.
Then I initialize the VBO:
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vector2f) * segments.size(), &segments[0], GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
And then I draw using:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2f), (void*)(sizeof(float) * 0));
glColor3f(0.0f, 1.0f, 0.0f);
glDrawArrays(GL_LINES, 0, segments.size());
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
In my example, I want to give to each segment a color. The color is previously defined and can only be 1 from 3 options.
How can I do it? And can I optimize it by using indexes for color instead of repeating them all over?
If so, how?
Also, is it possible to define the width of each individual segment?
How can I do it?
Extend your vertex struct to contain color values:
class Vector2f
{
public:
float x, y;
unsigned char r, g, b;
};
And use GL_COLOR_ARRAY + glColorPointer():
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2f), offsetof( Vector2f, x ) );
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(Vector2f), offsetof( Vector2f, r ) );
glDrawArrays(GL_LINES, 0, segments.size());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Also, is it possible to define the width of each individual segment?
Not really with fixed-function. You either end up with a glLineWidth() + draw-call per segment (losing the performance benefit of batching draw-calls) or converting the line into triangle geometry on the CPU (significantly more complicated).
I am currently using this: http://www.opengl-tutorial.org/beginners-tutorials/tutorial-7-model-loading/
All I've done so far is replace the model, changed up the camera so that it is isometric, and made the cursor show up again. So nothing major.
My new model shows up perfectly along with its textures. I was wondering how I can make it so that by pressing W, A, S, & D, I can move my model around?
I'm planning on making a very simple "game" where I just move my model around, and collide with other objects scattered around the map.
Any help is appreciated! Thanks everyone!
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
// Set our "myTextureSampler" sampler to user Texture Unit 0
glUniform1i(TextureID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
1, // attribute
2, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0, vertices.size() );
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
the MVP matricies encode the translation, rotation and scaling of the model. It is the product of the Projection * View * Modelmatrix. If you apply the translation the the Modelmatrix and recalculate mvp, then you should see the object moving.
I'm not very experience with the OpenGL library so I'm having trouble understanding why when I move some initialization code to a class or a function, GL stops drawing onto the screen. Some research indicates that the library is "global" or state-based rather than object based?
Anyway, here is some code that works
GLuint vertexArrayBuffer;
glGenVertexArrays(1, &vertexArrayBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBuffer);
// VBO is ready to accept vertex data
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(0);
while(!screen.isClosed()) {
// Give the screen a background color
screen.paint(0.0f, 0.0f, 0.5f, 1.0f);
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
// Switch to display buffer after drawing all of the above
screen.swapBuffers();
This is all enclosed in the main function, with not much programming structure. The output is a nice white triangle onto a blueish background.
This is the issue here, taking the exact code prior to the event loop and wrapping it into a function:
GLuint initVertexArray(vertex vertices[]) {
// Create file descriptor for the VBO for use as reference to gl vertex functions
GLuint vertexArrayBuffer;
glGenVertexArrays(1, &vertexArrayBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBuffer);
// VBO is ready to accept vertex data
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(0);
return vertexArrayBuffer;
}
and calling it GLuint vertexArrayBuffer = initVertexArray(vertices); in the main function, produces no output of any kind, no errors either, just the same blueish background.
Have you checked what sizeof(vertices) is returning. In this case vertices[] will decay into a pointer so I would imagine that sizeof(vertices) is sizeof(vertex*).
Try passing the size of the array alongside it like so:
GLuint initVertexArray(vertex vertices[], const unsigned int size);
Then you would use it like so:
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
instead of:
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
You would then call it in the same scope as you declared your vertices array:
vertex vertices[100];
// sizeof(vertices) here will give the actual size of the vertices array
// eg: sizeof(vertex) * 100 instead of just giving sizeof(vertex*)
GLuint vertexArrayBuffer = initVertexArray(vertices, sizeof(vertices));