finally fixed the particle system.

This commit is contained in:
Andreas Ortmann 2016-09-30 20:19:10 +02:00
parent 185f7d2748
commit 067cfb6203
8 changed files with 100 additions and 47 deletions

View file

@ -1,16 +1,27 @@
#version 120 #version 120
varying vec2 vertex; varying vec2 vertex;
varying vec2 velocity; varying vec2 velocity;
uniform float maxAge; varying float decay;
uniform float time;
vec3 hsv2rgb(vec3 c)
{
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() void main()
{ {
//gl_FragColor = vec4(0.5+0.5*vertex.x, 0.5+0.5*vertex.y, 0.0, 1.0); gl_FragColor = vec4(0.5+0.5*vertex.x, 0.5+0.5*vertex.y, 0.0, 1.0);
if (length(vertex) > 1.0) { float r = length(vertex);
discard; if (r > 1.0) {
discard;
} }
float decay = time / maxAge; float d = decay;
decay = 5.0*decay*decay; float h = (1.0-d)/6.0;
// (length(10.0*velocity)); float v = max(0.0, (1.0-d/2.0) - 0.1*(d*d*d));
gl_FragColor = vec4(1.0/max(1.0, decay), 1.0/max(1.0, 6.0*decay), 0.0, 1.0); float s = 1.0;
gl_FragColor = vec4(hsv2rgb(vec3(h, s, v)), 1.0);
//gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
} }

View file

@ -2,17 +2,25 @@
attribute vec2 in_vertex; attribute vec2 in_vertex;
attribute vec2 in_position; attribute vec2 in_position;
attribute vec2 in_velocity; attribute vec2 in_velocity;
uniform float maxAge;
varying float decay;
varying vec2 velocity; varying vec2 velocity;
varying vec2 vertex; varying vec2 vertex;
uniform float time; uniform float time;
uniform float size; uniform float size;
void main() void main()
{ {
vec2 p = size*in_vertex; //decay = min(1.0, time+5.0*length(velocity)) / maxAge;
//decay = max(decay*decay, sqrt(decay));
decay = time / maxAge;
vec2 base = in_vertex;
vec2 p = size*base;
p += log(1.0+time) * in_velocity; p += log(1.0+time) * in_velocity;
p += in_position; p += in_position;
gl_Position = vec4(p, 0.0, 1.0); gl_Position = vec4(p, 0.0, 1.0);
vertex = in_vertex; vertex = base;
velocity = in_velocity; velocity = in_velocity;
} }

View file

@ -6,12 +6,14 @@
int getDivisorForIndex(int index) int getDivisorForIndex(int index)
{ {
return (index == 0) ? 1 : 4; // 0 or 1?
return (index == 0) ? 0 : 3;
} }
namespace endofthejedi { namespace endofthejedi {
ParticleBatch::ParticleBatch(size_t numParticles, float particleSize, float maxAge) ParticleBatch::ParticleBatch(size_t id, size_t numParticles, float particleSize, float maxAge)
: m_numParticles(numParticles) : m_id(id)
, m_numParticles(numParticles)
, m_particleRadius(particleSize) , m_particleRadius(particleSize)
, m_maxAge(maxAge) , m_maxAge(maxAge)
, m_age(0.0) , m_age(0.0)
@ -36,11 +38,27 @@ namespace endofthejedi {
m_shader.init(); m_shader.init();
m_shader.loadFile(vss_particles, GL_VERTEX_SHADER); m_shader.loadFile(vss_particles, GL_VERTEX_SHADER);
m_shader.loadFile(fss_particles, GL_FRAGMENT_SHADER); m_shader.loadFile(fss_particles, GL_FRAGMENT_SHADER);
const char *names[] = {
"in_vertex",
"in_position",
"in_velocity",
"XXXunusedXXX",
"XXXunusedXXX"
};
for (int i=0; i<5; i++) {
const char *name = names[i];
GLint loc = glGetAttribLocation(m_shader.program(), name);
m_attr_locations[i] = loc;
//std::cout<<"attr location " << i << " " << loc << " " << name << std::endl;
}
} }
ParticleBatch::~ParticleBatch() ParticleBatch::~ParticleBatch()
{ {
// TODO: find out if stuff must be deallocated // TODO: find out if stuff must be deallocated
glDeleteBuffers(5, m_data_vbos);
} }
void ParticleBatch::setParticle(size_t index, const glm::vec2 &p, const glm::vec2 &v) void ParticleBatch::setParticle(size_t index, const glm::vec2 &p, const glm::vec2 &v)
@ -63,16 +81,14 @@ namespace endofthejedi {
for (size_t i=0; i<5; i++) { for (size_t i=0; i<5; i++) {
//std::cout<<"vbo #" << i << ": " << m_data_vbos[i] << std::endl; //std::cout<<"vbo #" << i << ": " << m_data_vbos[i] << std::endl;
glEnableVertexAttribArray(i); glEnableVertexAttribArray(m_attr_locations[i]);
glBindBuffer(GL_ARRAY_BUFFER, m_data_vbos[i]); glBindBuffer(GL_ARRAY_BUFFER, m_data_vbos[i]);
if (i != 0) { glVertexAttribDivisor(m_attr_locations[i], getDivisorForIndex(i));
glVertexAttribDivisor(i, getDivisorForIndex(i-1));
}
// TODO: i or index? at first argument? // TODO: i or index? at first argument?
glVertexAttribPointer( glVertexAttribPointer(
i, m_attr_locations[i],
dataSizeForIndex(i), dataSizeForIndex(i),
GL_FLOAT, // Data is floating point type GL_FLOAT, // Data is floating point type
GL_FALSE, // No fixed point scaling GL_FALSE, // No fixed point scaling
@ -85,9 +101,9 @@ namespace endofthejedi {
{ {
//std::cout<<"[ParticleBatch] upload to vbo's " << std::endl; //std::cout<<"[ParticleBatch] upload to vbo's " << std::endl;
glGenBuffers(4, m_data_vbos); // Generate buffer glGenBuffers(5, m_data_vbos); // Generate buffer
for (size_t i=0; i<4; i++) { for (size_t i=0; i<5; i++) {
size_t bufferDataSize = dataSizeForIndex(i) * m_numParticles * sizeof(float); size_t bufferDataSize = dataSizeForIndex(i) * m_numParticles * sizeof(float);
glEnableVertexAttribArray(i); glEnableVertexAttribArray(i);
@ -105,14 +121,8 @@ namespace endofthejedi {
void ParticleBatch::render() void ParticleBatch::render()
{ {
//std::cout<<"[ParticleBatch] render " << std::endl; //std::cout<<"[ParticleBatch] render " << std::endl;
m_shader.bind(); m_shader.bind();
// TODO: does that work?
glBindAttribLocation(m_shader.program(), 0, "in_vertex");
glBindAttribLocation(m_shader.program(), 1, "in_position");
glBindAttribLocation(m_shader.program(), 2, "in_velocity");
glUniform1f(m_shader.location("time"), m_age); glUniform1f(m_shader.location("time"), m_age);
glUniform1f(m_shader.location("maxAge"), m_maxAge); glUniform1f(m_shader.location("maxAge"), m_maxAge);
glUniform1f(m_shader.location("size"), m_particleRadius); glUniform1f(m_shader.location("size"), m_particleRadius);
@ -122,7 +132,10 @@ namespace endofthejedi {
//glDrawArrays(GL_TRIANGLE_FAN, 0, 4*m_numParticles); //glDrawArrays(GL_TRIANGLE_FAN, 0, 4*m_numParticles);
//glDrawArraysInstanced( GLenum mode, GLint first, GLsizei count, GLsizei primcount); //glDrawArraysInstanced( GLenum mode, GLint first, GLsizei count, GLsizei primcount);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, 4*m_numParticles); // XXX the 3 is a magical number.
// I dont know why this works
// without it, it will render 1/3 of the particles
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, 3*m_numParticles);
#if 0 #if 0
glBegin(GL_QUADS); glBegin(GL_QUADS);

View file

@ -9,7 +9,7 @@
namespace endofthejedi { namespace endofthejedi {
class ParticleBatch { class ParticleBatch {
public: public:
ParticleBatch(size_t numParticles, float particleRadius, float maxAge); ParticleBatch(size_t id, size_t numParticles, float particleRadius, float maxAge);
// deallocate opengl stuff on destroy // deallocate opengl stuff on destroy
~ParticleBatch(); ~ParticleBatch();
@ -27,11 +27,14 @@ namespace endofthejedi {
Shader *shader() { return &m_shader; } Shader *shader() { return &m_shader; }
size_t id() const { return m_id; }
private: private:
size_t dataSizeForIndex(int i); size_t dataSizeForIndex(int i);
void *dataSourceForIndex(int i); void *dataSourceForIndex(int i);
private: private:
size_t m_id;
size_t m_numParticles; size_t m_numParticles;
float m_particleRadius; float m_particleRadius;
const float m_maxAge; const float m_maxAge;
@ -45,6 +48,8 @@ namespace endofthejedi {
std::vector<float> m_data_kind; std::vector<float> m_data_kind;
std::vector<float> m_data_max_age; std::vector<float> m_data_max_age;
GLuint m_attr_locations[5];
Shader m_shader; Shader m_shader;
}; };
} }

View file

@ -72,6 +72,7 @@ namespace endofthejedi {
glEnableVertexAttribArray(m_attr_locations[0]); glEnableVertexAttribArray(m_attr_locations[0]);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id[i]); glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id[i]);
glVertexAttribPointer(m_attr_locations[i], 3, GL_FLOAT, GL_FALSE, 0, NULL); glVertexAttribPointer(m_attr_locations[i], 3, GL_FLOAT, GL_FALSE, 0, NULL);
glVertexAttribDivisor(m_attr_locations[i], 0); // restore default
} }
m_binding_active = true; m_binding_active = true;
@ -149,10 +150,6 @@ namespace endofthejedi {
return false; return false;
} }
/************************************************************/
/* Position data */
/************************************************************/
glGenBuffers(2, m_vbo_id); // Generate buffer glGenBuffers(2, m_vbo_id); // Generate buffer
glEnableVertexAttribArray(m_attr_locations[0]); glEnableVertexAttribArray(m_attr_locations[0]);

View file

@ -28,7 +28,7 @@ namespace endofthejedi {
#endif #endif
addModel("../data/mesh/small_atomic_bomb.stl", &m_missileModel); addModel("../data/mesh/small_atomic_bomb.stl", &m_missileModel);
addModel("../data/mesh/planet_64.stl", &m_planetModel); addModel("../data/mesh/planet_12.stl", &m_planetModel);
addModel("../data/mesh/ship_ufo.stl", &m_shipModel); addModel("../data/mesh/ship_ufo.stl", &m_shipModel);
} }
@ -65,9 +65,7 @@ namespace endofthejedi {
renderShips(); renderShips();
renderMissiles(); renderMissiles();
//glDisable(GL_DEPTH_TEST); renderParticles();
//renderParticles();
//glEnable(GL_DEPTH_TEST);
renderTraces(); renderTraces();
@ -90,18 +88,21 @@ namespace endofthejedi {
} }
} }
void RendererPolygon3d::addExplosionEffect(const glm::vec2 &pos, size_t n, float duration) void RendererPolygon3d::addExplosionEffect(size_t id, const glm::vec2 &pos, size_t n, float duration)
{ {
ParticleBatch *batch = new ParticleBatch(n, 0.005, duration); //float particleRadius = 0.005;
float particleRadius = 0.005;
ParticleBatch *batch = new ParticleBatch(id, n, particleRadius, duration);
for (size_t i=0; i<n; i++) { for (size_t i=0; i<n; i++) {
// distribute in a circle // distribute in a circle
float t = 4.0 * M_PI * i / (float) n; float t = 2.0 * M_PI * i / (float) n;
t += 0.2*util::randf_m1_1(); //t += 0.2*util::randf_m1_1();
// with random velocities // with random velocities
glm::vec2 v = 0.2f*glm::vec2(sin(t), cos(t)); glm::vec2 v = 0.5f*glm::vec2(sin(t), cos(t));
v *= 0.2+0.8*util::randf_0_1(); v *= util::randf_0_1() + util::randf_0_1();
batch->setParticle(i, pos, v); batch->setParticle(i, pos, v);
} }
@ -114,11 +115,23 @@ namespace endofthejedi {
void RendererPolygon3d::advanceGraphicObjects(float dt) void RendererPolygon3d::advanceGraphicObjects(float dt)
{ {
for (const game::Explosion *expl : m_state->explosions) { for (const game::Explosion *expl : m_state->explosions) {
if (expl->age == 0.0) { bool gotIt = false;
addExplosionEffect(expl->position, 200, 3.0); for (ParticleBatch *batch : m_particles) {
if (batch->id() == expl->id) {
gotIt = true;
break;
}
}
if (!gotIt) {
addExplosionEffect(expl->id, expl->position, 1000, 2.0);
} }
} }
//if (m_particles.size() == 0) {
// addExplosionEffect(0, glm::vec2(0.0, 0.0), 1000, 2.0);
//}
std::vector<ParticleBatch*> rm; std::vector<ParticleBatch*> rm;
for (ParticleBatch *batch : m_particles) { for (ParticleBatch *batch : m_particles) {
@ -246,7 +259,8 @@ namespace endofthejedi {
// revert to default // revert to default
glUseProgram(0); glUseProgram(0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // TODO dont use line mode. make that with own quads
glPolygonMode(GL_FRONT, GL_LINE);
for (const game::Trace *trace : m_state->traces) { for (const game::Trace *trace : m_state->traces) {
float fade_out = 1.0; float fade_out = 1.0;
if (trace->missile == nullptr) { if (trace->missile == nullptr) {
@ -260,5 +274,6 @@ namespace endofthejedi {
} }
glEnd(); glEnd();
} }
glPolygonMode(GL_FRONT, GL_FILL);
} }
} }

View file

@ -34,7 +34,7 @@ namespace endofthejedi {
void addModel(const std::string &filename, PolygonModel **dest); void addModel(const std::string &filename, PolygonModel **dest);
void addExplosionEffect(const glm::vec2 &pos, size_t n, float duration); void addExplosionEffect(size_t id, const glm::vec2 &pos, size_t n, float duration);
void advanceGraphicObjects(float dt); void advanceGraphicObjects(float dt);

View file

@ -19,6 +19,8 @@ namespace game {
, maxAge(maxAge * (1.0 + 0.1*util::randf_0_1())) , maxAge(maxAge * (1.0 + 0.1*util::randf_0_1()))
, maxRadius(0.05) , maxRadius(0.05)
{ {
static size_t id_counter = 0;
id = id_counter++;
} }
const Hit hit; // kind of the explosion depends on the hit type const Hit hit; // kind of the explosion depends on the hit type
@ -29,5 +31,7 @@ namespace game {
// anymore and will disappear afterwards // anymore and will disappear afterwards
const float maxAge; const float maxAge;
const float maxRadius; // current radius depends on time. const float maxRadius; // current radius depends on time.
size_t id;
}; };
} }