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
|
||||
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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue