http://blog.csdn.net/cxy200927099/article/details/38584487
刚学OpenGL 2个多星期,也算是入门了吧
在看了老外写的书 OpenGL ES 2 for Android A Quick - Start Guide.pdf
后,由于这本书上给的代码不够全,
自己功力太浅,对于一些了解有点疑惑,
费了差不多两天才调出想要的结果,下面就分享一下我的经历,若有问题,希望大家多多交流
本代码中包含的内容还是比较多的,使用OpenGL ES2.0编写,包含有顶点 shader和片段shader,
还包含了VBO(vertex buffer object),这里是我当时最疑惑的地方,因为对VBO的用法不熟悉,上网搜索了导致出不来结果,
后来还是在一个外国网站上找到答案的。
粒子系统是通过将时间作为一个变量绑定到绘制的点的位置信息中,由于时间是在流动的,因此粒子也会跟着在移动;从而就形成了粒子流,这里比较难理解
不废话了,直接上代码吧;
本程序代码结构:
先看MainActivity.java
- package com.cxy.particles;
- import android.app.Activity;
- import android.opengl.GLSurfaceView;
- import android.os.Bundle;
- public class MainActivity extends Activity {
- GLSurfaceView glSurfaceView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- glSurfaceView = new GLSurfaceView(this);
-
- glSurfaceView.setEGLContextClientVersion(2);
-
- MyRenderer mRenderer = new MyRenderer(this,glSurfaceView);
- glSurfaceView.setRenderer(mRenderer);
- glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
-
- setContentView(glSurfaceView);
- }
- }
最重要的渲染的文件MyRenderer.java
- package com.cxy.particles;
- import javax.microedition.khronos.egl.EGLConfig;
- import javax.microedition.khronos.opengles.GL10;
- import android.content.Context;
- import android.graphics.Color;
- import android.opengl.GLES20;
- import android.opengl.GLSurfaceView;
- import android.opengl.Matrix;
- public class MyRenderer implements GLSurfaceView.Renderer {
-
- GLSurfaceView glView;
- private Context context;
-
-
- private final float[] projectionMatrix=new float[16];
- private final float[] viewMatrix=new float[16];
- private final float[] viewProjectionMatrix=new float[16];
-
- private ParticleShaderProgram particleProgram;
- private ParticleSystem particleSystem;
- private ParticleShooter redParticleShooter;
- private ParticleShooter greenParticleShooter;
- private ParticleShooter blueParticleShooter;
- private long globalStartTime;
-
-
- public MyRenderer(Context context,GLSurfaceView view){
-
- this.context=context;
- this.glView = view;
- }
-
- @Override
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
-
- GLES20.glClearColor(0.0f,0.0f,0.0f,0.0f);
-
- particleProgram=new ParticleShaderProgram(context,glView);
-
- particleSystem=new ParticleSystem(10000);
-
- globalStartTime=System.nanoTime();
-
-
-
- final Vector3 particleDirection=new Vector3(0f,0.5f,0f);
-
- redParticleShooter=new ParticleShooter(
- new Point3(-1f,0f,0f),
- particleDirection,
- Color.rgb(255,50,5));
-
- greenParticleShooter=new ParticleShooter(
- new Point3(0f,0f,0f),
- particleDirection,
- Color.rgb(25,255,25));
-
- blueParticleShooter=new ParticleShooter(
- new Point3(1f,0f,0f),
- particleDirection,
- Color.rgb(5,50,255));
- }
-
- @Override
- public void onSurfaceChanged(GL10 gl, int width, int height) {
-
- GLES20.glViewport(0,0,width,height);
- Matrix.perspectiveM(
- projectionMatrix,
- 0,
- 45,
- (float)width/(float)height,
- 1f,
- 10f);
- Matrix.setIdentityM(viewMatrix,0);
- Matrix.translateM(viewMatrix,0,0f,-1.5f,-5f);
-
- Matrix.multiplyMM(
- viewProjectionMatrix,
- 0,
- projectionMatrix,
- 0,
- viewMatrix,
- 0);
- }
-
- @Override
- public void onDrawFrame(GL10 gl) {
-
- GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- float currentTime=(System.nanoTime()-globalStartTime)/1000000000f;
-
-
-
-
- redParticleShooter.addParticles(particleSystem,currentTime,5);
- greenParticleShooter.addParticles(particleSystem,currentTime,5);
- blueParticleShooter.addParticles(particleSystem,currentTime,5);
-
-
-
-
-
-
- particleProgram.useProgram();
-
- particleProgram.setUniforms(viewProjectionMatrix,currentTime);
-
-
-
-
-
- particleSystem.bindData(particleProgram);
-
-
- particleSystem.draw(particleProgram);
- }
- }
在上面的OnSurfaceCreate中,新建的
ParticleShaderProgram实例,下面看看这个类是怎么实现的
ParticleShaderProgram.java
- package com.cxy.particles;
- import android.content.Context;
- import android.opengl.GLES20;
- import android.opengl.GLSurfaceView;
- public class ParticleShaderProgram {
- protected static final String U_TIME = "u_Time";
- protected static final String U_MATRIX = "u_Matrix";
- protected static final String A_POSITION = "a_Position";
- protected static final String A_COLOR = "a_Color";
- protected static final String A_DIRECTION_VECTOR = "a_DirectionVector";
- protected static final String A_PARTICLE_START_TIME = "a_ParticleStartTime";
-
- private int uMatrixLocation;
- private int uTimeLocation;
-
- private int aPositionLocation;
- private int aColorLocation;
- private int aDirectionVectorLocation;
- private int aParticleStartTimeLocation;
-
- private String mVertexShader;
- private String mFragmentShader;
-
- int mProgram;
-
-
-
-
-
-
- public ParticleShaderProgram(Context context,GLSurfaceView mv) {
- initShader(mv);
- }
-
-
-
-
-
-
-
-
-
- public void initShader(GLSurfaceView mv) {
-
-
-
-
- mVertexShader = ShaderUtil.loadFromAssetsFile("vertex.sh",
- mv.getResources());
- mFragmentShader = ShaderUtil.loadFromAssetsFile("frag.sh",
- mv.getResources());
-
-
-
- mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
-
-
-
- uMatrixLocation = GLES20.glGetUniformLocation(mProgram, U_MATRIX);
- uTimeLocation = GLES20.glGetUniformLocation(mProgram, U_TIME);
-
-
-
-
-
- aPositionLocation = GLES20.glGetAttribLocation(mProgram, A_POSITION);
- aColorLocation = GLES20.glGetAttribLocation(mProgram, A_COLOR);
- aDirectionVectorLocation = GLES20.glGetAttribLocation(mProgram,
- A_DIRECTION_VECTOR);
- aParticleStartTimeLocation = GLES20.glGetAttribLocation(mProgram,
- A_PARTICLE_START_TIME);
- }
-
- public void useProgram(){
- GLES20.glUseProgram(mProgram);
- }
-
- public void setUniforms(float[] matrix, float elapsedTime) {
-
- GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, matrix, 0);
-
- GLES20.glUniform1f(uTimeLocation, elapsedTime);
- }
-
- public int getPositionAttributeLocation() {
- return aPositionLocation;
- }
-
- public int getColorAttributeLocation() {
- return aColorLocation;
- }
-
- public int getDirectionVectorAttributeLocation() {
- return aDirectionVectorLocation;
- }
-
- public int getParticleStartTimeAttributeLocation() {
- return aParticleStartTimeLocation;
- }
- }
ParticleShooter.java
- package com.cxy.particles;
- public class ParticleShooter {
-
- private final Point3 position;
- private final Vector3 direction;
- private final int color;
-
-
-
-
-
-
- public ParticleShooter(Point3 position,Vector3 direction,int color){
- this.position=position;
- this.direction=direction;
- this.color=color;
- }
-
- public void addParticles(ParticleSystem particleSystem,float currentTime,
- int count){
- for(int i=0;i<count;i++){
- particleSystem.addParticle(position,color,direction,currentTime);
- }
- }
- }
ParticleSystem.java
- package com.cxy.particles;
-
- import java.nio.ByteBuffer;
- import java.nio.ByteOrder;
- import java.nio.FloatBuffer;
- import java.util.Vector;
-
- import android.annotation.SuppressLint;
- import android.graphics.Color;
- import android.graphics.Point;
- import android.opengl.GLES20;
- import android.util.Log;
-
- public class ParticleSystem {
-
- 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 final float[] particles;
-
- private final int maxParticleCount;
- private int currentParticleCount;
- private int nextParticle = 0;
-
-
- private int[] vaoID;
- private int[] vboID = new int[1];
-
- private FloatBuffer vertexArrayBuffer;
-
- private int dataOffset = 0;
-
- public ParticleSystem(int maxParticleCount) {
- particles = new float[maxParticleCount * TOTAL_COMPONENT_COUNT];
- this.maxParticleCount = maxParticleCount;
-
-
-
- ByteBuffer qbb = ByteBuffer.allocateDirect(maxParticleCount * 4 *TOTAL_COMPONENT_COUNT);
-
- qbb.order(ByteOrder.nativeOrder());
- vertexArrayBuffer = qbb.asFloatBuffer();
-
-
- }
-
- 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;
-
-
-
-
- vertexArrayBuffer.position(particleOffset);
-
-
- vertexArrayBuffer.put(particles, particleOffset, TOTAL_COMPONENT_COUNT);
- vertexArrayBuffer.position(0);
-
- }
-
- public void bindData(ParticleShaderProgram particleProgram) {
- int dataOffset = 0;
-
-
-
-
-
-
-
- GLES20.glGenBuffers(1, vboID, 0);
-
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
-
-
- GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
- vertexArrayBuffer.capacity() * BYTES_PER_FLOAT,
- vertexArrayBuffer, GLES20.GL_DYNAMIC_DRAW);
-
-
- GLES20.glEnableVertexAttribArray(particleProgram
- .getPositionAttributeLocation());
- GLES20.glVertexAttribPointer(
- particleProgram.getPositionAttributeLocation(),
- POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE,
- dataOffset);
- dataOffset += POSITION_COMPONENT_COUNT * BYTES_PER_FLOAT;
-
- GLES20.glEnableVertexAttribArray(particleProgram
- .getColorAttributeLocation());
- GLES20.glVertexAttribPointer(
- particleProgram.getColorAttributeLocation(),
- COLOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE,
- dataOffset);
- dataOffset += COLOR_COMPONENT_COUNT * BYTES_PER_FLOAT;
-
- GLES20.glEnableVertexAttribArray(particleProgram
- .getDirectionVectorAttributeLocation());
- GLES20.glVertexAttribPointer(
- particleProgram.getDirectionVectorAttributeLocation(),
- VECTOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE,
- dataOffset);
- dataOffset += VECTOR_COMPONENT_COUNT * BYTES_PER_FLOAT;
-
- GLES20.glEnableVertexAttribArray(particleProgram
- .getParticleStartTimeAttributeLocation());
- GLES20.glVertexAttribPointer(
- particleProgram.getParticleStartTimeAttributeLocation(),
- PARTICLE_START_TIME_COMPONENT_COUNT, GLES20.GL_FLOAT, false,
- STRIDE, dataOffset);
-
-
- GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
-
-
- }
-
- public void draw(ParticleShaderProgram particleProgram) {
-
- GLES20.glDrawArrays(GLES20.GL_POINTS, 0, currentParticleCount);
-
-
-
-
-
-
-
-
-
- GLES20.glDeleteBuffers(1, vboID, 0);
-
- GLES20.glDisableVertexAttribArray(particleProgram
- .getPositionAttributeLocation());
- GLES20.glDisableVertexAttribArray(particleProgram
- .getColorAttributeLocation());
- GLES20.glDisableVertexAttribArray(particleProgram
- .getDirectionVectorAttributeLocation());
- GLES20.glDisableVertexAttribArray(particleProgram
- .getParticleStartTimeAttributeLocation());
-
- }
-
-
- public FloatBuffer floatBufferUtil(float[] arr) {
- FloatBuffer mbuffer;
-
- ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
-
- qbb.order(ByteOrder.nativeOrder());
-
- mbuffer = qbb.asFloatBuffer();
- mbuffer.put(arr);
- mbuffer.position(0);
-
- return mbuffer;
- }
-
- }
VBO将数据打包:
这里用到了一个 VBO,并且使用了将所有数据打包在一个buffer中处理,刚开始在调试的时候,由于对VBO的使用不是很清楚,犯下了很多错误,而在网上找到的也大都是Windows版本的,和Android上的用法还是有区别的,最终在一个外国网站上找到了解决思路;
这个网站,讲解的很不错,分类讲解了
VBO处理单个数据和 VBO将数据打包在一起的使用
这里我就只说一下VBO将数据打包在一起的用法:
前提需要声明的变量:
- private int[] vboID = new int[1];
- private FloatBuffer vertexArrayBuffer;
private int[] vboID = new int[1];
private FloatBuffer vertexArrayBuffer;
为FloatBuffer分配空间:
- ByteBuffer qbb = ByteBuffer.allocateDirect(maxParticleCount * 4 *TOTAL_COMPONENT_COUNT);
-
- qbb.order(ByteOrder.nativeOrder());
- vertexArrayBuffer = qbb.asFloatBuffer();
ByteBuffer qbb = ByteBuffer.allocateDirect(maxParticleCount * 4 *TOTAL_COMPONENT_COUNT);
// 数组排列用nativeOrder
qbb.order(ByteOrder.nativeOrder());
vertexArrayBuffer = qbb.asFloatBuffer();
关于怎么把
顶点位置坐标、方向坐标、颜色、时间等打包在一起到
vertexArrayBuffer
请直接参考代码
VBO用法流程:
1.创建VBO:
GLES20.glGenBuffers(1, vboID, 0);
2.绑定VBO:
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboID[0]);
3.绑定数据,最后一个参数要改为GL_DYNAMIC_DRAW,表示数据是在变化的
这里既是将
vertexArrayBuffer绑定了
GL_ARRAY_BUFFER,而
vertexArrayBuffer的内容既是我们在OpenGL程序里面添加包括,顶点位置坐标、方向坐标、颜色、时间等打包在一起的数据包
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
vertexArrayBuffer.capacity() * BYTES_PER_FLOAT,
vertexArrayBuffer, GLES20.GL_DYNAMIC_DRAW);
4.解除绑定:
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
将打包的VBO拆分传递给 shader:
具体怎么将这些数据从VBO Buffer中拆分出来传递给 GLSL shader,我们继续分析:
其实就是采用了
GLES20.glVertexAttribPointer()函数,但是这个函数有两个原形:
- public static native void glVertexAttribPointer(
- int indx,
- int size,
- int type,
- boolean normalized,
- int stride,
- int offset
- );
-
- public static void glVertexAttribPointer(
- int indx,
- int size,
- int type,
- boolean normalized,
- int stride,
- java.nio.Buffer ptr
- ) {
- glVertexAttribPointerBounds(
- indx,
- size,
- type,
- normalized,
- stride,
- ptr,
- ptr.remaining()
- );
- }
这两个函数就只有最后一个参数不同,
@1: 既是GLES20.glGetAttribLocation()的返回值,可理解为表示和shader中的变量交互的句柄
@2: 每一个顶点数据包含的 字节:只能是1,2,3,4;
@3: 数组的类型,如
GL_BYTE,
GL_UNSIGNED_BYTE,
GL_SHORT,
GL_UNSIGNED_SHORT,
GL_FIXED, or
GL_FLOAT,默认的是GL_FLOAT;
@4: 是否将数据归一化处理,GL_TRUE表示归一化,GL_FALSE表示不归一化
@5: stride表示紧密联系的数组的字节偏移,0,表示最后数组数据时紧密联系在一起
像我们这里
传递顶点位置属性的时候,stride = 顶点位置大小(byte)
传递顶点方向属性的时候,
stride =
方向大小
(byte)
传递顶点颜色属性的时候,
stride =
颜色大小
(byte)
传递顶点时间属性的时候,
stride =
时间大小
(byte)
@6:第二个函数比较好理解,最后一个参数就是上面定义的
vertexArrayBuffer;即理解为把这个相关联的数组传递给shader,
而在:第一个函数的,最后一个是偏移量;
刚开始不是很理解,仅仅传偏移量进去,他是怎么关联Buffer的,后来才慢慢理解GLES20.glBufferData()函数
关联了Buffer数组,因此这个glVertexAttribPointer()函数在使用的时候,必须搭配着VBO的整套流程使用,
即先创建VBO,然后绑定name,绑定数据,解除绑定
而以往我们使用glVertexAttribPointer()函数的时候,不使用VBO时,我们传递的最后一个参数都是直接传的Buffer实例,当时在网上收集资料,看到的大都是C++写的
绑定完成之后,就可在调用
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, currentParticleCount);绘制点了
关于一些参数,定义请参见上面.java文件中较全的代码:
注意:这里会有个问题,当我们创建VBO的时候,在绑定数据时
GLES20.glBufferData()这个函数申请了内存空间,而我原以为解除绑定后,应该就会释放空间了,但事实上并非如此:
经过我亲自测试,发现此时会照成内存泄露
唯有:调用
GLES20.glDeleteBuffers(1, vboID, 0);内存空间才会释放,
因此,最后一定记得调用
glDeleteBuffers()函数,具体参见代码原文。
ShaderUtil shader使用小工具类
- package com.cxy.particles;
-
- import java.io.ByteArrayOutputStream;
- import java.io.InputStream;
-
- import android.content.res.Resources;
- import android.opengl.GLES20;
- import android.util.Log;
-
-
-
-
- public class ShaderUtil {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public static int loadShader(int shaderType , String source){
-
- int shader = GLES20.glCreateShader(shaderType);
- if(shader != 0){
-
- GLES20.glShaderSource(shader, source);
-
- GLES20.glCompileShader(shader);
- checkGLError("glCompileShader");
- int[] compiled = new int[1];
-
- GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
- if(compiled[0] == 0){
- Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":");
- Log.e("ES20_ERROR", "ERROR: "+GLES20.glGetShaderInfoLog(shader));
-
- GLES20.glDeleteShader(shader);
- shader = 0;
- }
- }
- else{
- Log.e("ES20_ERROR", "Could not Create shader " + shaderType + ":"+
- "Error:"+ shader);
- }
- return shader;
- }
-
-
-
-
-
-
-
-
-
- public static void checkGLError(String op){
- int error;
-
- while( (error = GLES20.glGetError()) != GLES20.GL_NO_ERROR ){
- Log.e("ES20_ERROR", op + ": glError " + error);
- throw new RuntimeException(op + ": glError " + error);
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public static int createProgram(String vertexSource , String fragmentSource){
-
- int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
- if(vertexShader == 0)
- {
- Log.e("ES20_ERROR", "加载顶点着色器失败");
- return 0;
- }
-
- int fragShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
- if(fragShader == 0)
- {
- Log.e("ES20_ERROR", "加载片元着色器失败");
- return 0;
- }
-
- int program = GLES20.glCreateProgram();
- if(program != 0){
-
- GLES20.glAttachShader(program, vertexShader);
-
- checkGLError("glAttachShader");
-
- GLES20.glAttachShader(program, fragShader);
-
- checkGLError("glAttachShader");
-
-
- GLES20.glLinkProgram(program);
- int[] linkStatus = new int[1];
-
- GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
- if(linkStatus[0] != GLES20.GL_TRUE){
- Log.e("ES20.ERROR", "链接程序失败 : ");
- Log.e("ES20.ERROR", GLES20.glGetProgramInfoLog(program));
-
- GLES20.glDeleteProgram(program);
- program = 0;
- }
- }
- else{
- Log.e("ES20_ERROR", "glCreateProgram Failed: "+program);
- }
-
- return program;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- public static String loadFromAssetsFile(String fileName, Resources resources){
- String result = null;
- try {
-
- InputStream is = resources.getAssets().open(fileName);
- int ch = 0;
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- while((ch = is.read()) != -1){
- baos.write(ch);
- }
-
- byte[] buffer = baos.toByteArray();
- baos.close();
- is.close();
- result = new String(buffer, "UTF-8");
- result = result.replaceAll("\\r\\n", "\n");
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
-
- }
Vector3向量
- package com.cxy.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;
- };
-
- }
Point3向量
- package com.cxy.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;
- };
-
- }
-
下面附上Shader的代码:
顶点Shader:
- uniform mat4 u_Matrix;
- uniform float u_Time;
- attribute vec3 a_Position;
- attribute vec3 a_Color;
- attribute vec3 a_DirectionVector;
- attribute float a_ParticleStartTime;
- varying vec3 v_Color;
- varying float v_ElapsedTime;
- void main()
- {
- v_Color=a_Color;
- v_ElapsedTime=u_Time-a_ParticleStartTime;
- vec3 currentPosition=a_Position+(a_DirectionVector*v_ElapsedTime);
- gl_Position=u_Matrix*vec4(currentPosition,1.0);
- gl_PointSize=10.0;
- }
片段shader:
- precision mediump float;
- varying vec3 v_Color;
- varying float v_ElapsedTime;
- void main()
- {
- gl_FragColor=vec4(v_Color/v_ElapsedTime,1.0);
- }
最让我困惑的就是这里,我们看到在顶点shader中
v_ElapsedTime=u_Time-a_ParticleStartTime;
而u_Time和a_ParticleStartTime这两个值从OpenGL 程序传进来的都是同一个值;
代码如下:
- <span style="white-space:pre"> </span>
- redParticleShooter.addParticles(particleSystem,currentTime,5);
- greenParticleShooter.addParticles(particleSystem,currentTime,5);
- blueParticleShooter.addParticles(particleSystem,currentTime,5);
-
-
- particleProgram.useProgram();
-
- particleProgram.setUniforms(viewProjectionMatrix,currentTime);
这两个值既然一样了,在顶点shader中就相当于v_ElapsedTime等于0,currentPosition变量也应该等于零,因此可以,这样改一下shader:
vec3 currentPosition=a_Position+(a_DirectionVector*v_ElapsedTime);
改为:==> vec3 currentPosition=a_Position;
片段 shader中:
gl_FragColor=vec4(v_Color/v_ElapsedTime,1.0);
改为:===> gl_FragColor=vec4(v_Color,1.0);
理论上应该是这样的,但实际结果得不到想要的结果,还希望大神指点指点?????
程序最终的运行结果:
代码下载地址:
Android OpenGL ES2.0粒子系统