OPENGL-ES|android opengl es 粒子系统

先改正在"位图子体"中关于坐标的说法
正确的画法应如下图所示

哦哦,粒子系统的实现与星星实现有相似之处,大体上就是先创建一个类,这个类中包含了要创建原型的各类属性,然后再在Renderer中将其各类属性赋予相应的值。粒子系统呢,先用一个循环初始化所有的particles,然后在onDrawFrame中循环出每一个particle,NEHE把他们叫三角地带,最后判断运行一段时间的particle是否还为激活状态,若为false,则再初始化一次。大体思路就是这样,下面把今天代码粘上来。


(1)Activity

package sim.feel;

import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

/**
* Activity类ParticleActivity
*
* @author Sim
*/
public class ParticleActivity extends Activity {
private GLSurfaceView glSurfaceView;
private MyRenderer myRenderer;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LoadImage.load(getResources());
myRenderer = new MyRenderer();
glSurfaceView = new GLSurfaceView(this);
glSurfaceView.setRenderer(myRenderer);
setContentView(glSurfaceView);
}
}

/**
* 载入图片类LoadImage
*/
class LoadImage {
public static Bitmap bitmap;

public static void load(Resources res) {
bitmap = BitmapFactory.decodeResource(res, R.drawable.particle);
}
}

(2)Particle
package sim.feel;

/**
* 粒子类
*
* @author Sim
*/
public class Particle {
boolean active; // 是否激活
float life; // 粒子生命
float fade; // 衰减速度

float r; // 红色值
float g; // 绿色值
float b; // 蓝色值

float x; // X位置
float y; // Y位置
float z; // Z位置

float xi; // X方向
float yi; // Y方向
float zi; // Z方向

float xg; // X 方向重力加速度
float yg; // Y 方向重力加速度
float zg; // Z 方向重力加速度
}

(3)Renderer类

package sim.feel;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Random;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLUtils;

