Hello, Cinderists!
Young grasshopper here.
I’ve been using Cinder for a few weeks and I’m trying to wrap my head around it, I’m quite enjoying it as Cinder looks promising. I’m learning Cinder to improve my C++ skills and learn graphics programming from a low-level standpoint. I’m quite familiar with 3D graphics by using Houdini as an everyday tool, so I’m not totally green.
A the moment I’m trying to understand the Instancing workflow with ‘per-isntance’ attributes. I’m rewriting the samples included with cinder and reading a lot of materials from the web, but a general workflow seems hard to grasp. I have a few questions and an example that would be great if someone could answer.
Questions:
- Is there some kind of an hierarchy to better understand the relationship between vertBatch, Batch, Vbo or VboMesh? How are they connected? Is one a container for the other? Is the Vbo a component of the Batch?
- In Houdini I’m used to doing geometry manipulation using VEX. Am I assuming correct that the vertex shader in OpenGL is like a VEX wrangle in Houdini? Would I animate using the vertex shader?
Example:
I have re-written the ‘Instanced Teapots’ sample to pass more than one attribute to the instances. Could someone, please, check the code if I’m doing it correctly? The part that seems unclear is if I have to initialize multiple VBO’s to pass multiple attributes for a Batch? Couldn’t I just append multiple attributes to a single VBO?
The code runs and does what I want, but if someone more experienced would look at it, he might find some issues worth pointing out.
const int NUM_INSTANCES_X = 20;
const int NUM_INSTANCES_Y = 20;
const float DRAW_SCALE = 200;
const float camPosY = 50.0f;
void instancingApp::setup()
{
mCam.lookAt(vec3(0, camPosY, 0), vec3(0));
mGlsl = gl::GlslProg::create(loadAsset("shader.vert"), loadAsset("shader.frag"));
gl::VboMeshRef mesh = gl::VboMesh::create(geom::Torus());
std::vector<vec3> positions;
std::vector<float> myColor;
int loopNum = 0;
for (size_t posX = 0; posX < NUM_INSTANCES_X; ++posX)
{
for (size_t posY = 0; posY < NUM_INSTANCES_Y; ++posY)
{
float ratio = loopNum / ((float)NUM_INSTANCES_X * (float)NUM_INSTANCES_Y - 1);
myColor.push_back(ratio);
loopNum++;
float instanceX = posX / (float)NUM_INSTANCES_X - 0.5f;
float instanceY = posY / (float)NUM_INSTANCES_Y - 0.5f;
vec3 xPos = vec3(DRAW_SCALE, 0, 0) * instanceX;
vec3 yPos = vec3(0, 0, DRAW_SCALE) * instanceY;
positions.push_back(xPos + yPos);
}
loopNum++;
}
// POSITIONS
mInstanceDataVbo = gl::Vbo::create(GL_ARRAY_BUFFER, positions.size() * sizeof(vec3), positions.data(), GL_DYNAMIC_DRAW);
geom::BufferLayout instanceDataLayout;
instanceDataLayout.append(geom::Attrib::CUSTOM_0, 3, 0, 0, 1 );
mesh->appendVbo(instanceDataLayout, mInstanceDataVbo);
// COLORS BASED ON LOOP ID
mInstanceColorVbo = gl::Vbo::create(GL_ARRAY_BUFFER, myColor.size() * sizeof(float), myColor.data(), GL_DYNAMIC_DRAW);
geom::BufferLayout instanceColorLayout;
instanceColorLayout.append(geom::Attrib::CUSTOM_1, 1, 0, 0, 1); // It works, but I'm not really sure if I'm doing it correct.
mesh->appendVbo(instanceColorLayout, mInstanceColorVbo);
// Create Batch with Attributes
mBatch = gl::Batch::create(mesh, mGlsl, { {geom::Attrib::CUSTOM_0, "vInstancePosition"}, { geom::Attrib::CUSTOM_1, "fMyColor" } });
gl::enableDepthWrite();
gl::enableDepthRead();
}
void instancingApp::resize()
{
mCam.setPerspective(60, getWindowAspectRatio(), 1, 1000);
gl::setMatrices(mCam);
}
void instancingApp::draw()
{
gl::clear( Color( 0.2, 0.2, 0.2 ) );
gl::setMatrices(mCam);
mBatch->drawInstanced(NUM_INSTANCES_X * NUM_INSTANCES_Y);
}
Thank you for looking into this subject.