I am really new to Open GL and I am trying to build non deprecated code. Now what I can't grasp is VBO. This is all I got so far, can you please explain what I'm supposed to be doing. Also, I have the OpenGL programming guide, so if you can point out some pages to read that would be very helpful as well.
#include <GL/glew.h>
#include <GL/freeglut.h>
GLuint ID[2];
GLfloat PositionData[][2] ={{50,50},{100,50},{50,100}, {100,50}, {100, 100}, {50, 100}};
GLfloat Colors[][3] = {{0.1, 0.2, 0.3},{0.1, 0.2, 0.3},{0.1, 0.2, 0.3},{0.1, 0.2, 0.3},{0.1, 0.2, 0.3}};
void init(){
glewInit();
glClearColor(1.0, 1.0, 1.0, 0.0);
}
void display(){
glClear(GL_COLOR_BUFFER_BIT);
glShadeModel(GL_FLAT);
glGenBuffers(2, ID);
glBindBuffer(GL_ARRAY_BUFFER, ID[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(PositionData), PositionData, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, ID[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Colors), Colors, GL_STATIC_DRAW);
glEnableClientState(GL_COLOR_ARRAY);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 12);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDeleteBuffers(2, ID);
glFlush();
}
void reshape(int w, int h){
glViewport(0,0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0f, (GLdouble) w, 0.0f, (GLdouble) h);
}
int main(int argc, char *argv[]){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("I don't get VBOs");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
I did a quick look on your code, an one thing stood out: You're completely missing the point of VBOs. In each draw call you're creating the VBO objects, upload the data, try to draw them (it won't work, because the shaders giving the vertex attributes sense are misssing) and then delete them.
The whole point of VBO is to upload the geometry data into a GL object once and then only refer to it by it's abstract object ID handle and index arrays, which one would also place in a buffer object.
But there's so much else screwed in that code, like setting projection matrix in reshape callback. For one thing, in OpenGL-3 core you don't have those built-in matrices anymore. It's all shader uniforms. And then you set those matrices on demand in the rendering handler.
I think I should really write that definitive OpenGL-3 core tutorial, demonstrating the proper idioms.
You are setting up custom vertex attributes with indices 0 and 1, but I don't see a shader that uses them. If you don't have a shader yet, then it will not work, because Fixed-Function pipeline accepts specific attributes (set up by glVertexPointer and glColorPointer for your case).
If you decide to make a shader (your goal is to make it for GL-3 core, right?), don't forget to assign your vertex attributes with actual names you use in GLSL code before linking it:
glBindAttribLocation( program_id, attribute_id, attribute_variable_name )
Related
I've been looking into how to make the bubble texture transparent but haven't found anything that would fit in my code. I have tried with glColor4f() but I might be putting it in the wrong place. I'm a total beginner in openGL and I've been given a basic code to which I need to add other objects in order to make a 2D scene. I also don't exactly know what every single line does.
These are the relevant pieces of code:
// Globals
GLuint locT; // location of "T" uniform variable in myShaderProgram
GLuint locT2;
// Textures
GLuint myBubblesTexture = 0;
// Shader program object for applying textures to our shapes
GLuint myShaderProgram;
// Vertex Buffer Object IDs for the ground texture object
GLuint bubblesPosVBO, bubblesColourVBO, bubblesTexCoordVBO, bubblesIndicesVBO;
// 1) Position Array - Store vertices as (x,y) pairs
static GLfloat bubblesVertices[] = {
-0.2f, -0.2f,
-0.2f, 0.2f,
0.2f, -0.2f,
0.2f, 0.2f
};
// 2) Colour Array - Store RGB values as unsigned bytes
static GLubyte bubblesColors[] = {
255, 0, 0, 255,
255, 255, 0, 255,
0, 255, 0, 255,
0, 255, 255, 255
};
// 3) Texture coordinate array (store uv coordinates as floating point values)
static float bubblesTextureCoords[] = {
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
// 4) Index Array - Store indices to quad vertices - this determines the order the vertices are to be processed
static GLubyte bubblesVertexIndices[] = { 0, 1, 2, 3 };
void init(int argc, char* argv[]);
void setupBubblesTextureVBO(void);
void display(void);
void drawTexturedBubblesVBO(void);
int _tmain(int argc, char* argv[])
{
init(argc, argv);
glutMainLoop();
// Shut down COM
shutdownCOM();
return 0;
}
void init(int argc, char* argv[]) {
// Initialise COM so we can use Windows Imaging Component
initCOM();
// Initialise FreeGLUT
glutInit(&argc, argv);
glutInitContextVersion(3, 3);
glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(1200, 800);
glutInitWindowPosition(64, 64);
glutCreateWindow("Funky Fish");
// Register callback functions
glutDisplayFunc(display);
// Initialise GLEW library
GLenum err = glewInit();
// Setup colour to clear the window
glClearColor(0.2f, 0.2f, 0.8f, 0.0f);
glLineWidth(9.0f);
//Load textures
myBubblesTexture = fiLoadTextureA("bubbles.png");
//Shader setup
myShaderProgram = setupShaders(string("Shaders\\basic_vertex_shader.txt"), string("Shaders\\basic_fragment_shader.txt"));
// Get uniform location of "T" variable in shader program (we'll use this in the play function to give the uniform variable "T" a value)
locT = glGetUniformLocation(myShaderProgram, "T");
//Setup the bubbles using VBO
setupBubblesTextureVBO();
}
// our bubbles
void setupBubblesTextureVBO(void) {
// setup VBO for the quad object position data
glGenBuffers(1, &bubblesPosVBO);
glBindBuffer(GL_ARRAY_BUFFER, bubblesPosVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(bubblesVertices), bubblesVertices, GL_STATIC_DRAW);
// setup VBO for the quad object colour data
glGenBuffers(1, &bubblesColourVBO);
glBindBuffer(GL_ARRAY_BUFFER, bubblesColourVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(bubblesColors), bubblesColors, GL_STATIC_DRAW);
// setup VBO for the quad object texture coord data
glGenBuffers(1, &bubblesTexCoordVBO);
glBindBuffer(GL_ARRAY_BUFFER, bubblesTexCoordVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(bubblesTextureCoords), bubblesTextureCoords, GL_STATIC_DRAW);
// setup quad vertex index array
glGenBuffers(1, &bubblesIndicesVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bubblesIndicesVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(bubblesVertexIndices), bubblesVertexIndices, GL_STATIC_DRAW);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw our bubble
drawTexturedBubblesVBO();
glutSwapBuffers();
}
void drawTexturedBubblesVBO(void) {
glUseProgram(myShaderProgram);
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Move our bubble to the centre of the screen
GUMatrix4 T = GUMatrix4::translationMatrix(0.0f, 0.0f, 0.0f);
glUniformMatrix4fv(locT, 1, GL_FALSE, (GLfloat*)&T);
// Bind each vertex buffer and enable
// The data is still stored in the GPU but we need to set it up (which also includes validation of the VBOs behind-the-scenes)
// Bind texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, myBubblesTexture);
glUniform1i(glGetUniformLocation(myShaderProgram, "texture"), 0);
glEnable(GL_TEXTURE_2D);
glBindBuffer(GL_ARRAY_BUFFER, bubblesPosVBO);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, bubblesColourVBO);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, bubblesTexCoordVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);
glEnableVertexAttribArray(2);
// Bind the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bubblesIndicesVBO);
// Draw the object - same function call as used for vertex arrays but the last parameter is interpreted as an offset into the currently bound index buffer (set to 0 so we start drawing from the beginning of the buffer).
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (GLvoid*)0);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glDisable(GL_TEXTURE_2D);
// use to force disable our shaderprogram
// glUseProgram(0);
}
The code looks OK so:
Does your Texture have an alpha channel?
Does your OpenGL context pixel format has Alpha channel buffer?
What kind of transparency you want (whole texture have the same transparency, or the transparency should be modulated)?
The glColor4f(1.0,1.0,1.0,alpha) will work only if your textures are configured to be modulated by glColor and have nonzero alpha channel set so you need to add:
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
call after binding the texture to make it work.
In case you do not have alpha channel (in texture or in pixelformat) you can use:
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
Also take a look at:
OpenGL - How to create Order Independent transparency?
I recently created an OBJ loader, it works perfectly fine at the moment, which is without any VBO buffer objects. I am currently in the process of changing over to using VBO with my program and it crashes( doesn't respond) every time I try to run it.
My obj loader consists of drawing the normals and verts, it has the indicies aswell.
I am new to openGL and I somewhat have an idea of how VBO works.
This is it when I have made an attempt to add buffers to my program.
This is it without
This is my code that is currently crashing
#define GLEW_STATIC
#include <GL/glew.h
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
int main(int argc,char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("Object Loader!");
setUpArrays();
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glGenBuffers(1, &vbo);
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(normals), normals, GL_STATIC_DRAW);
GLfloat posLight0[] = {0.0f, 0.0f, -1.0f, 0.0f};
GLfloat lightColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, posLight0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
glutDisplayFunc(Draw);
glutSpecialFunc(specialKeys);
glutReshapeFunc(reshape);
glutTimerFunc(25,update,0);
glutMainLoop();
return 0;
}
This is my draw function
void Draw(void)
{
glPushMatrix();
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef( rotate_x, 1.0, 0.0, 0.0 );
glRotatef( rotate_y, 0.0, 1.0, 0.0 );
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT,0, vertices);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals);
glColor3f(0.5f, 0.0f, 0.8f);
glDrawElements(GL_TRIANGLES, amountOfFaces, GL_UNSIGNED_INT, faces);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glFlush();
glutSwapBuffers();
glPopMatrix();
}
These are the only two functions that I have changed,
I've defined the unsigned int vbo and vbo2 outside.
The problem (and cause of the crash) is that your glVertexPointer should have 0 as the offset because it is relative tot the beginning of the bound buffer. (0 is a special case that treats program memory as one big buffer)
glGenBuffers(1, &vbo);
glGenBuffers(1, &vbo2);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(normals), normals, GL_STATIC_DRAW);
That is another problem; the 4th line glBindBuffer fully overrides the previous call to glBindBuffer. Or more generally; only the last glBindBuffer call is used so you never actually use vbo.
Also how are vertices and normals declared? if they are just pointers then you should replace sizeof with sizeof(*vertices)*3*amountOfFaces
Your code sample indicates that you're trying to use GLEW, but you haven't called glewInit after glutCreateWindow. You can't use OpenGL extension functions without loading their addresses first - that's exactly what GLEW do, if you don't want to mess with it manually (most likely you don't).
Your code appears to be wrong even after that, but it probably wouldn't crash. Can't say without full code of course, but
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo2);
Don't making sense - bind one buffer, then immediately another - why is that?
I just get a black screen when I try to use a vbo. I'm using GLFW with GLEW. It does the same with textures but I didn't use textures to see if that'd work, but for some reason it's not. I had it working but I made some changes to the code, so I think I may have done something. PS: If the code has an error in it, let me know, as I removed code that doesn't affect rendering and I may have deleted important code on accident
Here is main.cpp, with some stuff that doesn't affect OpenGL removed:
//Include all OpenGL stuff, such as gl.h, glew.h, and glfw3.h
#include "gl.h"
//Include a header which adds some functions for loading shaders easier, there is nothing wrong with this code though
#include "shader.h"
float data[3][3] = {
{0.0, 1.0, 0.0},
{-1.0, -1.0, 0.0},
{1.0, -1.0, 0.0}
};
int main()
{
if (!glfwInit())
return 1;
GLFWwindow* window;
window = glfwCreateWindow(800, 600, "VBO Test", NULL, NULL);
if (!window)
{
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
if (GLEW_OK != glewInit())
{
return 1;
glfwTerminate();
}
//There are normal error handling stuff I do to ensure everything is loaded properly, so the shaders not loading isn't a concern as it'll clearly tell me :)
GLuint vertexShader = loadShader("shader.vert", GL_VERTEX_SHADER);
GLuint fragmentShader = loadShader("shader.frag", GL_VERTEX_SHADER);
GLuint program = createProgram(vertexShader, fragmentShader);
//Also, the shader files should make everything I draw yellow, and they are not defective
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glColorPointer(3, GL_FLOAT, 0, 0);
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
glUsePorgram(program);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
shader.vert
void main(void)
{
gl_Position = gl_Vertex;
}
shader.frag
void main()
{
//Set fragment
gl_FragColor = vec4( 1.0, 1.0, 0.0, 1.0 );
}
The main thing that jumps to mind is not enabling the client states for vertex and colour pointers.
Since the colour and position data overlaps, the colours will look a little strange. I'd start with just the glVertexPointer and glEnableClientState(GL_VERTEX_ARRAY), using a single glColor3f call. Then add a colour array later.
Also, you're buffering the same data to the same VBO twice. The VBO only needs to be bound before one call to glBufferData and the gl*Pointer functions.
Personally I don't like the 2D array, even though it probably works when declared statically. OpenGL will take data out of memory linearly. Using an array of structs can be quite nice.
See this for an small example:
http://goanna.cs.rmit.edu.au/~pknowles/SimpleVBO.c
I've been trying to render a cube in a QGLWidget, but it comes out wrong. No matter how I rotate it, it looks like a flat square. It's like it didn't notice the Z coordinates of its vertices. Just before I added clearing of the GL_DEPTH_BUFFER_BIT, the square looked like all of the cube's sides crammed into one. Now it seems to discard vertices which don't belong in the front side, but it still isn't a cube.!
Screenshots [link]
My initializeGL() and paintGL():
typedef struct
{
float XYZW[4];
float RGBA[4];
} Vertex;
Vertex Vertices[8] =
{
//vertices
};
const GLubyte Indices[36] =
{
//indices
};
void ModelView::initializeGL()
{
m_program = new QGLShaderProgram(this);
m_program->addShaderFromSourceCode(QGLShader::Vertex, vertexShaderSource);
m_program->addShaderFromSourceCode(QGLShader::Fragment, fragmentShaderSource);
m_program->link();
}
void ModelView::paintGL()
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearColor(.5f, .5f, .5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, width(), height());
m_program->bind();
QMatrix4x4 matrix;
matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
matrix.translate(0, 0, -2);
matrix.rotate(50.0, 1, 1, 1);
m_program->setUniformValue(m_matrixUniform, matrix);
m_posAttr = m_program->attributeLocation("posAttr");
m_colAttr = m_program->attributeLocation("colAttr");
m_matrixUniform = m_program->uniformLocation("matrix");
glGenBuffers(1, &BufferId);
glGenBuffers(1, &IndexBufferId);
glBindBuffer(GL_ARRAY_BUFFER, BufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);
glBufferData(GL_ARRAY_BUFFER, BufferSize, Vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, VertexSize, 0);
glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, VertexSize, (GLvoid *)RgbOffset);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, NULL);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
m_program->release();
}
Vertices and Indices should be defined correctly, they're taken from a tutorial, as is most of the code. Rendering of 2D object seems to be just fine, though.
Also, why does the tutorial call matrix.translate with the -2 argument? If I change it to anything else greater than 1 or remove it, the rendered object disappears.
Qt5, Windows Vista 32-bit.
Also, why does the tutorial call matrix.translate with the -2
argument? If I change it to anything else greater than 1 or remove it,
the rendered object disappears.
This is due to clipping. When you render objects, things that are "too close" or "too far" are discarded, via the near and far clipping planes (respectively).
By moving the cube closer (changing -2 to 1 or 0), you are bringing the cube forward, past the near clipping plane, and it consequently disappears.
glVertexAttribPointer() has a size parameter, which specifies the number of components per vertex. In the code it is 2, therefore everything is 2D. Changing to 3 solves the issue.
so I will need to edit this question. As stated in one of the comments, I changed to rendering method to use buffers. However, the geometry isn't being drawn correctly. If I use the same buffer and draw the vertices manually, it looks alright (without the texture though, something is messed up with it). I also tried constructing a buffer with just vertex information but that didn't help at all.
void ModelHandler::DrawModels(){
//go through each of the models
for(int i=0;i<Models3D.size();i++){
//glEnableClientState(GL_VERTEX_ARRAY);
//glVertexPointer(3, GL_FLOAT, 0, Models3D[i]->object.m_pVertice);
//now draw all the material groups with their vertices for the model
for(int j=0;j<Models3D[i]->object.mtlGroups.size();j++){
//Drawing the vertices manually from the buffer object seems to work
/*
for(int lj=0;lj<Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size();lj++){
int mtlIndex2 = Models3D[i]->object.FindMaterial(Models3D[i]->object.mtlGroups[j]->mtlName);
bool tOn = false;
//check if there was a texture for this material
if(Models3D[i]->object.materials[mtlIndex2]->texturePresent){
glEnable(GL_TEXTURE_2D);
//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, Models3D[i]->object.materials[mtlIndex2]->textureIDDiffuse);
tOn = true;
}
if(tOn){
glBegin (GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f (0.0+5, 0.0, -2.0f);
glTexCoord2f (1.0, 0.0);
glVertex3f (1.4f+5, 0.0, -2.0f);
glTexCoord2f (1.0, 1.0);
glVertex3f (1.4f+5, -1.0, -2.0f);
glTexCoord2f (0.0, 1.0);
glVertex3f (0.0f+5, -1.0, -2.0f);
glEnd ();
}
glBegin(GL_TRIANGLES);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[2]);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[2]);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[2]);
glEnd();
}
glDisable(GL_TEXTURE_2D);
*/
//####
glBindBuffer(GL_ARRAY_BUFFER, Models3D[i]->object.mtlGroups[j]->vboID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Models3D[i]->object.mtlGroups[j]->indexvboID);
/*
//this could also be used BUT if glDrawElements uses the indices (m_pgroupVerticeIndex), we will need to give the array with all the
//vertices to glVertexPointer. That array would be m_pVertice
//glVertexPointer(3, GL_FLOAT, 5, Models3D[i]->object.mtlGroups[j]->buffer);
*/
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
//Get the material that belongs to this mtlGroup
int mtlIndex = Models3D[i]->object.FindMaterial(Models3D[i]->object.mtlGroups[j]->mtlName);
//check if there was a texture for this material
if(Models3D[i]->object.materials[mtlIndex]->texturePresent){
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, Models3D[i]->object.materials[mtlIndex]->textureIDDiffuse);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
//glTexCoordPointer(2, GL_FLOAT, 5, Models3D[i]->object.mtlGroups[j]->buffer);
//glTexCoordPointer(2, GL_FLOAT, 0, Models3D[i]->object.m_pTexture);
}
// Resetup our pointers. This doesn't reinitialise any data, only how we walk through it
glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
glColorPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
glDrawElements(GL_TRIANGLES, Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size()*3, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
//glDrawElements(GL_TRIANGLES, Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size()*3, GL_UNSIGNED_INT, Models3D[i]->object.mtlGroups[j]->m_pgroupVerticeIndex);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
}
}
}
My buffer contains the vertices (array of Vertex structs):
struct Vertex {
GLfloat location[3];
GLfloat tex[2];
GLfloat normal[3];
GLfloat colour[3];
GLubyte padding[20]; //apparently to get 64 bytes -> improved performance
};
And here is how I initialize/generate buffers for each of the materials:
//This function was implemented based on the tutorial shown at
//http://sdickinson.com/wordpress/?p=122
void CObjLoader::GenerateVBO(){
for(int mj=0;mj<mtlGroups.size();mj++){
glGenBuffers(1, &mtlGroups[mj]->vboID);
//printf("bufferID: %d", mtlGroups[mj]->vboID);
glBindBuffer(GL_ARRAY_BUFFER, mtlGroups[mj]->vboID); // Bind the buffer (vertex array data)
// Allocate space. We could pass the mesh in here (where the NULL is), but it's actually faster to do it as a
// seperate step. We also define it as GL_STATIC_DRAW which means we set the data once, and never
// update it. This is not a strict rule code wise, but gives hints to the driver as to where to store the data
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3, mtlGroups[mj]->VBO); // Actually upload the data
// Set the pointers to our data. Except for the normal value (which always has a size of 3), we must pass
// the size of the individual component. ie. A vertex has 3 points (x, y, z), texture coordinates have 2 (u, v) etc.
// Basically the arguments are (ignore the first one for the normal pointer), Size (many components to
// read), Type (what data type is it), Stride (how far to move forward - in bytes - per vertex) and Offset
// (where in the buffer to start reading the data - in bytes)
// Make sure you put glVertexPointer at the end as there is a lot of work that goes on behind the scenes
// with it, and if it's set at the start, it has to do all that work for each gl*Pointer call, rather than once at
// the end.
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
glColorPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
// When we get here, all the vertex data is effectively on the card
// Our Index Buffer, same as above, the variable needs to be accessible wherever we draw
glGenBuffers(1, &mtlGroups[mj]->indexvboID); // Generate buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mtlGroups[mj]->indexvboID); // Bind the element array buffer
// Upload the index array, this can be done the same way as above (with NULL as the data, then a
// glBufferSubData call, but doing it all at once for convenience)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3*sizeof(GLubyte), mtlGroups[mj]->index, GL_STATIC_DRAW);
}
}
For the sake of simplicity, my index array looks like this: 0, 1, 2, 3, 4, 5, .... This means that my buffer contains some of the vertices twice. VBO and index have therefore the same length.
Maybe I am messing something up with the initialization?
So the error was the following (I will just copy my previous comments explaining the solution):
Ok, I've found the error. Apparently, I was using GLubyte for the indices and in my case, I have way more than 255 vertices. Changing to GLuint has resolved the issue. However, my texture still isn't drawn correctly onto the object. The object stays grey. But colors seem to work.
The .obj loader is yielding better results now and is ok with simpler models. I will do some further testing and in case of trouble, I will be back.