PDA

View Full Version : Displaying multiple objects using separate vbos



krunal
09-24-2017, 02:31 PM
Hey guys, I'm learning Opengl 3.3. So basically I would like to display three objects on the screen using a separate vbo for each object. I'm using the models of mobile, chair and table as my objects whose data is stored in files I'm reading. I'm not having any issues trying to display them on the screen one object at a time. But when I try to display them together, I'm facing issues.

void loadObject()
{
if(mode=='I')
{
initBuffersGL();
// changeObjects();
char file_name[100];
std::cout<<"Enter file to be loaded: ";
std::cin>>file_name;

FILE *fp;
int i;
float x,y,z;
float r,g,b;

/* open the file */
fp = fopen(file_name, "r");
if (fp == NULL)
{
printf("Couldn't open file for reading.\n");
exit(0);
}
i=0;
tri_idx=0;
// reinitializepos();
//6 float points constituting to x,y,z,r,g,b of a vertex.
while (fscanf(fp, "%f,%f,%f,%f,%f,%f\n", &x, &y, &z, &r, &g, &b) == 6)
{
v_positions[vbo_count][i]=glm::vec4(x,y,z,1.0f);
v_colors[vbo_count][i]=glm::vec4(r,g,b,1.0f);
i++;
}
fclose(fp);
tri_idx=i;
//reset the rotation and translation matrices
// recenter();
glBindBuffer (GL_ARRAY_BUFFER, vbo);
// glEnableVertexAttribArray(0);
glBufferData (GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count]) + sizeof(v_colors[vbo_count]) , NULL, GL_DYNAMIC_DRAW);
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof (v_positions[vbo_count]), v_positions[vbo_count] );
glBufferSubData( GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count]), sizeof(v_colors[vbo_count]), v_colors[vbo_count] );
// glBindVertexArray (vao);
glDrawArrays(GL_TRIANGLES, 0, num_vertices);
vbo_count++;

/* open the file */
// glGenVertexArrays(1, &vao1);
// glBindVertexArray(vao1);
glGenBuffers(1,&vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
// glEnableVertexAttribArray(0);
fp = fopen("chair.raw", "r");
if (fp == NULL)
{
printf("Couldn't open file for reading.\n");
exit(0);
}
i=0;
tri_idx=0;
// reinitializepos();
//6 float points constituting to x,y,z,r,g,b of a vertex.
while (fscanf(fp, "%f,%f,%f,%f,%f,%f\n", &x, &y, &z, &r, &g, &b) == 6)
{
v_positions[vbo_count][i]=glm::vec4(x,y,z,1.0f);
v_colors[vbo_count][i]=glm::vec4(r,g,b,1.0f);
i++;
}
fclose(fp);
glBindBuffer (GL_ARRAY_BUFFER, vbo1);
// glEnableVertexAttribArray(0);
glBufferData (GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count]) + sizeof(v_colors[vbo_count]) , NULL, GL_DYNAMIC_DRAW);
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof (v_positions[vbo_count]), v_positions[vbo_count] );
glBufferSubData( GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count]), sizeof(v_colors[vbo_count]), v_colors[vbo_count] );
glBindVertexArray (vao);
glDrawArrays(GL_TRIANGLES, 0, num_vertices);
vbo_count++;
}

Here I'm trying to load data of the objects into the separate vbos and get them displayed, but only the first object gets displayed.
Here's my initBuffersGL:

void initBuffersGL(void)
{
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
//Copy the points into the current buffer
glBufferData (GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count]) + sizeof(v_colors[vbo_count]), NULL, GL_DYNAMIC_DRAW);
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(v_positions[vbo_count]), v_positions[vbo_count] );
glBufferSubData( GL_ARRAY_BUFFER, sizeof(v_positions[vbo_count]), sizeof(v_colors[vbo_count]), v_colors[vbo_count] );

// Load shaders and use the resulting shader program
std::string vertex_shader_file("03_vshader.glsl");
std::string fragment_shader_file("03_fshader.glsl");

std::vector<GLuint> shaderList;
shaderList.push_back(csX75::LoadShaderGL(GL_VERTEX _SHADER, vertex_shader_file));
shaderList.push_back(csX75::LoadShaderGL(GL_FRAGME NT_SHADER, fragment_shader_file));

shaderProgram = csX75::CreateProgramGL(shaderList);
glUseProgram( shaderProgram );

// set up vertex arrays
GLuint vPosition = glGetAttribLocation( shaderProgram, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );

GLuint vColor = glGetAttribLocation( shaderProgram, "vColor" );
glEnableVertexAttribArray( vColor );
glVertexAttribPointer( vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(v_positions[vbo_count])) );

uModelViewMatrix = glGetUniformLocation( shaderProgram, "uModelViewMatrix");
}

