if cube is far don't render.

Started by
5 comments, last by MrDarkKnight 12 years, 2 months ago
Hello guys
I have function which creates a cube using VBO. I call this function outside the game loop, in Init() function.
I have a render() function that renders the cube. In this function I have a for loop that makes 10000 cubes and render them on the screen, everything shows up and works perfectly. Now if I don't render anything I get around ~1600FPS. But after rendering the 10000 cubes my FPS drops to ~80FPS.

I also have a free camera class where I can move in the world. The problem now is even if I move so far and I don't see the cubes anymore, my FPS still stays at ~80FPS. How can make it, that if I move far away I don't render the cubes and make my FPS get back to 1600FPS ?


void Engine::Init()
{
..... //Init OpenGL
CreateCubeVBO(5); // create cube with size of 5 units
}



void Engine::Render(sf::Window &Window)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
Camera1.Control(Window, 0.2, 0.2, Camera1.IsMouseIn);
SkyBox1.Draw(50.0);
Camera1.Update();

for(int i=0; i<10000; i++) //Draw 10000 cubes a move each one 10 units in the Z axis
{
glTranslatef(0.0f, 0.0f, 10.0f * i);

glBindVertexArray(VertexBufferID);

glDrawArrays(GL_QUADS, 0, 24);

glBindVertexArray(0);
}
}



void Engine::CreateCubeVBO(float Size)
{
GLfloat Vertices[] = {
Size/2, Size/2, Size/2,
-Size/2, Size/2, Size/2,
-Size/2, -Size/2, Size/2,
Size/2, -Size/2, Size/2,

-Size/2, Size/2, Size/2,
-Size/2, Size/2, -Size/2,
-Size/2, -Size/2, -Size/2,
-Size/2, -Size/2, Size/2,

Size/2, Size/2, -Size/2,
-Size/2, Size/2, -Size/2,
-Size/2, -Size/2, -Size/2,
Size/2, -Size/2, -Size/2,

Size/2, Size/2, -Size/2,
Size/2, Size/2, Size/2,
Size/2, -Size/2, Size/2,
Size/2, -Size/2, -Size/2,

Size/2, Size/2, Size/2,
-Size/2, Size/2, Size/2,
-Size/2, Size/2, -Size/2,
Size/2, Size/2, -Size/2,

Size/2, -Size/2, Size/2,
-Size/2, -Size/2, Size/2,
-Size/2, -Size/2, -Size/2,
Size/2, -Size/2, -Size/2
};

glGenVertexArrays(1, &VertexBufferID);
glBindVertexArray(VertexBufferID);

glGenBuffers(1, &VertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
}
Advertisement
Well, basicly you have to add a test for if this cube should be drawn or not.

The simplest possible would be to check the distance to the camera for each object and simply not draw it if its deemed to be "too far".

A common, and smarter way to do this efficiently is to put your object into a spatial data structure, which you can easily choose to draw objects only "close" to where you are now.

Quad/Oct-trees is one method that is fairly straight forward.

Which one is best depends on your scene and how your camera moves, and the ratio of dynamic vs static objects, to mention a few, and is impossible to answer generally.

It's not really an OpenGL-question since OpenGL has no concept of mesh management at all, that you have to implement yourself on top of it.
thank for the help.
I just relized the way i'm drawing the 10000 cubes is very bad. I think there is a much much better way to draw 10000 cubes.
I modified my Drawing code and i gained 700FPS !. now my FPS is ~780FPS. But its still bad considering there is only like 10 cubes show up on the screen at a time. I should get ~1500FPS.

so is there a better way to draw the 10000 cubes?


void Engine::Render(sf::Window &Window)
{
.... // Same as old
glBindVertexArray(VertexBufferID);
for(int i=0; i<10000; i++)
{
glTranslatef(0.0f, 0.0f, Z * i);
if(Camera1.Z >=Z * i)
{
glDrawArrays(GL_QUADS, 0, 24);
}
}
glBindVertexArray(0);
}
I modified my Drawing code and i gained 700FPS !. now my FPS is ~780FPS. But its still bad considering there is only like 10 cubes show up on the screen at a time. I should get ~1500FPS.


Frames per second isn't a linear measure of performance: 80 f/s is 12.5 ms/f, 780 f/s is 1.3 ms/f, and 1500 f/s is 0.7 ms/f.

It's not implausible, to me at least, that just the difference between drawing 'nothing' and drawing 'something' could account for ~600 microseconds. I think (without any benchmarking to back it up, admittedly) any sort of spatial subdivision, frustrum culling or whatever, would be likely to take more than that time. Your scene is too simple, the overhead of these methods at this scale outweighs their potential benefits which come with more complex scenes.
[TheUnbeliever]
if all you're after is drawing 10000 identical cubes you might want to use instancing. Otherwise do what hedman said and use a quad/oct-tree and implement batching. You are potentially making a crazy amount of drawcalls now so that could be improved.
View Frustum Culling is basically what you need. If you're just trying to randomly draw lots of cubes for fun or something don't worry about it. This is more helpful in actual complex scenes seen in games like Battlefield, Unreal, Quake, etc...

Olof Hedman up above was talking about organizing your geometry in a spatial datastructure. View Frustum Culling queries that data structure in some efficient ways to only get parts of your world that are in the view.

This way you don't send geometry that you don't see down the pipeline to the card. The card is good at culling invisible triangles but it doesn't exactly help if you're still using up Graphics Card Bandwidth sending millions of triangles when you might potentially be seeing only thousands.

This doesn't need to be insanely precise. As I said, the card is good at culling out invisible triangles, especially if you enable back face culling. You should be sending entire models to the card to draw if you determine that even a tiny part of the model is visible. It's easier to check if the entire model is visible by seeing if it's in the View Frustum on the CPU and just have the Graphics card cull out the rest of the model's triangles that aren't visible. The same is true for chunks of the level. If you have a room and the room is in the view frustum, just draw the whole room and the graphics card will take care of the rest. You'll still be saving a lot of work for the card by not drawing the ENTIRE level.

You don't wanna be culling individual triangles on the CPU with View Frustum culling because the CPU isn't built for that and performance will go down dramatically. So just send down entire models or chunks of your environment after determining they are roughly in the frustum.

You can extend View Frustum Culling with Occlusion Culling. This is more of an advanced topic and may only be necessary for a games like FPSes. I haven't gotten around to implementing this in my own engine yet so I'm not exactly a pro at it or anything so far. But basically if objects in the view frustum are completely occluding other objects in the view frustum, the occluded objects don't need to be drawn. So you are doing View Frustum Culling along with culling invisible objects in the View Frustum itself, sending even less objects to the card for drawing.
Thank you very very much, that was really helpful.
I googled View Frustum Culling and it look easy enough to implement.
I was just drawing cubes as you said, for fun, and just to check how powerful my card is.
Anyways I tried rendering with Immediate mode and with VBO and i have to say there is a huge performance difference between the two. I got 200FPS more with VBO rather than using Immediate mode.

On unrelated topic, the only thing that scares the hell out of me in OpenGL 4.0 is shaders, they look hard and they look like you need to write 1000 line of code to do simple thing.
And looks like everything moved from OpngGL to GLSL.

anyways thanks guys for all of your help.

This topic is closed to new replies.

Advertisement