PDA

View Full Version : Vertex Buffer



akashiraffee
12-14-2009, 06:40 PM
Okay, so I read a bit about VBO's and this was my first try with it:



void renderObjects () {
GLuint sqID;
float square1[]={-10.0f,-10.0f,0.0f,10.0f,-10.0f,0.0f,10.0f,10.0f,0.0f,-10.0f,10.0f,0.0f};
glGenBuffersARB(1,&sqID);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, sqID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(square1), square1, GL_STATIC_DRAW_ARB);
}


which does not work at all. What's the problem? Not to seem bitter, but it seems crappy that they would propose "obsoleting" everything else and then not provide anything beyond a couple of half-assed wikis and blog posts for documentation.

ps. please not point me to anything involving C++. This is an INCREDIBLY SIMPLE EXERCISE -- draw a square. Please.

Jan
12-14-2009, 06:56 PM
You are only generating a buffer and uploading data into it, you are not doing any rendering at all.

You first need to also setup vertex pointers (glVertexPointer or better glAttribPointer) and then do an actual drawcall via glDrawElements or glDrawArrays.

Google for some tutorial, i don't have anything at hand to point you to right now, but there are several tutorials that explain VBOs and vertex-arrays in general in more detail.

Jan.

marshats
12-14-2009, 08:55 PM
Are you using an openGL 3.2 context? With something like


// in SDL
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3 );
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,2 );
// or FREEGLUT
glutInitContextVersion( 3, 2 );


In any event, take a look at the excellent songho VBO tutorial (http://www.songho.ca/opengl/gl_vbo.html). Note the code you have in Render() only need to be called once -- no need to keep transferring them if they are not changing. But what you do put in the Render loop is a glDraw*() with the necessary glBind*.

Here's my gl3.2 "HelloWorld" that I use to start a new project -- it just uses a VBO to draw a blue square. It's C++ in only that it declares variables not at the begining of main -- you could quickly and easily make this to C -- no classes or polymorphism to worry about


//g++ main.cpp -lGL $(/usr/local/share/sdl13/bin/sdl-config --cflags --libs)
#define GL3_PROTOTYPES
#include <GL3/gl3.h> // wget http://www.opengl.org/registry/api/gl3.h
#include <SDL.h>

int main()
{
//SDL Initialization
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION,3 );
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,2 );
SDL_Init(SDL_INIT_VIDEO);
const int r_width(640),r_height(640);
SDL_WindowID window(SDL_CreateWindow("openGL3 HelloWorld",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,r_w idth,r_height,SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN)) ;
SDL_GLContext glcontext(SDL_GL_CreateContext(window));

//Create shaders and shader program
GLuint vshader(glCreateShader(GL_VERTEX_SHADER));
GLuint fshader(glCreateShader(GL_FRAGMENT_SHADER));
GLuint program(glCreateProgram());

const GLchar *vshader_source[] =
{
"#version 150 core\n"
"\n"
"in vec3 vert;\n"
"\n"
"void main() {\n"
" gl_Position=vec4(vert,1.);\n"
"}\n"
"\n"
};
glShaderSource(vshader,1,vshader_source,NULL);

const GLchar *fshader_source[] =
{
"#version 150 core\n"
"out vec4 fragcolor;\n"
"\n"
"void main() {\n"
"\n"
" fragcolor=vec4(0.0f,0.0f,1.0f,0.0f);\n"
"}\n"
"\n"
};
glShaderSource(fshader,1,fshader_source,NULL);

glCompileShader(vshader);
glCompileShader(fshader);

glAttachShader(program,vshader);
glAttachShader(program,fshader);
glLinkProgram(program);
glUseProgram(program);

//Get handles to shader uniforms
//... none for this simple vert/frag shader

//Datas destioned for video memory, can be local (and lost after bound to GPU!).
#define R 0.9
GLfloat vertices[] = { // in vec3 vert;
-R, R, 0.0, // xyz
-R, -R, 0.0,
R, R, 0.0,
R, -R, 0.0
};
size_t VertexArrayCount=sizeof(vertices)/sizeof(GLfloat)/3; // 3 for {x y z}

//Create geometry vertex array using Model definition
GLuint vao;
glGenVertexArrays(1,&amp;vao);
glBindVertexArray(vao);

