Graphics Programming
Buffer Objects
Thorsten Thormählen
December 10, 2021
Part 8, Chapter 1
Thorsten Thormählen
December 10, 2021
Part 8, Chapter 1
This is the print version of the slides.
Advance slides with the → key or
by clicking on the right border of the slide
Slides can also be advanced by clicking on the left or right border of the slide.
| Type | Font | Examples |
|---|---|---|
| Variables (scalars) | italics | $a, b, x, y$ |
| Functions | upright | $\mathrm{f}, \mathrm{g}(x), \mathrm{max}(x)$ |
| Vectors | bold, elements row-wise | $\mathbf{a}, \mathbf{b}= \begin{pmatrix}x\\y\end{pmatrix} = (x, y)^\top,$ $\mathbf{B}=(x, y, z)^\top$ |
| Matrices | Typewriter | $\mathtt{A}, \mathtt{B}= \begin{bmatrix}a & b\\c & d\end{bmatrix}$ |
| Sets | calligraphic | $\mathcal{A}, B=\{a, b\}, b \in \mathcal{B}$ |
| Number systems, Coordinate spaces | double-struck | $\mathbb{N}, \mathbb{Z}, \mathbb{R}^2, \mathbb{R}^3$ |
... glColor3f(1.0f, 1.0f, 0.0f); glBegin(GL_POLYGON); glTexCoord2f(0.25f,0.50f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.25f,0.25f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.50f,0.25f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(0.50f,0.50f); glVertex3f( 1.0f, 1.0f, 1.0f); glEnd(); ...
glBegin, glVertex, etc.)
are only supported in the "Compatibility Profile"init()
glGenBuffers(1, &bufID) is generating an unique identifier glBindBuffer(GL_ARRAY_BUFFER, bufID) a new VBO is created.
Possible targets are GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFERglBufferData(GL_ARRAY_BUFFER, size, inData, GL_STATIC_DRAW) transfers the vertex dataglBindBuffer(GL_ARRAY_BUFFER, bufID) glEnableClientState(GL_VERTEX_ARRAY).GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_SECONDARY_COLOR_ARRAY, GL_INDEX_ARRAY,
GL_NORMAL_ARRAY, GL_TEXTURE_COORD_ARRAY usw.glDrawArrays(GL_POLYGON, first, count);Possible arguments are the same as those of
glBegin(...), such as GL_POLYGON, GL_LINE_LOOP, GL_LINES, GL_POINTS, etc.
glDeleteBuffers(1, &bufID)
class Renderer {
public:
float t;
int mode;
private:
GLuint bufID;
int bufSize;
public:
// constructor
Renderer() : t(0.0), mode(0), bufID(0), bufSize(0) {}
//destructor
~Renderer() {
if(bufID !=0) glDeleteBuffers( 1, &bufID);
}
public:
void init() {
glEnable(GL_DEPTH_TEST);
// generating VBO input data
std::vector<float> dataIn;
unsigned ayimutSegs = 1000;
unsigned polarSegs = 1000;
float ayimutStep = 2.0f * M_PI / float(ayimutSegs);
float polarStep = M_PI / float(polarSegs);
float r = 1.0;
bufSize = 0;
for(unsigned m=0; m < ayimutSegs; m++) {
for(unsigned n=0; n < polarSegs; n++) {
float phi = ayimutStep*m;
float theta = polarStep * n;
// compute xyz from spherical coordinates
float x = r * sin(theta) * cos(phi);
float y = r * sin(theta) * sin(phi);
float z = r * cos(theta);
dataIn.push_back(x);
dataIn.push_back(y);
dataIn.push_back(z);
bufSize++;
}
}
// generating VBO
glGenBuffers(1, &bufID);
glBindBuffer(GL_ARRAY_BUFFER, bufID);
glBufferData(GL_ARRAY_BUFFER, dataIn.size()*sizeof(float),
&dataIn[0], GL_STATIC_DRAW);
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// set camera
gluLookAt(3.5, -1.0, 3.5, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
// draw scene
glRotatef(t, 0.0f, 0.0f, 1.0f);
// activating VBO
glBindBuffer(GL_ARRAY_BUFFER, bufID);
int stride = 0;
glVertexPointer(3, GL_FLOAT, stride, NULL);
glEnableClientState(GL_VERTEX_ARRAY);
if(mode == 0) {
glColor3f(1.0f,1.0f,1.0f);
}else{
glColorPointer(3, GL_FLOAT, stride, NULL);
glEnableClientState(GL_COLOR_ARRAY);
}
// render VBO
glDrawArrays(GL_POINTS, 0, bufSize);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
};
float vertexData[] =
{-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f
};
int indicesData[] =
{ 0, 1, 2, 3,
0, 4, 5, 1,
4, 7, 6, 5,
2, 6, 7, 3,
1, 5, 6, 2,
3, 7, 4, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufID)
glDrawElements(GL_POLYGON, count, GL_UNSIGNED_INT);
class Renderer {
public:
float t;
int mode;
unsigned ayimutSegs;
unsigned polarSegs;
private:
GLuint vertBufID, indicesBufID;
int vertSize;
public:
// constructor
Renderer() : t(0.0), mode(1), ayimutSegs(10), polarSegs(10),
vertBufID(0), indicesBufID(0), vertSize(0) {}
//destructor
~Renderer() {
if(vertBufID !=0) glDeleteBuffers( 1, &vertBufID);
if(indicesBufID !=0) glDeleteBuffers( 1, &indicesBufID);
}
public:
void init() {
glEnable(GL_DEPTH_TEST);
recreateVBOs();
}
void recreateVBOs() {
if(vertBufID !=0) glDeleteBuffers( 1, &vertBufID);
if(indicesBufID !=0) glDeleteBuffers( 1, &indicesBufID);
// generating VBO input data
std::vector<float> vertexData;
std::vector<int> indicesData;
int totalSegs = ayimutSegs * polarSegs;
float ayimutStep = 2.0f * M_PI / float(ayimutSegs);
float polarStep = M_PI / float(polarSegs);
float r = 1.0;
vertSize = 0;
for(unsigned m=0; m < ayimutSegs; m++) {
for(unsigned n=0; n < polarSegs; n++) {
float phi = ayimutStep*m;
float theta = polarStep * n;
// random radius
int rval = rand();
r = 1.0 - 0.3 * (fabs(float(rval))/float(RAND_MAX));
// create xyz from spherical coordinates
float x = r * sin(theta) * cos(phi);
float y = r * sin(theta) * sin(phi);
float z = r * cos(theta);
vertexData.push_back(x);
vertexData.push_back(y);
vertexData.push_back(z);
// create vertex indices
indicesData.push_back(vertSize % totalSegs);
indicesData.push_back((vertSize+ayimutSegs)%totalSegs);
indicesData.push_back((vertSize+ayimutSegs+1)%totalSegs);
indicesData.push_back((vertSize+1)%totalSegs);
vertSize++;
}
}
// generating vertex VBO
glGenBuffers(1, &vertBufID);
glBindBuffer(GL_ARRAY_BUFFER, vertBufID);
glBufferData(GL_ARRAY_BUFFER,
vertexData.size()*sizeof(float),
&vertexData[0], GL_STATIC_DRAW);
// generating index VBO
// generating index VBO
glGenBuffers(1, &indicesBufID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBufID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indicesData.size()*sizeof(int),
&indicesData[0], GL_STATIC_DRAW);
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// set camera
gluLookAt(3.5, -1.0, 3.5, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
// draw scene
glRotatef(t, 0.0f, 0.0f, 1.0f);
// activating VBO
glBindBuffer(GL_ARRAY_BUFFER, vertBufID);
int stride = 0;
glVertexPointer(3, GL_FLOAT, stride, NULL);
glEnableClientState(GL_VERTEX_ARRAY);
if(mode == 0) {
glColor3f(1.0f,1.0f,1.0f);
}else{
glColorPointer(3, GL_FLOAT, stride, NULL);
glEnableClientState(GL_COLOR_ARRAY);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBufID);
glDrawElements(GL_QUADS, vertSize*4, GL_UNSIGNED_INT, NULL);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
};
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW)
GL_STATIC_DRAW
the parameters GL_DYNAMIC_DRAW should be usedGL_STREAM_DRAW can be employedglBufferSubData(GL_ARRAY_BUFFER, offset, size, data)
struct Vertex
{
float position[3];
float color[4];
float texCoord[2];
float normal[3];
};
std::vector<Vertex> vertexData;
vertexData is created as one large VBO, memory access to the individual components is defined by
specifying the stride, which is the number of bytes between consecutive elements of the same type,
and the start address offset:
int stride = sizeof(Vertex); char* offset = (char*) NULL + (3+4+2)*sizeof(float); glNormalPointer(GL_FLOAT, stride, offset);
class Renderer {
private:
struct Vertex
{
float position[3];
float color[4];
float texCoord[2];
float normal[3];
};
public:
float t;
int mode;
private:
GLuint vertBufID;
GLuint texID;
int vertNo;
public:
// constructor
Renderer() : t(0.0), mode(0),
vertBufID(0), texID(0), vertNo(0) {}
//destructor
~Renderer() {
if(vertBufID !=0) glDeleteBuffers( 1, &vertBufID);
if(texID !=0) glDeleteTextures( 1, &texID);
}
public:
void init() {
glEnable(GL_DEPTH_TEST);
// generating VBO input data
float vertexData[] = {
0.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 1.0f, 0.0000f,-0.9701f, 0.2425f,
-0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0000f,-0.9701f, 0.2425f,
0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0000f,-0.9701f, 0.2425f,
0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.5f, 1.0f, 0.9701f, 0.0000f, 0.2425f,
0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.9701f, 0.0000f, 0.2425f,
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.9701f, 0.0000f, 0.2425f,
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, 1.0f, 0.0000f, 0.9701f, 0.2425f,
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0000f, 0.9701f, 0.2425f,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0000f, 0.9701f, 0.2425f,
0.0f, 0.0f, 2.0f, 1.0f, 1.0f, 0.0f, 1.0f,
0.5f, 1.0f,-0.9701f, 0.0000f, 0.2425f,
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f,-0.9701f, 0.0000f, 0.2425f,
-0.5f,-0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f,-0.9701f, 0.0000f, 0.2425f
};
vertNo = 12;
// generating vertex VBO
glGenBuffers(1, &vertBufID);
glBindBuffer(GL_ARRAY_BUFFER, vertBufID);
glBufferData(GL_ARRAY_BUFFER, vertNo*sizeof(Vertex),
vertexData, GL_STATIC_DRAW);
std::string fileName("checkerboard.ppm");
texID = loadTexture(fileName);
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// set camera
gluLookAt(3.0, -1.0, 4.5, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0);
// draw scene
glRotatef(t, 0.0f, 0.0f, 1.0f);
// activating VBO
glBindBuffer(GL_ARRAY_BUFFER, vertBufID);
int stride = sizeof(Vertex);
char *offset = (char*)NULL;
// position
glVertexPointer(3, GL_FLOAT, stride, offset);
glEnableClientState(GL_VERTEX_ARRAY);
// color
offset = (char*)NULL + 3*sizeof(float);
glColorPointer(4, GL_FLOAT, stride, offset);
glEnableClientState(GL_COLOR_ARRAY);
// texture
offset = (char*)NULL + (3+4)*sizeof(float);
glTexCoordPointer(2, GL_FLOAT, stride, offset);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// normals
offset = (char*)NULL + (3+4+2)*sizeof(float);
glNormalPointer(GL_FLOAT, stride, offset);
glEnableClientState(GL_NORMAL_ARRAY);
// bind texture
if(mode == 0) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID);
}else{
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
// render data
glDrawArrays(GL_TRIANGLES, 0, vertNo);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisable(GL_TEXTURE_2D);
}
...
};
display() function in the previous example, it is noticeable that in addition to the actual render call with glDrawArrays(...)
several additional function calls to glBindBuffer(...),
glXXXPointer(...) and glEnableClientState(...) are needed
glGenVertexArrays(1, &vaoID);
glBindVertexArray(...) and setting of the VBO states, they are stored to the currently bound VAO
glBindVertexArray(vaoID); glBindBuffer(GL_ARRAY_BUFFER, bufID); glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); glVertexPointer(3, GL_FLOAT, stride, offset); glEnableClientState(GL_VERTEX_ARRAY); ...
glBindVertexArray(vaoID); glDrawArrays(GL_TRIANGLES, 0, numOfTris);
glDeleteVertexArrays(1, &vaoID);When deleting the VAO its associated VBOs are not deleted. If desired, they must be released separately
class Renderer {
private:
struct Vertex
{
float position[3];
float color[4];
};
public:
float t;
int mode;
private:
enum {Pyramid, Cube, numVAOs};
enum {PyramidAll, CubePos, CubeCol, CubeIndices, numVBOs};
GLuint vaoID[numVAOs];
GLuint bufID[numVBOs];
int pyramidVertNo;
int cubeIndicesNo;
public:
// constructor
Renderer() : t(0.0), pyramidVertNo(0), cubeIndicesNo(0) {}
//destructor
~Renderer() {
glDeleteVertexArrays(numVAOs, vaoID);
glDeleteBuffers(numVBOs, bufID);
}
public:
void init() {
glEnable(GL_DEPTH_TEST);
// now we create 2 Vertex Array Objects (VAO):
// one for a pyramid and one for a cube.
// The pyramid uses one interleaved VBO
// which is later drawn with "glDrawArrays",
// while the cube uses 3 separate VBOs
// which are later drawn with "glDrawElements"
// create the Vertex Array Objects
glGenVertexArrays(numVAOs, vaoID);
// generating Vertex Buffer Objects (VBO)
glGenBuffers(numVBOs, bufID);
// specifying the pyramid VAO
glBindVertexArray(vaoID[Pyramid]);
float pyramidVertexData[] = {
0.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 2.0f, 1.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
-0.5f,-0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
};
pyramidVertNo = 12;
glBindBuffer(GL_ARRAY_BUFFER, bufID[PyramidAll]);
glBufferData(GL_ARRAY_BUFFER, pyramidVertNo*sizeof(Vertex),
pyramidVertexData, GL_STATIC_DRAW);
int stride = sizeof(Vertex);
char *offset = (char*)NULL;
// position
glVertexPointer(3, GL_FLOAT, stride, offset);
glEnableClientState(GL_VERTEX_ARRAY);
// color
offset = (char*)NULL + 3*sizeof(float);
glColorPointer(4, GL_FLOAT, stride, offset);
glEnableClientState(GL_COLOR_ARRAY);
// specifying the cube VAO
glBindVertexArray(vaoID[Cube]);
float cubePosData[] = {
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f
};
float cubeColorData[] = {
1.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
};
int cubeIndicesData[] =
{ 0, 1, 2, 3,
0, 4, 5, 1,
4, 7, 6, 5,
2, 6, 7, 3,
1, 5, 6, 2,
3, 7, 4, 0
};
cubeIndicesNo = 24;
// position
glBindBuffer(GL_ARRAY_BUFFER, bufID[CubePos]);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubePosData),
cubePosData, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, NULL);
glEnableClientState(GL_VERTEX_ARRAY);
// color
glBindBuffer(GL_ARRAY_BUFFER, bufID[CubeCol]);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeColorData),
cubeColorData, GL_STATIC_DRAW);
glColorPointer(3, GL_FLOAT, 0, NULL);
glEnableClientState(GL_COLOR_ARRAY);
// indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufID[CubeIndices]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndicesData),
cubeIndicesData, GL_STATIC_DRAW);
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (60.0, (float)w/(float)h, 0.1, 50.0);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// set camera
gluLookAt(3.0, -1.0, 4.5, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0);
// draw scene
glRotatef(t, 0.0f, 0.0f, 1.0f);
// bind cube VAO
glBindVertexArray(vaoID[Cube]);
// render data
glDrawElements(GL_QUADS, cubeIndicesNo,
GL_UNSIGNED_INT, NULL);
glTranslatef(0.0f, 0.0f, 1.0f);
// bind pyramid VAO
glBindVertexArray(vaoID[Pyramid]);
// render data
glDrawArrays(GL_TRIANGLES, 0, pyramidVertNo);
}
};
v 0.6 -2.5 0.1
vt 0.5 0.75
vn 0.0 -1.0 0.0
f v/vt/vn v/vt/vn v/vt/vn v/vt/vnwhere the respective first index refers to the list of vertices, the second one to the list of texture coordinates, and the third one to the list of normals
# Wavefront OBJ file example # o Cube v -1.0 1.0 1.0 v -1.0 -1.0 1.0 v 1.0 -1.0 1.0 v 1.0 1.0 1.0 v -1.0 1.0 -1.0 v -1.0 -1.0 -1.0 v 1.0 -1.0 -1.0 v 1.0 1.0 -1.0 # 8 vertices vt 0.0 0.0 vt 1.0 0.0 vt 1.0 1.0 vt 0.0 1.0 # 4 texture coordinates vn 0.0 0.0 1.0 vn -0.0 -0.0 -1.0 vn -1.0 -0.0 0.0 vn 0.0 -1.0 0.0 vn 1.0 0.0 -0.0 vn -0.0 1.0 -0.0 # 6 normals f 1/1/1 2/2/1 3/3/1 4/4/1 f 5/1/2 8/2/2 7/3/2 6/4/2 f 1/1/3 5/2/3 6/3/3 2/4/3 f 2/1/4 6/2/4 7/3/4 3/4/4 f 3/1/5 7/2/5 8/3/5 4/4/5 f 5/1/6 1/2/6 4/3/6 8/4/6 # 6 quads # indices start with 1 not 0
f v/vt/vn v/vt/vn v/vt/vn
f v v v
f v/vt v/vt v/vt
f v//vn v//vn v//vn
includedPerVertexData[] allows to adjust the composition of the generated float array so that
it fits to the required format of the VBOs (details in the source code)
struct Vertex
{
float position[3];
float color[4];
float texCoord[2];
float normal[3];
};
int includedPerVertexData[] = {POS_3f, DIFFUSE_3f, ALPHA_1f, TEXCOORD_2f, NORMAL_3f};
class Renderer {
private:
struct Vertex {
float position[3];
float color[4];
};
public:
float t;
private:
enum {Triangle, numVAOs};
enum {TriangleAll, numVBOs};
GLuint vaoID[numVAOs];
GLuint bufID[numVBOs];
int triangleVertNo;
int cubeIndicesNo;
public:
// constructor
Renderer() : t(0.0), triangleVertNo(0), cubeIndicesNo(0) {}
//destructor
~Renderer() {
glDeleteVertexArrays(numVAOs, vaoID);
glDeleteBuffers(numVBOs, bufID);
}
public:
void init() {
initExtensions();
glEnable(GL_DEPTH_TEST);
// create a Vertex Array Objects (VAO)
glGenVertexArrays(numVAOs, vaoID);
// generate a Vertex Buffer Object (VBO)
glGenBuffers(numVBOs, bufID);
// binding the Triangle VAO
glBindVertexArray(vaoID[Triangle]);
float triangleVertexData[] = {
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
};
triangleVertNo = 3;
glBindBuffer(GL_ARRAY_BUFFER, bufID[TriangleAll]);
glBufferData(GL_ARRAY_BUFFER, triangleVertNo*sizeof(Vertex),
triangleVertexData, GL_STATIC_DRAW);
int stride = sizeof(Vertex);
char *offset = (char*)NULL;
// position
int vertexLoc = 0;
glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, GL_FALSE,
stride, offset);
glEnableVertexAttribArray(vertexLoc);
}
void resize(int w, int h) {
glViewport(0, 0, w, h);
}
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// bind Triangle VAO
glBindVertexArray(vaoID[Triangle]);
// render data
glDrawArrays(GL_TRIANGLES, 0, triangleVertNo);
}
};
Please notify me by e-mail if you have questions, suggestions for improvement, or found typos: Contact