android OpenGL开发 一个爆炸效果的粒子发生器

本文介绍如何在Android平台上使用OpenGL开发一个粒子发生器,实现爆炸效果。关键在于粒子运行轨迹的算法控制。期待OpenGL高手提供优化建议。运行OpenGL的Activity需重写onResume和onPause,并调用GLSurfaceView的相关方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先声明这个程序基本上都是nehe的OpenGL教学的第十九课内容,我只是把他的代码用android表现了出来,由于本人对算法的了解不是很多,所以这只是一个很简单的例子(但我自己也是花了好长时间才弄出来的),仅供刚刚接触OpenGL的同学参考,有什么错误的地方欢迎指正,你可以说说你自己的想法,互相交流,下面把我的代码附在下面,有兴趣的同学可以研究一下:

下面是我们的自定义Renderer,主要的难点就是算法,也就是对particle的运行轨迹的控制,希望在OpenGL上有所成就的同学给我们一些好的建议。

public class MyRenderer extends GLSurfaceView implements Renderer {
	private float slowdown = 20.f; // Slow Down Particles
	private float zoom = -40.0f; // Used To Zoom Out
	private int[] texture = new int[1];// Storage For Our Particle Texture
	private Random random = new Random(); // to generate a int value randomly
	private FloatBuffer vertexBuffer; // to hold the particle's vertices
	private FloatBuffer textureBuffer; // to hold the particle's texture
										// vertices
	private float[] textureCoordinate = { 0.0f, 0.f, 1.0f, 0.0f, 0.0f, 1.0f,
			1.0f, 1.0f }; // the particle's texture coordinate
	private Particle[] particles = new Particle[1000];// to hold the particle
														// object array
	private Context context;// the activity context

	/**
	 * the method to generate a FloatBuffer reference with pass a float array
	 * */
	private FloatBuffer formatFloatBuffer(float[] array) {
		ByteBuffer bb = ByteBuffer.allocateDirect(array.length * 4);
		bb.order(ByteOrder.nativeOrder());
		FloatBuffer fb;
		fb = bb.asFloatBuffer();
		fb.put(array);
		fb.position(0);
		return fb;

	}

	// the particle color array
	private float colors[][] = { { 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.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 } };

	/**
	 * the MyRenderer constructor
	 * */
	public MyRenderer(Context context) {
		super(context);
		this.setRenderer(this);
		this.context = context;
	}

	/**
	 * the method to initiate the particle objects
	 * 
	 * */
	private void initParticals() {
		for (int i = 0; i < particles.length; i++) {
			particles[i] = new Particle();
			particles[i].active = true;
			particles[i].life = 1.0f;
			particles[i].fade = (float) (random.nextInt(10) % 100) / 1000.0f + 0.003f;
			particles[i].r = colors[random.nextInt(12)][0];
			particles[i].g = colors[random.nextInt(12)][1];
			particles[i].b = colors[random.nextInt(12)][2];
			particles[i].xi = (float) ((random.nextInt(100) % 50) - 26.0f) * 10.0f;
			particles[i].yi = (float) ((random.nextInt(100) % 50) - 25.0f) * 10.0f;
			particles[i].zi = (float) ((random.nextInt(100) % 50) - 25.0f) * 10.0f;
			particles[i].xg = 0.0f;
			particles[i].yg = -0.8f;
			particles[i].zg = 0.0f;

		}

	}

	/**
	 * draws the whole particles and change the each one's attribute after draws
	 * it
	 * */
	private void drawParticle(GL10 gl) {
		for (int i = 0; i < particles.length; i++) {

			if (particles[i].active) {
				float temVectex[] = { particles[i].x + 0.5f,
						particles[i].y + 0.5f, particles[i].z + zoom,
						particles[i].x + 0.5f, particles[i].y - 0.5f,
						particles[i].z + zoom, particles[i].x - 0.5f,
						particles[i].y + 0.5f, particles[i].z + zoom,
						particles[i].x - 0.5f, particles[i].y - 0.5f,
						particles[i].z + zoom };
				gl.glColor4f(particles[i].r, particles[i].g, particles[i].b,
						particles[i].life);
				vertexBuffer = formatFloatBuffer(temVectex);
				gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
				gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, temVectex.length / 3);
				particles[i].x += particles[i].xi / (slowdown * 10);
				particles[i].y += particles[i].yi / (slowdown * 10);
				particles[i].z += particles[i].zi / (slowdown * 10);
				particles[i].xi += particles[i].xg;
				particles[i].yi += particles[i].yg;
				particles[i].zi += particles[i].zg;
				particles[i].life -= particles[i].fade;
				if (particles[i].life < 0.0f) {
					particles[i].life = 1.0f;
					particles[i].fade = (float) (random.nextInt(100) % 100) / 1000.0f + 0.003f;
					particles[i].x = 0.0f;
					particles[i].y = 0.0f;
					particles[i].z = 0.0f;
					particles[i].xi = (float) ((random.nextInt(100) % 50) - 26.0f) * 10.0f;
					particles[i].yi = (float) ((random.nextInt(100) % 50) - 25.0f) * 10.0f;
					particles[i].zi = (float) ((random.nextInt(100) % 50) - 25.0f) * 10.0f;
					particles[i].xg = 0.0f;
					particles[i].yg = -0.8f;
					particles[i].zg = 0.0f;
				}

			}
		}
	}

	public void onDrawFrame(GL10 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);
		textureBuffer = formatFloatBuffer(textureCoordinate);
		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
		gl.glTranslatef(0.0f, 0.0f, -5.0f);
		drawParticle(gl);
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

	}

	public void onSurfaceChanged(GL10 gl, int width, int height) {
		if (height == 0) {
			height = 1;
		}
		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,
				200.0f);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glLoadIdentity();
	}

	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glShadeModel(GL10.GL_SMOOTH);
		gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		gl.glClearDepthf(1.0f);
		gl.glDisable(GL10.GL_DEPTH_TEST);
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
		loadTexture(gl, context);
		initParticals();
	}

	/**
	 * the method is to load texture for the particle
	 * */
	public void loadTexture(GL10 gl, Context context) {

		InputStream is = context.getResources()
				.openRawResource(R.drawable.star);
		Bitmap bitmap = null;
		try {

			bitmap = BitmapFactory.decodeStream(is);
		} finally {
			try {

				is.close();
				is = null;
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		gl.glGenTextures(1, texture, 0);

		gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
				GL10.GL_LINEAR);
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
				GL10.GL_LINEAR);
		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

		bitmap.recycle();
	}

	/**
	 * this is the particle class it has some attribute for each particle object
	 * */
	class Particle {
		// We start off with the boolean variable active. If this variable is
		// TRUE, our particle is alive and kicking. If it's FALSE our particle
		// is dead or we've turned it off! In this program I don't use active,
		// but it's handy to include.

		// The variables life and fade control how long the particle is
		// displayed, and how bright the particle is while it's alive. The
		// variable life is gradually decreased by the value stored in fade. In
		// this program that will cause some particles to burn longer than
		// others.

		private boolean active;
		private float life;
		private float fade;

		// The variables r, g and b hold the red intensity, green intensity and
		// blue intensity of our particle. The closer r is to 1.0f, the more red
		// the particle will be. Making all 3 variables 1.0f will create a white
		// particle.

		private float r;
		private float g;
		private float b;
		// The variables x, y and z control where the particle will be displayed
		// on the screen. x holds the location of our particle on the x axis. y
		// holds the location of our particle on the y axis, and finally z holds
		// the location of our particle on the z axis

		private float x, y, z;
		// The next three variables are important. These three variables control
		// how fast a particle is moving on specific axis, and what direction to
		// move. If xi is a negative value our particle will move left. Positive
		// it will move right. If yi is negative our particle will move down.
		// Positive it will move up. Finally, if zi is negative the particle
		// will move into the screen, and postive it will move towards the
		// viewer.
		private float xi, yi, zi;

		// Lastly, 3 more variables! Each of these variables can be thought of
		// as gravity. If xg is a positive value, our particle will pull to the
		// right. If it's negative our particle will be pulled to the left. So
		// if our particle is moving left (negative) and we apply a positive
		// gravity, the speed will eventually slow so much that our particle
		// will start moving the opposite direction. yg pulls up or down and zg
		// pulls towards or away from the viewer.
		private float xg, yg, zg;

	}

}


下面是运行OpenGL的activity,很简单的逻辑,但是必须重写onResume和onPause方法,并且调用GLSurfaceView的onResume和onPause方法(因为我们的MyRenderer类继承自GLSurfaceView类,所以也就是调用MyRenderer的)

public class TestActivity extends Activity {

	/** The OpenGL View */
	private MyRenderer glSurface;

	/**
	 * Initiate the OpenGL View and set our own Renderer
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		glSurface = new MyRenderer(this);
		setContentView(glSurface);
	}

	/**
	 * Remember to resume the glSurface
	 */
	@Override
	protected void onResume() {
		super.onResume();
		glSurface.onResume();
	}

	/**
	 * Also pause the glSurface
	 */
	@Override
	protected void onPause() {
		super.onPause();
		glSurface.onPause();
	}

}


用到的资源:

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值