Android OpenGL 使用

简介: 基本框架编写一个类来继承GLSurfaceView.Renderer,并实现其中的三个方法onSurfaceCreated、onSurfaceChanged、onDrawFrame。
  1. 基本框架
    编写一个类来继承GLSurfaceView.Renderer,并实现其中的三个方法onSurfaceCreated、onSurfaceChanged、onDrawFrame。

/**
 * 基本框架
 * Created by mazaiting on 2017/8/9.
 */
public class GLRenderer implements GLSurfaceView.Renderer {

  /**
   * 在窗口被创建时被调用,需要做一些必要的初始化工作:
   */
  @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    // 启动阴影平滑
    gl.glShadeModel(GL10.GL_SMOOTH);
    // 黑色背景,设置清楚屏幕时所用的颜色取值:RGBA.0f-1.0f
    gl.glClearColor(0, 0, 0, 1.0f);
    // 设置深度缓存--决定哪个物体先画
    gl.glClearDepthf(1.0f);
    // 启动深度测试
    gl.glEnable(GL10.GL_DEPTH_TEST);
    // 所作深度测试的类型
    gl.glDepthFunc(GL10.GL_LEQUAL);
    // 告诉系统对透视进行修正
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
  }

  /**
   * 当窗口大小发生改变时被调用,不管窗口的大小是否已经改变,在程序开始时至少运行一次。
   */
  @Override public void onSurfaceChanged(GL10 gl, int width, int height) {
    float ratio = (float) width / height;
    // 设置OpenGL场景的大小
    gl.glViewport(0, 0, width, height);
    // 设置投影矩阵--增加透视
    gl.glMatrixMode(GL10.GL_PROJECTION);
    // 重置投影矩阵--恢复原始状态
    gl.glLoadIdentity();
    // 设置视图的大小
    gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    // 选择模型观察矩阵
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    // 重置模型观察矩阵
    gl.glLoadIdentity();
  }

  /**
   * 在窗口内进行绘图操作。 在绘图之前,需要将屏幕清楚成前面指定的颜色,清楚深度缓存并且重置场景
   */
  @Override public void onDrawFrame(GL10 gl) {
    // 清楚屏幕和深度缓存
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    // 重置当前的模型观察矩阵
    gl.glLoadIdentity();
    // 具体绘图开始...

  }

  /**
     * OpenGL 是一个非常底层的画图接口,它所使用的缓冲区存储结构是和我们的 java 程序中不相同的。
     * Java 是大端字节序(BigEdian),而 OpenGL 所需要的数据是小端字节序(LittleEdian)。
     * 所以,我们在将 Java 的缓冲区转化为 OpenGL 可用的缓冲区时需要作一些工作。建立buff的方法如下
     **/
  public Buffer bufferUtil(int []arr){
    // 先初始化buffer,数组的长度*4,因为一个int占4个字节
    ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
    // 数组排列用nativeOrder
    qbb.order(ByteOrder.nativeOrder());
    // 将ByteBuffer转换为IntBuffer
    IntBuffer mBuffer = qbb.asIntBuffer();
    // 将数组设置进去
    mBuffer.put(arr);
    //mBuffer.position(0);
    // 重置
    mBuffer.flip();
    return mBuffer;
  }
}

其中都是一些具体的配置,在主Activity中,我们首先创建出一个GLRenderer对象 ,并创建GLSurfaceView对象,将GLRenderer对象设置在GLSurfaceView对象中。、


public class MainActivity extends AppCompatActivity {

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 基础框架
    GLSurfaceView.Renderer renderer = new GLRenderer();
    GLSurfaceView glView = new GLSurfaceView(this);
    glView.setRenderer(renderer);
    // 设置布局
    setContentView(glView);
  }
}

至此,我们将OpenGL开发时所要做的配置已完成,接下来我们在写新的Renderer时,只需要继承在GLRenderer,重写onDrawFrame(GL10 gl)方法即可。

  1. 绘制多边形
    实现此类后,要想看到效果,务必将主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();的此行代码更改为GLSurfaceView.Renderer renderer = new PolygonRenderer();
/**
 * 绘制多边形
 * Created by mazaiting on 2017/8/9.
 */
public class PolygonRenderer extends GLRenderer{
  int one = 0x00010000;
  //三角形三个顶点
  private int[] triggerBuffer = new int[] {
      0, one, 0,//上顶点
      - one, -one, 0, //左下点
      one, -one, 0,}; //右下点

  //正方形的4个顶点
  private int[] quaterBuffer = new int[]{
      one,one,0,
      -one,one,0,
      one,-one,0,
      -one,-one,0};

  @Override public void onDrawFrame(GL10 gl) {
    super.onDrawFrame(gl);
    // 此函数,就是将画笔沿X轴左移1.5f个单位,Y轴保持不变,Z轴向屏幕里面移动6.0f个单位。
    //gl.glTranslatef(-1.5f, 0.0f, -6.0f);
    // 左移 1.5 单位,并移入屏幕 6.0
    gl.glTranslatef(-1.5f, 0.0f, -6.0f);// z 轴值小于-1.0f
    // 允许设置顶点
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    // 设置三角形
    gl.glVertexPointer(3, GL10.GL_FIXED, 0, bufferUtil(triggerBuffer));
    // 绘制三角形
    gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);

    // 重置当前模型观察矩阵
    gl.glLoadIdentity();
    // 右移 1.5 单位,并移入屏幕 6.0
    gl.glTranslatef(1.5f, 0.0f, -6.0f);// z 轴值小于-1.0f
    // 设置四边形
    gl.glVertexPointer(3,GL10.GL_FIXED,0,bufferUtil(quaterBuffer));
    // 绘制四边形
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
    //取消顶点设置
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    // 重置当前的模型观察矩阵
    gl.glLoadIdentity();
  }
}

效果图:

img_775b4b30458b4c38a4405be7a37d6c4e.png
绘制多边形.png
  1. 绘制颜色
    实现此类后,要想看到效果,务必将主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();的此行代码更改为GLSurfaceView.Renderer renderer = new ColorRenderer();
/**
 * 绘制颜色
 * Created by mazaiting on 2017/8/9.
 */
public class ColorRenderer extends GLRenderer {
  int one = 0x10000;
  //三角形三个顶点 (r,g,b,a)
  private int[] triggerBuffer = new int[] {
      0, one, 0,//上顶点
      - one, -one, 0, //左下点
      one, -one, 0,}; //右下点

  //正方形的4个顶点
  private int[] quaterBuffer = new int[]{
      one,one,0,
      -one,one,0,
      one,-one,0,
      -one,-one,0};
  //三角形的顶点颜色值(r,g,b,a)
  private int[] colorBuffer = new int[]{
      one,0,0,one,
      0,one,0,one,
      0,0,one,one,
      };

  @Override public void onDrawFrame(GL10 gl) {
    super.onDrawFrame(gl);
    // 左移 1.5 单位,并移入屏幕 6.0
    gl.glTranslatef(-1.5f,0.0f,-6.0f);
    //设置定点数组
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    //设置颜色数组 -- 开启颜色渲染功能.
    gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
    // 设置三角形顶点的颜色
    gl.glColorPointer(4,GL10.GL_FIXED,0,bufferUtil(colorBuffer));
    // 设置三角形顶点
    gl.glVertexPointer(3,GL10.GL_FIXED,0,bufferUtil(triggerBuffer));
    gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);
    //关闭颜色数组 -- 关闭颜色渲染功能.
    gl.glDisableClientState(GL10.GL_COLOR_ARRAY);

    gl.glLoadIdentity();
    // 右移 1.5 单位,并移入屏幕 6.0
    gl.glTranslatef(1.5f,0.0f,-6.0f);
    // 设置当前色为蓝色
    gl.glColor4f(0.0f,0.5f,1.0f,1.0f);
    //设置和绘制正方形
    gl.glVertexPointer(3,GL10.GL_FIXED,0,bufferUtil(quaterBuffer));
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
    //取消顶点数组
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
  }
}

效果图:

img_4d432058869b2a2f70afc256c1bab1c4.png
绘制颜色.png
  1. 绘制旋转
    实现此类后,要想看到效果,务必将主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();的此行代码更改为GLSurfaceView.Renderer renderer = new RotateRenderer();
/**
 * 绘制旋转图形
 * Created by mazaiting on 2017/8/9.
 */
public class RotateRenderer extends GLRenderer {
  int one = 0x00010000;
  //三角形三个顶点
  private int[] triggerBuffer = new int[] {
      0, one, 0,//上顶点
      - one, -one, 0, //左下点
      one, -one, 0,}; //右下点

  @Override public void onDrawFrame(GL10 gl) {
    super.onDrawFrame(gl);

    gl.glTranslatef(-1.5f,0.0f,-6.0f);
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glRotatef(180f,0,0,0);//旋转180
    gl.glVertexPointer(3,GL10.GL_FIXED,0,bufferUtil(triggerBuffer));
    gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glLoadIdentity();
  }
}

