Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify single vertex position in OpenGL

Tags:

c++

opengl

I am now in the middle of converting my code from OpenGL 2 where I was using glBegin(), glVertex3f() to OpenGL 3.3 and use of VBOs, EBOs. I read number of tutorials but I cannot find one very important thing and I hope someone would be able to help me here.

In previous version thanks to glBegin(GL_POLYGON) and 4 glVertex3f(floa, float, float) I was able to create shapes that I want. Or more precisely user wanted - he could just grab one of vertices and modify base rectangle. So it was possible to create something like this:

previous

Now my code for drawing base rectangle looks like this:

box_vertices[] = {
            0.5f, 0.5f, 0.0f,
            0.5f, -0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            -0.5f, 0.5f, 0.0f
};

box_indices[] = {
            0, 1, 3,
            1, 2, 3
};

GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(box_vertices), box_vertices, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(box_indices), box_indices, GL_STATIC_DRAW);

// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindVertexArray(0); 

while(true) {
    GLint modelLoc = glGetUniformLocation(box_shader.Program, "model");
    GLint viewLoc = glGetUniformLocation(box_shader.Program, "view");
    GLint projLoc = glGetUniformLocation(box_shader.Program, "projection");

    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    glBindVertexArray(VAO);

    model = glm::mat4();
    model = glm::scale(model, glm::vec3(0.25, 0.75, 1.0));
    // Position box at it's location
    model = glm::translate(model, glm::vec3(x, y, z));
    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

and the result looks something like this:

now

And maybe it might be helpful this is my vertex shader code:

#version 330 core
layout (location = 0) in vec3 position;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
}

I just cannot find any idea how I can modify one vertex, because first it is embedded as I understand within VBO and second it has to be normalized to one as I understood (if it isn't OpenGL will do that for me). I doubt that I need each time generate new box_vertices array, so how it can be done?

Can someone please advice me how I can achieve my goal?

EDIT:

Modified code based on vesan's answer

while(true) {
    GLint modelLoc = glGetUniformLocation(box_shader.Program, "model");
    GLint viewLoc = glGetUniformLocation(box_shader.Program, "view");
    GLint projLoc = glGetUniformLocation(box_shader.Program, "projection");

    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    glBindVertexArray(VAO);

    MakeSomeChangesToVerticesArray();
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(box_vertices), box_vertices, GL_DYNAMIC_DRAW);

    model = glm::mat4();
    model = glm::scale(model, glm::vec3(0.25, 0.75, 1.0));
    // Position box at it's location
    model = glm::translate(model, glm::vec3(x, y, z));
    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}
like image 277
sebap123 Avatar asked Oct 29 '25 09:10

sebap123


1 Answers

You can simply modify the data in your buffer(s). The data is still there, the VAO is only pointing to it.

So, at the beginning of your rendering cycle, simply modify your box_vertices array as desired, then call the same thing as when you're putting data in for the first time:

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(box_vertices), box_vertices, GL_STATIC_DRAW);

Your array is very small, so performance should not be a concern. If it is, be sure to only modify the buffer only if the shape has actually changed, consider using GL_DYNAMIC_DRAW instead of GL_STATIC_DRAW or use glBufferSubData to only replace a part of the buffer (I don't have a good example for this handy, unfortunately).

EDIT: The code to modify the buffer does not have to be inside the drawing loop, of course. It can be anywhere (for example in a mouse or keyboard handler). I suggested putting it inside the loop because the way the code is structured, there is nowhere else to place it.

like image 124
vesan Avatar answered Oct 31 '25 13:10

vesan