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)