PDA

View Full Version : Vertex buffer objects and animations



Chedra
04-20-2016, 05:28 AM
Hello OpenGL-Community,

I am quiet new as you will be able to tell in some minutes.
I started to do some OpenGL programming few days ago with the help of Anton Gerdelan's "Hello Trianlge" tutorial.

The tutorial explained the use of Vertex Buffer Objects instead of redrawing every vertex with every frame.
After completing, I wanted to extend by creating an animation for the triangle (a simple rotation).

So I was looking for some examples on how to do this (the tutorial didn't include one) and I found an example directly provided by the GLFW3 library:


#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>

static void error_callback(int error, const char* description)
{
fputs(description, stderr);
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}

int main(void)
{
GLFWwindow* window;

glfwSetErrorCallback(error_callback);

if (!glfwInit())
exit(EXIT_FAILURE);

window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}

glfwMakeContextCurrent(window);
glfwSwapInterval(1);

glfwSetKeyCallback(window, key_callback);

while (!glfwWindowShouldClose(window))
{
float ratio;
int width, height;

glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float) height;

glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
glMatrixMode(GL_MODELVIEW);

glLoadIdentity();
glRotatef((float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f);

glBegin(GL_TRIANGLES);
glColor3f(1.f, 0.f, 0.f);
glVertex3f(-0.6f, -0.4f, 0.f);
glColor3f(0.f, 1.f, 0.f);
glVertex3f(0.6f, -0.4f, 0.f);
glColor3f(0.f, 0.f, 1.f);
glVertex3f(0.f, 0.6f, 0.f);
glEnd();

glfwSwapBuffers(window);
glfwPollEvents();
}

glfwDestroyWindow(window);

glfwTerminate();
exit(EXIT_SUCCESS);
}

The code above works like a charm, but does not use VBOs. So a tried to use the logic in it for my own work.
In addition I read a some words about matrix stacks and how they are working.
Before making the changes my code looked like this:



#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>

int main () {
if (!glfwInit ()) {
fprintf (stderr, "ERROR: could not start GLFW3\n");
return 1;
}

glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

GLFWwindow* window = glfwCreateWindow (640, 480, "Hello Triangle", NULL, NULL);
if (!window) {
fprintf (stderr, "ERROR: could not open window with GLFW3\n");
glfwTerminate();
return 1;
}
glfwMakeContextCurrent (window);
glewExperimental = GL_TRUE;
glewInit ();

glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LESS);

float points[] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};

GLuint vbo = 0;
glGenBuffers (1, &vbo);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), points, GL_STATIC_DRAW);

GLuint vao = 0;
glGenVertexArrays (1, &vao);
glBindVertexArray (vao);
glEnableVertexAttribArray (0);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

const char* vertex_shader = "#version 400"
"in vec3 vp;"
"void main() {"
"gl_Position = vec4 (vp, 1.0);"
"}";
const char* fragment_shader = "#version 400"
"out vec4 frag_colour;"
"void main() {"
"frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);"
"}";

GLuint vs = glCreateShader (GL_VERTEX_SHADER);
glShaderSource (vs, 1, &vertex_shader, NULL);
glCompileShader (vs);
GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);
glShaderSource (fs, 1, &fragment_shader, NULL);
glCompileShader (fs);

GLuint shader_programme = glCreateProgram ();
glAttachShader (shader_programme, fs);
glAttachShader (shader_programme, vs);
glLinkProgram (shader_programme);

while (!glfwWindowShouldClose (window)) {
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram (shader_programme);
glBindVertexArray(vao);
glDrawArrays (GL_TRIANGLES, 0, 3);
glfwSwapBuffers (window);
glfwPollEvents ();
}

glfwTerminate();
return 0;
}

In order to achieve the animation I changed the code inside the while-loop to:


float ratio;
int width, height;

glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float) height;

glViewport(0, 0, width, height);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);

glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef((float) glfwGetTime() * 50.f,0.0f,0.0f,1.0f);

glUseProgram (shader_programme);
glBindVertexArray(vao);
glDrawArrays (GL_TRIANGLES, 0, 3);

glPopMatrix();
glfwSwapBuffers (window);
glfwPollEvents ();

The triangle is showing, but not rotating at all. What am I missing?
I think there is something wrong with my logic.

Thanks for any advice :)

Chedra

Hermannicus
04-25-2016, 02:18 AM
Hi,

I'm pretty new to OpenGL myself, so I'm not sure if my answer is right, but I think you're mixing OpenGL 4 with OpenGL 2 code here. glLoadIdentity();, glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f); and glMatrixMode(GL_MODELVIEW); seem not to be part of OpenGL 4 anymore. I can only find them in the legacy documentations of OpenGL 2.

I used this Tutorial for learning: https://open.gl/

It was quiet good and also includes transformation. I can only recommend it.

GClements
04-25-2016, 07:01 AM
I'm pretty new to OpenGL myself, so I'm not sure if my answer is right, but I think you're mixing OpenGL 4 with OpenGL 2 code here. glLoadIdentity();, glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f); and glMatrixMode(GL_MODELVIEW); seem not to be part of OpenGL 4 anymore. I can only find them in the legacy documentations of OpenGL 2.

They are still available as part of the compatibility profile.

However, if you use a vertex shader, the only effect of changing the built-in matrices via the legacy matrix functions is to change the pre-defined compatibility variables such as as gl_ModelViewMatrix and gl_ProjectionMatrix. That will only affect the vertex positions if your shader actually transforms the vertices by those matrices, and those in the posted code don't.

Also, in the compatibility profile, the use of VBOs/VAOs is orthogonal to the use of shaders. You can use VBOs and/or VAOs with the fixed-function pipeline and you can use shaders with glBegin/glEnd. Actually, use of VBOs (or even client-side vertex arrays) is orthogonal to the use of glBegin/glEnd, as you can use glArrayElement() to generate a vertex whose attributes are taken from the enabled arrays.

I wouldn't recommend mixing modern and legacy OpenGL as a design strategy, but if you're converting legacy OpenGL code to modern OpenGL, you can do it in stages: replace the use of glBegin/glEnd with glDrawArrays or glDrawElements using client-side arrays, replace client-side arrays with VBOs, use VAOs to encapsulate attribute state, replace the use of the fixed-function pipeline with shaders (possibly using compatibility variables), replace any use of compatibility variables with user-defined uniforms and attributes. If you started with a working program, you should still have a working program after each step, rather than needing to change everything at once and having no idea what went wrong if the resulting program doesn't work.