粒子爆炸:ParticleExplosion - MartinRGB/GLES30_ProgrammingGuide_NDK GitHub Wiki
粒子爆炸首先需要粒子的一些属性
//粒子个数
#define NUM_PARTICLES 10000
//粒子属性占据空间
#define PARTICLE_SIZE 7
//内存位置
#define ATTRIBUTE_LIFETIME_LOCATION 0
#define ATTRIBUTE_STARTPOSITION_LOCATION 1
#define ATTRIBUTE_ENDPOSITION_LOCATION 2
typedef struct
{
// 程序对象
GLuint programObject;
// 时间 色彩 中心点 采样器的内存地址
GLint timeLoc;
GLint colorLoc;
GLint centerPositionLoc;
GLint samplerLoc;
// 材质Id
GLuint textureId;
// Particle vertex data
float particleData[ NUM_PARTICLES * PARTICLE_SIZE ];
// 当前时间
float time;
} UserData;
读取粒子 texture 后,在 Init() 中,给random 设置 feed,然后 loop 粒子个数次,生成 随机寿命 随机始末位置 (稍后传入 attribute 中)
srand(1);
for ( i = 0; i < NUM_PARTICLES; i++ )
{
float *particleData = &userData->particleData[i * PARTICLE_SIZE];
// Lifetime of particle
( *particleData++ ) = ( ( float ) ( rand() % 10000 ) / 10000.0f );
// End position of particle
( *particleData++ ) = ( ( float ) ( rand() % 10000 ) / 5000.0f ) - 1.0f;
( *particleData++ ) = ( ( float ) ( rand() % 10000 ) / 5000.0f ) - 1.0f;
( *particleData++ ) = ( ( float ) ( rand() % 10000 ) / 5000.0f ) - 1.0f;
// Start position of particle
( *particleData++ ) = ( ( float ) ( rand() % 10000 ) / 40000.0f ) - 0.125f;
( *particleData++ ) = ( ( float ) ( rand() % 10000 ) / 40000.0f ) - 0.125f;
( *particleData++ ) = ( ( float ) ( rand() % 10000 ) / 40000.0f ) - 0.125f;
}
// 同时设置重置时间点
userData->time = 1.0f;
在 update() 中设置,当粒子动画超过了 1s,将时间重置为 0s,并且重设位置和颜色
if ( userData->time >= 1.0f )
{
float centerPos[3];
float color[4];
userData->time = 0.0f;
// Pick a new start location and color
centerPos[0] = ( ( float ) ( rand() % 10000 ) / 10000.0f ) - 0.5f;
centerPos[1] = ( ( float ) ( rand() % 10000 ) / 10000.0f ) - 0.5f;
centerPos[2] = ( ( float ) ( rand() % 10000 ) / 10000.0f ) - 0.5f;
glUniform3fv ( userData->centerPositionLoc, 1, ¢erPos[0] );
// Random color
color[0] = ( ( float ) ( rand() % 10000 ) / 20000.0f ) + 0.5f;
color[1] = ( ( float ) ( rand() % 10000 ) / 20000.0f ) + 0.5f;
color[2] = ( ( float ) ( rand() % 10000 ) / 20000.0f ) + 0.5f;
color[3] = 0.5;
glUniform4fv ( userData->colorLoc, 1, &color[0] );
}
然后 Draw() 中设置 attribute和 uniform。本粒子中,顶点数组数值从不改变,因此要使用顶点缓冲区,能降低顶点带宽。
GLSL 中的动画解析:
Vert
#version 300 es
uniform float u_time;
uniform vec3 u_centerPosition;
layout(location = 0) in float a_lifetime;
layout(location = 1) in vec3 a_startPosition;
layout(location = 2) in vec3 a_endPosition;
out float v_lifetime;
void main()
{
//如果仍在寿命期
if ( u_time <= a_lifetime )
{
//从 start 运动到 end 位置
gl_Position.xyz = a_startPosition +
(u_time * a_endPosition);
//移动
gl_Position.xyz += u_centerPosition;
gl_Position.w = 1.0;
}
else
{
gl_Position = vec4( -1000, -1000, 0, 0 );
}
//向frag 传入寿命
v_lifetime = 1.0 - ( u_time / a_lifetime );
v_lifetime = clamp ( v_lifetime, 0.0, 1.0 );
//粒子根据寿命,越来越小
gl_PointSize = ( v_lifetime * v_lifetime ) * 40.0;
}
Frag:
#version 300 es
precision mediump float;
uniform vec4 u_color;
in float v_lifetime;
layout(location = 0) out vec4 fragColor;
uniform sampler2D s_texture;
void main()
{
vec4 texColor;
// Set texture to Sprite
texColor = texture( s_texture, gl_PointCoord );
// Set Color
fragColor = vec4( u_color ) * texColor;
// Set particles' alpha
fragColor.a *= v_lifetime;
}