/**
* Renderer类MyRenderer
*
* @author Sim
*/
public class MyRenderer implements Renderer {
// 纹理相关
private int[] textures = new int[1];
// 随机数
private Random random = new Random();
// 定义最在的粒子数
private static final int MAX_PARTICLES = 1000;
// 减速粒子
private float slowdown = 0.5f;
// X方向的速度
private float xspeed = 20;
// Y方向的速度
private float yspeed = 20;
// 沿Z轴缩放
private float zoom = -30.0f;
// 循环变量
private int loop;

// 创建一个名为Particle的数组,存储MAX_PARTICLES个元素
private Particle particles[] = new Particle[MAX_PARTICLES];

// 存储12种不同颜色
private float colors[][] = { { 1.0f, 0.75f, 0.5f }, { 1.0f, 0.75f, 0.5f },
{ 1.0f, 1.0f, 0.5f }, { 0.75f, 1.0f, 0.5f }, { 0.5f, 1.0f, 0.5f },
{ 0.5f, 1.0f, 0.75f }, { 0.5f, 1.0f, 1.0f }, { 0.5f, 0.75f, 1.0f },
{ 0.5f, 0.5f, 1.0f }, { 0.75f, 0.5f, 1.0f }, { 1.0f, 0.5f, 1.0f },
{ 1.0f, 0.5f, 0.75f } };

// vertexBuffer
private FloatBuffer vertexBuffer;
// texCoordBuffer
private FloatBuffer texCoordBuffer;
// vertex
private float[] vertex = new float[12];
// texCoord
private float[] texCoord = new float[8];

// LoadBuffer
public void LoadBuffer(GL10 gl) {
ByteBuffer vertexByteBuffer = ByteBuffer
.allocateDirect(vertex.length * 4);
vertexByteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = vertexByteBuffer.asFloatBuffer();
vertexBuffer.put(vertex);
vertexBuffer.position(0);

ByteBuffer texCoordByteBuffer = ByteBuffer
.allocateDirect(texCoord.length * 4);
texCoordByteBuffer.order(ByteOrder.nativeOrder());
texCoordBuffer = texCoordByteBuffer.asFloatBuffer();
texCoordBuffer.put(texCoord);
texCoordBuffer.position(0);
}

@Override
public void onDrawFrame(GL10 gl) {
// LoadBuffer
LoadBuffer(gl);
// 清除屏幕和颜色缓存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置模型变换矩阵
gl.glLoadIdentity();

// 开启顶点纹理状态
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texCoordBuffer);

// 循环所有的粒子
for (loop = 0; loop < MAX_PARTICLES; loop++) {
// 如果粒子为激活的
if (particles[loop].active) {
// 返回X轴的位置
float x = particles[loop].x;
// 返回Y轴的位置
float y = particles[loop].y;
// 返回Z轴的位置
float z = particles[loop].z + zoom;
// 设置粒子颜色
gl.glColor4f(particles[loop].r, particles[loop].g,
particles[loop].b, particles[loop].life);
// 开始准备绘制"三角地带"(名字怪怪的)
texCoordBuffer.clear();
vertexBuffer.clear();
texCoordBuffer.put(1.0f);
texCoordBuffer.put(1.0f);
vertexBuffer.put(x + 0.5f);
vertexBuffer.put(y + 0.5f);
vertexBuffer.put(z);
texCoordBuffer.put(1.0f);
texCoordBuffer.put(0.0f);
vertexBuffer.put(x + 0.5f);
vertexBuffer.put(y);
vertexBuffer.put(z);
texCoordBuffer.put(0.0f);
texCoordBuffer.put(1.0f);
vertexBuffer.put(x);
vertexBuffer.put(y + 0.5f);
vertexBuffer.put(z);
texCoordBuffer.put(0.0f);
texCoordBuffer.put(0.0f);
vertexBuffer.put(x);
vertexBuffer.put(y);
vertexBuffer.put(z);
// 绘制
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
// 更新X坐标的位置
particles[loop].x += particles[loop].xi / (slowdown * 1000);
// 更新Y坐标的位置
particles[loop].y += particles[loop].yi / (slowdown * 1000);
// 更新Z坐标的位置
particles[loop].z += particles[loop].zi / (slowdown * 1000);

// 更新X轴方向速度大小
particles[loop].xi += particles[loop].xg;
// 更新Y轴方向速度大小
particles[loop].yi += particles[loop].yg;
// 更新Z轴方向速度大小
particles[loop].zi += particles[loop].zg;

// 减少粒子的生命值
particles[loop].life -= particles[loop].fade;

// 如果粒子生命小于0
if (particles[loop].life < 0.0f) {
float xi, yi, zi;
xi = xspeed + (float) ((rand() % 60) - 32.0f);
yi = yspeed + (float) ((rand() % 60) - 30.0f);
zi = (float) ((rand() % 60) - 30.0f);
initParticle(loop, random.nextInt(12), xi, yi, zi);
}

}
}
// 关闭顶点纹理状态
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glFinish();
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// ratio
float ratio;
if (height == 0) {
height = 1;
}
ratio = (float) width / (float) height;
gl.glViewport(0, 0, (int) width, (int) height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 1.0f, 200.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重置模型矩阵
gl.glLoadIdentity();
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
// 黑色背景
gl.glClearColor(0, 0, 0, 0);
// 关闭深度测试
gl.glDisable(GL10.GL_DEPTH_TEST);
// 阴影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 启用混合
gl.glEnable(GL10.GL_BLEND);
// 精细修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

// 启用纹理
gl.glEnable(GL10.GL_TEXTURE_2D);
// 创建纹理
gl.glGenTextures(1, textures, 0);
// 绑定纹理
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// 生成纹理
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, LoadImage.bitmap, 0);
// 线性滤波
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_LINEAR);

for (loop = 0; loop < MAX_PARTICLES; loop++) {
float xi, yi, zi;
xi = (float) ((rand() % 50) - 26.0f) * 10.0f;
yi = zi = (float) ((rand() % 50) - 25.0f) * 10.0f;
// 初始化粒子
initParticle(loop, random.nextInt(12), xi, yi, zi);
}
}

public int rand() {
return Math.abs(random.nextInt(1000));
}

// initParticle初始化粒子
public void initParticle(int num, int color, float xDir, float yDir,
float zDir) {
Particle par = new Particle();
// 使所有粒子为激活状态
par.active = true;
// 所有粒子生命值为最大
par.life = 1.0f;
// 随机生成衰率(0~99)/1000+0.003f
par.fade = rand() % 100 / 1000.0f + 0.003f;

// 赋予粒子颜色分量r,g,b
// r
par.r = colors[color][0];
// g
par.g = colors[color][1];
// b
par.b = colors[color][2];

// 设定粒子方向xi,yi,zi
// xi
par.xi = xDir;
// yi
par.yi = yDir;
// zi
par.zi = zDir;

// x,y,z方向加速度
// xg
par.xg = 0.0f;
// yg
par.yg = -0.5f;
// zg
par.zg = 0.0f;

particles[loop] = par;
}
}

运行效果:
【OPENGL-ES|android opengl es 粒子系统】

    推荐阅读