Since my first object was getting displayed just fine, I also tried an alternative approach, here:

void loadObject()
{
// Same code as previous
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count])*3 + sizeof(v_colors[vbo_count])*3 , NULL, GL_DYNAMIC_DRAW);

vbo_count++;

// Same code

glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof (v_positions[vbo_count-1]), v_positions[vbo_count-1] );
glBufferSubData( GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count-1]), sizeof(v_colors[vbo_count-1]), v_colors[vbo_count-1] );
glBufferSubData( GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count-1]) + sizeof(v_colors[vbo_count-1]),sizeof (v_positions[vbo_count]) , v_positions[vbo_count] );
glBufferSubData( GL_ARRAY_BUFFER, sizeof (v_positions[vbo_count-1]) + sizeof (v_positions[vbo_count]) + sizeof (v_colors[vbo_count-1]), sizeof(v_colors[vbo_count]), v_colors[vbo_count] );

glDrawArrays(GL_TRIANGLES, 0, num_vertices);
vbo_count++;
}

Here I'm trying to load data of both objects into the same vbo and get them displayed, but again only the first object gets displayed.
So how can I get my objects to display on the screen simultaneously?
Added note: Just thought I'd mention that I'm using glfw, contrary to glut which i found being used in tutorials all over.

Dark Photon
09-25-2017, 05:39 AM
Search for "vao". You've got the Gen and Bind commands of your "vao1" commented out, as well as the Gen of your "vao" (in the code you posted at least). But you've still got a Bind of "vao" in there.

My suggestion: In your app init code, do a single glGenVertexArrays and glBindVertexArrays to activate a dummy vertex array object (VAO), and then for now just don't do anything else with VAOs in your program. Note that these two steps are only needed if your GL context was created using a "core" profile. If you're using a GL context created in a "compatibility" profile, you can skip the Gen and Bind of this dummy VAO up-front and never use VAOs.

Also, right before your glDraw* call is when you should be setting up your vertex attrib bindings and enables (e.g.
glBindBuffer (GL_ARRAY_BUFFER, ...), glVertexAttribPointer( ... ), gl{Enable,Disable}VertexAttribArray(...)).

The reason I suggest this starter approach is that VAOs tend to be confusing for new GL users. They're pretty simple, but they add a bit of complexity to your GL code that you don't need to worry about when you're getting started. If you structure your code as I describe above, then added them in later will be a snap. Further, understanding what they buy you will be much more obvious.

Also, I don't see you Checking for GL errors (https://www.khronos.org/opengl/wiki/GL_Error_Codes). You should do this as it will catch many GL usage problems for you.

krunal
09-25-2017, 03:20 PM
Thanks for the response. I was trying to bind separate vaos as well among the things I tried, and hence I commented out my vao1. As for my vao, it is getting generated and bound once in the main() function.

I tried your suggestion, and it might have worked as it's showing a jumbled up image of my objects, since I haven't yet applied any transformations to it. What's odd is it's a 2d jumble while my models are 3d and were rotating just fine.

Also I realized why overloading that one vbo with data for 2 objects was not working, I didn't adjust the offset in my initBuffersGL method. Anyways I don't plan on using this method as using separate vbos seems the right way to do things.

I'll try adding in some transformations, which is also part of my assignment and see if this thing show up properly. I'd also like to ask if it's necessary to use a 2d array to store the data of the models.I'm using a 3x500 vPositions array, to store the data of the 3 objects. Is there a need to keep it this way or can we optimize this and just save the vertex data in the vbos. In other words using a 1d array of size 500 and clearing it out after storing the vertex data, and re-using it to load the contents of the next object. Would it still be possible to display multiple objects in this ?

Dark Photon
09-25-2017, 05:30 PM
I'd also like to ask if it's necessary to use a 2d array to store the data of the models.
I'm using a 3x500 vPositions array, to store the data of the 3 objects.
Is there a need to keep it this way or can we optimize this and just save the vertex data in the vbos.
In other words using a 1d array of size 500 and clearing it out after storing the vertex data, and re-using it to load the contents of the next object.
Would it still be possible to display multiple objects in this ?

Well, I'd ask your instructor what he wants you to do. I think you're talking about some CPU memory layout in your app.

Once you get to uploading it to the GPU, OpenGL doesn't care. VBOs are just 1D arrays of bytes in GPU/driver memory. You can populate them anyway you want, from:

1) for i=1..numbytes: do load 1 byte from disk; upload 1 byte to GL; to
2) load all bytes; upload all bytes.

Just think about efficiency. You wouldn't do #1. But somewhere in between? Perhaps, if not #2.

All you have to make sure of is that the memory layout in VBO memory is a format that the GPU/driver can read.