openGL es2.0 粒子系统之烟花

一、Java代码

package com.gzdxid.particles;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.graphics.Color;
import android.opengl.GLES20;

 public class ParticleSystem {

	private int mProgram;
	private int muMVPMatrixHandle;
	private int muTimeHandle;
	private int maPositionHandle;
	private int maColorHandle;
	private int maDirectionVectorHandle;
	private int maParticleStartTimeHandle;
	
	private static final int BYTES_PER_FLOAT = 4;
	private static final int POSITION_COMPONENT_COUNT = 3;
	private static final int COLOR_COMPONENT_COUNT = 3;
	private static final int VECTOR_COMPONENT_COUNT = 3;
	private static final int PARTICLE_START_TIME_COMPONENT_COUNT = 1;
	private static final int TOTAL_COMPONENT_COUNT = POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT + VECTOR_COMPONENT_COUNT + PARTICLE_START_TIME_COMPONENT_COUNT;
	private static final int STRIDE = TOTAL_COMPONENT_COUNT * BYTES_PER_FLOAT;
	
	private int maxParticleCount;
	private float[] particles;
	private FloatBuffer mVertexArrayBuffer;
	private int nextParticle=0;
	private int currentParticleCount;
	private int[] vboID;
	
	public ParticleSystem(int maxParticleCount,int mProgram) {
		initVertex(maxParticleCount);
		initShader(mProgram);
	}
	
	private void initVertex(int maxParticleCount) {
		this.maxParticleCount=maxParticleCount;
		particles=new float[maxParticleCount*TOTAL_COMPONENT_COUNT];
		vboID=new int[1];
		ByteBuffer vbb=ByteBuffer.allocateDirect(maxParticleCount*TOTAL_COMPONENT_COUNT*4);
		vbb.order(ByteOrder.nativeOrder());
		mVertexArrayBuffer=vbb.asFloatBuffer();
	}

	private void initShader(int mProgram) {
		this.mProgram=mProgram;
		muMVPMatrixHandle=GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
		muTimeHandle=GLES20.glGetUniformLocation(mProgram, "uTime");
		maPositionHandle=GLES20.glGetAttribLocation(mProgram, "aPosition");
		maColorHandle=GLES20.glGetAttribLocation(mProgram, "aColor");
		maDirectionVectorHandle=GLES20.glGetAttribLocation(mProgram, "aDirectionVector");
		maParticleStartTimeHandle=GLES20.glGetAttribLocation(mProgram, "aParticleStartTime");
	}
	
	public void addParticle(Point3 position,int color,Vector3 direction,float particleStartTime){
		int particleOffset=nextParticle*TOTAL_COMPONENT_COUNT;
		int currentOffset=particleOffset;
		nextParticle++;
		if(currentParticleCount<maxParticleCount){
			currentParticleCount++;
		}
		if(nextParticle==maxParticleCount){
			nextParticle=0;
		}
		particles[currentOffset++]=position.Px;
		particles[currentOffset++]=position.Py;
		particles[currentOffset++]=position.Pz;
		particles[currentOffset++]=Color.red(color)/255f;
		particles[currentOffset++]=Color.green(color)/255f;
		particles[currentOffset++]=Color.blue(color)/255f;
		particles[currentOffset++]=direction.Vx;
		particles[currentOffset++]=direction.Vy;
		particles[currentOffset++]=direction.Vz;
		particles[currentOffset++]=particleStartTime;
		mVertexArrayBuffer.position(particleOffset);
		mVertexArrayBuffer.put(particles, particleOffset, TOTAL_COMPONENT_COUNT);
		mVertexArrayBuffer.position(0);
	}

	 public void drawSelf(float[] viewProjectionMatrix,float elapsedTime){
		int dataOffset=0;
		GLES20.glUseProgram(mProgram);
		GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, viewProjectionMatrix, 0);
		GLES20.glUniform1f(muTimeHandle, elapsedTime);
		
		GLES20.glGenBuffers(1, vboID,0);
		
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
		GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexArrayBuffer.capacity()*BYTES_PER_FLOAT, mVertexArrayBuffer, GLES20.GL_DYNAMIC_DRAW);
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
		
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
		GLES20.glEnableVertexAttribArray(maPositionHandle);
		GLES20.glVertexAttribPointer(maPositionHandle, POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, dataOffset);
		dataOffset+=POSITION_COMPONENT_COUNT*BYTES_PER_FLOAT;
		
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
		GLES20.glEnableVertexAttribArray(maColorHandle);
		GLES20.glVertexAttribPointer(maColorHandle, COLOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, dataOffset);
		dataOffset+=COLOR_COMPONENT_COUNT*BYTES_PER_FLOAT;
		
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
		GLES20.glEnableVertexAttribArray(maDirectionVectorHandle);
		GLES20.glVertexAttribPointer(maDirectionVectorHandle, VECTOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, dataOffset);
		dataOffset+=VECTOR_COMPONENT_COUNT*BYTES_PER_FLOAT;
		
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
		GLES20.glEnableVertexAttribArray(maParticleStartTimeHandle);
		GLES20.glVertexAttribPointer(maParticleStartTimeHandle, PARTICLE_START_TIME_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, dataOffset);
		
		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
		
		GLES20.glDrawArrays(GLES20.GL_POINTS, 0, currentParticleCount);
		
		GLES20.glDeleteBuffers(1, vboID,0);
		GLES20.glDisableVertexAttribArray(maPositionHandle);
		GLES20.glDisableVertexAttribArray(maColorHandle);
		GLES20.glDisableVertexAttribArray(maDirectionVectorHandle);
		GLES20.glDisableVertexAttribArray(maParticleStartTimeHandle);
	}
	
}

package com.gzdxid.particles;

import java.util.Random;

import android.opengl.Matrix;

public class ParticleShooter {

	private Point3 position;
	private int color;
	private float angleVariance;
	private float speedVariance;
	private float[] directionVector=new float[4];
	
	private final Random random=new Random();
	private float[] resultVector=new float[4];
	private float[] rotationMatrix=new float[16];
	
	public ParticleShooter(Point3 position,Vector3 direction,int color,float angleVarianceInDegrees,float speedVariance) {
		this.position=position;
		this.color=color;
		this.speedVariance=speedVariance;
		this.angleVariance=angleVarianceInDegrees;
        directionVector[0]=direction.Vx;
        directionVector[1]=direction.Vy;
        directionVector[2]=direction.Vz;
        directionVector[3]=0;
	}
	
	public void toParticleSystem(ParticleSystem particleSystem,float currentTime,int count){
		for(int i=0;i<count;i++){
			Matrix.setRotateEulerM(
					rotationMatrix, 
					0, 
					(random.nextFloat()-0.5f)*angleVariance,
					(random.nextFloat()-0.5f)*angleVariance, 
					(random.nextFloat()-0.5f)*angleVariance);
			Matrix.multiplyMV(resultVector, 0, rotationMatrix, 0, directionVector, 0);
			float speedAdjustment=1f+random.nextFloat()*speedVariance;
			Vector3 thisDirection=new Vector3(
					resultVector[0]*speedAdjustment, 
					resultVector[1]*speedAdjustment, 
					resultVector[2]*speedAdjustment);
			particleSystem.addParticle(position, color, thisDirection, currentTime);
		}
	}
}

package com.gzdxid.particles;

public class Vector3 {

	protected float Vx;
	protected float Vy;
	protected float Vz;
	
	public Vector3(float x,float y,float z) {
		Vx=x;
		Vy=y;
		Vz=z;
	}
}

package com.gzdxid.particles;

public class Point3 {

	protected float Px;
	protected float Py;
	protected float Pz;
	
	public Point3(float x,float y,float z) {
		Px=x;
		Py=y;
		Pz=z;
	}
}

二、顶点着色器:

uniform mat4 uMVPMatrix;
uniform float uTime;

attribute vec3 aPosition;
attribute vec3 aColor;
attribute vec3 aDirectionVector;
attribute float aParticleStartTime;

varying vec3 vColor;
varying float vElapsedTime;

void main()
{
   vColor=aColor;
   vElapsedTime=uTime-aParticleStartTime;
   vec3 currentPosition=aPosition+(aDirectionVector*vElapsedTime);
   float gravityFactor=vElapsedTime*vElapsedTime/10.0;
   currentPosition.y-=gravityFactor;
   gl_Position=uMVPMatrix*vec4(currentPosition,1.0);
   gl_PointSize=25.0;
}

三、片源着色器:

precision mediump float;

varying vec3 vColor;
varying float vElapsedTime;

void main()
{
   float xDistance=0.5-gl_PointCoord.x;
   float yDistance=0.5-gl_PointCoord.y;
   float distanceFromCenter=sqrt(xDistance*xDistance+yDistance*yDistance);
   if(distanceFromCenter>0.5){
   discard;
   }else{
   gl_FragColor=vec4(vColor/vElapsedTime,1.0);
   }
}

四、使用方法:

public void initParticle(){
		final Point3 position=new Point3(0, 0, 0);
		final Vector3 particleDirection=new Vector3(0f, 0.5f, 0);
		final float angleVarianceInDegrees=10f;
		final float speedVariance=1f;
		globalStartTime=System.nanoTime();
		particleSystem=new ParticleSystem(10000, ShaderManager.getParticleColorShaderProgram());
		particleShooter=new ParticleShooter(position, particleDirection, Color.rgb(255, 50, 5), angleVarianceInDegrees, speedVariance);
		grainShooter=new GrainShooter(2, 8000, ShaderManager.getGrainColorShaderProgram());
		
	}

private void drawParticle(){
			
			float currentTime=(System.nanoTime()-globalStartTime)/1000000000f;
			GLES20.glEnable(GLES20.GL_BLEND);
			GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE);
			MatrixState.pushMatrix();
			MatrixState.translate(-0.2f, -0.6f, 0);
			particleShooter.toParticleSystem(particleSystem, currentTime, 5);
			particleSystem.drawSelf(MatrixState.getFinalMatrix(),currentTime);
			MatrixState.popMatrix();
			GLES20.glDisable(GLES20.GL_BLEND);
			
			GLES20.glEnable(GLES20.GL_DEPTH_TEST);
			GLES20.glEnable(GLES20.GL_CULL_FACE);
			MatrixState.pushMatrix();
			MatrixState.rotate(-180, 1, 0, 0);
			MatrixState.translate(-0.2f, 0.2f, 0);
			grainShooter.drawSelf();
			MatrixState.popMatrix();
			GLES20.glDisable(GLES20.GL_DEPTH_TEST);
			GLES20.glDisable(GLES20.GL_CULL_FACE);
			
          		}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值