Skip to content

Instantly share code, notes, and snippets.

@paulhoux
Last active August 29, 2015 14:02
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 paulhoux/09d5211604da8586bda7 to your computer and use it in GitHub Desktop.
Save paulhoux/09d5211604da8586bda7 to your computer and use it in GitHub Desktop.
One way to create a particle system where all particles move across a unit sphere surface.
#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"
#include "cinder/gl/Vbo.h"
#include "cinder/Camera.h"
#include "cinder/MayaCamUI.h"
#include "cinder/Quaternion.h"
#include "cinder/Rand.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class ParticlesOnSphereApp : public AppNative {
public:
void setup();
void update();
void draw();
void mouseDown( MouseEvent event );
void mouseDrag( MouseEvent event );
void resize();
private:
static const int kNumParticles = 10000;
Vec3f mPosition[kNumParticles];
Vec3f mAxis[kNumParticles];
float mVelocity[kNumParticles];
gl::VboMesh mVBO;
CameraPersp mCamera;
MayaCamUI mMayaCam;
double mCurrentTime;
};
void ParticlesOnSphereApp::setup()
{
// setup camera
mCamera.setPerspective(45.0f, getWindowAspectRatio(), 0.1f, 100.0f);
mCamera.setWorldUp( Vec3f::yAxis() );
mCamera.setEyePoint( Vec3f(0, 0, -3) );
mCamera.setCenterOfInterestPoint( Vec3f(0, 0, 0) );
// create particles
for(int i=0; i<kNumParticles; ++i) {
// set a random position on unit sphere
mPosition[i] = Rand::randVec3f();
// set a random rotation axis of unit length
mAxis[i] = Rand::randVec3f();
// set a random velocity in radians per second
mVelocity[i] = Rand::randFloat(0.1f, 0.5f);
}
// create dynamic VBO, so we can draw all particles in a single draw call
gl::VboMesh::Layout layout;
layout.setDynamicPositions();
layout.setStaticIndices();
std::vector<uint32_t> indices(kNumParticles);
for(int i=0; i<kNumParticles; ++i)
indices[i] = i;
mVBO = gl::VboMesh(kNumParticles, kNumParticles, layout, GL_POINTS);
mVBO.bufferIndices(indices);
// keep track of time
mCurrentTime = getElapsedSeconds();
}
void ParticlesOnSphereApp::update()
{
// calculate elapsed time in seconds
double elapsedTime = getElapsedSeconds() - mCurrentTime;
mCurrentTime += elapsedTime;
// update particles
for(auto itr = mVBO.mapVertexBuffer(); itr.isDone(); ++itr)
{
size_t i = itr.getIndex();
// slowly rotate around axis (adjusted for frame rate)
mPosition[i] = Quatf( mAxis[i], (float)elapsedTime * mVelocity[i] ) * mPosition[i];
// normalize position to avoid accumulating rounding errors
mPosition[i].normalize();
// update dynamic position
itr.setPosition( mPosition[i] );
}
}
void ParticlesOnSphereApp::draw()
{
gl::clear();
// enable camera
gl::pushMatrices();
gl::setMatrices(mCamera);
// enable depth buffer
gl::enableDepthRead();
gl::enableDepthWrite();
// draw particles
gl::color( Color(1,1,1) );
gl::draw( mVBO );
// draw transparent sphere (using back face culling)
gl::disableDepthWrite();
gl::enableAlphaBlending();
gl::color( ColorA(0.10f, 0.10f, 0.10f, 0.75f) );
gl::enable( GL_CULL_FACE );
glCullFace( GL_BACK );
gl::drawSphere( Vec3f::zero(), 1.0f, 40 );
gl::disable( GL_CULL_FACE );
gl::disableAlphaBlending();
// disable depth buffer
gl::disableDepthRead();
gl::disableDepthWrite();
// disable camera
gl::popMatrices();
}
void ParticlesOnSphereApp::mouseDown( MouseEvent event )
{
mMayaCam.setCurrentCam( mCamera );
mMayaCam.mouseDown( event.getPos() );
}
void ParticlesOnSphereApp::mouseDrag( MouseEvent event )
{
mMayaCam.mouseDrag( event.getPos(), event.isLeftDown(), event.isMiddleDown(), event.isRightDown() );
mCamera = mMayaCam.getCamera();
}
void ParticlesOnSphereApp::resize()
{
mCamera.setAspectRatio( getWindowAspectRatio() );
}
CINDER_APP_NATIVE( ParticlesOnSphereApp, RendererGl )
@brucelane
Copy link

funny, I got the sphere, but no particles...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment