使用opengl实现爆炸特效

 

原理是用点阵展示图片,将点阵传给glsl里面的噪音方法更改位置。

图像对象 储存顶点数据

这里我设置了顶点数据和图片的顶点数据传入,因为顶点和图片的点阵不一样分开储存。

public class PointPicture {
    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_COMPONENT_COUNT = 1;
    private final ObjectBuilder.GeneratedData generatedData;
    private final ObjectBuilder.GeneratedData generatedData2;
    private final VertexArray vertexArray;
    private final VertexArray vertexArray2;

    public PointPicture() {
        generatedData= ObjectBuilder.createPicture(100,100);
        generatedData2= ObjectBuilder.createPicture2(100,100);
        Log.e( "Picture: ",generatedData.toString() +"");
        Log.e("Picture: ",generatedData2.toString()  +"");
        this.vertexArray = new VertexArray(generatedData.vertexData);
        this.vertexArray2 = new VertexArray(generatedData2.vertexData);
    }
    public  void bindData(PointPictureShaderProgram program){
        vertexArray.setVertexAttribPointer(0,program.getA_PositionLocation(),
                POSITION_COMPONENT_COUNT, 0);
       vertexArray2.setVertexAttribPointer(0,program.getA_TextureCoodinatesLocation()
                ,2,0);

    }
    public void draw(){

        for (int i = 0; i < generatedData.drawCommands.size(); i++) {
            generatedData.drawCommands.get(i).draw();
        }
    }
}

生成顶点数据

  //图片顶点
private void appendPicturePoint(int clums ,int rows){
        float perX= 2f/ ((float) clums);
        float perY= 2f/ ((float) rows);
        float Z = 0 ;
        final float size = clums*rows;
        //起点需要复用闭合
        for (int i = 0; i < size; i++) {
            //x上面的点
            vertexData[offset++] =  1- ((int) (i % clums))*perX;
            //y
            vertexData[offset++] =  2- ((int) (i / clums))*perY;
            //z
            vertexData[offset++] = Z;

        }
        drawCommands.add(new DrawCommand() {
            @Override
            public void draw() {
                GLES20.glDrawArrays(GLES20.GL_POINTS,0, (int) size);
            }
        });

    }
//图片纹理顶点
    private void appendPicturePoint2(int clums ,int rows){
        float perX= 1f/ ((float) clums);
        float perY= 1f/ ((float) rows);
        Log.e( "appendPicturePoint2: ",perX+"m"+perY );
        final float size = clums*rows;
        //起点需要复用闭合
        for (int i = 0; i < size; i++) {
            //x上面的点
            vertexData[offset++] =   (float)((int) (i % clums))*perX;
            //y
            vertexData[offset++] =   (float)((int) (i / clums))*perY;
            //z
            Log.e( "appendPicturePoint2: ", "-------"+vertexData[offset-1]+"-------"+vertexData[offset-2]+"-------");
            Log.e( "appendPicturePoint2: ", size+"");
        }
        drawCommands.add(new DrawCommand() {
            @Override
            public void draw() {
                GLES20.glDrawArrays(GLES20.GL_POINTS,0, (int) size);
            }
        });

    }

着色器程序

