l 实现一个工具类ShalderUtil,用于将着色器代码加载进显卡进行编译
l 实现一个三角形Triangle类 在该类中加载着色器、初始化顶点数据、初始化着色器以及绘制三角形方法
l 实现一个视图类,继承GLSurfaceView类,并通过内部类SceneRenderer创建渲染器。
l 实现MainActivity类,将视图类加载进Activity中
l ShalderUtil.java
package com.flying.opengl_1;
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import android.content.res.Resources; import android.opengl.GLES20; import android.util.Log; /** * 将着色器脚本加载进显卡并编译 加载定点和片元着色器类 * @author min * */ public class ShaderUtil { public static final String=DEBUG_ES20_ERROR="ES20_ERROR"; /** * 加载指定着色器方法 * @param shaderType 着色器类型 * @param source 着色器脚本资源 * @return返回着色器id */ public static int loadShader(int shaderType,String source){ int shader=GLES20.glCreateShader(shaderType); //创建一个着色器并返回id if(shader!=0) { GLES20.glShaderSource(shader, source); //加载着色器源代码 GLES20.glCompileShader(shader); //编译 int []compiled=new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); if(compiled[0]==0) //编译失败 { Log.e(DEBUG_ES20_ERROR, "Counld not Compiled Shader "+shaderType +":"+GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader=0; } } return shader; } /** * 创建着色器程序 * @param vertexSource 顶点着色器脚本 * @param fragmentSource 片元着色器脚本 * @return */ public static int createProgram(String vertexSource,String fragmentSource){ int vertextShader=loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); //加载顶点着色器 if(vertextShader==0){ return 0; } int pixelShader=loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); //加载片元着色器 if(pixelShader==0) { return 0; } int program=GLES20.glCreateProgram(); //创建程序 if(program!=0) { GLES20.glAttachShader(program, vertextShader); //向程序中加载顶点着色器 checkGlError("glAttachShader"); GLES20.glAttachShader(program, pixelShader); //向程序中加载片元着色器 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(DEBUG_ES20_ERROR, "Cound link program"); Log.e(DEBUG_ES20_ERROR, GLES20.glGetProgramInfoLog(program)); GLES20.glDeleteProgram(program); //删除程序 return 0; }
} return program; } //检查每步操作是否有错误 public static void checkGlError(String op){ int error; while((error=GLES20.glGetError())!=GLES20.GL_NO_ERROR){ Log.e(DEBUG_ES20_ERROR, op+": gkError"+ error); throw new RuntimeException(op+": gkError"+ error); //抛出异常 }
} //从sh脚本加载着色器内容的方法 public static String loadFromAssetsFile(String fname,Resources r){ String result=null; ByteArrayOutputStream baos=null; InputStream in=null; try { in=r.getAssets().open(fname);//从assets文件夹中读取 int ch=0; baos=new ByteArrayOutputStream(); while((ch=in.read())!=-1) { baos.write(ch); } byte[] buff=baos.toByteArray(); result=new String(buff,"UTF-8"); result=result.replaceAll("\\r\\n", "\n"); } catch (IOException e) { e.printStackTrace(); } finally{ try { baos.close(); } catch (IOException e) { e.printStackTrace(); } try { in.close(); } catch (IOException e) { e.printStackTrace(); } }
return result; }
}
|
l Triangle.java类
package com.flying.opengl_1;
import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer;
import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.Matrix; import android.util.Log;
/** * 三角形类 * @author min * */ public class Triangle { public static final String DEBUG="Triangle"; public static float[] mProjMatrix=new float[16] ; //4*4投影矩阵 public static float[] mVMMatrix=new float[16] ; //摄像机位置朝向的参数矩阵 public static float[] mMVPMatrix; //总变换矩阵 int mProgram; //自定义渲染管线着色器程序 id int muMVPMatrixHandle ; //总变换矩阵引用 int maPositionHandle ; //顶点位置属性引用 int maColorHandle; //顶点颜色属性引用 String mVertexShader ;//顶点着色器脚本代码 String mFragmentShader ;//片元着色器脚本代码 static float []mMMatrix=new float[16]; //具体物体的3D变换矩阵包括旋转平移缩放 FloatBuffer mVertexBuff ;//顶点坐标数据缓冲 FloatBuffer mColorBuff ;// 顶点着色数据缓冲 int vCount=0; //顶点数量
float xAngle=0; //绕x轴旋转角度
public Triangle(GLSurfaceView mv) { initVertexData(); initShader(mv); }
/* * 自定义初始化顶点数据方法 */ public void initVertexData(){ Log.d(DEBUG, "---------initVertexData-------------"); vCount=3; final float UNIT_SIZE=0.2f; float vertices[]=new float[] { -4*UNIT_SIZE,0, 0,0,-4*UNIT_SIZE, 0,4*UNIT_SIZE,0,0 };
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4); vbb.order(ByteOrder.nativeOrder()); mVertexBuff = vbb.asFloatBuffer(); mVertexBuff.put(vertices); mVertexBuff.position(0);
float colors[]=new float[] { 1,1,1,0, 0,0,1,0, 0,1,0,0 };
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4); cbb.order(ByteOrder.nativeOrder()); mColorBuff = cbb.asFloatBuffer(); mColorBuff.put(colors); mColorBuff.position(0); }
//初始化着色器以及绘制图形方法 public void initShader(GLSurfaceView mv) { Log.d(DEBUG, "---------initShader-------------"); mVertexShader=ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources()); mFragmentShader=ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources()); mProgram=ShaderUtil.createProgram(mVertexShader, mFragmentShader); maPositionHandle=GLES20.glGetAttribLocation(mProgram, "aPosition"); maColorHandle=GLES20.glGetAttribLocation(mProgram, "aColor"); muMVPMatrixHandle=GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); }
public void drawSelf(){ //Log.d(DEBUG, "---------drawSelf-------------"); GLES20.glUseProgram(mProgram); Matrix.setRotateM(mMMatrix, 0, 0, 0, 1, 0); //初始化变换矩阵 Matrix.translateM(mMMatrix, 0, 0, 0, 1) ; //初始化沿Z轴正向位移 Matrix.rotateM(mMMatrix, 0, xAngle, 1, 0, 0); //设置绕x轴旋转 GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Triangle.getFinalMatrix(mMMatrix),0); GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,3*4, mVertexBuff); GLES20.glVertexAttribPointer(maColorHandle, 3, GLES20.GL_FLOAT, false,4*4, mColorBuff); GLES20.glEnableVertexAttribArray(maPositionHandle); GLES20.glEnableVertexAttribArray(maColorHandle); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount); }
/** * 产生最终变换矩阵方法 * @param spec * @return */ public static float[]getFinalMatrix(float []spec){ mMVPMatrix=new float[16]; Matrix.multiplyMM(mMVPMatrix, 0, mVMMatrix, 0, spec, 0); Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0); return mMVPMatrix; } } |
l MyTDView.java类
public class MyTDView extends GLSurfaceView { public static final String DEBUG="MyTDView"; final float ANGLE_SPAN=0.375f; //每次三角形旋转角度 RotateThread rThread; //自定义线程类 SceneRenderer mRenderer; //自定义渲染器
public MyTDView(Context context) { super(context); this.setEGLContextClientVersion(2); //使用 OpenGl 2.0 需设置该值为2 mRenderer=new SceneRenderer(); this.setRenderer(mRenderer); this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); }
public class SceneRenderer implements GLSurfaceView.Renderer{
Triangle tle; //一直持续执行 @Override public void onDrawFrame(GL10 gl) { //Log.d(DEBUG, "--------onDrawFrame------"); GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT|GLES20.GL_COLOR_BUFFER_BIT); tle.drawSelf(); //绘制三角形
}
@Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { Log.d(DEBUG, "--------onSurfaceCreated------"); GLES20.glClearColor(0, 0, 0, 1.0F); //设置背景色 tle=new Triangle(MyTDView.this); GLES20.glEnable(GLES20.GL_DEPTH_TEST); rThread=new RotateThread(); rThread.start(); }
@Override public void onSurfaceChanged(GL10 gl, int width, int height) { Log.d(DEBUG, "--------onSurfaceChanged------"); GLES20.glViewport(0, 0, width, height); //设置视口 float ratio=(float)width/height; Matrix.frustumM(Triangle.mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 10); //设置透视投影 Matrix.setLookAtM(Triangle.mVMMatrix,0,0 ,0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); //设置摄影机
}
} public class RotateThread extends Thread{ public boolean flag=true;
@Override public void run() {
super.run(); while (flag) { mRenderer.tle.xAngle=mRenderer.tle.xAngle+ANGLE_SPAN; try { Thread.sleep(20); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }
} }
} } |
l 最后就是MainActivity.java类
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); MyTDView mv=new MyTDView(this); mv.requestFocus(); mv.setFocusableInTouchMode(true); setContentView(mv); } } } |
l 最后就是顶点着色器和片元着色器
片元着色器 frag.sh
precision mediump float; varying vec4 vColor; //接收从顶点着色器过来的参数
void main() { gl_FragColor = vColor;//给此片元颜色值 } |
顶点着色器 vertex.sh
uniform mat4 uMVPMatrix; attribute vec3 aPosition ; attribute vec4 aColor; varying vec4 vColor ; void main(){ gl_Position=uMVPMatrix *vec4(aPosition,1); vColor =aColor; } |
注意,着色器文件放在assets文件夹中。以sh为后缀。有关着色器语法的详细介绍,请参照http://blog.csdn.net/xy849288321/article/details/8598948里面有详细的介绍。
至此,一个简单的三角形绘制完毕。。。(参考 吴亚峰编著《android 3d游戏开发技术宝典》)