From 067cfb620399610cd8be442005acb1d4be3f0251 Mon Sep 17 00:00:00 2001 From: Andreas Ortmann Date: Fri, 30 Sep 2016 20:19:10 +0200 Subject: [PATCH] finally fixed the particle system. --- data/shader/particle.frag | 29 ++++++++---- data/shader/particle.vert | 12 ++++- game/renderer_polygon_3d/particle_batch.cpp | 47 ++++++++++++------- game/renderer_polygon_3d/particle_batch.hpp | 7 ++- game/renderer_polygon_3d/polygon_model.cpp | 5 +- .../renderer_polygon_3d.cpp | 41 +++++++++++----- .../renderer_polygon_3d.hpp | 2 +- game/state/explosion.hpp | 4 ++ 8 files changed, 100 insertions(+), 47 deletions(-) diff --git a/data/shader/particle.frag b/data/shader/particle.frag index c79fd63..66a59ab 100644 --- a/data/shader/particle.frag +++ b/data/shader/particle.frag @@ -1,16 +1,27 @@ #version 120 varying vec2 vertex; varying vec2 velocity; -uniform float maxAge; -uniform float time; +varying float decay; + +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() { - //gl_FragColor = vec4(0.5+0.5*vertex.x, 0.5+0.5*vertex.y, 0.0, 1.0); - if (length(vertex) > 1.0) { - discard; + gl_FragColor = vec4(0.5+0.5*vertex.x, 0.5+0.5*vertex.y, 0.0, 1.0); + float r = length(vertex); + if (r > 1.0) { + discard; } - float decay = time / maxAge; - decay = 5.0*decay*decay; - // (length(10.0*velocity)); - gl_FragColor = vec4(1.0/max(1.0, decay), 1.0/max(1.0, 6.0*decay), 0.0, 1.0); + float d = decay; + float h = (1.0-d)/6.0; + float v = max(0.0, (1.0-d/2.0) - 0.1*(d*d*d)); + 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); } \ No newline at end of file diff --git a/data/shader/particle.vert b/data/shader/particle.vert index 4815a04..bf64a62 100644 --- a/data/shader/particle.vert +++ b/data/shader/particle.vert @@ -2,17 +2,25 @@ attribute vec2 in_vertex; attribute vec2 in_position; attribute vec2 in_velocity; + +uniform float maxAge; +varying float decay; varying vec2 velocity; varying vec2 vertex; uniform float time; uniform float size; 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 += in_position; gl_Position = vec4(p, 0.0, 1.0); - vertex = in_vertex; + vertex = base; velocity = in_velocity; } \ No newline at end of file diff --git a/game/renderer_polygon_3d/particle_batch.cpp b/game/renderer_polygon_3d/particle_batch.cpp index 1e0f4a5..8198b97 100644 --- a/game/renderer_polygon_3d/particle_batch.cpp +++ b/game/renderer_polygon_3d/particle_batch.cpp @@ -6,12 +6,14 @@ int getDivisorForIndex(int index) { - return (index == 0) ? 1 : 4; + // 0 or 1? + return (index == 0) ? 0 : 3; } namespace endofthejedi { - ParticleBatch::ParticleBatch(size_t numParticles, float particleSize, float maxAge) - : m_numParticles(numParticles) + ParticleBatch::ParticleBatch(size_t id, size_t numParticles, float particleSize, float maxAge) + : m_id(id) + , m_numParticles(numParticles) , m_particleRadius(particleSize) , m_maxAge(maxAge) , m_age(0.0) @@ -36,11 +38,27 @@ namespace endofthejedi { m_shader.init(); m_shader.loadFile(vss_particles, GL_VERTEX_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() { // 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) @@ -63,16 +81,14 @@ namespace endofthejedi { for (size_t i=0; i<5; i++) { //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]); - if (i != 0) { - glVertexAttribDivisor(i, getDivisorForIndex(i-1)); - } + glVertexAttribDivisor(m_attr_locations[i], getDivisorForIndex(i)); // TODO: i or index? at first argument? glVertexAttribPointer( - i, + m_attr_locations[i], dataSizeForIndex(i), GL_FLOAT, // Data is floating point type GL_FALSE, // No fixed point scaling @@ -85,9 +101,9 @@ namespace endofthejedi { { //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); glEnableVertexAttribArray(i); @@ -105,14 +121,8 @@ namespace endofthejedi { void ParticleBatch::render() { //std::cout<<"[ParticleBatch] render " << std::endl; - 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("maxAge"), m_maxAge); glUniform1f(m_shader.location("size"), m_particleRadius); @@ -122,7 +132,10 @@ namespace endofthejedi { //glDrawArrays(GL_TRIANGLE_FAN, 0, 4*m_numParticles); //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 glBegin(GL_QUADS); diff --git a/game/renderer_polygon_3d/particle_batch.hpp b/game/renderer_polygon_3d/particle_batch.hpp index 273b484..a75ffe7 100644 --- a/game/renderer_polygon_3d/particle_batch.hpp +++ b/game/renderer_polygon_3d/particle_batch.hpp @@ -9,7 +9,7 @@ namespace endofthejedi { class ParticleBatch { 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 ~ParticleBatch(); @@ -27,11 +27,14 @@ namespace endofthejedi { Shader *shader() { return &m_shader; } + size_t id() const { return m_id; } + private: size_t dataSizeForIndex(int i); void *dataSourceForIndex(int i); private: + size_t m_id; size_t m_numParticles; float m_particleRadius; const float m_maxAge; @@ -45,6 +48,8 @@ namespace endofthejedi { std::vector m_data_kind; std::vector m_data_max_age; + GLuint m_attr_locations[5]; + Shader m_shader; }; } diff --git a/game/renderer_polygon_3d/polygon_model.cpp b/game/renderer_polygon_3d/polygon_model.cpp index 0bb6f55..de2895f 100644 --- a/game/renderer_polygon_3d/polygon_model.cpp +++ b/game/renderer_polygon_3d/polygon_model.cpp @@ -72,6 +72,7 @@ namespace endofthejedi { glEnableVertexAttribArray(m_attr_locations[0]); glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id[i]); glVertexAttribPointer(m_attr_locations[i], 3, GL_FLOAT, GL_FALSE, 0, NULL); + glVertexAttribDivisor(m_attr_locations[i], 0); // restore default } m_binding_active = true; @@ -149,10 +150,6 @@ namespace endofthejedi { return false; } - /************************************************************/ - /* Position data */ - /************************************************************/ - glGenBuffers(2, m_vbo_id); // Generate buffer glEnableVertexAttribArray(m_attr_locations[0]); diff --git a/game/renderer_polygon_3d/renderer_polygon_3d.cpp b/game/renderer_polygon_3d/renderer_polygon_3d.cpp index 98af3d5..a449262 100644 --- a/game/renderer_polygon_3d/renderer_polygon_3d.cpp +++ b/game/renderer_polygon_3d/renderer_polygon_3d.cpp @@ -28,7 +28,7 @@ namespace endofthejedi { #endif 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); } @@ -65,9 +65,7 @@ namespace endofthejedi { renderShips(); renderMissiles(); - //glDisable(GL_DEPTH_TEST); - //renderParticles(); - //glEnable(GL_DEPTH_TEST); + renderParticles(); 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; isetParticle(i, pos, v); } @@ -114,11 +115,23 @@ namespace endofthejedi { void RendererPolygon3d::advanceGraphicObjects(float dt) { for (const game::Explosion *expl : m_state->explosions) { - if (expl->age == 0.0) { - addExplosionEffect(expl->position, 200, 3.0); + bool gotIt = false; + 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 rm; for (ParticleBatch *batch : m_particles) { @@ -246,7 +259,8 @@ namespace endofthejedi { // revert to default 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) { float fade_out = 1.0; if (trace->missile == nullptr) { @@ -260,5 +274,6 @@ namespace endofthejedi { } glEnd(); } + glPolygonMode(GL_FRONT, GL_FILL); } } diff --git a/game/renderer_polygon_3d/renderer_polygon_3d.hpp b/game/renderer_polygon_3d/renderer_polygon_3d.hpp index fea9003..5f86483 100644 --- a/game/renderer_polygon_3d/renderer_polygon_3d.hpp +++ b/game/renderer_polygon_3d/renderer_polygon_3d.hpp @@ -34,7 +34,7 @@ namespace endofthejedi { 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); diff --git a/game/state/explosion.hpp b/game/state/explosion.hpp index 32169eb..9e8145d 100644 --- a/game/state/explosion.hpp +++ b/game/state/explosion.hpp @@ -19,6 +19,8 @@ namespace game { , maxAge(maxAge * (1.0 + 0.1*util::randf_0_1())) , maxRadius(0.05) { + static size_t id_counter = 0; + id = id_counter++; } const Hit hit; // kind of the explosion depends on the hit type @@ -29,5 +31,7 @@ namespace game { // anymore and will disappear afterwards const float maxAge; const float maxRadius; // current radius depends on time. + + size_t id; }; }