软糖的基本效果图如下:
软糖的长方体类,其代码如下:
import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import android.opengl.GLES20; //代表软糖的长方体 public class Cuboid { int mProgram;//自定义渲染管线着色器程序id int muMVPMatrixHandle;//总变换矩阵引用id int maPositionHandle; //顶点位置属性引用id int maTexCoorHandle; //顶点纹理坐标属性引用id int uAngleSpanHandle;//扭曲总角度跨度引用id int uYStartHandle;//Y坐标起始引用id int uYSpanHandle;//Y坐标跨度引用id String mVertexShader;//顶点着色器 String mFragmentShader;//片元着色器 FloatBuffer mVertexBuffer;//顶点坐标数据缓冲 FloatBuffer mTexCoorBuffer;//顶点纹理坐标数据缓冲 int vCount=0; final float Y_MAX=1.5f; final float Y_MIN=-1.5f; final int FD=6; final float hw=0.575f; float angleSpan=0; float angleStep=2f; public Cuboid(MySurfaceView mv) { //初始化顶点坐标与着色数据 initVertexData(); //初始化shader intShader(mv); } //初始化顶点坐标与着色数据的方法 public void initVertexData() { //顶点坐标数据的初始化================begin============================ vCount=FD*4*6; float vertices[]=new float[vCount*3]; float texCoor[]=new float[vCount*2]; float yStart=Y_MIN; float ySpan=(Y_MAX-Y_MIN)/FD; int count=0; int tCount=0; for(int i=0;i<FD;i++) { float x1=-hw; float y1=yStart; float z1=hw; float x2=hw; float y2=yStart; float z2=hw; float x3=hw; float y3=yStart; float z3=-hw; float x4=-hw; float y4=yStart; float z4=-hw; float x5=-hw; float y5=yStart+ySpan; float z5=hw; float x6=hw; float y6=yStart+ySpan; float z6=hw; float x7=hw; float y7=yStart+ySpan; float z7=-hw; float x8=-hw; float y8=yStart+ySpan; float z8=-hw; //512 vertices[count++]=x5; vertices[count++]=y5; vertices[count++]=z5; vertices[count++]=x1; vertices[count++]=y1; vertices[count++]=z1; vertices[count++]=x2; vertices[count++]=y2; vertices[count++]=z2; //526 vertices[count++]=x5; vertices[count++]=y5; vertices[count++]=z5; vertices[count++]=x2; vertices[count++]=y2; vertices[count++]=z2; vertices[count++]=x6; vertices[count++]=y6; vertices[count++]=z6; // vertices[count++]=x6; vertices[count++]=y6; vertices[count++]=z6; vertices[count++]=x2; vertices[count++]=y2; vertices[count++]=z2; vertices[count++]=x3; vertices[count++]=y3; vertices[count++]=z3; vertices[count++]=x6; vertices[count++]=y6; vertices[count++]=z6; vertices[count++]=x3; vertices[count++]=y3; vertices[count++]=z3; vertices[count++]=x7; vertices[count++]=y7; vertices[count++]=z7; vertices[count++]=x7; vertices[count++]=y7; vertices[count++]=z7; vertices[count++]=x3; vertices[count++]=y3; vertices[count++]=z3; vertices[count++]=x4; vertices[count++]=y4; vertices[count++]=z4; vertices[count++]=x7; vertices[count++]=y7; vertices[count++]=z7; vertices[count++]=x4; vertices[count++]=y4; vertices[count++]=z4; vertices[count++]=x8; vertices[count++]=y8; vertices[count++]=z8; vertices[count++]=x8; vertices[count++]=y8; vertices[count++]=z8; vertices[count++]=x4; vertices[count++]=y4; vertices[count++]=z4; vertices[count++]=x1; vertices[count++]=y1; vertices[count++]=z1; vertices[count++]=x8; vertices[count++]=y8; vertices[count++]=z8; vertices[count++]=x1; vertices[count++]=y1; vertices[count++]=z1; vertices[count++]=x5; vertices[count++]=y5; vertices[count++]=z5; yStart=yStart+ySpan; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=0; texCoor[tCount++]=0; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=1; texCoor[tCount++]=0; } //创建顶点坐标数据缓冲 //vertices.length*4是因为一个整数四个字节 ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4); vbb.order(ByteOrder.nativeOrder());//设置字节顺序 mVertexBuffer = vbb.asFloatBuffer();//转换为Float型缓冲 mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据 mVertexBuffer.position(0);//设置缓冲区起始位置 //特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer //转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题 //顶点坐标数据的初始化================end============================ //顶点纹理坐标数据的初始化================begin============================ //创建顶点纹理坐标数据缓冲 ByteBuffer cbb = ByteBuffer.allocateDirect(texCoor.length*4); cbb.order(ByteOrder.nativeOrder());//设置字节顺序 mTexCoorBuffer = cbb.asFloatBuffer();//转换为Float型缓冲 mTexCoorBuffer.put(texCoor);//向缓冲区中放入顶点着色数据 mTexCoorBuffer.position(0);//设置缓冲区起始位置 //特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer //转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题 //顶点纹理坐标数据的初始化================end============================ } //初始化shader public void intShader(MySurfaceView mv) { //加载顶点着色器的脚本内容 mVertexShader=ShaderUtil.loadFromAssetsFile("vertex_tex.sh", mv.getResources()); //加载片元着色器的脚本内容 mFragmentShader=ShaderUtil.loadFromAssetsFile("frag_tex.sh", mv.getResources()); //基于顶点着色器与片元着色器创建程序 mProgram = createProgram(mVertexShader, mFragmentShader); //获取程序中顶点位置属性引用id maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); //获取程序中顶点纹理坐标属性引用id maTexCoorHandle= GLES20.glGetAttribLocation(mProgram, "aTexCoor"); //获取程序中总变换矩阵引用id muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); //获取程序中总扭曲角度跨度 uAngleSpanHandle = GLES20.glGetUniformLocation(mProgram, "angleSpan"); //获取程序中Y坐标起始引用id uYStartHandle = GLES20.glGetUniformLocation(mProgram, "yStart"); //获取程序中Y坐标跨度引用id uYSpanHandle = GLES20.glGetUniformLocation(mProgram, "ySpan"); } public void drawSelf(int texId) { //制定使用某套shader程序 GLES20.glUseProgram(mProgram); //将最终变换矩阵传入shader程序 GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0); //将顶点位置数据传入渲染管线 GLES20.glVertexAttribPointer ( maPositionHandle, 3, GLES20.GL_FLOAT, false, 3*4, mVertexBuffer ); //将顶点纹理坐标数据传入渲染管线 GLES20.glVertexAttribPointer ( maTexCoorHandle, 2, GLES20.GL_FLOAT, false, 2*4, mTexCoorBuffer ); //启用顶点位置、纹理坐标数据 GLES20.glEnableVertexAttribArray(maPositionHandle); GLES20.glEnableVertexAttribArray(maTexCoorHandle); //绑定纹理 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId); angleSpan=(float) (angleSpan+Math.toRadians(angleStep)); if(Math.toDegrees(angleSpan)>90) { angleStep=-2f; } else if(Math.toDegrees(angleSpan)<-90) { angleStep=2f; } GLES20.glUniform1f(uAngleSpanHandle , angleSpan); GLES20.glUniform1f(uYStartHandle , Y_MIN); GLES20.glUniform1f(uYSpanHandle , Y_MAX-Y_MIN); try { Thread.sleep(20); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //绘制纹理矩形 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount); } }
实现软糖扭动的顶点着色器:
uniform mat4 uMVPMatrix; //总变换矩阵 attribute vec3 aPosition; //顶点位置 attribute vec2 aTexCoor; //顶点纹理坐标 varying vec2 vTextureCoord; //用于传递给片元着色器的变量 uniform float angleSpan;//扭曲总角度跨度 uniform float yStart;//Y坐标起始点 uniform float ySpan;//Y坐标跨度 void main() { //计算当前顶点角度跨度 float tempAS= angleSpan*(aPosition.y-yStart)/ySpan; vec3 tPosition=aPosition; //若不是最下面一排顶点计算XZ位置 if(aPosition.y>yStart) { tPosition.x=(cos(tempAS)*aPosition.x-sin(tempAS)*aPosition.z); tPosition.z=(sin(tempAS)*aPosition.x+cos(tempAS)*aPosition.z); } gl_Position = uMVPMatrix * vec4(tPosition,1); //根据总变换矩阵计算此次绘制此顶点位置 vTextureCoord = aTexCoor;//将接收的纹理坐标传递给片元着色器 }