粒子爆炸: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, &centerPos[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;                         
}