Пример #1
0
void BulletSpheresApp::update()
{
	// update time
	// update bullet context
	updateTime(); 
	
	mContext->setGravity( vec3( 0 ) );
	mContext->update();

	// add attractive force
	mat4 * matrices = (mat4*)mMatrices->map( GL_WRITE_ONLY );
	for( auto &body : mRigidBodies ){
		body.update( mTimeElapsed );
		int index = body.getId();
		if( index >=2 ){		// small orbs
			for( int i=0; i<2; i++ ){
				vec3 pos		= mRigidBodies[i].getPos();
				float size		= mRigidBodies[i].getSize();
				float strength	= mRigidBodies[i].getStrength();
				body.attract( pos, size, strength );
			}
			matrices[index-2] = body.getMatrix();
		} else {				// big orbs
			float size			= mRigidBodies[index].getSize();
			body.attract( vec3( 0 ), size, 1.0f );
		}
	}
	mMatrices->unmap();
}
void TessellationSampleApp::createIcosahedron()
{
	const int faces[] = {
		2, 1, 0,
		3, 2, 0,
		4, 3, 0,
		5, 4, 0,
		1, 5, 0,
		
		11, 6,	7,
		11, 7,	8,
		11, 8,	9,
		11, 9,	10,
		11, 10, 6,
		
		1, 2, 6,
		2, 3, 7,
		3, 4, 8,
		4, 5, 9,
		5, 1, 10,
		
		2,	7, 6,
		3,	8, 7,
		4,	9, 8,
		5, 10, 9,
		1,	6, 10
	};
	
	const float verts[] = {
		0.000f,	 0.000f,  1.000f,
		0.894f,	 0.000f,  0.447f,
		0.276f,	 0.851f,  0.447f,
		-0.724f,  0.526f,  0.447f,
		-0.724f, -0.526f,  0.447f,
		0.276f, -0.851f,  0.447f,
		0.724f,	 0.526f, -0.447f,
		-0.276f,  0.851f, -0.447f,
		-0.894f,  0.000f, -0.447f,
		-0.276f, -0.851f, -0.447f,
		0.724f, -0.526f, -0.447f,
		0.000f,	 0.000f, -1.000f
	};
	
	mIndexCount = sizeof(faces) / sizeof(faces[0]);
	
	vertexArrayObject->bind();
	
	// Create the VBO for positions:
	GLsizei stride = 3 * sizeof(float);
	vertexBufferObject->bind();
	vertexBufferObject->bufferData(sizeof(verts), verts, GL_STATIC_DRAW);
	gl::enableVertexAttribArray( (GLuint)mPositionIndex );
	gl::vertexAttribPointer( (GLuint)mPositionIndex, 3, GL_FLOAT, GL_FALSE, stride, 0 );
	
	// Create the VBO for indices:
	indexBufferObject->bind();
	indexBufferObject->bufferData( sizeof(faces), faces, GL_STATIC_DRAW );
}
void TransformFeedbackIntroApp::runTransformFeedback()
{
	gl::ScopedVao		scopeVao( mVao );
	gl::ScopedGlslProg	scopeGlsl( mGlsl );
	gl::ScopedState		scopeState( GL_RASTERIZER_DISCARD, true );
	// Bind the capture vbo to the TransformVertex binding point to capture the calculations
	gl::bindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, TransformIndex, mCaptureVbo );
	
	// Begin Transform Feedback, using the primitive we plan to draw
	gl::beginTransformFeedback( GL_POINTS );
	gl::drawArrays( GL_POINTS, 0, NumVertices );
	// End Transform Feedback
	gl::endTransformFeedback();
	
    glFlush();
	
    // Fetch and print results
    GLfloat feedback[NumVertices];
	mCaptureVbo->getBufferSubData( 0, sizeof(float) * NumVertices, feedback );
	
    console() << feedback[0] << " "
				<< feedback[1] << " "
				<< feedback[2] << " "
				<< feedback[3] << " "
				<< feedback[4] << std::endl;
}
Пример #4
0
void SinOrbitApp::reset(bool pShader)
{
	mColor = vec4(randVec3(), randFloat(0.005f, 0.025f));
	mAlpha = randFloat(0.01f, 0.1f);
	auto w = randFloat(5.0f,10.0f);
	auto maxR = randFloat(350.0f, 400.0f);
	auto numPtcls = randInt(500, 1000);

	mPtcls.clear();

	for (int i = 0; i < numPtcls; ++i) {
		mPtcls.push_back(
			ptcl(
				randFloat(0.2f, 0.8f),
				randFloat(400.0f-w, 400.0f+w),
				randFloat(0.01f, 0.05f),
				randFloat(-0.5f, 0.5f),
				randFloat(1.0f, 3.0f)
			)
		);
	}

	if (pShader) {
		mPointShader = gl::GlslProg::create(loadAsset("points.vert"), loadAsset("points.frag"));

		geom::BufferLayout attribs;
		attribs.append(geom::POSITION, 2, sizeof(ptcl), offsetof(ptcl, Pos), 0);
		mPointData = gl::Vbo::create(GL_ARRAY_BUFFER, mPtcls, GL_DYNAMIC_DRAW);
		mPointMesh = gl::VboMesh::create(mPtcls.size(), GL_POINTS, { {attribs, mPointData} });
	}
	else {
		mPointData->bufferData(mPtcls.size()*sizeof(ptcl), mPtcls.data(), GL_DYNAMIC_DRAW);
	}
}
Пример #5
0
void PointCloudVAO::updateCloud()
{
	mDS->update();
	auto depth = mDS->getDepthFrame();
	auto iter = depth->getIter();

	mPoints.clear();
	while (iter.line())
	{
		while (iter.pixel())
		{
			if (iter.x() % mParamStep == 0 && iter.y() % mParamStep == 0)
			{
				float x = (float)iter.x();
				float y = (float)iter.y();
				float z = (float)iter.v();
				if (z > mParamDepthMin && z < mParamDepthMax)
				{
					auto world = mDS->getDepthSpacePoint(vec3(x, y, z));
					auto diffuse = mDS->getColorFromDepthSpace(world);
					mPoints.push_back(Pt(world, diffuse));
				}
			}
		}
	}

	mVbo->bufferData(mPoints.size()*sizeof(Pt), mPoints.data(), GL_DYNAMIC_DRAW);
}
void PointCloudApp::update()
{
	
	mCinderRS->update();
	mPoints.clear();
	Channel16u cChanDepth = mCinderRS->getDepthFrame();

	mTexRgb->update(mCinderRS->getRgbFrame());
	for (int dy = 0; dy < mDepthDims.y; ++dy)
	{
		for (int dx = 0; dx < mDepthDims.x; ++dx)
		{
			float cDepth = (float)*cChanDepth.getData(dx, dy);
			if (cDepth > 100 && cDepth < 1000)
			{
				vec3 cPos = mCinderRS->getDepthSpacePoint(vec3(dx, dy, cDepth));
				vec2 cUV = mCinderRS->getColorCoordsFromDepthImage(static_cast<float>(dx),
																	static_cast<float>(dy),
																	cDepth);
				mPoints.push_back(CloudPoint(cPos, cUV));
			}
		}
	}

	mBufferObj->bufferData(mPoints.size()*sizeof(CloudPoint), mPoints.data(), GL_DYNAMIC_DRAW);
	mMeshObj = gl::VboMesh::create(mPoints.size(), GL_POINTS, { { mAttribObj, mBufferObj } });
	mDrawObj->replaceVboMesh(mMeshObj);
}
Пример #7
0
void InstancedTeapotsApp::update()
{
	// move the camera up and down on Y
	mCam.lookAt( vec3( 0, CAMERA_Y_RANGE.first + abs(sin( getElapsedSeconds() / 4)) * (CAMERA_Y_RANGE.second - CAMERA_Y_RANGE.first), 0 ), vec3( 0 ) );
	
	// update our instance positions; map our instance data VBO, write new positions, unmap
	vec3 *positions = (vec3*)mInstanceDataVbo->mapWriteOnly( true );
	for( size_t potX = 0; potX < NUM_INSTANCES_X; ++potX ) {
		for( size_t potY = 0; potY < NUM_INSTANCES_Y; ++potY ) {
			float instanceX = potX / (float)NUM_INSTANCES_X - 0.5f;
			float instanceY = potY / (float)NUM_INSTANCES_Y - 0.5f;
			// just some nonsense math to move the teapots in a wave
			vec3 newPos(	instanceX * vec3( DRAW_SCALE, 0, 0 ) +
							instanceY * vec3( 0, 0, DRAW_SCALE ) +
							vec3( 0, 30, 0 ) * sinf( getElapsedSeconds() * 3 + instanceX * 3 + instanceY * 3 ) );
			*positions++ = newPos;
		}
	}
	mInstanceDataVbo->unmap();
}
Пример #8
0
void SinOrbitApp::update()
{
	if (mStarted) {
		if (getElapsedFrames() % 300 == 0) {
			reset(false);
		}
		for (auto &p : mPtcls) {
			p.step();
		}
		mPointData->bufferData(mPtcls.size()*sizeof(ptcl), mPtcls.data(), GL_DYNAMIC_DRAW);
	}
}
Пример #9
0
void SpiderWebApp::reset()
{
	
		mIterationIndex = 0;


		mPositionBufTexs[0].reset();
		mPositionBufTexs[1].reset();
	
		mPositionBufTexs[0] = nullptr;
		mPositionBufTexs[1] = nullptr;
	
		mVaos[0].reset();
		mVaos[1].reset();
	
		mVaos[0] = nullptr;
		mVaos[1] = nullptr;
		
	//	mPositions[0] = nullptr;	// with these, we only get movement the first time around
	//	mPositions[1] = nullptr;
	//	mVelocities[0] = nullptr;
	//	mVelocities[1] = nullptr;
	//	mConnections[0] = nullptr;
	//	mConnections[1] = nullptr;
	//	mConnectionLen[0] = nullptr;
	//	mConnectionLen[1] = nullptr;
	//	mLineIndices = nullptr;
		
		// adding this gives us 3 rounds of movement
		mPositions[0]->mapReplace();
		mPositions[1]->mapReplace();
		mVelocities[0]->mapReplace();
		mVelocities[1]->mapReplace();
		mConnections[0]->mapReplace();
		mConnections[1]->mapReplace();
		mConnectionLen[0]->mapReplace();
		mConnectionLen[1]->mapReplace();
		mLineIndices->mapReplace();
	
		// RESET and generate web
		mWeb->reset();
		mWeb = nullptr;
		generateWeb();
		setupBuffers();
}
Пример #10
0
void RandomSpawn::updateParticles()
{
    mCinderDS->update();
    mChanDepth = mCinderDS->getDepthFrame();
    //Channel16u::Iter cIter = mChanDepth.getIter();

    for (int sp = 0; sp < S_SPAWN_COUNT; ++sp)
    {
        if (mPointsParticles.size() < S_MAX_COUNT)
        {
            int cX = randInt(0, mDepthDims.x);
            int cY = randInt(0, mDepthDims.y);

            float cZ = (float)mChanDepth.getValue(ivec2(cX, cY));
            if (cZ > S_MIN_Z&&cZ < S_MAX_Z)
            {
                vec3 cWorld = mCinderDS->getDepthSpacePoint(static_cast<float>(mDepthDims.x-cX),
                              static_cast<float>(cY),
                              static_cast<float>(cZ));

                // pos, acc size life
                vec3 cAcc(randFloat(-5.f, 5.f), randFloat(0.5f, 3.5f), randFloat(-5.f, 5.f));
                float cSize = randFloat(S_POINT_SIZE*0.25f, S_POINT_SIZE);
                int cLife = randInt(60, 120);
                ColorA cColor = ColorA(randFloat(), 0.1f, randFloat(), 1.0f);

                mPointsParticles.push_back(CloudParticle(cWorld, cSize, cLife, cColor));
            }
        }
    }

    //now update particles
    for (auto pit = mPointsParticles.begin(); pit != mPointsParticles.end();)
    {
        if (pit->PAge == 0)
            pit = mPointsParticles.erase(pit);
        else
        {
            pit->step(mPerlin);
            ++pit;
        }
    }

    mDataInstance_P->bufferData(mPointsParticles.size()*sizeof(CloudParticle), mPointsParticles.data(), GL_DYNAMIC_DRAW);
}
Пример #11
0
void Choreo3DApp::update()
{
    setFrameRate(frameRate);
    
    //DISABLE CAMERA INTERACTION IF MOUSE IS OVER UI REGION
    if (getMousePos().x > 3 * getWindowWidth()/4. && camActive)
    {
        camActive = false;
        mCamUi.disconnect();
        mCamUi.disable();
        cout << "disabling camera UI" << endl;
    } else {
        if (!camActive)
        {
            mCamUi.connect(getWindow());
            mCamUi.enable();
        }
        camActive = true;
        cout << "enabling camera UI" << endl;
    }
    
    mGlsl->uniform("uColor", markerColour );
    
    if (!paused)
    {
        
        
        //UPDATE POSITIONS
        //MAP INSTANCE DATA TO VBO
        //WRITE NEW POSITIONS
        //UNMAP
        
        glm::vec3 *newPositions = (glm::vec3*)mInstanceDataVbo->mapReplace();
        
        for( int i = 0; i < jointList.size(); ++i )
        {
            
            float instanceX = jointList[i].jointPositions[FRAME_COUNT].x;
            float instanceY = jointList[i].jointPositions[FRAME_COUNT].y;
            float instanceZ = jointList[i].jointPositions[FRAME_COUNT].z;
            
            vec3 newPos(vec3(instanceX,instanceY, instanceZ)); //CREATE A NEW VEC3 FOR UPDATING THE VBO
            
            framePositions[i] = newPos;
            
        }
        
        //REPLACE VEC3s IN VBO BY INCREMENTING THE POINTER
        for (int i = 0; i < framePositions.size(); i++){
            *newPositions++ = framePositions[i];
        }
        
        handTrail.update(framePositions[26], dancerColor);
        
        //    std::cout << framePositions[17] << std::endl;
        
        
        skeleton.update(framePositions);

        
        mInstanceDataVbo->unmap();
        // std::cout << "position: " << positions[0] << std::endl;
        
        if (ribbonsActive)updateRibbons();
        
        //MANUALLY INCREMENT THE FRAME, IF THE FRAME_COUNT EXCEEDS TOTAL FRAMES, RESET THE COUNTER
        if (FRAME_COUNT < TOTAL_FRAMES)
        {
            FRAME_COUNT += 1;
        } else {
            FRAME_COUNT = 0;
        }
        
        //std::cout << getAverageFps() << std:: endl;
        // std::cout << "frame rate: " << getAverageFps() << ", frame count: " << FRAME_COUNT << std::endl;
        
        //define changed color
      //  Color temp = Color(dancerColor[0],dancerColor[1],dancerColor[2]);
        
        
        mCurrentFrame++; //MANUALLY ADVANCE THE CURRENT FRAME - WITH RESPECT TO THE DANCERS
    
    }
    
    updateGui();
}
Пример #12
0
void SpiderWebApp::setupBuffers()
{
	
	// get all of the points from the spider web
	
	 // buffer the positions
	std::array<vec4, MAX_POINTS> positions;
	std::array<vec3, MAX_POINTS> velocities;
	std::array<ivec4, MAX_POINTS> connections;
	std::array<vec4, MAX_POINTS> connectionLen;
	std::array<vec4, MAX_POINTS> colors;
	
	vector<ParticleRef> webPoints = mWeb->getPoints();
	int n = 0;
	Perlin p = Perlin();
	for( auto iter = webPoints.begin(); iter != webPoints.end(); ++iter ) {
		auto point = (*iter);
		vec2 pos = point->getPosition();
		// create our initial positions
		positions[point->getId()] = vec4(
			pos.x, pos.y,
			0.0,
			1.0f );
		// zero out velocities
		velocities[point->getId()] = vec3( 0.0f );
		
		connections[n] = ivec4( -1 );
		connectionLen[n] = vec4( 0.0 );
		auto conn = point->getNeighbors();
		// use first 4 connections of there are more
		int max = min(int(conn.size()), 4);

		for( int i = 0; i < max; ++i ){
			auto connection = conn[i];
			connections[n][i] = connection->getId();
//			connectionLen[n][i] = distance( normalize(pos), normalize(connection->getPosition()) );
			connectionLen[n][i] = distance( pos, connection->getPosition() );
		}
		n++;
		
		// DEFINE alpha - helps make the line thickness look a bit varied
		float x = pos.x / getWindowWidth();
		float y = pos.y / getWindowHeight();
		float a = p.fBm( x, y ) * 2.0;
		a += 0.35;
		colors[point->getId()] = vec4( vec3( 1.0 ), a );
	}
	
	for ( int i = 0; i < 2; i++ ) {
		mVaos[i] = gl::Vao::create();
		gl::ScopedVao scopeVao( mVaos[i] );
		{
			// buffer the positions
			mPositions[i] = gl::Vbo::create( GL_ARRAY_BUFFER, positions.size() * sizeof(vec4), positions.data(), GL_STATIC_DRAW );
			{
				// bind and explain the vbo to your vao so that it knows how to distribute vertices to your shaders.
				gl::ScopedBuffer sccopeBuffer( mPositions[i] );
				gl::vertexAttribPointer( POSITION_INDEX, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) 0 );
				gl::enableVertexAttribArray( POSITION_INDEX );
			}
			
			// buffer the velocities
			mVelocities[i] = gl::Vbo::create( GL_ARRAY_BUFFER, velocities.size() * sizeof(vec3), velocities.data(), GL_STATIC_DRAW );
			{
				// bind and explain the vbo to your vao so that it knows how to distribute vertices to your shaders.
				gl::ScopedBuffer scopeBuffer( mVelocities[i] );
				gl::vertexAttribPointer( VELOCITY_INDEX, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) 0 );
				gl::enableVertexAttribArray( VELOCITY_INDEX );
			}
			// buffer the connections
			mConnections[i] = gl::Vbo::create( GL_ARRAY_BUFFER, connections.size() * sizeof(ivec4), connections.data(), GL_STATIC_DRAW );
			{
				// bind and explain the vbo to your vao so that it knows how to distribute vertices to your shaders.
				gl::ScopedBuffer scopeBuffer( mConnections[i] );
				gl::vertexAttribIPointer( CONNECTION_INDEX, 4, GL_INT, 0, (const GLvoid*) 0 );
				gl::enableVertexAttribArray( CONNECTION_INDEX );
			}
			// buffer the connection lengths
			mConnectionLen[i] = gl::Vbo::create( GL_ARRAY_BUFFER, connectionLen.size() * sizeof(vec4), connectionLen.data(), GL_STATIC_DRAW );
			{
				// bind and explain the vbo to your vao so that it knows how to distribute vertices to your shaders.
				gl::ScopedBuffer scopeBuffer( mConnectionLen[i] );
				gl::vertexAttribPointer( CONNECTION_LEN_INDEX, 4, GL_FLOAT, GL_FLOAT, 0, (const GLvoid*) 0 );
				gl::enableVertexAttribArray( CONNECTION_LEN_INDEX );
			}
			
			// buffer the colors
			mColors[i] = gl::Vbo::create( GL_ARRAY_BUFFER, colors.size() * sizeof(vec4), colors.data(), GL_STATIC_DRAW );
			{
				// bind and explain the vbo to your vao so that it knows how to distribute vertices to your shaders.
				gl::ScopedBuffer scopeBuffer( mColors[i] );
				gl::vertexAttribPointer( COLOR_INDEX, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid*) 0 );
				gl::enableVertexAttribArray( COLOR_INDEX );
			}
			
			// Create a TransformFeedbackObj, which is similar to Vao
			// It's used to capture the output of a glsl and uses the
			// index of the feedback's varying variable names.
			mFeedbackObj[i] = gl::TransformFeedbackObj::create();
			// Bind the TransformFeedbackObj and bind each corresponding buffer
			// to it's index.
			mFeedbackObj[i]->bind();
			gl::bindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, POSITION_INDEX, mPositions[i] );
			gl::bindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, VELOCITY_INDEX, mVelocities[i] );
			mFeedbackObj[i]->unbind();
		}
	}
	// create your two BufferTextures that correspond to your position buffers.
	mPositionBufTexs[0] = gl::BufferTexture::create( mPositions[0], GL_RGBA32F );
	mPositionBufTexs[1] = gl::BufferTexture::create( mPositions[1], GL_RGBA32F );
	
	auto strands = mWeb->getUniqueStrands();
	int lines = strands.size();
	mConnectionCount = lines;
	// create the indices to draw links between the cloth points
	mLineIndices = gl::Vbo::create( GL_ELEMENT_ARRAY_BUFFER, lines * 2 * sizeof(int), nullptr, GL_STATIC_DRAW );

	auto e = (int *) mLineIndices->mapReplace();
	for( auto iter = strands.begin(); iter != strands.end(); ++iter ){
		auto strand = *iter;
		*e++ = strand.first->getId();
		*e++ = strand.second->getId();
	}
	
	
	mLineIndices->unmap();
}
void TransformFeedbackClothSimulationApp::loadBuffers()
{
	int n = 0;
	
	array<vec4, POINTS_TOTAL> positions;
	array<vec3, POINTS_TOTAL> velocities;
	array<ivec4, POINTS_TOTAL> connections;
	
	// We set all connections to -1, because these will only be updated
	// if there are connection indices. Explanation below.
	connections.fill( ivec4( -1 ) );
	
	for( int j = 0; j < POINTS_Y; j++ ) {
		float fj = (float)j / (float)POINTS_Y;
		for( int i = 0; i < POINTS_X; i++ ) {
			float fi = (float)i / (float)POINTS_X;
			
			// This fills the position buffer data, basically makes a grid
			positions[n] = vec4((fi - 0.5f) * (float)POINTS_X,	// x coordinate
								 (fj - 0.5f) * (float)POINTS_Y,	// y coordinate
								 0.6f * sinf(fi) * cosf(fj),	// z coordinate
								 1.0f);							// homogenous coordinate or w
			
			// This allows us to figure out the indices of the four points
			// surrounding the current point. This will be used to index
			// into the texture buffer.
			if( j != (POINTS_Y - 1) ) {	// if it's not one of the top row, don't move
				if( i != 0 )
					connections[n][0] = n - 1;
				if( j != 0 )
					connections[n][1] = n - POINTS_X;
				if( i != (POINTS_X - 1) )
					connections[n][2] = n + 1;
				if( j != (POINTS_Y - 1) )
					connections[n][3] = n + POINTS_X;
			}
			n++;
		}
	}
	
	// Create the Position Buffer with the intial position data
	mPositions[0] = gl::Vbo::create( GL_ARRAY_BUFFER, positions.size() * sizeof(vec4), positions.data(), GL_STATIC_DRAW );
	// Create another Position Buffer that is null, for ping-ponging
	mPositions[1] = gl::Vbo::create( GL_ARRAY_BUFFER, positions.size() * sizeof(vec4), nullptr, GL_STATIC_DRAW );
	
	// Create the Velocity Buffer with the intial velocity data
	mVelocities[0] = gl::Vbo::create( GL_ARRAY_BUFFER, velocities.size() * sizeof(vec3), velocities.data(), GL_STATIC_DRAW );
	// Create another Velocity Buffer that is null, for ping-ponging
	mVelocities[1] = gl::Vbo::create( GL_ARRAY_BUFFER, velocities.size() * sizeof(vec3), nullptr, GL_STATIC_DRAW );
	
	// Create Connection Buffer to index into the Texture Buffer
	mConnections = gl::Vbo::create( GL_ARRAY_BUFFER, connections.size() * sizeof(ivec4), connections.data(), GL_STATIC_DRAW );
	
	for( int i = 0; i < 2; i++ ) {
		// Initialize the Vao's holding the info for each buffer
		mVaos[i] = gl::Vao::create();
		
		// Bind the vao to capture index data for the glsl
		mVaos[i]->bind();
		mPositions[i]->bind();
		gl::vertexAttribPointer( POSITION_INDEX, 4, GL_FLOAT, GL_FALSE, 0, NULL );
		gl::enableVertexAttribArray( POSITION_INDEX );
		
		mVelocities[i]->bind();
		gl::vertexAttribPointer( VELOCITY_INDEX, 3, GL_FLOAT, GL_FALSE, 0, NULL );
		gl::enableVertexAttribArray( VELOCITY_INDEX );
		
		mConnections->bind();
		gl::vertexAttribIPointer( CONNECTION_INDEX, 4, GL_INT, 0, NULL );
		gl::enableVertexAttribArray( CONNECTION_INDEX );
		
		// Create a TransformFeedbackObj, which is similar to Vao
		// It's used to capture the output of a glsl and uses the
		// index of the feedback's varying variable names.
		mFeedbackObjs[i] = gl::TransformFeedbackObj::create();
		
		// Bind the TransformFeedbackObj and bind each corresponding buffer
		// to it's index.
		mFeedbackObjs[i]->bind();
		gl::bindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, POSITION_INDEX, mPositions[i] );
		gl::bindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, VELOCITY_INDEX, mVelocities[i] );
		mFeedbackObjs[i]->unbind();
		
		// Create Texture buffers to gain access to the lookup tables for
		// calculations in the update shader
		mPosBufferTextures[i] = gl::BufferTexture::create( mPositions[i], GL_RGBA32F );
	}
	
	// Create an element buffer to draw the lines (connections) between the points
	array<uint32_t, CONNECTIONS_TOTAL*2> lineIndices;
	uint32_t * e = lineIndices.data();
	for( int j = 0; j < POINTS_Y; j++ ) {
		for( int i = 0; i < POINTS_X - 1; i++ ) {
			*e++ = i + j * POINTS_X;
			*e++ = 1 + i + j * POINTS_Y;
		}
	}
	
	for( int i = 0; i < POINTS_X; i++ ) {
		for( int j = 0; j < POINTS_Y - 1; j++ ) {
			*e++ = i + j * POINTS_X;
			*e++ = POINTS_X + i + j * POINTS_X;
		}
	}
	
	mLineIndices = lineIndices.size();
	mLineElementBuffer = gl::Vbo::create( GL_ELEMENT_ARRAY_BUFFER, lineIndices.size() * sizeof(uint32_t), lineIndices.data(), GL_STATIC_DRAW );
}