PDA

View Full Version : Drawing VBO elements (very basic question)



Wasabi
01-17-2011, 07:30 AM
I've just recently (very recently) started looking at how to use VBO's and whatnot with OpenGL (my teachers always taught me to use glBegin() and glEnd(), which I now see hasn't been used for a few generations). However, now I'm quite desperately stuck on the first step of this ladder. I can't even draw a single damned triangle. I found the "VBO - Just Examples" (http://www.opengl.org/wiki/VBO_-_just_examples) page of the wiki and tried using the second version (which doesn't use depreciated Vertex/TexCoordPointer). It's clearly incomplete, so I filled it in as best I could, but to no avail. The code is as follows:


#include <stdlib.h>
#include <windows.h>
#include <glee.h>
#include <glut.h>

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

struct MyVertex
{
float x, y, z; //Vertex
float nx, ny, nz; //Normal
float s0, t0; //Texcoord0
};
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
gluLookAt(0,0,4,0,0,3,0,1,0);

MyVertex pvertex[3];
//VERTEX 0
pvertex[0].x = 0.0;
pvertex[0].y = 0.0;
pvertex[0].z = 0.0;
pvertex[0].nx = 0.0;
pvertex[0].ny = 0.0;
pvertex[0].nz = 1.0;
pvertex[0].s0 = 0.0;
pvertex[0].t0 = 0.0;
//VERTEX 1
pvertex[1].x = 1.0;
pvertex[1].y = 0.0;
pvertex[1].z = 0.0;
pvertex[1].nx = 0.0;
pvertex[1].ny = 0.0;
pvertex[1].nz = 1.0;
pvertex[1].s0 = 1.0;
pvertex[1].t0 = 0.0;
//VERTEX 2
pvertex[2].x = 0.0;
pvertex[2].y = 1.0;
pvertex[2].z = 0.0;
pvertex[2].nx = 0.0;
pvertex[2].ny = 0.0;
pvertex[2].nz = 1.0;
pvertex[2].s0 = 0.0;
pvertex[2].t0 = 1.0;

GLuint VertexVBOID,IndexVBOID;
glGenBuffers(1, &amp;VertexVBOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBufferData(GL_ARRAY_BUFFER, sizeof(MyVertex)*3, &amp;pvertex[0].x, GL_STATIC_DRAW);
unsigned short pindices[3];
pindices[0] = 0;
pindices[1] = 1;
pindices[2] = 2;
glGenBuffers(1, &amp;IndexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*3, pindices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(12));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); //The starting point of the IBO
}
int main(int argc, char **argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(500,300);
glutCreateWindow("Camera");
glutDisplayFunc(Display);
glutMainLoop();
return 0;
}

The screen appears, is cleared, but no triangle appears. I have literally just started using the VBO concept, so I'm absolutely certain I made a completely beginner mistake. But I don't know what it is, so... help?

Should it be relevant, I'm using OpenGL 3.3, since it's the latest my video card runs (on updated drivers).

mobeen
01-17-2011, 08:48 AM
There are a couple of things missing from ur code.
1) You have not specified the buffer type to glut usually its either single buffer or double buffer support which we give as follows,


glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);//for double buffer
rendering,
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);//for single buffer rendering

if u use double buffered support make sure to add a glutSwapBuffers call at the end of your display function.
2) In your vbo, u r not putting the correct number of bytes, since your array is the whole vertex data using the sizeof operator on the array returns the total number of bytes needed to allocate your array. Also you are creating new vbo each frame which is not appropriate. Instead put the init code in a separate func and call it from main. Also give ur vbo id global as follows,


GLuint VertexVBOID,IndexVBOID;
unsigned short pindices[3]={0,1,2};

void InitGL() {
MyVertex pvertex[3];
//VERTEX 0
pvertex[0].x = 0.0;
pvertex[0].y = 0.0;
pvertex[0].z = 0.0;
pvertex[0].nx = 0.0;
pvertex[0].ny = 0.0;
pvertex[0].nz = 1.0;
pvertex[0].s0 = 0.0;
pvertex[0].t0 = 0.0;
//VERTEX 1
pvertex[1].x = 1.0;
pvertex[1].y = 0.0;
pvertex[1].z = 0.0;
pvertex[1].nx = 0.0;
pvertex[1].ny = 0.0;
pvertex[1].nz = 1.0;
pvertex[1].s0 = 1.0;
pvertex[1].t0 = 0.0;
//VERTEX 2
pvertex[2].x = 0.0;
pvertex[2].y = 1.0;
pvertex[2].z = 0.0;
pvertex[2].nx = 0.0;
pvertex[2].ny = 0.0;
pvertex[2].nz = 1.0;
pvertex[2].s0 = 0.0;
pvertex[2].t0 = 1.0;

glGenBuffers(1, &amp;VertexVBOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBufferData(GL_ARRAY_BUFFER, sizeof(pvertex), &amp;pvertex[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(12));

glGenBuffers(1, &amp;IndexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*3, pindices, GL_STATIC_DRAW);

}

Your display func becomes this


void Display(void)
{

glClear(GL_COLOR_BUFFER_BIT);

glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); //The starting point of the IBO

//uncomment for double buffered rendering
//also replace GLUT_SINGLE with GLUT_DOUBLE
//glutSwapBuffers();
}
and your main becomes this


int main(int argc, char **argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowSize(500,300);
glutCreateWindow("Camera");
glutDisplayFunc(Display);
InitGL();
glutMainLoop();
return 0;
}



See if this help,
Regards,
Mobeen

Wasabi
01-17-2011, 10:33 AM
Unfortunately not. Indeed, I'd forgotten to add the single-buffer flag (it'll probably be double-buffer, but that's not relevant right now). And I'd even tried making the VBOs global before posting, but when that didn't change anything, I put them back.

However, even if I make a complete copy-paste of your code (as plagiarized below), it doesn't work. It compiles just fine, but the window doesn't get cleared or draw (the window keeps the image of whatever was behind it).


#include <stdlib.h>
#include <windows.h>
#include <glew.h>
#include <glut.h>

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

struct MyVertex
{
float x, y, z; //Vertex
float nx, ny, nz; //Normal
float s0, t0; //Texcoord0
};

GLuint VertexVBOID,IndexVBOID;
unsigned short pindices[3]={0,1,2};

void InitGL()
{
MyVertex pvertex[3];
//VERTEX 0
pvertex[0].x = 0.0;
pvertex[0].y = 0.0;
pvertex[0].z = 0.0;
pvertex[0].nx = 0.0;
pvertex[0].ny = 0.0;
pvertex[0].nz = 1.0;
pvertex[0].s0 = 0.0;
pvertex[0].t0 = 0.0;
//VERTEX 1
pvertex[1].x = 1.0;
pvertex[1].y = 0.0;
pvertex[1].z = 0.0;
pvertex[1].nx = 0.0;
pvertex[1].ny = 0.0;
pvertex[1].nz = 1.0;
pvertex[1].s0 = 1.0;
pvertex[1].t0 = 0.0;
//VERTEX 2
pvertex[2].x = 0.0;
pvertex[2].y = 1.0;
pvertex[2].z = 0.0;
pvertex[2].nx = 0.0;
pvertex[2].ny = 0.0;
pvertex[2].nz = 1.0;
pvertex[2].s0 = 0.0;
pvertex[2].t0 = 1.0;

glGenBuffers(1, &amp;VertexVBOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBufferData(GL_ARRAY_BUFFER, sizeof(pvertex), &amp;pvertex[0], GL_STATIC_DRAW);

glGenBuffers(1, &amp;IndexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*3, pindices, GL_STATIC_DRAW);
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(0));

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(12));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); //The starting point of the IBO
}
int main(int argc, char **argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowSize(500,300);
glutCreateWindow("Camera");
glutDisplayFunc(Display);
glewInit();
InitGL();
glutMainLoop();
return 0;
}

mhagain
01-17-2011, 10:45 AM
Are you on Vista or Windows 7? I'd advise to either add a glFlush/glFinish to the end of your display function, or switch to double buffered if so.

Essential reading: http://www.opengl.org/pipeline/article/vol003_7/


Windowed applications that use frontbuffer rendering without ever calling glFlush or glFinish (as they should) are likely to appear completely black, because the rendering will sit forever in the offscreen frontbuffer. Not even switching the DWM off is likely to fix these, given that the offscreen frontbuffer is a requirement of the driver model itself....and...
If an application renders to the frontbuffer, remember to call glFinish or glFlush whenever it needs the contents to be made visible on the screen. For the same reason, do not call those two functions too frequently, as they will incur the penalty of copying the contents of the offscreen frontbuffer to the desktop.

Dan Bartlett
01-17-2011, 11:11 AM
You also need to set up a shader program, since you're using custom vertex attributes, and openGL can't tell that attribute #0 is meant to represent the position + attribute #1 is the normal, so it doesn't know how to render anything.

If you wanted a simple rendering test using fixed function in a non-core context, you could use glVertexPointer + glNormalPointer instead of glVertexAttribPointer, otherwise you will need to create + use a shader program (the correct way).

There's an example of setting up a shader program at http://www.opengl.org/wiki/Shading_languages:_GLSL , although there are probably better tutorial sites out there

mobeen
01-17-2011, 11:27 AM
Unfortunately not. Indeed, I'd forgotten to add the single-buffer flag (it'll probably be double-buffer, but that's not relevant right now). And I'd even tried making the VBOs global before posting, but when that didn't change anything, I put them back.

However, even if I make a complete copy-paste of your code (as plagiarized below), it doesn't work. It compiles just fine, but the window doesn't get cleared or draw (the window keeps the image of whatever was behind it).


#include <stdlib.h>
#include <windows.h>
#include <glew.h>
#include <glut.h>

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

struct MyVertex
{
float x, y, z; //Vertex
float nx, ny, nz; //Normal
float s0, t0; //Texcoord0
};

GLuint VertexVBOID,IndexVBOID;
unsigned short pindices[3]={0,1,2};

void InitGL()
{
MyVertex pvertex[3];
//VERTEX 0
pvertex[0].x = 0.0;
pvertex[0].y = 0.0;
pvertex[0].z = 0.0;
pvertex[0].nx = 0.0;
pvertex[0].ny = 0.0;
pvertex[0].nz = 1.0;
pvertex[0].s0 = 0.0;
pvertex[0].t0 = 0.0;
//VERTEX 1
pvertex[1].x = 1.0;
pvertex[1].y = 0.0;
pvertex[1].z = 0.0;
pvertex[1].nx = 0.0;
pvertex[1].ny = 0.0;
pvertex[1].nz = 1.0;
pvertex[1].s0 = 1.0;
pvertex[1].t0 = 0.0;
//VERTEX 2
pvertex[2].x = 0.0;
pvertex[2].y = 1.0;
pvertex[2].z = 0.0;
pvertex[2].nx = 0.0;
pvertex[2].ny = 0.0;
pvertex[2].nz = 1.0;
pvertex[2].s0 = 0.0;
pvertex[2].t0 = 1.0;

glGenBuffers(1, &amp;VertexVBOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBufferData(GL_ARRAY_BUFFER, sizeof(pvertex), &amp;pvertex[0], GL_STATIC_DRAW);

glGenBuffers(1, &amp;IndexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*3, pindices, GL_STATIC_DRAW);
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(0));

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(12));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); //The starting point of the IBO
}
int main(int argc, char **argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowSize(500,300);
glutCreateWindow("Camera");
glutDisplayFunc(Display);
glewInit();
InitGL();
glutMainLoop();
return 0;
}
well i copy pasted the code and it works fine i get a white triangle as seen in the attachment. One more thing if u r on ATI hardware u would need to create a vao just before binding the vbos make a call to


GLuint vaoID;
glGenVertexArrays(1, &amp;vaoID);
glBindVertexArray(vaoID);
//your vbo stuff
. I think this might be the reason that u dont see anything my hardware is nvidia which provides a default vao in case u dont give it. See if this helps. Try this code.


#include <stdlib.h>
#include <windows.h>
#include <gl/glew.h>
#include <gl/glut.h>

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

struct MyVertex
{
float x, y, z; //Vertex
float nx, ny, nz; //Normal
float s0, t0; //Texcoord0
};

GLuint VertexVBOID,IndexVBOID, vaoID;
unsigned short pindices[3]={0,1,2};

void InitGL()
{
MyVertex pvertex[3];
//VERTEX 0
pvertex[0].x = 0.0;
pvertex[0].y = 0.0;
pvertex[0].z = 0.0;
pvertex[0].nx = 0.0;
pvertex[0].ny = 0.0;
pvertex[0].nz = 1.0;
pvertex[0].s0 = 0.0;
pvertex[0].t0 = 0.0;
//VERTEX 1
pvertex[1].x = 1.0;
pvertex[1].y = 0.0;
pvertex[1].z = 0.0;
pvertex[1].nx = 0.0;
pvertex[1].ny = 0.0;
pvertex[1].nz = 1.0;
pvertex[1].s0 = 1.0;
pvertex[1].t0 = 0.0;
//VERTEX 2
pvertex[2].x = 0.0;
pvertex[2].y = 1.0;
pvertex[2].z = 0.0;
pvertex[2].nx = 0.0;
pvertex[2].ny = 0.0;
pvertex[2].nz = 1.0;
pvertex[2].s0 = 0.0;
pvertex[2].t0 = 1.0;

glGenVertexArrays(1, &amp;vaoID);
glBindVertexArray(vaoID);
glGenBuffers(1, &amp;VertexVBOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBufferData(GL_ARRAY_BUFFER, sizeof(pvertex), &amp;pvertex[0], GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(0));

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(12));

glGenBuffers(1, &amp;IndexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*3, pindices, GL_STATIC_DRAW);
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); //The starting point of the IBO
}
int main(int argc, char **argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
glutInitWindowSize(500,300);
glutCreateWindow("Camera");
glutDisplayFunc(Display);
glewInit();
InitGL();
glutMainLoop();
return 0;
}

Wasabi
01-19-2011, 07:53 AM
Well, thanks for the help guys, glFlush() did it. A nice dull white triangle. Progress!

ZbuffeR
01-19-2011, 12:04 PM
You should instead use double-buffering.

OctopusPrime314
01-21-2012, 10:08 AM
I am having similar problems but I get this error.

drmRadeonCmdBuffer: -22. Kernel failed to parse or rejected command stream. See dmesg for more info.

One of the posts says if your card is not nvidia then you have to do add something to the code. I tried that and still got the same error here is my code.

.h file


#ifndef TERRAIN_H
#define TERRAIN_H

#include <GL/glut.h> // Header File For The GLUT Library
#include <GL/gl.h> // Header File For The OpenGL32 Library
#include <GL/glu.h> // Header File For The GLu32 Library
#include <unistd.h> // Header File For sleeping.
#include <stdio.h> // Header file for standard file i/o.
#include <stdlib.h> // Header file for malloc/free.
#include <math.h>
#include <iostream>
#include <time.h>
using namespace std;

#define HEADERSIZE 0x1C
#define BUFFER_OFFSET(i) ((char *)NULL + (i))

class Terrain{
public:
Terrain();
void createBlock();
void findSlope();
void dispTerr();
void drawMap();
void mapTexture();

private:
unsigned char* land;
int width;
int height;
GLuint VertexVBOID,IndexVBOID, vaoID;
unsigned short pindices[3];

};
#endif

.cpp file


#include "Terrain.h"

struct MyVertex
{
float x, y, z; //Vertex
float nx, ny, nz; //Normal
float s0, t0; //Texcoord0
};

Terrain::Terrain() {

land = 0;
width = 0;
height = 0;
pindices[0] = 0;
pindices[1] = 1;
pindices[2] = 2;

MyVertex pvertex[3];
//VERTEX 0
pvertex[0].x = 0.0;
pvertex[0].y = 0.0;
pvertex[0].z = 0.0;
pvertex[0].nx = 0.0;
pvertex[0].ny = 0.0;
pvertex[0].nz = 1.0;
pvertex[0].s0 = 0.0;
pvertex[0].t0 = 0.0;
//VERTEX 1
pvertex[1].x = 1.0;
pvertex[1].y = 0.0;
pvertex[1].z = 0.0;
pvertex[1].nx = 0.0;
pvertex[1].ny = 0.0;
pvertex[1].nz = 1.0;
pvertex[1].s0 = 1.0;
pvertex[1].t0 = 0.0;
//VERTEX 2
pvertex[2].x = 0.0;
pvertex[2].y = 1.0;
pvertex[2].z = 0.0;
pvertex[2].nx = 0.0;
pvertex[2].ny = 0.0;
pvertex[2].nz = 1.0;
pvertex[2].s0 = 0.0;
pvertex[2].t0 = 1.0;

glGenVertexArrays(1, &amp;vaoID);
glBindVertexArray(vaoID);
glGenBuffers(1, &amp;VertexVBOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBufferData(GL_ARRAY_BUFFER, sizeof(pvertex), &amp;pvertex[0], GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(0));

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MyVertex), BUFFER_OFFSET(12));

glGenBuffers(1, &amp;IndexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*3, pindices, GL_STATIC_DRAW);


}
void Terrain::drawMap(){

glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

}

V-man
01-22-2012, 03:20 AM
Where is your shader? Where does 0 and 1 go to? You forgot to bind your VAO when you call glDrawElements.

OctopusPrime314
01-22-2012, 09:08 AM
I didn't realize you needed a shader and what do you mean by 0 and 1? For binding VA0 do I need to bind that to the buffer seeing that I already binded it to the bindVertexArrays.

V-man
01-23-2012, 10:11 AM
You are using glVertexAttribPointer and you are using position 0 for vertices and 1 for normals. How is GL suppose to know what that means? You need to setup a shader.

A VAO just encapsulates all the calls to glBindBuffer and the glVertexAttribPointer calls.

There is a VAO example here
http://www.opengl.org/wiki/Tutorial1:_Re...B_/_freeGLUT%29 (http://www.opengl.org/wiki/Tutorial1:_Rendering_shapes_with_glDrawRangeElemen ts,_VAO,_VBO,_shaders_%28C%2B%2B_/_freeGLUT%29)