public class PointPictureShaderProgram extends ShaderProgram {
    private final int uProgressLoctaion;
    //UNIFORM LOCATIONS
    private int u_MatrixLocation;
    //attribute locations
    private int a_PositionLocation;
    private int a_TextureCoodinatesLocation;
    private int a_ColorLocation;
    private int u_TextureUnitLocation;
    private int u_TimeLocation;
    public PointPictureShaderProgram(Context context, int resVertex, int resFrag) {
        super(context, resVertex, resFrag);
        u_MatrixLocation = GLES20.glGetUniformLocation(program, Constants.U_MATRIX);
        u_TextureUnitLocation = GLES20.glGetUniformLocation(program, Constants.U_TEXTUREUNIT);
        a_TextureCoodinatesLocation = GLES20.glGetAttribLocation(program, Constants.A_TEXTURECOODINATES);
        a_PositionLocation = GLES20.glGetAttribLocation(program, Constants.A_POSITION);
        a_ColorLocation = GLES20.glGetUniformLocation(program, Constants.U_COLOR);
        u_TimeLocation = GLES20.glGetUniformLocation(program, Constants.U_TIME);
        uProgressLoctaion = GLES20.glGetUniformLocation(program, "uProgress");
    }
//设置矩阵和贴图纹理
    public void setUniforms(float[]matrix ,int textureId){
        GLES20.glUniformMatrix4fv(u_MatrixLocation,1,false,matrix,0);
//        GLES20.glUniform4f(a_ColorLocation,1f,0f,0f,1f);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureId);
        GLES20.glUniform1i(u_TextureUnitLocation,0);
    }
    //设置uniform的float参数
    public void setUniformsUTime(float uTime,float uprogress){

        GLES20.glUniform1f(u_TimeLocation,uTime);
        GLES20.glUniform1f(uProgressLoctaion,uprogress);
    }

主要特效是实现粒子的动态效果,这个是我从一个webgl网站上找到修改的下面是链接

three.js 实现图片粒子爆炸特效 - 掘金

noise.glsl

precision  mediump float;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform float uTime;
attribute vec3 a_Position;
attribute vec2 a_TextureCoodinates;
uniform float uProgress;
uniform mat4 u_Matrix;

varying vec2 v_TextureCoodinates;

vec4 permute(vec4 x){return mod(((x*34.)+1.)*x,289.);}
vec4 taylorInvSqrt(vec4 r){return 1.79284291400159-.85373472095314*r;}

float snoise(vec3 v){
    const vec2 C=vec2(1./6.,1./3.);
    const vec4 D=vec4(0.,.5,1.,2.);

    // First corner
    vec3 i=floor(v+dot(v,C.yyy));
    vec3 x0=v-i+dot(i,C.xxx);

    // Other corners
    vec3 g=step(x0.yzx,x0.xyz);
    vec3 l=1.-g;
    vec3 i1=min(g.xyz,l.zxy);
    vec3 i2=max(g.xyz,l.zxy);

    //  x0 = x0 - 0. + 0.0 * C
    vec3 x1=x0-i1+1.*C.xxx;
    vec3 x2=x0-i2+2.*C.xxx;
    vec3 x3=x0-1.+3.*C.xxx;

    // Permutations
    i=mod(i,289.);
    vec4 p=permute(permute(permute(
    i.z+vec4(0.,i1.z,i2.z,1.))
    +i.y+vec4(0.,i1.y,i2.y,1.))
    +i.x+vec4(0.,i1.x,i2.x,1.));

    // Gradients
    // ( N*N points uniformly over a square, mapped onto an octahedron.)
    float n_=1./7.;// N=7
    vec3 ns=n_*D.wyz-D.xzx;

    vec4 j=p-49.*floor(p*ns.z*ns.z);//  mod(p,N*N)

    vec4 x_=floor(j*ns.z);
    vec4 y_=floor(j-7.*x_);// mod(j,N)

    vec4 x=x_*ns.x+ns.yyyy;
    vec4 y=y_*ns.x+ns.yyyy;
    vec4 h=1.-abs(x)-abs(y);

    vec4 b0=vec4(x.xy,y.xy);
    vec4 b1=vec4(x.zw,y.zw);

    vec4 s0=floor(b0)*2.+1.;
    vec4 s1=floor(b1)*2.+1.;
    vec4 sh=-step(h,vec4(0.));

    vec4 a0=b0.xzyw+s0.xzyw*sh.xxyy;
    vec4 a1=b1.xzyw+s1.xzyw*sh.zzww;

    vec3 p0=vec3(a0.xy,h.x);
    vec3 p1=vec3(a0.zw,h.y);
    vec3 p2=vec3(a1.xy,h.z);
    vec3 p3=vec3(a1.zw,h.w);

    //Normalise gradients
    vec4 norm=taylorInvSqrt(vec4(dot(p0,p0),dot(p1,p1),dot(p2,p2),dot(p3,p3)));
    p0*=norm.x;
    p1*=norm.y;
    p2*=norm.z;
    p3*=norm.w;

    // Mix final noise value
    vec4 m=max(.6-vec4(dot(x0,x0),dot(x1,x1),dot(x2,x2),dot(x3,x3)),0.);
    m=m*m;
    return 42.*dot(m*m,vec4(dot(p0,x0),dot(p1,x1),
    dot(p2,x2),dot(p3,x3)));
}

vec3 snoiseVec3(vec3 x){
    return vec3(snoise(vec3(x)*2.-1.),
    snoise(vec3(x.y-19.1,x.z+33.4,x.x+47.2))*2.-1.,
    snoise(vec3(x.z+74.2,x.x-124.5,x.y+99.4)*2.-1.)
    );
}

vec3 curlNoise(vec3 p){
    const float e=.1;
    vec3 dx=vec3(e,0.,0.);
    vec3 dy=vec3(0.,e,0.);
    vec3 dz=vec3(0.,0.,e);

    vec3 p_x0=snoiseVec3(p-dx);
    vec3 p_x1=snoiseVec3(p+dx);
    vec3 p_y0=snoiseVec3(p-dy);
    vec3 p_y1=snoiseVec3(p+dy);
    vec3 p_z0=snoiseVec3(p-dz);
    vec3 p_z1=snoiseVec3(p+dz);

    float x=p_y1.z-p_y0.z-p_z1.y+p_z0.y;
    float y=p_z1.x-p_z0.x-p_x1.z+p_x0.z;
    float z=p_x1.y-p_x0.y-p_y1.x+p_y0.x;

    const float divisor=1./(2.*e);
    return normalize(vec3(x,y,z)*divisor);
}


void main() {

   /* vec3 noise=curlNoise(vec3(position.x*.02,position.y*.008,uTime*.05));
    vec3 distortion=vec3(position.x*2.,position.y,1.)*noise*uProgress;
    vec3 newPos=position+distortion;
    vec4 modelPosition=modelMatrix*vec4(newPos,1.);
    vec4 viewPosition=viewMatrix*modelPosition;
    vec4 projectedPosition=projectionMatrix*viewPosition;*/
    float uTime2=uTime+10.;
   
  /*  vec4 modelPosition=modelMatrix*vec4(newPos,1.);
    vec4 viewPosition=viewMatrix*modelPosition;
    vec4 projectedPosition=projectionMatrix*viewPosition;
    gl_Position=projectedPosition;*/
//    gl_PointSize=2.;
    vec3 noise=curlNoise(vec3(a_Position.x*2.,a_Position.y*.8,uTime*.5));
    vec3 distortion=vec3(a_Position.x*2.,a_Position.y,1.)*noise*uProgress;
    vec3 newPos=a_Position+distortion;
    gl_Position=u_Matrix*vec4(newPos,1.);
    gl_PointSize= 8.5;
    v_TextureCoodinates=a_TextureCoodinates;

}

设置视图矩阵

  //一个标准的定义
        GLES20.glViewport(0,0,width,height);
        MatrixHelper.perspectiveM(projectMatrix,45,(float)width/ ((float) height),1f,10f);
        Matrix.setIdentityM(viewMatrix,0);
        Matrix.translateM(viewMatrix,0,0f,-1.5f,-5f);
        Matrix.multiplyMM(viewProjectMatrix,0,projectMatrix,0,viewMatrix,0);

设置动态更改uprogress动画

@Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_ONE,GLES20.GL_ONE);
        GLES20.glClearColor(0f,0f,0f,0f);
        pointPicture = new PointPicture();
        pointPictureShaderProgram = new PointPictureShaderProgram(context,
                R.raw.texture_noise_vertex_shader,R.raw.point_picture_fragment_shader);
        textureId = TextrueHelper.loadTextrue(context,R.drawable.bg4);
        ValueAnimator valueAnimator=new ValueAnimator();
        valueAnimator.setFloatValues(0f,1f,0f);
        valueAnimator.setDuration(1000*10);
        valueAnimator.setRepeatMode(RESTART);
        valueAnimator.setRepeatCount(INFINITE);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //获取动态值
                uProgress  = (float) animation.getAnimatedValue();
                //设置动态值
                Log.e("onAnimationUpdate: ", uProgress+"");
                //重新绘制

            }
        });
        ((Activity) context).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                valueAnimator.start();
            }
        });

    }

执行绘制 

   int i=0;
    @Override
    public void onDrawFrame(GL10 gl) {

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        pointPictureShaderProgram.useProgram();
        pointPictureShaderProgram.setUniforms(viewProjectMatrix,textureId);
        Log.e("onDrawFrame: ", i+"");
        pointPictureShaderProgram.setUniformsUTime(i++/300f,uProgress);
        pointPicture.bindData(pointPictureShaderProgram);
        pointPicture.draw();

    }

图形点是正方形的你可以添加以下方法优化其中注释的方法是将正方形变成圆

/*    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(v_Color/v_ElapsedTime,1.0);
    }*/
//点加载整个贴图方法
    gl_FragColor =texture2D(u_TextureUnit,vec2(gl_PointCoord.x,gl_PointCoord.y));

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值