I’m trying to manipulate the color (and eventually also a custom) attribute on a geom::SourceMods object in Cinder.
Thanks to some previous inquiries I’ve managed to execute this after the geom::SourceMods is turned into a Batch via the following rough code:
auto glslFullStockLambertColor = ci::gl::getStockShader( ci::gl::ShaderDef().lambert().color() );
// We can either set colors on each cube side super easily
//auto cube = ci::geom::Cube().size( ci::vec3( 20, 20, 20 ) ).colors( ci::Color( "red" ), ci::Color( "yellow" ), ci::Color( "blue" ), ci::Color( "green" ), ci::Color( "purple" ), ci::Color( "white" ) );
//mBatchCube = ci::gl::Batch::create( cube, glslFullStockLambertColor );
// Or we can add it after the cube has been created
auto cube = ci::geom::Cube().size( ci::vec3( 20, 20, 20 ) );
mBatchCube = ci::gl::Batch::create( cube >> ci::geom::Constant( ci::geom::COLOR, ci::ColorAf( "green" ) ), glslFullStockLambertColor );
int colorIdx = 1;
auto mVerticesMesh = mBatchCube->getVboMesh();
uint32_t numVerticesColors = mVerticesMesh->getNumVertices();
ci::gl::VboMesh::MappedAttrib<ci::vec4> vertexColorIter = mVerticesMesh->mapAttrib4f( ci::geom::COLOR, false );
for (uint32_t idx = 0; idx < numVerticesColors; ++idx, ++colorIdx) {
if (<vertex should stay green>)
continue;
ci::vec4 color = ci::vec4( 1.0f, 0.0f, 0.0f, 1.0f ); // Fully red
*vertexColorIter++ = color;
}
vertexColorIter.unmap();
But! I’d ideally like to actually manipulate this data prior to it turning into a batch (along with a VboMesh). Why? Because I generate my mesh in a separate thread and VBO meshes don’t share well across OpenGL contexts, as far as I am aware.
But try as I might, I’ve not found any method as simple as the one above to manipulate a partial set of attributes. My dive into the Cinder code also hasn’t been too fruitful, so perhaps the answer is… There isn’t a way, unless I’m willing to start playing around with gl::VboMesh::Layout which looks really scary to me. Especially because the mesh I want to manipulate colors on comes from ci::geom::Extrude.
With a little more time on my hands, and a little bit more sleuthing, it would seem this is a fairly easy way of manipulating the data prior to it becoming a thing on the GPU:
I would use an AttribFn here I think, though i’m not sure it provides you enough information to determine the vertIndex out of the box, but assuming it iterates over the vertices in order, you may be able to keep a running count to know which invocation of the lambda corresponds to which vertex, but i’ll leave that up to you to figure out. Written inline and not tested:
I was entirely unaware of the AttribFn approach. No current sample appears to use it - many thanks for highlighting this approach @lithium.
For anyone reading along, the actual implementation needs to rely on vec's as these are the only defined template specializations (in the cinder library), otherwise you’ll end up with large/confusing linker errors.
A compiling example:
int vertexIndex = 0;
auto cubeWithAlteredColors = cube >> ci::geom::AttribFn<ci::vec4, ci::vec4>( ci::geom::COLOR, [&vertexIndex]( ci::vec4 ) {
ci::vec4 color( 1.0f, 0.0f, 0.0f, 1.0f ); // Std. Red
if (vertexIndex < 4)
color = ci::vec4( 1.0f, 1.0f, 0.0f, 1.0f );
++vertexIndex;
return color;
} );