Hey there. I’ve worked through the ‘OpenGL in Cinder’ guide and I’m looking to optimize some existing code with some of the techniques mentioned in the guide. Just to be clear up front - I’m only currently working in 2D.
In this basic setup, I’m loading an SVG and saving it as a
DocRef. I’m drawing the SVG shape multiple times each frame, at different locations and with different colors. Currently I’ve achieved this by simple doing my translation and setting the color, then calling
gl::draw(mSvgDoc->getShapeAbsolute()) for each time I want to draw the shape.
I have adjusted my code and instead of saving the
DocRef, I’m saving a
BatchRef that I’ve constructed using a
VboMeshRef created with
gl::VboMesh::create(Triangulator(mLogoSvgDoc->getShapeAbsolute(), 1.0f).calcMesh()). Now I draw the SVG using
Everything is working the same way as before and it looks exactly the same. I’m just trying to understand if / why this is a more efficient way of drawing the same thing several times. The examples in the guide were all in 3D space, does this even make a difference for my project in 2D space only? Is it actually drawing them together in a batch at the same time, where my old version had a draw call for every time, this only has a single draw call that draws them all?
Thanks for any tips, much appreciated! Loving the new forum!
The easiest way of thinking about it (in this specific case), is that
gl::draw() is, for all intents and purposes, doing what your second bit of code does, but every frame. This means that all the vertex information has be to constantly discarded and re-sent to the GPU even though it isn’t changing. By using a VBO, you’re caching the geometry on the GPU and just asking for it to be redrawn.
…but every frame.
It’s even worse: it’s sending the geometry every time you draw the SVG, which can be multiple times per frame.
Thanks guys! Yeah, I have my setup to draw the same SVG anywhere from 1 to 100 times per frame, so it seems like this is a more efficient way to go.
That definitely helps, appreciate it!
Depending on your specific needs, you can also look into instanced drawing (gl::Batch has a drawInstanced member function), which is even more efficient as you’re only submitting one draw call to the GPU.
drawInstanced all about? I’m doing some model matrix translation and setting a new color for each time I draw the shape, is that still possible with
Instancing is basically a way to draw the same geometry multiple times with a single draw call (in OpenGL this is glDrawArraysInstanced, though there are a few variations). As you hinted at, there are indeed ways to set up vertex attributes (i.e. transformations like scale, rotation, and translation, color, etc.) that vary per instance.
There’s a really good example of this in the samples folder called “Earthquake.” Check out the constructor for the Earth class, where he sets up per-instance transformation matrices.
It does require a bit more setup, so if simply drawing your Batch a bunch of times in a for-loop works, I wouldn’t worry about it… just wanted to throw the idea out there.
Cool, I’ll work through that example and see what else I can pick up. If not for this project, perhaps something in the future.
The sample _opengl/InstancedTeapots is a good place to start.