Hi Everyone,
I’m new to Cinder, coming from a webdev background. I’ve experimented with a bit of WebGL, but trying to expand my horizons.
I’m trying to learn about Instanced Rendering using the InstancedTeapots sample. I understand the general concept, but can’t quite translate that into practical changes to the code.
I want to assign each teapot a different color, but think I’m approaching it incorrectly.
My setup
// Shader for the 3D instanced object
mGlsl = ci::gl::GlslProg::create( ci::app::loadAsset( "shader.vert" ), ci::app::loadAsset( "shader.frag" ) );
ci::gl::VboMeshRef mesh = ci::gl::VboMesh::create( ci::geom::Teapot() );
// create an array of initial per-instance positions laid out in a 2D grid
std::vector<ci::vec3> bufferData;
bufferData.resize(2*(mNumX * mNumY));
for( size_t potX = 0; potX < mNumX; ++potX ) {
for( size_t potY = 0; potY < mNumY; ++potY ) {
float instanceX = potX / (float)mNumX - 0.5f;
float instanceY = potY / (float)mNumY - 0.5f;
ci::vec3 pos;
pos = ci::vec3( instanceX * mGridSpacing, 0 , instanceY * mGridSpacing);
bufferData.push_back( pos );
bufferData.push_back(ci::vec3(ci::randFloat(), ci::randFloat(), ci::randFloat() ));
}
}
// create the VBO which will contain per-instance (rather than per-vertex) data
mInstanceDataVbo = ci::gl::Vbo::create( GL_ARRAY_BUFFER, bufferData.size() * sizeof(ci::vec3), bufferData.data(), GL_DYNAMIC_DRAW );
// we need a geom::BufferLayout to describe this data as mapping to the CUSTOM_0 semantic, and the 1 (rather than 0) as the last param indicates per-instance (rather than per-vertex)
ci::geom::BufferLayout instanceDataLayout;
instanceDataLayout.append( ci::geom::Attrib::CUSTOM_0, 3, sizeof(ci::vec3), 0, 1 /* per instance */ );
// need to change the offset
instanceDataLayout.append( ci::geom::Attrib::CUSTOM_1, 3, sizeof(ci::vec3), sizeof(ci::vec3), 1 /* per instance */ );
// now add it to the VboMesh we already made of the Teapot
mesh->appendVbo( instanceDataLayout, mInstanceDataVbo );
// and finally, build our batch, mapping our CUSTOM_0 attribute to the "vInstancePosition" GLSL vertex attribute
mInstanceBatch = ci::gl::Batch::create( mesh, mGlsl, { { ci::geom::Attrib::CUSTOM_0, "vInstancePosition" },
{ ci::geom::Attrib::CUSTOM_1, "vInstanceColor" }
} );
ci::gl::enableDepthWrite();
ci::gl::enableDepthRead();
// Shader for the 3D instanced object
mGlsl = ci::gl::GlslProg::create( ci::app::loadAsset( "shader.vert" ), ci::app::loadAsset( "shader.frag" ) );
My Update:
ci::vec3 *sphere = (ci::vec3*)mInstanceDataVbo->mapReplace();
for( size_t potX = 0; potX < mNumX; ++potX ) {
for( size_t potY = 0; potY < mNumY; ++potY ) {
float instanceX = potX / (float)mNumX - 0.5f;
float instanceY = potY / (float)mNumY - 0.5f;
ci::vec3 newPos( instanceX * mGridSpacing, 0 , instanceY * mGridSpacing);
*sphere++ = newPos;
*sphere++ = ci::vec3(1.,1.,1.); // try resetting the color
}
}
mInstanceDataVbo->unmap();
vert shader:
#version 150
uniform mat4 ciModelViewProjection;
uniform mat4 ciProjectionMatrix, ciViewMatrix;
uniform mat3 ciNormalMatrix;
in vec4 ciPosition;
in vec2 ciTexCoord0;
in vec3 ciNormal;
in vec4 ciColor;
in vec3 vInstancePosition; // per-instance position variable
in vec3 vInstanceColor;
out highp vec2 TexCoord;
out lowp vec4 Color;
out highp vec3 Normal;
void main( void )
{
gl_Position = ciModelViewProjection * (ciPosition + vec4( vInstancePosition, 0 ) );
Color = vec4(vInstanceColor, 1.f);
TexCoord = ciTexCoord0;
Normal = ciNormalMatrix * ciNormal;
}
Should I be separating the positions and colors into separate buffers? Or is there a different way to update the buffer instead of mapReplace()?
Thanks!
Dan
[Solved]
The StereoscopicRendering sample shows how to do this. Solution was to create a struct and reference the color and position using:
data->position = newPos;
data->color = newColor;