opengles特效之飘扬的旗帜

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hb707934728/article/details/52998569

效果图





核心代码 主要看shader中的实现

x方向飘扬shader

uniform mat4 uMVPMatrix; //总变换矩阵
uniform float uStartAngle;//本帧起始角度
uniform float uWidthSpan;//横向长度总跨度
attribute vec3 aPosition;  //顶点位置
attribute vec2 aTexCoor;    //顶点纹理坐标
varying vec2 vTextureCoord;  //用于传递给片元着色器的变量
void main()
{
   //计算X向波浪
   float angleSpanH=4.0*3.14159265;//横向角度总跨度
   float startX=-uWidthSpan/2.0;//起始X坐标
   //根据横向角度总跨度、横向长度总跨度及当前点X坐标折算出当前点X坐标对应的角度
   float currAngle=uStartAngle+((aPosition.x-startX)/uWidthSpan)*angleSpanH;
   float tz=sin(currAngle)*0.1;

   //根据总变换矩阵计算此次绘制此顶点位置
   gl_Position = uMVPMatrix * vec4(aPosition.x,aPosition.y,tz,1);
    // gl_Position = uMVPMatrix * vec4(aPosition.x,tz,aPosition.y,1);

   vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器
}

斜向飘扬shader

uniform mat4 uMVPMatrix; //总变换矩阵
uniform float uStartAngle;//本帧起始角度
uniform float uWidthSpan;//横向长度总跨度
attribute vec3 aPosition;  //顶点位置
attribute vec2 aTexCoor;    //顶点纹理坐标
varying vec2 vTextureCoord;  //用于传递给片元着色器的变量
void main()
{
   //计算X向角度
   float angleSpanH=4.0*3.14159265;//横向角度总跨度
   float startX=-uWidthSpan/2.0;//起始X坐标
   //根据横向角度总跨度、横向长度总跨度及当前点X坐标折算出当前点X坐标对应的角度
   float currAngleH=uStartAngle+((aPosition.x-startX)/uWidthSpan)*angleSpanH;

   //计算出随Y向发展起始角度的扰动值
   float angleSpanZ=4.0*3.14159265;//纵向角度总跨度
   float uHeightSpan=0.75*uWidthSpan;//纵向长度总跨度
   float startY=-uHeightSpan/2.0;//起始Y坐标
   //根据纵向角度总跨度、纵向长度总跨度及当前点Y坐标折算出当前点Y坐标对应的角度
   float currAngleZ=((aPosition.y-startY)/uHeightSpan)*angleSpanZ;

   //计算斜向波浪
   float tzH=sin(currAngleH-currAngleZ)*0.1;
   //根据总变换矩阵计算此次绘制此顶点位置
   gl_Position = uMVPMatrix * vec4(aPosition.x,aPosition.y,tzH,1);
   vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器
}
xy双向飘扬shader

uniform mat4 uMVPMatrix; //总变换矩阵
uniform float uStartAngle;//本帧起始角度
uniform float uWidthSpan;//横向长度总跨度
attribute vec3 aPosition;  //顶点位置
attribute vec2 aTexCoor;    //顶点纹理坐标
varying vec2 vTextureCoord;  //用于传递给片元着色器的变量
void main()
{
   //计算X向波浪
   float angleSpanH=4.0*3.14159265;//横向角度总跨度
   float startX=-uWidthSpan/2.0;//起始X坐标
   //根据横向角度总跨度、横向长度总跨度及当前点X坐标折算出当前点X坐标对应的角度
   float currAngleH=uStartAngle+((aPosition.x-startX)/uWidthSpan)*angleSpanH;
   float tzH=sin(currAngleH)*0.1;

   //计算Y向波浪
   float angleSpanZ=4.0*3.14159265;//纵向角度总跨度
   float uHeightSpan=0.75*uWidthSpan;//纵向长度总跨度
   float startY=-uHeightSpan/2.0;//起始Y坐标
   //根据纵向角度总跨度、纵向长度总跨度及当前点Y坐标折算出当前点Y坐标对应的角度
   float currAngleZ=uStartAngle+3.14159265/3.0+((aPosition.y-startY)/uHeightSpan)*angleSpanZ;
   float tzZ=sin(currAngleZ)*0.1;

   //根据总变换矩阵计算此次绘制此顶点位置
   gl_Position = uMVPMatrix * vec4(aPosition.x,aPosition.y,tzH+tzZ,1);
   vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器
}

同时需要启动一个线程不断修改当前帧起始角度

package test.com.opengles_1_1;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.annotation.SuppressLint;
import android.opengl.GLES20;
/**
 * Created by hbin on 2016/11/1.
 * 有波浪效果的纹理矩形
 */

public class TextureRect {
    int[] mPrograms=new int[3];//自定义渲染管线着色器程序id
    int[] muMVPMatrixHandle=new int[3];//总变换矩阵引用
    int[] maPositionHandle=new int[3]; //顶点位置属性引用
    int[] maTexCoorHandle=new int[3]; //顶点纹理坐标属性引用
    int[] maStartAngleHandle=new int[3]; //本帧起始角度属性引用
    int[] muWidthSpanHandle=new int[3];//横向长度总跨度引用
    int currIndex=0;//当前着色器索引
    FloatBuffer   mVertexBuffer;//顶点坐标数据缓冲
    FloatBuffer   mTexCoorBuffer;//顶点纹理坐标数据缓冲
    int vCount=0;
    final float WIDTH_SPAN=3.3f;//2.8f;//横向长度总跨度
    float currStartAngle=0;//当前帧的起始角度0~2PI

    public TextureRect(MySurfaceView mv)
    {
        //初始化顶点坐标与着色数据
        initVertexData();
        //初始化shader
        initShader(mv,0,"vertex_tex_x.sh");
        initShader(mv,1,"vertex_tex_xie.sh");
        initShader(mv,2,"vertex_tex_xy.sh");
        //启动一个线程定时换帧
        new Thread()
        {
            public void run()
            {
                while(Constant.threadFlag)
                {
                    currStartAngle+=(float) (Math.PI/16);
                    try
                    {
                        Thread.sleep(50);
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    private void initVertexData()
    {
        final int cols=12;//列数
        final int rows=cols*3/4;//行数
        final float UNIT_SIZE=WIDTH_SPAN/cols;//每格的单位长度
        vCount=cols*rows*6;//每个格子两个三角形,每个三角形3个顶点
        float vertices[]=new float[vCount*3];//每个顶点xyz三个坐标
        int count=0;
        for (int j=0;j<rows;j++){
            for (int i=0;i<cols;i++){
                float zsx=-UNIT_SIZE*cols/2+i*UNIT_SIZE;
                float zsy=UNIT_SIZE*rows/2-j*UNIT_SIZE;
                float zsz=0;

                vertices[count++]=zsx;
                vertices[count++]=zsy;
                vertices[count++]=zsz;

                vertices[count++]=zsx;
                vertices[count++]=zsy-UNIT_SIZE;
                vertices[count++]=zsz;

                vertices[count++]=zsx+UNIT_SIZE;
                vertices[count++]=zsy;
                vertices[count++]=zsz;

                vertices[count++]=zsx+UNIT_SIZE;
                vertices[count++]=zsy;
                vertices[count++]=zsz;

                vertices[count++]=zsx;
                vertices[count++]=zsy-UNIT_SIZE;
                vertices[count++]=zsz;

                vertices[count++]=zsx+UNIT_SIZE;
                vertices[count++]=zsy-UNIT_SIZE;
                vertices[count++]=zsz;
            }
        }
        //创建顶点坐标数据缓冲
        //vertices.length*4是因为一个整数四个字节
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
        vbb.order(ByteOrder.nativeOrder());//设置字节顺序
        mVertexBuffer = vbb.asFloatBuffer();//转换为Float型缓冲
        mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
        mVertexBuffer.position(0);//设置缓冲区起始位置
        //顶点纹理坐标数据的初始化================begin============================
        float texCoor[]=generateTexCoor(cols,rows);
        //创建顶点纹理坐标数据缓冲
        ByteBuffer cbb = ByteBuffer.allocateDirect(texCoor.length*4);
        cbb.order(ByteOrder.nativeOrder());//设置字节顺序
        mTexCoorBuffer = cbb.asFloatBuffer();//转换为Float型缓冲
        mTexCoorBuffer.put(texCoor);//向缓冲区中放入顶点着色数据
        mTexCoorBuffer.position(0);//设置缓冲区起始位置
    }

    public void initShader(MySurfaceView mv,int index,String vertexName)
    {
        //加载顶点着色器的脚本内容
        String mVertexShader=ShaderUtil.loadFromAssetsFile(vertexName, mv.getResources());
        //加载片元着色器的脚本内容
        String mFragmentShader=ShaderUtil.loadFromAssetsFile("frag_tex.sh", mv.getResources());
        //基于顶点着色器与片元着色器创建程序
        mPrograms[index] = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
        //获取程序中顶点位置属性引用
        maPositionHandle[index] = GLES20.glGetAttribLocation(mPrograms[index], "aPosition");
        //获取程序中顶点纹理坐标属性引用
        maTexCoorHandle[index]= GLES20.glGetAttribLocation(mPrograms[index], "aTexCoor");
        //获取程序中总变换矩阵引用
        muMVPMatrixHandle[index] = GLES20.glGetUniformLocation(mPrograms[index], "uMVPMatrix");
        //获取本帧起始角度属性引用
        maStartAngleHandle[index]=GLES20.glGetUniformLocation(mPrograms[index], "uStartAngle");
        //获取横向长度总跨度引用
        muWidthSpanHandle[index]=GLES20.glGetUniformLocation(mPrograms[index], "uWidthSpan");
    }

    public void drawSelf(int texId)
    {
        //制定使用某套shader程序
        GLES20.glUseProgram(mPrograms[currIndex]);
        //将最终变换矩阵传入shader程序
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle[currIndex], 1, false, MatrixState.getFinalMatrix(), 0);
        //将本帧起始角度传入shader程序
        GLES20.glUniform1f(maStartAngleHandle[currIndex], currStartAngle);
        //将横向长度总跨度传入shader程序
        GLES20.glUniform1f(muWidthSpanHandle[currIndex], WIDTH_SPAN);
        //将顶点位置数据传入渲染管线
        GLES20.glVertexAttribPointer
                (
                        maPositionHandle[currIndex],
                        3,
                        GLES20.GL_FLOAT,
                        false,
                        3*4,
                        mVertexBuffer
                );
        //将顶点纹理坐标数据传入渲染管线
        GLES20.glVertexAttribPointer
                (
                        maTexCoorHandle[currIndex],
                        2,
                        GLES20.GL_FLOAT,
                        false,
                        2*4,
                        mTexCoorBuffer
                );
        //启用顶点位置、纹理坐标数据
        GLES20.glEnableVertexAttribArray(maPositionHandle[currIndex]);
        GLES20.glEnableVertexAttribArray(maTexCoorHandle[currIndex]);
        //绑定纹理
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
    }

    //自动切分纹理产生纹理数组的方法
    public float[] generateTexCoor(int bw,int bn)
    {
        float[] result=new float[bw*bn*6*2];
        float sizew=1.0f/bw;//列数
        float sizeh=0.75f/bn;//行数
        int c=0;
        for(int i=0;i<bn;i++)
        {
            for(int j=0;j<bw;j++)
            {
                //每行列一个矩形,由两个三角形构成,共六个点,12个纹理坐标
                float s=j*sizew;
                float t=i*sizeh;
                //第一个纹理三角形
                result[c++]=s;
                result[c++]=t;

                result[c++]=s;
                result[c++]=t+sizeh;

                result[c++]=s+sizew;
                result[c++]=t;

                //第二个纹理三角形
                result[c++]=s+sizew;
                result[c++]=t;

                result[c++]=s;
                result[c++]=t+sizeh;

                result[c++]=s+sizew;
                result[c++]=t+sizeh;
            }
        }
        return result;
    }
}


完整代码下载地址

http://download.csdn.net/detail/hb707934728/9670345

展开阅读全文

没有更多推荐了,返回首页