Merging multiple meshes into one

Started by
5 comments, last by nullhandle 6 years, 9 months ago

I'm currently working on a Minecraft-like game ( a world made of blocks ).

Until now it seems to be working very fine. But I can feel that the more blocks I'm adding to one world the slowlier it runs ( CPU throttles it ).

My solution would be to put the vertex/index data of all same blocks ( same texture etc. ) into one one vertex/index buffer to relieve the CPU since I wont need that much draw calls anymore.

Have you got any ideas of how I could do this the best way?

Advertisement

Make a larger buffer, fill it, and send it to the GPU?

Likely you can also add a field what texture to draw etc, and pass that data to the fragment shader.

 

However, did you actually check that drawing is the problem? Lots of things take more time when you make your world larger / more complex.

By profiling the code, you get information where the real problem actually is, rather than random guessing and changing areas that you believe to take time (which in my experience is consistently wrong, or at least, I haven't yet been able to guess correctly).

Right now I'm calling the render function for every cube. I'll try to create a function that puts all the single cubes into one big buffer. Thats exactly what my first idea was.

Iterating through the list of cubes takes the most time I guess ( don't have a profiler but I commentend out different parts of the code ).

So I played around a little bit. This is what I'm doing:


void Mesh::AddMesh( Mesh& other, glm::vec3 translation )
{
    std::cout << "I'm adding meshes." << std::endl;

    if ( ( other.vecVertices.size(  ) % 5 != 0 ) && ( other.vecIndices.size(  ) % 3 != 0 ) )
    {
        std::cout << "The mesh you wanted to add didn't contain good data. Canceling addition." << std::endl;
        return;
    }
    for ( unsigned int i = 0; i < other.vecVertices.size(  ) / 5; ++i )
    {
        // Add translated position coords
        vecVertices.push_back( other.vecVertices[i * 5] + translation.x );
        vecVertices.push_back( other.vecVertices[i * 5 + 1] + translation.y );
        vecVertices.push_back( other.vecVertices[i * 5 + 2] + translation.z );
        // Add same texture coords
        vecVertices.push_back( other.vecVertices[i * 5 + 3] );
        vecVertices.push_back( other.vecVertices[i * 5 + 4] );
        
        // Demo Output
        std::cout << other.vecVertices[i * 5] + translation.x << ",\t";
        std::cout << other.vecVertices[i * 5 + 1] + translation.y << ",\t";
        std::cout << other.vecVertices[i * 5 + 2] + translation.z << ",\t";
        std::cout << other.vecVertices[i * 5 + 3] << ",\t";
        std::cout << other.vecVertices[i * 5 + 4] << std::endl;


        /*std::cout << vecVertices << ",\t";
        std::cout << vecVertices[i + 1] << ",\t";
        std::cout << vecVertices[i + 2] << ",\t";
        std::cout << vecVertices[i + 3] << ",\t";
        std::cout << vecVertices[i + 4] << std::endl;*/
    }
    for ( unsigned int i = 0; i < other.vecIndices.size(  ); ++i )
    {
        //std::cout << other.vecIndices + ( vecVertices.size(  ) / 5 ) << std::endl;
        vecIndices.push_back( other.vecIndices[i] + vecVertices.size(  ) - 1 );
    }

    UpdateBuffers(  );
}

It's a method for adding the vertex index data from one mesh to another. The vertices get translated by the given vec3 so the 2 objects aren't just inside of each other. At the end the vao/vbo/ibo get recreated.

I checked the output in the console and it looked correct to me. But there still is only showing up one cube after adding another one to it.


void Mesh::UpdateBuffers(  )
{
    // Deleting old stuff
    glDeleteVertexArrays( 1, &m_VAO );
    glDeleteBuffers( 1, &m_VBO );
    glDeleteBuffers( 1, &m_IBO );

    // Generating new buffers
    glGenVertexArrays( 1, &m_VAO );
    glGenBuffers( 1, &m_VBO );
    glGenBuffers( 1, &m_IBO );

    glBindVertexArray( m_VAO );
    glBindBuffer( GL_ARRAY_BUFFER, m_VBO );
    glBufferData( GL_ARRAY_BUFFER, vecVertices.size(  ) * sizeof( GLfloat ), &vecVertices[0], GL_STATIC_DRAW );

    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_IBO );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, vecIndices.size(  ) * sizeof( GLushort ), &vecIndices[0], GL_STATIC_DRAW );

    // Position Attribute
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof( GLfloat ), (void*) 0 );
    glEnableVertexAttribArray( 0 );

    // texture coord attribute
    glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof( GLfloat ), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray( 1 );

    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    glBindVertexArray( 0 );



    std::cout << "Vertex count: " << vecVertices.size(  ) / 5 << std::endl;
    std::cout << "Index count: " << vecIndices.size(  ) << std::endl;
}

void Mesh::Render(  )
{
    glBindVertexArray( m_VAO );
    //std::cout << "Num Vertices/Indices: " << vecVertices.size(  ) << "/" << vecIndices.size(  ) << std::endl;
    glDrawElements( GL_TRIANGLES, vecIndices.size(  ), GL_UNSIGNED_SHORT, 0 );
}

When rendering it says that I have 72 ( 36 * 2 for 2 cubes ) indices and 2 times the amount of vertices of the single cube.

Are the positions of vertices allowed to exceed 1 btw? Does openGL accept vertex positions like vec3( 0.0f, 1.5f, 2.0f )?

I don't know about the OpenGL code, someone else should answer that.

 

58 minutes ago, nullhandle said:

Are the positions of vertices allowed to exceed 1 btw? Does openGL accept vertex positions like vec3( 0.0f, 1.5f, 2.0f )?

Sure, you can store anything that  fits in a float. The only thing you need to consider is that OpenGL draws things between -1 and +1, so you need a position transformation in the vertex shader to move the right part in sight of the camera.

I found the problem..... should buy a rubber duck soon. I wasn't correctly adding the indices of the mesh I wanted to add. For people wondering, this is the working function:


void Mesh::AddMesh( Mesh& other, glm::vec3 translation )
{
    std::cout << "I'm adding meshes." << std::endl;

    if ( ( other.vecVertices.size(  ) % 5 != 0 ) && ( other.vecIndices.size(  ) % 3 != 0 ) )
    {
        std::cout << "The mesh you wanted to add didn't contain good data. Canceling addition." << std::endl;
        return;
    }
    size_t oldVecVerticesSize = vecVertices.size(  );
    for ( unsigned int i = 0; i < other.vecVertices.size(  ) / 5; ++i )
    {
        // Add translated position coords
        vecVertices.push_back( other.vecVertices[i * 5] + translation.x );
        vecVertices.push_back( other.vecVertices[i * 5 + 1] + translation.y );
        vecVertices.push_back( other.vecVertices[i * 5 + 2] + translation.z );
        // Add same texture coords
        vecVertices.push_back( other.vecVertices[i * 5 + 3] );
        vecVertices.push_back( other.vecVertices[i * 5 + 4] );
    }
    for ( unsigned int i = 0; i < other.vecIndices.size(  ); ++i )
    {
        std::cout << other.vecIndices[i] + ( vecVertices.size(  ) / 5 ) << std::endl;
        vecIndices.push_back( other.vecIndices[i] + ( oldVecVerticesSize / 5 ) );
    }

    UpdateBuffers(  );
}

 

This topic is closed to new replies.

Advertisement