效果图:

img_c0b4792432a1299ea951075432a8062d.png
绘制旋转.png
  1. 绘制三棱锥
    实现此类后,要想看到效果,务必将主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();的此行代码更改为GLSurfaceView.Renderer renderer = new PyramidRenderer();
/**
 * 四棱锥
 * Created by mazaiting on 2017/8/9.
 */

public class PyramidRenderer extends GLRenderer {
  int one = 0x10000;

  // 四棱锥顶点数组:
  private int[] triggerBuffer = new int[] {
      0, one, 0,
      -one, -one, one,
      one, -one, one,

      0,one, 0,
      one,-one, one,
      one, -one, -one,

      0, one, 0,
      one, -one, -one,
      -one, -one, -one,

      0, one, 0,
      -one, -one, -one,
      -one, -one, one
  };

  /**
   * Every vertex has got its own color, described by 4 values
   * R(ed)
   * G(green)
   * B(blue)
   * A(lpha)
   */
  int colors[] = {
      0, 0, 0, one, one, 0, 0, one, one, one, 0, one, 0, one, 0, one, 0, 0, one, one, one, 0, one,
      one, one, one, one, one, 0, one, one, one,
  };

  /**
   * The last thing is that we need to describe some Triangles.
   * A triangle got 3 vertices.
   * The confusing thing is, that it is important in which order
   * the vertices of each triangle are described.
   * So describing a triangle through the vertices: "0, 4, 5"
   * will not result in the same triangle as: "0, 5, 4"
   * You probably ask: Why the hell isn't that the same ???
   * The reason for that is the call of: "gl.glFrontFace(gl.GL_CW);"
   * which means, that we have to describe the "visible" side of the
   * triangles by naming its vertices in a ClockWise order!
   * From the other side, the triangle will be 100% lookthru!
   * You can create a kind of magic mirror with that
   **/
  byte indices[] = {
      0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 3, 7, 4, 3, 4, 0, 4, 7, 6, 4, 6, 5, 3,
      0, 1, 3, 1, 2
  };

  @Override public void onSurfaceChanged(GL10 gl, int width, int height) {
    super.onSurfaceChanged(gl, width, height);
    // 设置透视范围
    GLU.gluPerspective(gl, 45.0f, ((float) width) / height, 0.1f, 10f);
  }
  float xRot = 0.0f;
  float yRot = 0.0f;
  @Override public void onDrawFrame(GL10 gl) {
    super.onDrawFrame(gl);
    gl.glMatrixMode(GL10.GL_MODELVIEW);// 切换至模型观察矩阵
    gl.glLoadIdentity();// 重置当前的模型观察矩阵
    GLU.gluLookAt(gl, 0f, 0f, 3f, 0f, 0f, 0f, 0f, 1f, 0f);//设置视点和模型中心位置

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(3, GL10.GL_FIXED, 0, bufferUtil(triggerBuffer));
    gl.glRotatef(xRot,1f,0f,0f);// 绕着(0,0,0)与(1,0,0)即x轴旋转
    gl.glRotatef(yRot,0f,1f,0f);

    gl.glColor4f(1.0f,0.0f,0.0f,1.0f);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
    gl.glColor4f(0.0f,1.0f,0.0f,1.0f);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 3, 3);
    gl.glColor4f(0.0f,0.0f,1.0f,1.0f);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 6, 3);
    gl.glColor4f(1.0f,0.0f,1.0f,1.0f);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 9, 3);

    xRot += 1.0f;
    yRot += 0.5f;
  }
}

效果图:

img_a6c909907850409e4c9620604727b794.png
三棱锥.png
  1. 绘制正方体
    实现此类后,要想看到效果,务必将主AcitivityGLSurfaceView.Renderer renderer = new GLRenderer();的此行代码更改为GLSurfaceView.Renderer renderer = new CubeRenderer();

/**
 * 绘制正方体
 * Created by mazaiting on 2017/8/10.
 */
public class CubeRenderer extends GLRenderer{

