Here I leave you an example of what I am trying to do (the complete example is attached as .zip file).
I use a VBO to store all the vertex and color data. The variable “behavior” determines the way particles are going to move in the screen. In this case, 0 represents boid behavior.
The performance is but 25fps: extremely poor for just 500 particles!! I am on a MBP intel core Duo, 8GB, OS X 10.6.8, NVIDIA GeForce GT 330M
Question 1:
Are Vbos the way to go in this case? How can I boost performance?
Question 2:
I initialize particles at random positions of the screen (ofRandom(screenWidth), ofRandom(screenHeight)). However they appear in the screen corners. Why is this?
//////CODE////////////////////////////////////////////////////////
Object.h
#ifndef __H__OBJECT
#define __H__OBJECT
#include "ofMain.h"
class Object {
public:
void init(const int& _nParticles);
void setWSize(ofVec2f w);
void update();
void draw();
void setBehaviour(int n);
int getBehaviour() const;
int getNParticles() const;
private:
void borders(const int& index);
//BOID BEHAVIOUR FUNCTIONS
void flocking (const int& index);
ofVec3f separate (const int& thisBoid);
ofVec3f align (const int& thisBoid);
ofVec3f cohesion (const int& thisBoid);
void addBoid();
int nParticles;
int behaviour;
ofVec2f WSize;
ofVec3f* pnPos;
ofVec3f* pnVel;
ofVec3f* pnAccel;
ofColor* pnColor;
float* pnTime;
ofVbo vbo;
static float maxSpeed, maxForce, r;
};
#endif;
Object.cpp
#include "Object.h"
//static variables
float Object::maxSpeed = 3.0f;
float Object::maxForce = 0.1f;
float Object::r = 4.0f;
void Object::setBehaviour(int b) {
behaviour = b;
//does this imply any change on vertex arrays?
}
int Object::getBehaviour() const {
return behaviour;
}
void Object::setWSize(ofVec2f w) {
WSize = w;
}
int Object::getNParticles() const {
return(nParticles);
}
void Object::init(const int& _nParticles) {
behaviour = 0;
//prevention in case the object is already initalized...
// (avoid double allocation)
if (nParticles > 0)
{
ofLog(OF_LOG_WARNING, "Object: Already initialized");
delete[] pnPos;
delete[] pnVel;
delete[] pnColor;
delete[] pnAccel;
delete[] pnTime;
nParticles = 0;
}
//initialization of arrays
nParticles = _nParticles;
pnPos = new ofVec3f [nParticles];
pnVel = new ofVec3f [nParticles];
pnAccel = new ofVec3f [nParticles];
pnColor = new ofColor [nParticles];
pnTime = new float [nParticles];
ofSeedRandom();
//initialize array data
for(int i=0; i<nParticles; i++) {
pnPos[i].set(ofRandom(WSize.x), ofRandom(WSize.y), 0.0f);
pnVel[i].set(ofRandom(-1.0, 1.0f), ofRandom(-1.0f, 1.0f), ofRandom(-1.0f, 1.0f));
pnAccel[i] = 0;
pnColor[i].set(255, 255, 255, 255);
pnTime[i] = ofRandom(1.0f);
}
vbo.setColorData(pnColor, nParticles, GL_STATIC_DRAW);
vbo.setVertexData(pnPos, nParticles, GL_DYNAMIC_DRAW);
}
void Object::borders(const int& index) {
if (pnPos[index].x < -r) pnPos[index].x = WSize.x+r;
if (pnPos[index].y < -r) pnPos[index].y = WSize.y+r;
if (pnPos[index].x > WSize.x+r) pnPos[index].x = -r;
if (pnPos[index].y > WSize.y+r) pnPos[index].y = -r;
}
void Object::update() {
switch(behaviour) {
case 0:
//UPDATE BOID
for (int i=0; i<nParticles; i++) {
flocking(i); //calculate acceleration for this boid in relation to other boids
pnVel[i] += pnAccel[i];
pnVel[i].limit(maxSpeed);
pnPos[i] += pnVel[i];
borders(i);
pnAccel[i] *= 0.0f;
}
break;
/*
case 1:
borders();
break;
case 2:
borders();
break;
*/
default:
break;
}
}
void Object::draw () {
ofSetLineWidth(3.0f);
//update the vbo
vbo.setColorData(pnColor, nParticles, GL_STATIC_DRAW);
vbo.setVertexData(pnPos, nParticles, GL_DYNAMIC_DRAW);
// and draw
vbo.draw(GL_POINTS, 0, nParticles); //arguments: drawMode, first, total
}
/////////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS FOR BOID BEHAVIOR ///////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
void Object::flocking(const int& index) {
ofVec3f sep = separate(index);
ofVec3f ali = align(index);
ofVec3f coh = cohesion(index);
//Arbitrarily weight these forces
sep *= 1.2f;
ali *= 1.5f;
coh *= 1.0f;
//Add the force vectors to acceleration
pnAccel[index] += sep;
pnAccel[index] += ali;
pnAccel[index] += coh;
}
ofVec3f Object::separate (const int& thisBoid) {
float desiredseparation = 25.0f;
ofVec3f steer(0.0f, 0.0f, 0.0f);
int count = 0;
//For every boid in the system, check if it is too close
for (int i = 0; i < nParticles; i++) {
ofVec3f other = pnPos[i];
float d = ofVec3f(pnPos[thisBoid] - other).length();
if ((d >0) && (d < desiredseparation)) {
ofVec2f diff = pnPos[thisBoid] - other;
diff.normalize();
diff /= d; //weight by distance. The closer, the stronger the steer vector
steer += diff;
count++;
}
}
//average distance of this boid to all other boids
if(count > 0) steer /= (float)count;
if (steer.length() > 0) {
steer.normalize();
steer *= maxSpeed;
steer -= pnVel[thisBoid];
steer.limit(maxForce);
}
return steer;
}
ofVec3f Object::align (const int& thisBoid) {
float neighbordist = 50.0f;
ofVec3f steer(0.0f, 0.0f, 0.0f);
int count = 0;
for (int i = 0; i < nParticles; i++) {
float d = ofVec3f(pnPos[thisBoid] - pnPos[i]).length();
if ((d >0) && (d < neighbordist)) {
steer += pnVel[i];
count++;
}
}
if (count > 0) {
steer /= (float)count;
}
if (steer.length() > 0) {
steer.normalize();
steer *= maxSpeed;
steer -= pnVel[thisBoid];
steer.limit(maxForce);
}
return steer;
}
ofVec3f Object::cohesion (const int& thisBoid) {
float neighbordist = 50.0f;
ofVec3f sum (0.0f, 0.0f, 0.0f);
int count = 0;
for (int i = 0; i < nParticles; i++) {
float d = ofVec3f(pnPos[thisBoid] - pnPos[i]).length();
if ((d > 0.0f) && (d < neighbordist)) {
sum += pnPos[i];
count++;
}
}
if (count > 0) {
sum /= (float)count;
//steer vector towards the location
ofVec3f steer; //the steering vector
ofVec3f desired = sum - pnPos[thisBoid];
float d = desired.length(); //magnitude
if (d > 0.0f) {
desired.normalize();
desired *= maxSpeed;
//steering = desired - velocity
steer = desired-pnVel[thisBoid];
steer.limit(maxForce);
}
else steer.set(0.0f, 0.0f);
return steer;
}
return sum;
}
void Object::addBoid() {
//still to determine....
}
VBO_example_particles.zip