//in vec3 vert;
GLuint bon_vert; // buffer object name
glGenBuffers(1,&amp;bon_vert);
glBindBuffer(GL_ARRAY_BUFFER,bon_vert);
glBufferData(GL_ARRAY_BUFFER,sizeof(GLfloat)*3*Ver texArrayCount,vertices,GL_STATIC_DRAW);
const GLint loc_vert(glGetAttribLocation(program,"vert"));
glVertexAttribPointer(loc_vert,3,GL_FLOAT,GL_TRUE, 0,NULL);
glEnableVertexAttribArray(loc_vert);

//Render loop
SDL_Event event;
do {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLE_STRIP,0,VertexArrayCount) ;

SDL_GL_SwapWindow(window);

SDL_PollEvent(&amp;event); //non-blocking
} while (event.type!=SDL_MOUSEBUTTONDOWN);

//Quiting, so cleanup resources
glDeleteProgram(program);
glDeleteShader(fshader);
glDeleteShader(vshader);
glDeleteBuffers(1,&amp;bon_vert);
glDeleteVertexArrays(1,&amp;vao);
SDL_GL_DeleteContext(glcontext);
SDL_DestroyWindow(window);
SDL_Quit();
}

akashiraffee
12-15-2009, 01:37 AM
Are you using an openGL 3.2 context?

No. I want to remain compatible with 1.5+. Or at least 2.0+.



In any event, take a look at the excellent songho VBO tutorial (http://www.songho.ca/opengl/gl_vbo.html).


This is very very far from being "excellent". Halfway down the page we reach:



glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vboId2); // for indices

"vboId2" has not been initialiazed or referred to at all so far, and the author provides absolutely no explanation of why we are working with it now. So what else have we skipped? I guess anything! Suddenly we are allowed to use random, uninitialized variables when programming? Where I come from, that would not be called "excellent" that would be called "incorrect". Should I just assume the rest of the stuff is okay anyway? I might have no choice, because the only way this could be considered "excellent" is by comparison to the rest of the incomplete and hack-written VBO material.

Drawing a square is a completely and utterly trivial task. If I could find one decent demonstration of this, I would be done in fifteen minutes. Instead, I will no doubt be spending hours sifting thru the HTML'ified notes of semi-literate cretins before I can figure out what is fundamental and essential to this process. I expanded my code a bit:



void renderObjects () {
GLuint sqID;
float square1[12]={-10.0f,-10.0f,0.0f,10.0f,-10.0f,0.0f,10.0f,10.0f,0.0f,-10.0f,10.0f,0.0f};
glGenBuffersARB(1,&amp;sqID);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, sqID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(square1), square1, GL_STATIC_DRAW_ARB);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,0);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}

However, this produces a seg fault "in pthread_attr_setdetachstate ()".

I absolutely promise that I will be writing a tutorial on switching over to the soon to be mandatory (?) VBO method in the very near future, just as soon as I figure it out. I am POSITIVE my problem is not because of

1) my stupidity or lack or programming experience.
2) because drawing a square is such a complex task.

It is because the openGL community has TOTALLY FAILED to produce anything resembling halfway decent documentation here. I only say this because I notice from searching this forum about this question that I am not the first one THIS YEAR to complain about this mystifying lack of examples (do we intend to be POINTLESSLY mystifying? That is the impression I get.). I have not found ONE SINGLE WORKING EXAMPLE OF VBO use in C on the web. I am not even the second one to complain, but like I said, I will be rectifying the situation, for posterity ;)



Here's my gl3.2 "HelloWorld" that I use to start a new project -- it just uses a VBO to draw a blue square. It's C++ in only that it declares variables not at the begining of main -- you could quickly and easily make this to C


Wrong. This is more than 50 lines of code. I would like to draw a square, not be introduced to the gratuitous excesses common to C++ programmers, thank you. Why is there a need for (a lot of) SDL calls in this? Do you need SDL to use VBOs? I thought this was the "openGL" forum"...

Perhaps openGL is on it's way to becoming a C++ only API, but this is sad and pathetic.

Don't get me wrong -- I like the idea. All those glVertex calls are ridiculous. But now there is a sane standard, how about some SANE explanations instead of something that looks even worse?

Jan
12-15-2009, 04:56 AM
You know, with that attitude you drive people away from helping you. You can find out how VBOs work even with code that has a bug.

Well, if you want bug-free code you can download GLIM (link in my signature) and look at its code.

Anyway i'm fed up with people that complain, complain, complain and don't RTFM properly. Maybe you are just not meant to do this kind of programming.

Jan.

mbentrup
12-15-2009, 06:38 AM
void renderObjects () {
GLuint sqID;
float square1[12]={-10.0f,-10.0f,0.0f,10.0f,-10.0f,0.0f,10.0f,10.0f,0.0f,-10.0f,10.0f,0.0f};
glGenBuffersARB(1,&amp;sqID);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, sqID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(square1), square1, GL_STATIC_DRAW_ARB);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,0);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}



You are passing 0 as indices pointer to glDrawElements and consequently get a NULL-pointer exception. Either specify an array of indices and pass it to glDrawElements (http://www.opengl.org/sdk/docs/man/xhtml/glDrawElements.xml) or switch to glDrawArrays (http://www.opengl.org/sdk/docs/man/xhtml/glDrawArrays.xml).

Y-tension
12-15-2009, 07:14 AM
I will try to be as polite as possible because frankly, I don't like your attitude either. But anyway, we all started somewhere didn't we?

1st, VBO builds upon vertex arrays, that is, vertex data passed as arrays to reduce function call overhead. That is, people some time like 11 years ago, realized that, indeed, as you say, the glVertex paradigm is very ineffective. Now, if you missed that, it's not our fault.

This is knowledge you would have acquired if you had read a good book like the red book( http://www.opengl.org/documentation/red_book/ newer versions cover up to version 2.1 but you'll have to buy those) which still is, in my opinion the best resource for openGL 2.x out there. Without that knowledge it is unlikely you will be able to understand papers like the one written, for example, by these amateurs:

http://developer.nvidia.com/object/using_VBOs.html

Now it is understandable that you must be a student who just wants to get his grade fast and easy, but please do understand that in real world conditions, research is what you will have to do.

Now for your question:



#define BUFFER_OFFSET(n) ((GLubyte *)NULL + n)

GLuint sqID;

int main()
{
float square1[]={-10.0f,-10.0f,0.0f,10.0f,-10.0f,0.0f,10.0f,10.0f,0.0f,-10.0f,10.0f,0.0f};

/*...initialize window, openGL etc...*/

/* Create Vertex Buffers and fill them with data*/
glGenBuffersARB(1,&amp;sqID);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, sqID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(square1), square1, GL_STATIC_DRAW_ARB);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
glEnableClientState(GL_VERTEX_ARRAY);
renderObjects();
}

void renderObjects () {
glBindBufferARB(GL_ARRAY_BUFFER_ARB, sqID);
glDrawArrays(GL_QUADS, 0, 4);
}




Of course glDrawElements throws a seg fault. You gave it a NULL pointer of indices and expected of it to draw 4 vertices, something you wold have known if you had read the reference(http://www.opengl.org/sdk/docs/man/). Don't ask what an index is or I will kindly ask you to get out of this forum now.

I think my friend that what you lack is patience. I had similar problems when I started with VBO's but I didn't start yelling at people. I simply read through the docs. If you plan to do this professionally you will often have to use new and undocumented techniques so just keep at it and don't get easily frustrated. We all get bugs sometimes.

Oh and do the tutorial if you have the time. Although personally I found the existing documentation more than enough for my needs.

Y-tension
12-15-2009, 07:24 AM
Oh and since you are THAT clever, I look forward to your less than 50 lines of READABLE and WORKING code, without external libraries (no glut) that will create a window and display a square. Sorry to insist but arrogance always offends me when it comes from the undeserving(That is people who don't deserve to be arrogant ;) )

marshats
12-15-2009, 08:21 AM
Why is there a need for (a lot of) SDL calls in this?

Well, openGL does not provide any means to create a window -- the SDL stuff is there to get a window with openGL 3.2 context. What library are you using to open a window? I could have used GLUT or FTLK or QT or Windows or <insert your favorite context here>. That's the nature of programming everybody has their own favorite and openGL doesn't try to force anyone down the same path.

Same goes for programming language -- openGL programmers use a multitude of languages; C, C++, python, ruby, C#/mono, Java, <insert your favorite language here>. I have to sometimes read thru a language I don't particularly like but still gain great benefit by observing its openGL usage. C++ allows variables to be declared nearest where they are used -- to me that helps make the code easier to read than C since I don't have to go hunting for what type a variable is since it is one or two lines away from where it is used. But C is a good language too -- I use it a lot too but I have ben corrupted by the C++ side :p

;) Ah the frustration. I have been there. Sorry about the 50 lines of "trivial" code -- did you know that a minimal change of that code will produce this image ... Just change the numbers in the array
http://24.130.61.216/temporary/discard.png


GLfloat vertices[] = { // in vec3 vert;
x1, y1, y2, // xyz
...
xN, yN, yN
};

And add a two samplers to the shader and whola a non trivial drawing in very few lines of code :)... So it really is a very elegant code for creating complex displays. I supplied that code to try and help you with seeing that you upload/buffer the data once outside the render loop and then inside the display loop bind the vertex array and call DrawArrays only. That was my mistake -- I should have asked you to state a SPECIFIC question about a particular part of your code.

I do this as a volunteer who happens to get a lot of enjoyment out of openGL. I agree it can seem frustrating at times -- this move to openGL 3.2 has not helped since the documentation is lagging far behind it. But I have found I like the 3.2 way of doing things. And a bigger mistake was giving you 3.2 code at all since you are limiting yourself to "1.5+. Or at least 2.0+". It was not a good idea to post the entire thing since your frustration sounds like you just want to get an running code working and to understand the details from that -- I learn that way too.

Maybe you can post your complete code and I can help you get a working version -- keep it under 100 lines and no "windows.h"/"stdfx.h" stuff though or I will get upset ;) Just joking. Please post your entire code. It looks like you are one or two lines away from it working and it is easier if I can compile and run it to debug your problem.

akashiraffee
12-15-2009, 11:15 AM
people some time like 11 years ago, realized that, indeed, as you say, the glVertex paradigm is very ineffective. Now, if you missed that, it's not our fault.

I am not blaming anyone for my ignorance, and if you do not like my attitude, please ignore this thread. I'm not here to butt-heads, I am not trying to offend anyone, I am just trying to draw some attention to a serious issue. I am sorry if I seem a bit angry -- I honestly am "a bit angry".

I "missed" this trend because immediate mode is fine for my needs; altho I do like the VBO idea better, from what I have read, it will probably not result in noticeable performance differences with what I am doing.

The reason I am taking an interest is because it would appear that all other rendering methods other than VBO's will soon be removed from GL completely.


This is knowledge you would have acquired if you had read a good book like the red book( http://www.opengl.org/documentation/red_book/ newer versions cover up to version 2.1 but you'll have to buy those) which still is, in my opinion the best resource for openGL 2.x out there.

I do have access to a copy of the redbook, from which I learned "immediate mode" in part. However, I don't own one -- the only gl book I own is a 2004 2nd edition of the superbible, which does not mention VBO's at all, and is not very well written generally IMO. Should've bought my own red book instead!



Now it is understandable that you must be a student who just wants to get his grade fast and easy, but please do understand that in real world conditions, research is what you will have to do.

I enjoy doing research. My professional work is perl and web oriented, and there is often a need for learning new and little documented techniques there.

I only show up with questions when that research gets me nowhere, which is why by that point I have issues with the available material. Particularly when I can clearly perceive this IS NOT a very complex issue. Again, I am positive that if properly explained, it should not take anyone longer than 15 minutes to understand this.

But finding such a explanation has proved WAY too difficult IMO. For example, going back to the "excellent" tutorial recommended by marchats, that is where I got this line:


glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,0);

which, as someone points out, is simply an incorrect use of the command and caused my seg fault. I am clearly being a little too optimistic in hoping that all these wonderful examples and tutorials actually use the commands properly. The fact that they do not is part of what makes them useless. How am I suppose to learn anything from someone else's bad example?



I think my friend that what you lack is patience. I had similar problems when I started with VBO's but I didn't start yelling at people. I simply read through the docs. If you plan to do this professionally you will often have to use new and undocumented techniques so just keep at it and don't get easily frustrated.

Yes, I am frustrated, because it is ridiculous that what really should be the equivalent of How to screw in a light bulb has produced such a glut (no pun) of convoluted, overblown commentaries that still do not include ONE SINGLE PIECE OF FUNCTIONING C CODE.

Fortunately, Y-tension, yours does work. Thank you very much for that, it should be enough to get me going.

I do not use openGL professionally (altho I am ecstatic to learn of the new "webGL" draft) . My point is that if immediate mode is going to be obsoleted and VBO will be the only method, it should not be considered "new and undocumented".



Oh and do the tutorial if you have the time. Although personally I found the existing documentation more than enough for my needs.

I very much promise that I will, after I have played around with this a bit.

I also promise that once it's drafted, I will post it here and ask interested parties to comment and criticize, and then incorporate that into a more finalized version. I have done this before (in an unrelated programming realm) and it worked out very well -- the needs and perspectives of amateur beginners were met, while incorporating some of the wisdom and perspective of professionals.

I spend time everyday at cprogramming.com answering beginner questions and it is not hard for me to discern what is helpful and what is just obfuscation. You may be very good at what you do, that does not always make you a good teacher.


Sorry about the 50 lines of "trivial" code -- did you know that a minimal change of that code will produce this image


That is very interesting marshats, but -- you seem like a well intentioned person -- do you honestly think it is going to help a beginner draw a square on the screen?



Don't ask what an index is or I will kindly ask you to get out of this forum now.


Haha. Well of course I am going to ask then: what is this index that should be the final arg pointer to glDrawElements? I have some idea from the half dozen tutorials I have gone thru that it involves a set of triangles paralleling the vertices, but this has not been made clear anywhere, and as I have pointed out, basic errors are common in all this example code. Also, I have no idea what the purpose of this "index" is.

So thank you all for overcoming your distaste, vis, "my attitude" enough to get me to square one on this (pun intended). If you have any further comments, or an answer to that last question about "indices", please post. And expect to be seeing more VBO oriented questions from me in the near future :roll:

marshats
12-15-2009, 11:50 AM
That is very interesting marshats, but -- you seem like a well intentioned person -- do you honestly think it is going to help a beginner draw a square on the screen?


Why ask me a question if you want all the commentary to stop :)

I look forward to seeing your tutorial on drawing a quad. Please do post it here. Others will learn from it I am certain.

BTW, you should post your solution that Y-tension solved for you -- other beginners will benefit from your frustration and resulting solution.

Alfonse Reinheart
12-15-2009, 12:25 PM
The reason I am taking an interest is because it would appear that all other rendering methods other than VBO's will soon be removed from GL completely.

Appearances can be deceiving. NVIDIA has dedicated themselves to sabotaging the deprecation and removal system that the ARB has tried to do in 3.x by encouraging everyone within earshot to not avoid deprecated and removed functionality. And they've been successful; don't expect any GL implementations to come out soon that aren't laden with the 10+ years of cruft that is the full compatibility specification.

Jan
12-15-2009, 12:55 PM
If you really only need immediate mode rendering, then glim is actually made for you. Though you do need to use GLSL-shaders in conjunction with it (any other method for shading is deprecated anyways).

Jan.

akashiraffee
12-15-2009, 01:24 PM
BTW, you should post your solution that Y-tension solved for you -- other beginners will benefit from your frustration and resulting solution.

Okay. The only extraneous detail here is some frames/second code. I am still using glColor() for the color:



#include <stdio.h>
#include <time.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glext.h>

/* OGL demo1-VBO.c
basic 3D, no lighting, no textures
*/

#define WIDTH 600
#define HEIGHT 400
#define BUFFER_OFFSET(n) ((GLubyte *)NULL + n)

void drawScene();
void renderObjects ();
void setView (int w, int h);

GLuint sqID;

int main(int argc, char *argv[]) {
float square1[12]={-10.0f,-10.0f,0.0f,10.0f,-10.0f,0.0f,10.0f,10.0f,0.0f,-10.0f,10.0f,0.0f};
glutInit(&amp;argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(WIDTH,HEIGHT);
glutCreateWindow("openGL test");
glutReshapeFunc(setView);
glutDisplayFunc(drawScene);

glShadeModel(GL_SMOOTH);
glClearColor(1.0f,1.0f,1.0f,1.0f);

glGenBuffersARB(1,&amp;sqID);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, sqID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(square1), square1, GL_STATIC_DRAW_ARB);
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));
glEnableClientState(GL_VERTEX_ARRAY);

glutMainLoop();
return 0;
}


void drawScene() {
static int reps = -1;
static time_t t = 0;
time_t x;

if (!(reps%1000)) {
if (t) {
x = time(NULL);
if (x-t) printf("%d frames per second\n",1000/((int)x-(int)t));
}
t = time(NULL);
}
reps++;

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

gluLookAt(0.0f, 0.0f, 100.0f, 0.0f, 0.0f ,0.0f, 0.0f, 1.0f, 0.0f);

glColor4f(0.0f,0.0f,0.0f,1.0f);
renderObjects();

if (glGetError() != GL_NO_ERROR) puts("GL Error!\n");

glutSwapBuffers();
glutPostRedisplay();
}


void renderObjects () {
glDrawArrays(GL_QUADS,0,4);
}


void setView (int w, int h) {
float aspect=(float)w/(float)h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f,aspect,1.0f,500.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

Y-tension
12-16-2009, 05:32 AM
Haha. Well of course I am going to ask then: what is this index that should be the final arg pointer to glDrawElements? I have some idea from the half dozen tutorials I have gone thru that it involves a set of triangles paralleling the vertices, but this has not been made clear anywhere, and as I have pointed out, basic errors are common in all this example code. Also, I have no idea what the purpose of this "index" is.


I see you removed my extraneous call to glBindBuffer from renderObjects(). Better that way!

Actually an index is conceptually the same as a C array index, in this case an array of vertices. Each vertex may be thought of as a struct of 2, 3 or 4 floats(When working on a 2D surface it may be 2 for example). The first argument of glVertexPointer indicates the number of floats per vertex.

Now, each primitive(QUAD, TRIANGLE, etc) must be formed by a corresponding number of vertices (3 or 4 in the latter cases).
So, an index array is an array of integer indices to select vertices from the array. It is the same as writing:



struct {
float x;
float y;
float z;
} VERTEX;

VERTEX vertices[4] =
/* your vertex data here*/
{{0.0, 0.0, 0.0},{ 1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0}};

glBegin(GL_TRIANGLES);
/* Numbers 0 to 4 in this example are indices */
glVertex3fv((float *)&amp;vertices[0]);
glVertex3fv((float *)&amp;vertices[1]);
glVertex3fv((float *)&amp;vertices[2]);

glVertex3fv((float *)&amp;vertices[1]);
glVertex3fv((float *)&amp;vertices[2]);
glVertex3fv((float *)&amp;vertices[3]);
glEnd();


exactly the same as:



struct {
float x;
float y;
float z;
} VERTEX;

VERTEX vertices[4] =
/* your vertex data here*/
{{0.0, 0.0, 0.0},{ 1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0}};

#define INDEXARRAYSIZE = 6;

unsigned int indices[INDEXARRAYSIZE] = {0,1,2,1,2,3};

glBegin(GL_TRIANGLES);
for(int i = 0; i < INDEXARRAYSIZE; i++)
glVertex3fv((float *)&amp;vertices[indices[i]]);
glEnd();


exactly the same as:



struct {
float x;
float y;
float z;
} VERTEX;

VERTEX vertices[4] =
/* your vertex data here*/
{{0.0, 0.0, 0.0},{ 1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0}};

#define INDEXARRAYSIZE = 6;

unsigned int indices[INDEXARRAYSIZE] = {0,1,2,1,2,3};

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(0, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLES, INDEXARRAYSIZE, GL_UNSIGNED_INT, indices);


Note that the 3rd argument of glVertexPointer allows vertices to be more than 3(in this case) floats apart, allowing for interleaved data, but I will leave this as an exercise for you...zero means close packed, one vertex after the other.

In these examples I didn't use VBO but it is trivial once you are comfortable with vertex arrays.
Of course you must first generate and bind your buffers and fill them with your data.
The only thing that changes is that instead of providing glVertexPointer and glDrawElements with array pointers you provide them with the buffer offset (in bytes) of your data inside the bound vertex buffer and element buffer object respectively. Since your data were at the beginning of the buffer in your program, that was BUFFER_OFFSET(0). Remember BUFFER_OFFSET(n) is defined as ((GLubyte)NULL + n) which still makes it a pointer.

That is, yes, indices can themselves be inside a buffer, an element buffer. That must be the reason why the tutorial you came across used 0 at glDrawElements. He must have used an element buffer and 0 was the offset inside the buffer. Of course if you don't use VBO's you must provide a valid memory pointer.



#BUFFER_OFFSET(n) ((GLubyte)NULL + n)

struct {
float x;
float y;
float z;
} VERTEX;

VERTEX vertices[4] =
/* your vertex data here*/
{{0.0, 0.0, 0.0},{ 1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0}};

#define INDEXARRAYSIZE = 6;

unsigned int indices[INDEXARRAYSIZE] = {0,1,2,1,2,3};

GLuint vbo, ebo;
glGenBuffers(1, &amp;vbo);
glGenBuffers(1, &amp;ebo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ARRAY_BUFFER, 12*sizeof(float), vertices, GL_STATIC_DRAW)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*sizeof(unsigned int), indices, GL_STATIC_DRAW)

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(0, GL_FLOAT, 0, BUFFER_OFFSET(0));
glDrawElements(GL_TRIANGLES, INDEXARRAYSIZE, GL_UNSIGNED_INT, BUFFER_OFFSET(0));



I hope all is clear now..

akashiraffee
12-16-2009, 09:57 AM
I hope all is clear now..

Cool. So you can do a cube with only 8 vertices:


GLuint cube_indixes[] = { 0,1,2,3,4,5,6,7, 2,4,0,6,1,7,3,5 };

glDrawElements(GL_QUAD_STRIP,8,GL_UNSIGNED_INT,BUF FER_OFFSET(0));

glDrawElements(GL_QUAD_STRIP,8,GL_UNSIGNED_INT,BUF FER_OFFSET(8*sizeof(GLuint)));

Altho the outcome looks the same, I'm presuming that two calls to glDrawElements here is more proper than one involving "GL_QUAD_STRIP,16"?

This only makes it more baffling that none of the "tutorial writers" could explain this in a simple, direct way...

Dark Photon
12-16-2009, 12:16 PM
Altho the outcome looks the same, I'm presuming that two calls to glDrawElements here is more proper than one involving "GL_QUAD_STRIP,16"
Generally speaking, use the minimum number of draw calls, and order your vertices for best vertex cache coherence. Though with this few tris in a batch, we're not really concerned about performance.

CPU perf ranges all over the map these days, and anytime you have to get the CPU involved, you risk introducing GPU pipeline bubbles which reduce your performance. For instance,tThe difference in GL perf between a Nehalem (latest-and-greatest core) 2.0 GHz and 2.66 GHz is completely ridiculous in some cases (more than 33%; more like 2X sometimes; partly due to lower mem B/W and smaller cache sizes typically assigned to slower cores).

Though you do sometimes need to break a batch to stop/start a stripped primitive, unless you use degenerate triangles or primitive restart to connect them, OR (more common nowadays I imagine) is to just use TRIANGLES primitives. You can actually get better perf with TRIANGLES than stripped primitives in most cases, due to vertex cache reuse.

There's also glMultiDrawElements, but I ignore that because AFAIK that is a loop on the CPU in the GL driver.


This only makes it more baffling that none of the "tutorial writers" could explain this in a simple, direct way...
Well, not every permutation is spelled out in a tutorial. At some point, you have to pick up the The Red Book (http://www.opengl.org/documentation/red_book/) and read.


Cool. So you can do a cube with only 8 vertices
If you're happy with using the same vertex attribute values (normal, color, etc.) for the same vertex on different faces, then yes.

Y-tension
12-18-2009, 08:45 AM
BUFFER_OFFSET(0). Remember BUFFER_OFFSET(n) is defined as ((GLubyte)NULL + n) which still makes it a pointer.


Gah, I meant ((GLubyte *)NULL + n) of course!

As Dark Photon said, another way to render disconnected quad strips is by using primitive restart, now a part of OpenGL 3.2 and available as an extension to older versions. The way this works is: you define an index (usually 0xffff or something similar) as a restart index. Then, when the driver encounters the index in a stream of indices it simply issues a new gl*Draw*Elements call with the remaining indices. That way, only a single draw call is made by the application. But don't believe me, simply read http://www.opengl.org/registry/specs/NV/primitive_restart.txt or the latest OpenGL specs to get an idea.