Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: Insane lags when drawing cubes

  1. #1
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    5

    Insane lags when drawing cubes

    hello guys,
    I'm trying to create a game that has tons of cubes ( around millions or even more ), so i have read about instancing and i have done what the tutorial said.
    but when i add 100,000 cubes to the scene i have insane lags ( can't move the mouse or exit ).

    here is my source:
    Cube:
    Code :
    void Cube::Add(std::vector<glm::vec3> position)
    {
    	glGenVertexArrays(1, &instanceVBO);
    	glBindVertexArray(instanceVBO);
    	glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * position.size(), &position[0], GL_STATIC_DRAW);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);
     
    	glGenVertexArrays(1, &VAO);
    	glGenBuffers(1, &VBO);
    	glBindVertexArray(VAO);
    	glBindBuffer(GL_ARRAY_BUFFER, VBO);
    	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STREAM_DRAW);
     
    	glActiveTexture(GL_TEXTURE0);
    	glBindTexture(GL_TEXTURE_2D, Texture);
    	glUniform1i(TextureID, 0);
     
    	glEnableVertexAttribArray(0);
    	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
     
    	glEnableVertexAttribArray(1);
    	glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
    	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
     
    	glEnableVertexAttribArray(2);
    	glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
     
    	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)2);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);
    	glVertexAttribDivisor(2, 1);
     
    	size = position.size();
    }
     
    void Cube::Draw(GLuint& programID)
    {
    	// Use Shaders
    	glUseProgram(programID);
     
    	// Bind Texture to Cube
    	glBindVertexArray(VAO);
    	glDrawArraysInstanced(GL_TRIANGLES, 0, vertices.size(), size);
    	glBindVertexArray(0);
    }

    Cube Vertex Shaer:
    Code :
    #version 330 core
     
    layout (location = 0) in vec3 position;
    layout (location = 1) in vec2 vertexUV;
    layout (location = 2) in vec3 offset;
     
    out vec2 UV;
     
    uniform mat4 MVP;
     
    void main()
    {
    	gl_Position = MVP * vec4(position + offset, 1);
     
    	UV = vertexUV;
    }

    Camera Update:
    Code :
    void Camera::Update(glm::vec3 const& scale,
    					glm::vec3 const& position)
    {
    	Camera::computeMatricesFromInputs();
     
    	glm::mat4 Model = glm::mat4();
    	Model = glm::scale(Model, scale);
    	Model = glm::translate(Model, position);
    	glm::mat4 mvp = ProjectionMatrix * ViewMatrix * Model;
     
    	glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &mvp[0][0]);
    }

    Main:
    Code :
    int main()
    {
    	Functions funcs;
     
    	Window window(WIDTH, HEIGHT, "Minecraft Mechanics");
     
    	// Creating Shader
    	GLuint programID = funcs.LoadShaders("src/shaders/cube.vert", "src/shaders/cube.frag");
     
    	// Creating Cube
    	Cube cube(programID);
    	std::vector<glm::vec3> pos;
    	int cx = 0, cz = 0;
     
    	for(unsigned int x = 0; x < 100; x++)
    	{
    		pos.push_back(glm::vec3(cx, 0, cz));
     
    		for(unsigned int z = 0; z < 100; z++)
    		{
    			pos.push_back(glm::vec3(cx, 0, cz));
    			cz += CUBEDIST;
    		}	
     
    		cx += CUBEDIST;
    		cz = 0;
    	}
     
    	cube.Add(pos);
    	pos.clear();
     
    	Camera camera(glm::vec3(0, 10, 0), 90.f, 0.001f);
    	camera.Setup(*window.getWindow(), programID);
     
    	glClearColor(0.53f, 0.81f, 0.98f, 1.0f);
     
    	double lastTime = glfwGetTime();
     	int nbFrames = 0;
     
    	while(window.Running())
    	{
    		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     
    		// ----- FPS ------ //
         	double currentTime = glfwGetTime();
         	nbFrames++;
     
         	if ( currentTime - lastTime >= 1.0 )
    		{
             	printf("%f ms/frame\n", 1000.0/double(nbFrames));
             	nbFrames = 0;
             	lastTime += 1.0;
      		}
     
    		// Cube
    		for(unsigned int i = 0; i < cube.getSize(); i++)
    		{
    			cube.Draw(programID);
    			camera.Update(cube.getScale(), pos[i]);
    		}
     
    		window.SwapBuffers();
    	}
     
    	glDeleteProgram(programID);
     
    	return 0;
    }

    And i have added what the profiler said:
    Click image for larger version. 

Name:	profiler.jpg 
Views:	27 
Size:	19.3 KB 
ID:	2567

    For couple of days I've been trying to fix this.
    What am i doing wrong ?
    Thanks for help!
    Last edited by therealcain; 12-07-2017 at 02:46 AM.

  2. #2
    Intern Contributor
    Join Date
    Dec 2016
    Location
    Ocean Shores, WA USA
    Posts
    71
    Actually....... 100,000 cubes in a scene would cause lag probably, depending upon your graphics card's abilities.

    Try starting with smaller amounts, like 1,000, and keep ramping it up, until you find the lag starts. You are probably doing everything correctly, because, again yeah, 100,000 cubes should cause lag.

    Jeff
    (here is a link to my youtube channel on opengl programming tutorials, by the way...)
    https://www.youtube.com/channel/UCzx..._as=subscriber

  3. #3
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,728
    What you've done wrong is make the classic OO mistake of having each object maintain it's own GL state and GL objects, and be responsible for drawing itself. This approach just doesn't scale, leads to 100,000 draw calls, and will bring most hardware to it's knees.

    Instead of this you need to start hatching objects, so that you can handle multiple objects per draw call and start getting performance back. Modern hardware can easily handle the object counts you have; this is a design problem.

    One approach is that instead of drawing each object as it passes (i.e. In an object::draw call) you instead add it to a list of drawables. At some later time you take that list, construct a big batch out of it, then draw it in as few draw calls as possible.

  4. #4
    Intern Contributor
    Join Date
    Dec 2016
    Location
    Ocean Shores, WA USA
    Posts
    71
    I see what mhagain is saying, yeah, I had that problem early on in learning opengl as well when I started to put classes into the picture. The CPU would be the bottleneck, or more to the point the CPU to GPU communication is your bottleneck.

    Jeff

  5. #5
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,728
    At this stage I also have to mention the dreaded unbinding.

    Simplified, what goes on inside a GL driver when you issue a draw call looks something like this:
    Code :
    if (StateHasChanged)
    {
        // this part is really really expensive
        ValidateState();
    }
    Draw();
    If you have a draw loop with no unbinding, something like:
    Code :
    for (LotsOfObjects)
    {
        glBind(obj);
        glDraw();
    }
    Then your driver may be able to intelligently optimize for cases where state doesn't actually change, and you can get lots of draw calls done fairly quickly.

    On the other hand, look at it with unbinding:
    Code :
    for (LotsOfObjects)
    {
        glBind(obj);
        glDraw();
        glBind(0);
    }
    Now you're going to hit the validation check every single iteration through the loop. You've taken what could have been a quick and simple driver optimization and completely destroyed it.

    If you have a problem that unbinding solves, then don't unbind - go back and fix the real source of the problem. If you don't have a problem that unbinding solves, then why the f%#*!; are you unbinding? Either way - don't unbind.

  6. #6
    Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    427
    And to make it simple and more clear to the OP:

    * Keep a single VAO (so a single VBO)
    * Read (again ?) this tutorial about instancing.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •