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
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) {
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);
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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<float> m_data_kind;
std::vector<float> m_data_max_age;
GLuint m_attr_locations[5];
Shader m_shader;
};
}

View file

@ -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]);

View file

@ -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; i<n; i++) {
// distribute in a circle
float t = 4.0 * M_PI * i / (float) n;
t += 0.2*util::randf_m1_1();
float t = 2.0 * M_PI * i / (float) n;
//t += 0.2*util::randf_m1_1();
// with random velocities
glm::vec2 v = 0.2f*glm::vec2(sin(t), cos(t));
v *= 0.2+0.8*util::randf_0_1();
glm::vec2 v = 0.5f*glm::vec2(sin(t), cos(t));
v *= util::randf_0_1() + util::randf_0_1();
batch->setParticle(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<ParticleBatch*> 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);
}
}

View file

@ -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);

View file

@ -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;
};
}