finally fixed the particle system.
This commit is contained in:
parent
185f7d2748
commit
067cfb6203
8 changed files with 100 additions and 47 deletions
|
@ -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);
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue