Android OpenGL ES 2.0绘制简单三角形
實現步驟
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游戲開發技術寶典》)
總結
以上是生活随笔為你收集整理的Android OpenGL ES 2.0绘制简单三角形的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关掉Ctrl+Alt+方向键转屏功能
- 下一篇: Java设计模式学习之工厂模式