I’m coming to Cinder from several years of openFrameworks experience. I made a few apps with Cinder with 0.8.4 years ago but didn’t keep up with it.
I’m struggling a bit with some of the new 0.9.0/glNext conventions and I’m wondering if there are suggestions for good posts to look at for understanding some of the beginner level GL changes. I’ve found the brief doc on 0.9.0 changes and the OpenGL in Cinder guide ( https://libcinder.org/docs/guides/opengl/index.html ). Most of the old examples and books I’ve found are usually 0.8.6 and earlier so a few things dot transfer. At the moment I’m looking specifically for information on how to work simply with lights (since gl::Light is deprecated apparently) and meshes.
As for meshes:
I translated a simple OF sketch into Cinder, but I’m unsure if this is a good way to go about doing things: https://github.com/laserpilot/Cinder_Simple_Mesh_Ribbon/blob/master/src/Simple_Mesh_RibbonApp.cpp#L112
When I run this same draw method in a loop 100 times (with the gl::Begin and end in the loop…actually a vector of base ribbon objects with this draw method), the performance isn’t great, so I’m obviously doing something not smart.
I’m unclear on a more efficient way to do it, however, and also do things like add normals (something that is done very differently with ofMesh in OF). Is this a case for TriMesh or VboMesh? Is there a good simple example out there for understanding how best to dynamically add vertices (and normals) to a mesh?
As for lights:
Also looking for a fairly simple sample for the new way of working with lights. I understand it’s all to be done within a shader now instead of gl::Light as in old examples? I’ve been looking through the samples but maybe haven’t stumbled upon the one that demonstrates this the most concisely.
Thanks for any help!
it sure is quite a shock to see your application grind to a halt after a quick 'n dirty conversion to Cinder v0.9.0. We’ve all been there. But you’ll learn to love OpenGL core eventually. The trick is to batch, batch, batch. Minimize the number of draw calls, avoid recreating buffers and shaders each frame, use instanced rendering where possible, etc.
Have a look at the
gl::Batch class. It combines a mesh (
VboMesh) with a shader (
GlslProg). It creates and stores all related buffers (
Vbo) so they can be used over and over again. A good sample to start with is this one.
Instanced rendering can be used when you want to render the same object many times. You create a buffer with information per instance, for example a
mat4 containing its position, scale and rotation. Or add a
vec4 for its color. You then bind the buffer and tell OpenGL to render a thousand teapots. This way, you can render all of them with a single call, minimizing communication between the CPU and GPU. A great sample can be found here.
For lights: this is a bit more complicated. You’ll need to do all the calculations yourself in a shader, which you will also have to write yourself. Here, too, you need to supply all light source information to the shader in the form of uniform variables or even uniform buffer objects. How you do this is entirely up to you and you can make it as complicated as you want. I do not have source code available, nor the time to quickly write something in this post, but have a look at the basics here. Cinder will help you by providing many shader uniforms and attributes for you, see also the ObjLoader sample.
Hey - as someone who is fairly new to Cinder but used OF a bunch in the past, I can totally understand your observations!
Just adding a bit to Paul’s comments re: lighting:
The simplest example of this would be using the stock lambertian shader from
gl::getStockShader(gl::ShaderDef().lambert()), however, this builds a fragment shader where the light is at a hard-coded position in front of the object. I’ve referenced this article a bunch in the past for lighting equations (shouldn’t be too hard to port some of the shaders over to Cinder).
I may share my Lights Project source code soon™.
That is a damn sexy looking teapot, Paul.
Thanks Mike as well (We’ve met and chatted before! At SFPC - your twombly generator was awesome). I’m wondering if it would be helpful to make a doc somewhere that has sort of a OF<->Cinder conventions explanation for people that reach these crossroads (i.e. ofGetFramerate() = getAverageFps(), not getFrameRate! ) - not sure of the best place to put something like that - maybe medium or just github.
Thanks for the notes! Definitely understand the lighting notes - that will be a challenge to work out at first I think, but hopefully will get a bit easier when I get the right shader to click into place.
To clarify my mesh question/problem of scale - I’m not actually rendering identical elements, but a vector of ribbons that all have their own individual noise and color values applied to their vertices. Looks like this (moving in 3d):
Should I instead be looking at rendering instances of a single ribbon and then applying offsets to vertices of each instance? Similarly to how the open_gl/VboMesh sample works - where a plane is created in setup and then those positions are altered during update? Trying to think of a way to adapt my thinking.
Hmm, you could create a thin, flat ribbon mesh for a single ribbon. Then create a grayscale texture to hold height offsets, do a texture lookup in the vertex shader to offset the vertices. Then update the texture, either on the CPU or using a fragment shader on the GPU (use an
Fbo to render to texture). Then, finally, render 1000 instances of the ribbon with an offset to the Y-coordinate of the texture per instance and you can draw all ribbons using a single draw call.
Haha I was going to say something but didn’t think you’d remember me! That is awesome - good to see you here I think that guide would be super helpful! I know I have a lot of friends who are curious about Cinder but are worried about the transition…
Another way you could animate the ribbons is by using Perlin noise in your vertex shader, using
gl_InstanceID to offset the noise (this will make each ribbon look “unique”).
This is the noise function I usually use:
vec2 hash(in vec2 p)
p = vec2(dot(p, vec2(12.9898, 78.233)),
dot(p, vec2(139.234, 98.187)));
return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
vec2 quinticHermine(in vec2 x)
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
float noise(in vec2 p)
vec2 i = floor(p);
vec2 f = fract(p);
vec2 a = hash(i + vec2(0.0, 0.0));
vec2 b = hash(i + vec2(1.0, 0.0));
vec2 c = hash(i + vec2(0.0, 1.0));
vec2 d = hash(i + vec2(1.0, 1.0));
vec2 u = quinticHermine(f);
float val = mix(mix(dot(a, f - vec2(0.0,0.0)),
dot(b, f - vec2(1.0,0.0)), u.x),
mix(dot(c, f - vec2(0.0,1.0)),
dot(d, f - vec2(1.0,1.0)), u.x), u.y);
EDIT: I forgot to add - yes, if you can upload your vertices to a VBO once and simply reuse that VBO (or ideally, a
gl::BatchRef) for drawing, that will always be more efficient than the
gl::begin / gl::end variants, which require the application to re-upload the vertex data to the GPU every frame… I think OF has an equivalent ofVboMesh class?
I checked out your github ribbons project. that is a beautiful foundation! I am learning cinder (without the OF background) and your sample has some neat stuff. there is a github repository, https://github.com/SethGibson/LearnCinderGL, where someone made cinder versions of a basic opengl tutorial site’s examples, along with his own knowledge. it is a little scattered but might help you connect some of the cinder-specific techniques with what you know/are looking for. Paul Houx’s repository has some nice samples as well.
I wrote a line renderer that makes it pretty easy to draw (nice, fat, ribbony) lines with reasonable performance.
It could be a good starting place for thinking about how to render your ribbons while still performing animation on the CPU.
Thanks all -
Seth - these tutorials look like something I definitely need to take a look at, absolutely something I was looking for.
Sansumbrella - this line renderer looks like a nice compact example to take a look at as well, thanks!
I think this will still be a couple days before I can really process all of this stuff, but if I come up with anything good, I’ll try and hit this thread again.
Did you ever find the time to share out the Lights Project?
no, I never released that code. To be honest, I am not even sure I still have it somewhere. If I find it again, I’ll post it. Sorry to disappoint you
No problem. You clearly do so much for the community. Thank you.