Skip to content

Instantly share code, notes, and snippets.

@gregkepler
Created November 2, 2016 19:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gregkepler/06a9e0ec5d68fee98fda5afb9e2a5bd9 to your computer and use it in GitHub Desktop.
Save gregkepler/06a9e0ec5d68fee98fda5afb9e2a5bd9 to your computer and use it in GitHub Desktop.
#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/Rand.h"
#include "cinder/CameraUi.h"
using namespace ci;
using namespace ci::app;
using namespace std;
const int POINT_NUM = 100;
const uint32_t POSITION_INDEX = 1;
const uint32_t VELOCITY_INDEX = 2;
const uint32_t LINE_INDEX = 3;
const float MAX_DIST = 100.0f;
class IndexTransformFeedbackApp : public App {
public:
void setup() override;
void mouseDown( MouseEvent event ) override;
void mouseDrag( MouseEvent event ) override;
void update() override;
void draw() override;
void initGlsl();
void initBuffers();
gl::GlslProgRef mLineRenderGlsl, mLineUpdateGlsl, mPointGlsl, mPointUpdateGlsl;
gl::VboRef mPositions[2], mVelocities[2], mLineIndices[2];
gl::BatchRef mPointBatch[2], mLineBatch[2];
gl::VboMeshRef mLineVboMesh[2];
gl::VaoRef mVao[2], mLineVao[2];
std::uint32_t mSourceIndex = 0;
std::uint32_t mDestinationIndex = 1;
CameraPersp mCam;
CameraUi mCamUi;
};
void IndexTransformFeedbackApp::setup()
{
initGlsl();
initBuffers();
// create a camera
mCam = CameraPersp( getWindowWidth(), getWindowHeight(), 60, 0.1f, 10000.0f );
mCam.lookAt( vec3( 0, 0, 1000.0f ), vec3() );
mCamUi = CameraUi( &mCam );
}
void IndexTransformFeedbackApp::initGlsl()
{
{
// line render shader
gl::GlslProg::Format renderFormat;
renderFormat.vertex( loadAsset( "lineRender.vert" ) );
renderFormat.fragment( loadAsset( "lineRender.frag" ) );
mLineRenderGlsl = gl::GlslProg::create( renderFormat );
}
{
// line update shader
std::vector<std::string> feedbackVaryings = {
"tf_index"
};
gl::GlslProg::Format updateFmt;
updateFmt.vertex( loadAsset( "lineUpdate.vert" ) )
.feedbackFormat( GL_SEPARATE_ATTRIBS )
.feedbackVaryings( feedbackVaryings )
.attribLocation( "vIndex", 0 );
mLineUpdateGlsl = gl::GlslProg::create( updateFmt );
mLineUpdateGlsl->uniform( "uParticleCount", POINT_NUM );
mLineUpdateGlsl->uniform( "uStride", POINT_NUM );
mLineUpdateGlsl->uniform( "uMaxDist", MAX_DIST );
}
// point update shader
{
std::vector<std::string> feedbackVaryings = {
"tf_position"//, "tf_boxindex"
};
gl::GlslProg::Format updateFmt;
updateFmt.vertex( loadAsset( "update.vert" ) )
.feedbackFormat( GL_SEPARATE_ATTRIBS )
.feedbackVaryings( feedbackVaryings )
.attribLocation( "vPosition", POSITION_INDEX );
.attribLocation( "vVelocity", VELOCITY_INDEX );
mPointUpdateGlsl = gl::GlslProg::create( updateFmt );
}
{
// point render shader
gl::GlslProg::Format format;
format.vertex( loadAsset( "pointRender.vert" ) );
format.fragment( loadAsset( "pointRender.frag" ) );
format.attribLocation( "vPosition", POSITION_INDEX );
mPointGlsl = gl::GlslProg::create( format );
}
}
void IndexTransformFeedbackApp::initBuffers()
{
// fill positions
vector<vec4> positions;
for( int i = 0; i < POINT_NUM; i++ ){
positions.push_back( vec4( randFloat( -0.5, 0.5 ) * getWindowWidth(), randFloat( -0.5, 0.5) * getWindowHeight(), randFloat( -0.5, 0.5) * 500, 1 ) );
}
// connect points within
int lineCount = POINT_NUM * POINT_NUM * 2;
vector<int> lineIndices( lineCount, -1 );
int index = 0;
for( int i = 0; i < POINT_NUM; i++ ){
for( int j = 0; j < POINT_NUM; j++){
vec4 pt1 = positions[i];
vec4 pt2 = positions[j];
if( pt1 != pt2 && distance( pt1, pt2 ) < MAX_DIST ){
lineIndices[index] = i;
lineIndices[index+1] = j;
}
index += 2;
}
}
// make velocities ---------
vector<ci::vec3> velocities;
for( int i = 0; i < positions.size(); i++ ){
velocities.push_back( vec3( randFloat( -0.5f, 0.5f ), randFloat( -0.5f, 0.5f ), 0.0f ) );
}
mPositions[mSourceIndex] = ci::gl::Vbo::create( GL_ARRAY_BUFFER, positions.size() * sizeof(vec3), positions.data(), GL_STATIC_DRAW );
mPositions[mDestinationIndex] = ci::gl::Vbo::create( GL_ARRAY_BUFFER, positions.size() * sizeof(vec3), nullptr, GL_STATIC_DRAW );
mVelocities[mSourceIndex] = ci::gl::Vbo::create( GL_ARRAY_BUFFER, velocities.size() * sizeof(vec3), velocities.data(), GL_STATIC_DRAW );
mVelocities[mDestinationIndex] = ci::gl::Vbo::create( GL_ARRAY_BUFFER, velocities.size() * sizeof(vec3), nullptr, GL_STATIC_DRAW );
// VBO for storing line indices
mLineIndices[mSourceIndex] = gl::Vbo::create( GL_ELEMENT_ARRAY_BUFFER, lineCount * sizeof(uint32_t), lineIndices.data(), GL_STATIC_DRAW );
mLineIndices[mDestinationIndex] = gl::Vbo::create( GL_ELEMENT_ARRAY_BUFFER, lineCount * sizeof(uint32_t), nullptr, GL_STATIC_DRAW );
for( int i = 0; i < 2; i++ ) {
{
// Initialize the Vao's holding the info for each buffer
mVao[i] = ci::gl::Vao::create();
// Bind the vao to capture index data for the glsl
gl::ScopedVao vao( mVao[i] );
{
gl::ScopedBuffer sccopeBuffer( mPositions[i] );
ci::gl::enableVertexAttribArray( POSITION_INDEX );
ci::gl::vertexAttribPointer( POSITION_INDEX, 4, GL_FLOAT, GL_FALSE, sizeof(vec4), (const GLvoid*) 0 );
}
{
gl::ScopedBuffer sccopeBuffer( mVelocities[i] );
ci::gl::vertexAttribPointer( VELOCITY_INDEX, 3, GL_FLOAT, GL_FALSE, sizeof(vec3), (const GLvoid*) 0 );
ci::gl::enableVertexAttribArray( VELOCITY_INDEX );
}
}
}
// Describe the shader attributes.
geom::BufferLayout instanceDataLayout;
instanceDataLayout.append( geom::Attrib::CUSTOM_1, 4, sizeof( vec4 ), 0, 1 /* per instance */ );
{
auto mesh = gl::VboMesh::create( geom::Sphere().radius( 5.0 ) );
mesh->appendVbo( instanceDataLayout, mPositions[0] );
mPointBatch[0] = gl::Batch::create( mesh, mPointGlsl, {
{ geom::Attrib::CUSTOM_1, "vPosition" } } );
}
{
auto mesh = gl::VboMesh::create( geom::Sphere().radius( 5.0 ) );
mesh->appendVbo( instanceDataLayout, mPositions[1] );
mPointBatch[1] = gl::Batch::create( mesh, mPointGlsl, {
{ geom::Attrib::CUSTOM_1, "vPosition" } } );
}
geom::BufferLayout lineDataLayout;
lineDataLayout.append( geom::Attrib::POSITION, 4, sizeof( vec4 ), 0 );
mLineVboMesh[mSourceIndex] = gl::VboMesh::create( lineIndices.size(), GL_LINES, { { lineDataLayout, mPositions[mSourceIndex] } }, lineIndices.size(), GL_UNSIGNED_INT, mLineIndices[0] );
mLineVboMesh[mDestinationIndex] = gl::VboMesh::create( lineIndices.size(), GL_LINES, { { lineDataLayout, mPositions[mDestinationIndex] } }, lineIndices.size(), GL_UNSIGNED_INT, mLineIndices[1] );
mLineBatch[0] = gl::Batch::create( mLineVboMesh[0], mLineRenderGlsl );
mLineBatch[1] = gl::Batch::create( mLineVboMesh[1], mLineRenderGlsl );
for( int i = 0; i < 2; i++ ) {
{
mLineVao[i] = ci::gl::Vao::create();
gl::ScopedVao vao( mLineVao[i] );
{
gl::ScopedBuffer sccopeBuffer( mLineIndices[i] );
ci::gl::vertexAttribPointer( LINE_INDEX, 1, GL_UNSIGNED_INT, GL_FALSE, 0, (const GLvoid*) 0 );
ci::gl::enableVertexAttribArray( LINE_INDEX );
}
}
}
}
void IndexTransformFeedbackApp::mouseDown( MouseEvent event )
{
mCamUi.mouseDown( event );
}
void IndexTransformFeedbackApp::mouseDrag( MouseEvent event )
{
mCamUi.mouseDrag( event );
}
void IndexTransformFeedbackApp::update()
{
gl::ScopedState stateScope( GL_RASTERIZER_DISCARD, true );
// UPDATE POSITIONS --------------------------------------------------------
{
gl::ScopedGlslProg glslScope( mPointUpdateGlsl );
gl::ScopedVao vaoScope( mVao[mSourceIndex] );
gl::bindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, 0, mPositions[mDestinationIndex] );
gl::bindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, 1, mVelocities[mDestinationIndex] );
// We begin Transform Feedback, using the same primitive that
// we're "drawing". Using points for the particle system.
gl::beginTransformFeedback( GL_POINTS );
gl::drawArrays( GL_POINTS, 0, POINT_NUM );
gl::endTransformFeedback();
mPositionTexture = gl::BufferTexture::create( mPositions[mDestinationIndex], GL_RGBA32F );
}
// UPDATE INDICES ----------------------------------------------------------
if( mLineUpdateGlsl ){
gl::ScopedGlslProg glslScope( mLineUpdateGlsl );
gl::ScopedVao vaoScope( mLineVao[mSourceIndex] );
// TODO: bind to mPositionTexture
gl::bindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, 0, mLineIndices[mDestinationIndex] );
gl::beginTransformFeedback( GL_POINTS );
gl::drawArrays( GL_POINTS, 0, POINT_NUM * POINT_NUM );
gl::endTransformFeedback();
}
std::swap( mSourceIndex, mDestinationIndex );
}
void IndexTransformFeedbackApp::draw()
{
gl::ScopedMatrices scpMatrx;
gl::setMatrices( mCam );
gl::clear( Color( 0, 0, 0 ) );
{
gl::ScopedBlendAdditive scpAdd;
gl::enableAdditiveBlending();
gl::setDefaultShaderVars();
// draw points
{
mPointBatch[mSourceIndex]->drawInstanced( POINT_NUM );
}
// draw lines
{
mLineBatch[mSourceIndex]->draw();
}
}
}
CINDER_APP( IndexTransformFeedbackApp, RendererGl( RendererGl::Options().msaa( 16 ) ) )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment