Hi everyone,
I’m writing a simple N-Body simulation (i.e particles moving in a box with/out gravity, and without interacting with each other)
It worked as expected when I was using gl::drawSphere()
, but this obviously won’t really take a big number of particles. Thereby, I’m trying to move rendering to the GPU as describe here:
https://libcinder.org/docs/guides/opengl/part3.html
That actually works well for one particle, but as soon as more particles are added they start to move aggressively out of the box in what seems to be a joint cloud of all particles but the first one.
here’s some code:
CinderApp.cpp:
class BasicApp : public App {
public:
void keyDown(KeyEvent event) override;
void update() override;
void setup() override;
void draw() override;
private:
std::vector<Particle*> m_paricles;
CameraPersp m_camera;
int m_cameraZoom;
gl::BatchRef m_sphereRef;
};
void BasicApp::mouseDrag( MouseEvent event )
{
}
void BasicApp::setup()
{
auto lambert = gl::ShaderDef().lambert().color();
gl::GlslProgRef shader = gl::getStockShader(lambert);
auto sphere = geom::Sphere();
m_sphereRef = gl::Batch::create(sphere, shader);
m_cameraZoom = 50;
m_camera.lookAt(vec3(m_cameraZoom, 0, 0), vec3(0));
setFpsSampleInterval(getFpsSampleInterval() / 100);
}
void prepareSettings(BasicApp::Settings* settings)
{
}
void BasicApp::keyDown( KeyEvent event )
{
if( event.getChar() == 'p' ) {
m_paricles.push_back(
new Particle( Utils::GetRandomVec3(5),
Utils::GetRandomVec3(1),
Rand::randFloat(1,2),
1/30)
);
}
if (event.getChar() == '-') {
++m_cameraZoom;
m_camera.lookAt(vec3(m_cameraZoom, 0, 0), vec3());
}
else if( event.getCode() == KeyEvent::KEY_SPACE ) {
vec3 earthGravity(9.8, 0, 0);
for (Particle* particle : m_paricles)
particle->setGravity(earthGravity);
}
else if( event.getCode() == KeyEvent::KEY_ESCAPE ) {
vec3 earthGravity(0);
for (Particle* particle : m_paricles)
particle->setGravity(vec3());
}
}
void BasicApp::update()
{
for (Particle* particle : m_paricles)
particle->makeStep();
}
void BasicApp::draw()
{
gl::clear();
gl::enableDepthRead();
gl::enableDepthWrite();
gl::setMatrices(m_camera);
for (Particle* particle : m_paricles) {
gl::color(particle->getColor());
gl::translate(particle->getLocation());
m_sphereRef->draw();
}
}
// This line tells Cinder to actually create and run the application.
CINDER_APP( BasicApp, RendererGl, prepareSettings )
And here’s Particle definition and implementation:
class Particle {
public:
Particle(ci::vec3 initialLocation, ci::vec3 initialVelocity, int mass, float dt);
ci::vec3 getLocation() const { return m_location; }
ci::vec3 getVelocity() const { return m_velocity; }
int getMass() const { return m_mass; }
ci::Color getColor() { return m_color; }
void makeStep();
ci::vec3 getGravity() const { return m_gravity; }
void setGravity(ci::vec3 val) { m_gravity = val; }
private:
ci::vec3 m_location;
ci::vec3 m_velocity;
int m_mass;
ci::Color m_color;
const int m_bounds = 10;
ci::vec3 m_gravity;
float m_dt;
};
Particle::Particle(ci::vec3 initialLocation, ci::vec3 initialVelocity, int mass, float dt)
: m_location(initialVelocity), m_velocity(initialVelocity), m_mass(mass), m_dt(dt)
{
ci::Color color(ci::Rand::randFloat(1),
ci::Rand::randFloat(1),
ci::Rand::randFloat(1));
m_color = color;
}
void Particle::makeStep()
{
if(ci::length(m_gravity) > 0){
m_velocity = m_velocity - m_gravity * m_dt;
}
m_location = m_location + m_velocity;
if (ci::math<float>::abs(m_location.x) > m_bounds) m_velocity.x *= -1;
if (ci::math<float>::abs(m_location.y) > m_bounds) m_velocity.y *= -1;
if (ci::math<float>::abs(m_location.z) > m_bounds) m_velocity.z *= -1;
}
Thanks.