GPUParticles: Implement box emitter

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@14870 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
vincentlj 2014-01-01 18:11:28 +00:00
parent 245910d3a7
commit 28ebf0c08c
2 changed files with 121 additions and 52 deletions

View File

@ -244,12 +244,117 @@ ParticleSystemProxy::ParticleSystemProxy(bool createDefaultEmitter,
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void ParticleSystemProxy::generateParticlesFromPointEmitter(scene::IParticlePointEmitter *emitter)
{
float *particles = new float[COMPONENTCOUNT * count], *initialvalue = new float[COMPONENTCOUNT * count];
unsigned lifetime_range = emitter->getMaxLifeTime() - emitter->getMinLifeTime();
float sizeMin = emitter->getMinStartSize().Height;
float sizeMax = emitter->getMaxStartSize().Height;
for (unsigned i = 0; i < count; i++) {
particles[COMPONENTCOUNT * i] = 0;
particles[COMPONENTCOUNT * i + 1] = 0;
particles[COMPONENTCOUNT * i + 2] = 0;
// Initial lifetime is 0 percent
particles[COMPONENTCOUNT * i + 3] = rand();
particles[COMPONENTCOUNT * i + 3] /= RAND_MAX;
initialvalue[COMPONENTCOUNT * i] = 0.;
initialvalue[COMPONENTCOUNT * i + 1] = 0.;
initialvalue[COMPONENTCOUNT * i + 2] = 0.;
initialvalue[COMPONENTCOUNT * i + 3] = rand() % lifetime_range;
initialvalue[COMPONENTCOUNT * i + 3] += emitter->getMinLifeTime();
core::vector3df particledir = emitter->getDirection();
particledir.rotateXYBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particledir.rotateYZBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particledir.rotateXZBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particles[COMPONENTCOUNT * i + 4] = particledir.X;
particles[COMPONENTCOUNT * i + 5] = particledir.Y;
particles[COMPONENTCOUNT * i + 6] = particledir.Z;
initialvalue[COMPONENTCOUNT * i + 4] = particledir.X;
initialvalue[COMPONENTCOUNT * i + 5] = particledir.Y;
initialvalue[COMPONENTCOUNT * i + 6] = particledir.Z;
initialvalue[COMPONENTCOUNT * i + 7] = rand();
initialvalue[COMPONENTCOUNT * i + 7] /= RAND_MAX;
initialvalue[COMPONENTCOUNT * i + 7] *= (sizeMax - sizeMin);
initialvalue[COMPONENTCOUNT * i + 7] += sizeMin;
}
glGenBuffers(1, &initial_values_buffer);
glBindBuffer(GL_ARRAY_BUFFER, initial_values_buffer);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), initialvalue, GL_STREAM_DRAW);
glGenBuffers(2, tfb_buffers);
glBindBuffer(GL_ARRAY_BUFFER, tfb_buffers[0]);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), particles, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, tfb_buffers[1]);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), 0, GL_STREAM_DRAW);
delete[] particles;
delete[] initialvalue;
}
void ParticleSystemProxy::generateParticlesFromBoxEmitter(scene::IParticleBoxEmitter *emitter)
{
float *particles = new float[COMPONENTCOUNT * count], *initialvalue = new float[COMPONENTCOUNT * count];
unsigned lifetime_range = emitter->getMaxLifeTime() - emitter->getMinLifeTime();
float sizeMin = emitter->getMinStartSize().Height;
float sizeMax = emitter->getMaxStartSize().Height;
const core::vector3df& extent = emitter->getBox().getExtent();
printf("particle lifetime [%d-%d]\n", emitter->getMinLifeTime(), emitter->getMaxLifeTime());
for (unsigned i = 0; i < count; i++) {
particles[COMPONENTCOUNT * i] = emitter->getBox().MinEdge.X + os::Randomizer::frand() * extent.X;
particles[COMPONENTCOUNT * i + 1] = emitter->getBox().MinEdge.Y + os::Randomizer::frand() * extent.Y;
particles[COMPONENTCOUNT * i + 2] = emitter->getBox().MinEdge.Z + os::Randomizer::frand() * extent.Z;
// Initial lifetime is 0 percent
particles[COMPONENTCOUNT * i + 3] = rand();
particles[COMPONENTCOUNT * i + 3] /= RAND_MAX;
initialvalue[COMPONENTCOUNT * i] = particles[COMPONENTCOUNT * i];
initialvalue[COMPONENTCOUNT * i + 1] = particles[COMPONENTCOUNT * i + 1];
initialvalue[COMPONENTCOUNT * i + 2] = particles[COMPONENTCOUNT * i + 2];
initialvalue[COMPONENTCOUNT * i + 3] = (lifetime_range > 0) ? rand() % lifetime_range : 0;
initialvalue[COMPONENTCOUNT * i + 3] += emitter->getMinLifeTime();
core::vector3df particledir = emitter->getDirection();
particledir.rotateXYBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particledir.rotateYZBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particledir.rotateXZBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particles[COMPONENTCOUNT * i + 4] = particledir.X;
particles[COMPONENTCOUNT * i + 5] = particledir.Y;
particles[COMPONENTCOUNT * i + 6] = particledir.Z;
initialvalue[COMPONENTCOUNT * i + 4] = particledir.X;
initialvalue[COMPONENTCOUNT * i + 5] = particledir.Y;
initialvalue[COMPONENTCOUNT * i + 6] = particledir.Z;
initialvalue[COMPONENTCOUNT * i + 7] = rand();
initialvalue[COMPONENTCOUNT * i + 7] /= RAND_MAX;
initialvalue[COMPONENTCOUNT * i + 7] *= (sizeMax - sizeMin);
initialvalue[COMPONENTCOUNT * i + 7] += sizeMin;
}
glGenBuffers(1, &initial_values_buffer);
glBindBuffer(GL_ARRAY_BUFFER, initial_values_buffer);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), initialvalue, GL_STREAM_DRAW);
glGenBuffers(2, tfb_buffers);
glBindBuffer(GL_ARRAY_BUFFER, tfb_buffers[0]);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), particles, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, tfb_buffers[1]);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), 0, GL_STREAM_DRAW);
delete[] particles;
delete[] initialvalue;
}
void ParticleSystemProxy::setEmitter(scene::IParticleEmitter* emitter)
{
if (!emitter)
return;
CParticleSystemSceneNode::setEmitter(emitter);
if (emitter->getType() != scene::EPET_POINT)
if (emitter->getType() != scene::EPET_POINT && emitter->getType() != scene::EPET_BOX)
return;
// Pass a fake material type to force irrlicht to update its internal states on rendering
setMaterialType(irr_driver->getShader(ES_RAIN));
@ -295,57 +400,19 @@ void ParticleSystemProxy::setEmitter(scene::IParticleEmitter* emitter)
uniform_screen = glGetUniformLocation(RenderProgram, "screen");
uniform_normal_and_depths = glGetUniformLocation(RenderProgram, "normals_and_depth");
float *particles = new float[COMPONENTCOUNT * count], *initialvalue = new float[COMPONENTCOUNT * count];
unsigned lifetime_range = emitter->getMaxLifeTime() - emitter->getMinLifeTime();
float sizeMin = emitter->getMinStartSize().Height;
float sizeMax = emitter->getMaxStartSize().Height;
printf("count:%d\nduration_min:%d\nduration_max:%d\nsize_min:%f\nsize_max:%f\n", count,
emitter->getMinLifeTime(), emitter->getMaxLifeTime(),
sizeMin, sizeMax);
for (unsigned i = 0; i < count; i++) {
particles[COMPONENTCOUNT * i] = 0;
particles[COMPONENTCOUNT * i + 1] = 0;
particles[COMPONENTCOUNT * i + 2] = 0;
// Initial lifetime is 0 percent
particles[COMPONENTCOUNT * i + 3] = rand();
particles[COMPONENTCOUNT * i + 3] /= RAND_MAX;
initialvalue[COMPONENTCOUNT * i] = 0.;
initialvalue[COMPONENTCOUNT * i + 1] = 0.;
initialvalue[COMPONENTCOUNT * i + 2] = 0.;
initialvalue[COMPONENTCOUNT * i + 3] = rand() % lifetime_range;
initialvalue[COMPONENTCOUNT * i + 3] += emitter->getMinLifeTime();
core::vector3df particledir = emitter->getDirection();
particledir.rotateXYBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particledir.rotateYZBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particledir.rotateXZBy(os::Randomizer::frand() * emitter->getMaxAngleDegrees());
particles[COMPONENTCOUNT * i + 4] = particledir.X;
particles[COMPONENTCOUNT * i + 5] = particledir.Y;
particles[COMPONENTCOUNT * i + 6] = particledir.Z;
initialvalue[COMPONENTCOUNT * i + 4] = particledir.X;
initialvalue[COMPONENTCOUNT * i + 5] = particledir.Y;
initialvalue[COMPONENTCOUNT * i + 6] = particledir.Z;
initialvalue[COMPONENTCOUNT * i + 7] = rand();
initialvalue[COMPONENTCOUNT * i + 7] /= RAND_MAX;
initialvalue[COMPONENTCOUNT * i + 7] *= (sizeMax - sizeMin);
initialvalue[COMPONENTCOUNT * i + 7] += sizeMin;
switch (emitter->getType())
{
case scene::EPET_POINT:
generateParticlesFromPointEmitter(emitter);
break;
case scene::EPET_BOX:
generateParticlesFromBoxEmitter(static_cast<scene::IParticleBoxEmitter *>(emitter));
break;
default:
assert(0 && "Wrong particle type");
}
glGenBuffers(1, &initial_values_buffer);
glBindBuffer(GL_ARRAY_BUFFER, initial_values_buffer);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), initialvalue, GL_STREAM_DRAW);
glGenBuffers(2, tfb_buffers);
glBindBuffer(GL_ARRAY_BUFFER, tfb_buffers[0]);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), particles, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, tfb_buffers[1]);
glBufferData(GL_ARRAY_BUFFER, COMPONENTCOUNT * count * sizeof(float), 0, GL_STREAM_DRAW);
delete [] particles;
delete [] initialvalue;
}
}
void ParticleSystemProxy::simulate()
@ -459,7 +526,7 @@ void ParticleSystemProxy::draw()
}
void ParticleSystemProxy::render() {
if (getEmitter()->getType() != scene::EPET_POINT)
if (getEmitter()->getType() != scene::EPET_POINT && getEmitter()->getType() != scene::EPET_BOX)
{
CParticleSystemSceneNode::render();
return;

View File

@ -45,6 +45,8 @@ protected:
virtual void simulate();
virtual void draw();
void generateParticlesFromPointEmitter(scene::IParticlePointEmitter *);
void generateParticlesFromBoxEmitter(scene::IParticleBoxEmitter *);
public:
static IParticleSystemSceneNode *addParticleNode(
bool withDefaultEmitter = true, ISceneNode* parent = 0, s32 id = -1,