  float box[] = new float[] {
      // FRONT
      -0.5f, -0.5f,  0.5f,
      0.5f, -0.5f,  0.5f,
      -0.5f,  0.5f,  0.5f,
      0.5f,  0.5f,  0.5f,
      // BACK
      -0.5f, -0.5f, -0.5f,
      -0.5f,  0.5f, -0.5f,
      0.5f, -0.5f, -0.5f,
      0.5f,  0.5f, -0.5f,
      // LEFT
      -0.5f, -0.5f,  0.5f,
      -0.5f,  0.5f,  0.5f,
      -0.5f, -0.5f, -0.5f,
      -0.5f,  0.5f, -0.5f,
      // RIGHT
      0.5f, -0.5f, -0.5f,
      0.5f,  0.5f, -0.5f,
      0.5f, -0.5f,  0.5f,
      0.5f,  0.5f,  0.5f,
      // TOP
      -0.5f,  0.5f,  0.5f,
      0.5f,  0.5f,  0.5f,
      -0.5f,  0.5f, -0.5f,
      0.5f,  0.5f, -0.5f,
      // BOTTOM
      -0.5f, -0.5f,  0.5f,
      -0.5f, -0.5f, -0.5f,
      0.5f, -0.5f,  0.5f,
      0.5f, -0.5f, -0.5f,
  };

  FloatBuffer cubeBuff;
  float xRot = 0.0f;
  float yRot = 0.0f;

  public CubeRenderer(){
    cubeBuff = makeFloatBuffer(box);//转换为float数组
  }

  @Override public void onSurfaceChanged(GL10 gl, int width, int height) {
    super.onSurfaceChanged(gl, width, height);
    // 设置透视范围
    GLU.gluPerspective(gl,45.0f,((float)width)/height,0.1f,10f);
  }

  @Override public void onDrawFrame(GL10 gl) {
    super.onDrawFrame(gl);

    gl.glMatrixMode(GL10.GL_MODELVIEW);// 切换至模型观察矩阵
    gl.glLoadIdentity();// 重置当前的模型观察矩阵
    GLU.gluLookAt(gl,0f,0f,3f,0f,0f,0f,0f,1f,0f);//设置视点和模型中心位置

    gl.glVertexPointer(3,GL10.GL_FLOAT, 0,cubeBuff);//设置顶点数据
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

    gl.glRotatef(xRot,1f,0f,0f);// 绕着(0,0,0)与(1,0,0)即x轴旋转
    gl.glRotatef(yRot,0f,1f,0f);

    gl.glColor4f(1.0f,0f,0f,1.0f);//设置颜色,红色
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);//绘制正方形FRONT面
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,4,4);

    gl.glColor4f(0f,1.0f,0f,1.0f);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,8,4);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,12,4);

    gl.glColor4f(0f,0f,1.0f,1.0f);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,16,4);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,20,4);

    xRot += 1.0f;
    yRot += 0.5f;

  }

  /**
   * 将float数组转换为存储在字节缓冲数组
   * @param arr
   * @return
   */
  public FloatBuffer makeFloatBuffer(float[] arr){
    // 分配缓冲空间,一个float占4个字节
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(arr.length*4);
    // 设置字节顺序,其中ByteOrder.nativeOrder()是获取本机字节顺序
    byteBuffer.order(ByteOrder.nativeOrder());
    // 转换为float型
    FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
    // 添加数据
    floatBuffer.put(arr);
    // 设置数组的起始位置
    floatBuffer.position(0);
    return floatBuffer;
  }
}

效果图:

img_751577be3369967af28fc0b0fc2bf6a0.png
立方体.png
目录
相关文章
|
21天前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
23 1
Android开发之使用OpenGL实现翻书动画
|
21天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
18 1
Android开发之OpenGL的画笔工具GL10
|
4月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
51 0
|
4月前
|
XML 前端开发 Java
【Android App】三维处理中三维投影OpenGL功能的讲解及实战(附源码和演示 超详细必看)
【Android App】三维处理中三维投影OpenGL功能的讲解及实战(附源码和演示 超详细必看)
33 1
|
4月前
|
XML Java Android开发
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
37 1
|
Android开发
Android OpenGL例子学习
Android OpenGL例子学习
114 0
|
缓存 API Android开发
Android OpenGL添加纹理
Android OpenGL添加纹理
Android OpenGL添加纹理
|
API Android开发 C++
Android OpenGL添加光照和材料属性
Android OpenGL添加光照和材料属性
Android OpenGL添加光照和材料属性
|
Android开发 C++
Android OpenGL显示任意3D模型文件
Android OpenGL显示任意3D模型文件
Android OpenGL显示任意3D模型文件
|
存储 缓存 Java
Android OpenGL 显示基本图形及相关概念解读
Android OpenGL 显示基本图形及相关概念解读
Android OpenGL 显示基本图形及相关概念解读