Hey all,
I’m trying to optimize my program to a relatively modern openGL standard. In that interest, I’m trying to write a class for 3D objects with a model and texture loading function (with SOIL) as well as a display function for the VBOs generated in the loader functions. However, nothing ever shows up on the screen. I think I might be mixing something up with the element array.
My object loader code is:
bool MainWindow::VBO::loadOBJFile(const char* file)
{
std::vector<GLfloat> temp_coords, v_idx, n_idx, uv_idx, final_vertices, final_normals, final_uvs;
std::vector<glm::vec3> temp_vertices, temp_normals, middle_vertices, middle_normals;
std::vector<glm::vec2> temp_uv, middle_uvs;
char buffer[512];
FILE *Data = NULL;
int bufferError,
readError = 3;
errno_t test;
test = fopen_s(&Data, file, "r");
if(Data == NULL)
{
qDebug() << "OBJ file" << file << "not found!";
return false;
}
else
{
qDebug() << "OBJ file" << file << "loading now into" << this;
}
do
{
bufferError = fscanf(Data, "%s", buffer);
if(bufferError == EOF)
{
break;
}
if(strcmp(buffer, "v") == 0)
{
glm::vec3 vertex;
readError = fscanf(Data, "%f %f %f
", &vertex.x, &vertex.y, &vertex.z);
temp_coords.push_back(vertex.x);
temp_coords.push_back(vertex.y);
temp_coords.push_back(vertex.z);
temp_vertices.push_back(vertex);
}
else if(strcmp(buffer, "vt") == 0)
{
glm::vec2 uv;
readError = fscanf(Data, "%f %f
", &uv.x, &uv.y);
temp_uv.push_back(uv);
}
else if(strcmp(buffer, "vn") == 0)
{
glm::vec3 normal;
readError = fscanf(Data, "%f %f %f
", &normal.x, &normal.y, &normal.z);
temp_normals.push_back(normal);
}
else if(strcmp(buffer, "f") == 0)
{
unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
int matches = fscanf(Data, "%d/%d/%d %d/%d/%d %d/%d/%d
", &vertexIndex[0], &uvIndex[0], &normalIndex[0],
&vertexIndex[1], &uvIndex[1], &normalIndex[1],
&vertexIndex[2], &uvIndex[2], &normalIndex[2] );
if (matches != 9){
qDebug() << "File can't be read by our simple parser! Try exporting with other options";
qDebug() << "matches is" << matches;
return false;
}
v_idx.push_back(vertexIndex[0]);
v_idx.push_back(vertexIndex[1]);
v_idx.push_back(vertexIndex[2]);
uv_idx.push_back(uvIndex[0]);
uv_idx.push_back(uvIndex[1]);
uv_idx.push_back(uvIndex[2]);
n_idx.push_back(normalIndex[0]);
n_idx.push_back(normalIndex[1]);
n_idx.push_back(normalIndex[2]);
}
else if(strcmp(buffer, "o") == 0)
{
readError = fscanf(Data, "%s", modelName);
qDebug() << "name of the model is" << modelName;
}
else
{
// qDebug() << "testString is" << buffer << "and won't be recognized";
}
}while(1);
fclose(Data);
for( unsigned int i=0; i<v_idx.size(); i++ ){
unsigned int vertexIndex = v_idx[i];
glm::vec3 vertex = temp_vertices[ vertexIndex-1 ];
middle_vertices.push_back(vertex);
}
for( unsigned int i=0; i<uv_idx.size(); i++ ){
unsigned int uvIndex = uv_idx[i];
glm::vec2 uv = temp_uv[ uvIndex-1 ];
middle_uvs.push_back(uv);
}
for( unsigned int i=0; i<n_idx.size(); i++ ){
unsigned int normalIndex = n_idx[i];
glm::vec3 normal = temp_normals[ normalIndex-1 ];
middle_normals.push_back(normal);
}
for(unsigned int i= 0; i<middle_vertices.size();i++)
{
final_vertices.push_back(middle_vertices.at(i).x);
final_vertices.push_back(middle_vertices.at(i).y);
final_vertices.push_back(middle_vertices.at(i).z);
}
for(unsigned int i= 0; i<middle_normals.size();i++)
{
final_normals.push_back(middle_normals.at(i).x);
final_normals.push_back(middle_normals.at(i).y);
final_normals.push_back(middle_normals.at(i).z);
}
for(unsigned int i= 0; i<middle_uvs.size();i++)
{
final_uvs.push_back(middle_uvs.at(i).x);
final_uvs.push_back(middle_uvs.at(i).y);
}
glGenBuffers(1, &vertices);
glBindBuffer(GL_ARRAY_BUFFER, vertices);
glBufferData(GL_ARRAY_BUFFER, final_vertices.size(), final_vertices.data(), GL_STATIC_DRAW);
glGenBuffers(1, &normals);
glBindBuffer(GL_ARRAY_BUFFER, normals);
glBufferData(GL_ARRAY_BUFFER, final_normals.size(), final_normals.data(), GL_STATIC_DRAW);
glGenBuffers(1, &uvs);
glBindBuffer(GL_ARRAY_BUFFER, uvs);
glBufferData(GL_ARRAY_BUFFER, final_uvs.size(), final_uvs.data(), GL_STATIC_DRAW);
for( unsigned int i=0; i<v_idx.size(); i++ ){
v_idx[i]--;
}
glGenBuffers(1, &elements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, v_idx.size(), v_idx.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
return true;
}
Texture loader is:
bool MainWindow::VBO::loadTexture(const char* texfile)
{
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
// inspired by http://open.gl/textures
int width, height;
unsigned char* image =
SOIL_load_image(texfile, &width, &height, 0, SOIL_LOAD_RGB);
if(image == 0)
{
qDebug() << "Texture file" << texfile << "not found!";
return false;
}
else
{
qDebug() << "image =" << image << "from file" << texfile;
qDebug() << "width and height =" << width << height;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return true;
}
The display function:
glm::mat4 anim = glm::yawPitchRoll(-handPitch, -handRoll, -handYaw);
glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(handX, handY, handZ));
glm::mat4 view = glm::lookAt(glm::vec3(xPosTranslate, 0.0, 5.0), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
glm::mat4 projection = glm::perspective(45.0f, /*1.0*/0.5f*this->width()/this->height(), 0.1f, 100.0f);
glm::mat4 mvp = projection * view * model * anim;
glUseProgram(program);
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
glUseProgram(program);
glEnableVertexAttribArray(attribute_coord3d);
void MainWindow::drawOBJ(VBO object)
{
glEnableVertexAttribArray(attribute_coord3d);
glBindBuffer(GL_ARRAY_BUFFER, object.vertices);
glVertexAttribPointer(
attribute_coord3d, // attribute
3, // number of elements per vertex, here (x,y,z)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
0, // no extra data between each position
0 // offset of first element
);
glEnableVertexAttribArray(attribute_v_normal);
glBindBuffer(GL_ARRAY_BUFFER, object.normals);
glVertexAttribPointer(
attribute_v_normal, // attribute
3, // number of elements per vertex, here (x,y,z)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
0, // no extra data between each position
0 // offset of first element
);
glEnableVertexAttribArray(attribute_v_uv);
glBindBuffer(GL_ARRAY_BUFFER, object.uvs);
glVertexAttribPointer(
attribute_v_uv, // attribute
2, // number of elements per vertex, here (U,V)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
0, // no extra data between each position
0 // offset of first element
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object.elements);
}
int size;
glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);
glDisableVertexAttribArray(attribute_coord3d);
glDisableVertexAttribArray(attribute_v_color);
glDisableVertexAttribArray(attribute_v_uv);
glDisableVertexAttribArray(attribute_v_normal);
glUseProgram(0);
I don’t see where my error is, however I’m pretty certain, as I wrote, that something is not quite right about the handling of the elements. I haev a whole bunch of glGetError() calls in between (deleted those here for readability), they return no errors. If any of you pros around here might give the code a quick look, it’d be appreciated.