原文地址: http://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;//将接收的纹理坐标传递给片元着色器
- }
- 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