OpenGL ES渲染管线概述(一)

渲染管线一般是由显示芯片GPU内部处理图形信号的并行处理单元组成,这些并行处理单元之间是独立的,从另一个角度看,渲染管线实际上也是一系列绘制过程,这一系列过程的输入是待绘制物体的相关描述信息,输出的是要显示的图像帧数据。

OpenGL ES管线主要包括:

读取顶点数据—>顶点着色器—>组装图元—>光栅化图元—>片元着色器—>写入帧缓冲区—>显示到屏幕上

  • 读取顶点数据指的是将待绘制的图形的顶点数据传递给渲染管线中。
  • 顶点着色器最终生成每个定点的最终位置,执行顶点的各种变换,它会针对每个顶点执行一次,确定了最终位置后,OpenGL就可以把这些顶点集合按照给定的参数类型组装成点,线或者三角形。
  • 组装图元阶段包括两部分:图元的组装和图元处理,图元组装指的是顶点数据根据设置的绘制方式参数结合成完整的图元,例如点绘制方式中每个图元就只包含一个点,线段绘制方式中每个图源包含两个点;图元处理主要是剪裁以使得图元位于视景体内部的部分传递到下一个步骤,视景体外部的部分进行剪裁。视景体的概念与投影有关。
  • 光栅化图元主要指的是将一个图元离散化成可显示的二维单元片段,这些小单元称为片元。一个片元对应了屏幕上的一个或多个像素,片元包括了位置,颜色,纹理坐标等信息,这些值是由图元的顶点信息进行插值计算得到的。
  • 片元着色器为每个片元生成最终的颜色,针对每个片元都会执行一次。一旦每个片元的颜色确定了,OpenGL就会把它们写入到帧缓冲区中。

在OpenGL ES2.0中主要的两个部分就是上面的可编程顶点着色器和片段着色器。学习OpenGL ES主要是要了解渲染管线,了解CPU的渲染过程,主要编程工作在于顶点着色器和片元着色器的编写。

绘制一个六边形

效果如图所示

六边形类

public class SixShape {
 private FloatBuffer mVertexBuffer;
 private FloatBuffer mColorBuffer;
 private int mProgram;
 private int mPositionHandle;
 private int mColorHandle;
 private int muMVPMatrixHandle;

 public SixShape(float r) {
  initVetexData(r);
 }

 public void initVetexData(float r) {
  // 初始化顶点坐标
  float[] vertexArray = new float[8*3];
  // 初始化顶点颜色
  float[] colorArray=new float[8*4];
  int j = 0, k = 0;
  vertexArray[j++] = 0;
  vertexArray[j++] = 0;
  vertexArray[j++] = 0;

  colorArray[k++] = 1;
  colorArray[k++] = 1;
  colorArray[k++] = 1;
  colorArray[k++] = 0;
  for (int angle = 0; angle <= 360; angle += 60) {
   vertexArray[j++] = (float) (r*Math.cos(Math.toRadians(angle)));
   vertexArray[j++] = (float) (r*Math.sin(Math.toRadians(angle)));
   vertexArray[j++] = 0;

   colorArray[k++] = 1;
   colorArray[k++] = 0;
   colorArray[k++] = 0;
   colorArray[k++] = 0;
  }
  ByteBuffer buffer = ByteBuffer.allocateDirect(vertexArray.length * 4);
  buffer.order(ByteOrder.nativeOrder());
  mVertexBuffer = buffer.asFloatBuffer();
  mVertexBuffer.put(vertexArray);
  mVertexBuffer.position(0);

  ByteBuffer cbb=ByteBuffer.allocateDirect(colorArray.length*4);
  cbb.order(ByteOrder.nativeOrder());
  mColorBuffer=cbb.asFloatBuffer();
  mColorBuffer.put(colorArray);
  mColorBuffer.position(0);

  int vertexShader = loaderShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
  int fragmentShader = loaderShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

  mProgram = GLES20.glCreateProgram();
  GLES20.glAttachShader(mProgram, vertexShader);
  GLES20.glAttachShader(mProgram, fragmentShader);
  GLES20.glLinkProgram(mProgram);

  mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
  mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
  muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
 }

 public void draw(float[] mvpMatrix) {
  GLES20.glUseProgram(mProgram);
  // 将顶点数据传递到管线,顶点着色器
  GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer);
  // 将顶点颜色传递到管线,顶点着色器
  GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false,4*4, mColorBuffer);
  // 将变换矩阵传递到管线
  GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mvpMatrix, 0);
  GLES20.glEnableVertexAttribArray(mPositionHandle);
  GLES20.glEnableVertexAttribArray(mColorHandle);
  // 绘制图元
  GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 8);
 }

 private int loaderShader(int type, String shaderCode) {
  int shader = GLES20.glCreateShader(type);
  GLES20.glShaderSource(shader, shaderCode);
  GLES20.glCompileShader(shader);
  return shader;
 }

 private String vertexShaderCode = "uniform mat4 uMVPMatrix;"
   + "attribute vec3 aPosition;"
   + "attribute vec4 aColor;"
   + "varying vec4 aaColor;"
   + "void main(){"
   + "gl_Position = uMVPMatrix * vec4(aPosition,1);"
   + "aaColor = aColor;"
   + "}";

 private String fragmentShaderCode = "precision mediump float;"
   + "varying vec4 aaColor;"
   + "void main(){"
   + "gl_FragColor = aaColor;"
   + "}";

}

六边形View

public class SixView extends GLSurfaceView{

 public SixView(Context context) {
  super(context);
  setEGLContextClientVersion(2);
  setRenderer(new MyRender());
 }

 class MyRender implements GLSurfaceView.Renderer {
  private SixShape circle;

  @Override
  public void onSurfaceCreated(GL10 gl, EGLConfig config) {
   GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1);
   circle = new SixShape(0.5f);
   GLES20.glEnable(GLES20.GL_DEPTH_TEST);
  }

  // 投影矩阵
  private final float[] mProjectionMatrix = new float[16];
  // 视图矩阵
  private final float[] mViewMatrix = new float[16];
  // 模型矩阵
  private final float[] mMMatrix = new float[16];
  private final float[] mViewProjectionMatrix = new float[16];
  private final float[] mMVPMatrix = new float[16];

  @Override
  public void onSurfaceChanged(GL10 gl, int width, int height) {
   GLES20.glViewport(0, 0, width, height);
   float ratio= (float) width / height;
   // 设置正交投影
   Matrix.orthoM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 0, 5);
   // 设置视图矩阵
   Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0);
  }

  @Override
  public void onDrawFrame(GL10 gl) {
   GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
   Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
   // 设置模型矩阵
   Matrix.setIdentityM(mMMatrix, 0);
   Matrix.translateM(mMMatrix,0,0,0,1);
   Matrix.rotateM(mMMatrix, 0, 30, 0, 0, 1);
   Matrix.multiplyMM(mMVPMatrix, 0, mViewProjectionMatrix, 0, mMMatrix, 0);
   circle.draw(mMVPMatrix);
  }
 }

}

接下来在Activity中就可以使用这个View了。上面的例子虽然简单,但是包括了使用OpenGL ES编程的主要流程,包括生成顶点数据,编写顶点着色器,片元着色器,传递数据给顶点/片元着色器,这里最主要的就是着色器语言。此外包括投影,平移,旋转等操作。在后面会详细学习每个细节以及上面例子没有涉及到的光照,纹理等OpenGL的知识。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • OpenGL ES纹理详解

    使用前面学过的技术已经可以利用OpenGL ES构建立体图形,并通过顶点着色器和片元着色器对其进行各种变化呢和光照等效果使得三维效果更加真实,实际上我看看到很多的3D游戏漂亮多了,那是因为有各种各样的漂亮的图像带给人很多视觉盛宴,这篇文章在前面的基础上,增加物体的表面贴图,使得物体更加好看. 纹理概念 纹理用来表示图像照片或者说一系列的数据,使用纹理可以使物体用用更多的细节.OpenGL ES 2.0 中有两种贴图:二维纹理和立方体纹理. 每个二维纹理都由许多小的纹理元素组成,类似与片元和像素,

  • SDL2和OpenGL使用踩坑笔记经验分享

    SDL + OpenGL使用笔记 LFTK 是一个嵌入式GUI,为了开发方便,需要提供PC运行环境.我选择了SDL2+OpenGL+nanovg来实现底层的渲染,让LFTK可以运行在各个平台上.GLFW+OpenGL也是一个不错的选择,但是GLFW没有Android和iOS的移植,而且没有提供原生输入法的支持.LFTK虽然最初是为嵌入式系统而生,但也有一个小目标:可以用于开发嵌入式系统,也可以开发PC软件和移动APP,所以最后选择了SDL2+OpenGL+nanovg.在使用SDL2+OpenG

  • opengl实现任意两点间画圆柱体

    本文实例为大家分享了opengl实现任意两点间画圆柱体的具体代码,供大家参考,具体内容如下 1.问题提出 两点间画线简单: glBegin(GL_LINES);  //注意是LINES不是LINE,这个错误一定要注意. glVertexf(x1, y1, z1); glVertexf(x2, y2, z2); glEnd(); 画线函数不会影响opengl的矩阵堆栈. 但是很多时候线条效果会比较差,比如我要做一个骨骼动画,关节点间的骨头用线条太难看,即使使用glLineWidth设置线宽,视觉效

  • android使用OPENGL ES绘制圆柱体

    本文实例为大家分享了android使用OPENGL ES绘制圆柱体的具体代码,供大家参考,具体内容如下 效果图: 编写jiem.java *指定屏幕所要显示的假面,并对见.界面进行相关设置     *为Activity设置恢复处理,当Acitvity恢复设置时显示界面同样应该恢复     *当Activity暂停设置时,显示界面同样应该暂停 package com.scout.eeeeeee; import android.app.Activity; import android.os.Bund

  • OpenGL关于glStencilFuncSeparate()和glStencilFunc()函数的区别讲解

    glStencilFunc()函数是OpenGL提供的对模板缓冲区进行控制的命令,这是OpenGL2.0之前使用的函数,其函数原型为 void glStencilFunc(GLenum func, GLint ref, GLuint mask). func指定比较函数,它指定了测试通过的条件,其取值可以是:(为方便表示,参考值为refValue, 缓冲区值bufferValue) GL_NEVER                        总是不通过测试 GL_ALWAYS        

  • Android利用OpenGLES绘制天空盒实例教程

    前言 天空盒这个效果最早是在腾讯的实景地图里看到的,当时觉得很牛逼,但是没有想过自己去实现以下.最近这段时间对opengl很有兴趣,顺便就搞了这个天空盒,话不多说,先上效果. 天空盒的原理就是在三维空间中放置一个正方体,然后将我们的相机放置在正方体内,当我们的视点转动,相机跟着转动.我们就可以看到相应的景色的变换了,天空盒本质上是一个立方体. OpenGL 关于什么是OpenGL,什么是OpenGLES就不细说了,不了解的就自行百度吧,我们主要是关注代码.整个项目采用了Kotlin + Ndk的

  • OpenGL ES透视投影实现方法(四)

    在之前的学习中,我们知道了一个顶点要想显示到屏幕上,它的x.y.z分量都要在[-1,1]之间,我们回顾一下渲染管线的图元装配阶段,它实际上做了以下几件事:剪裁坐标.透视分割.视口变换.图元装配的输入是顶点着色器的输出,抓哟是物体坐标gl_Position,之后到光栅化阶段. 图元装配 剪裁坐标 当顶点着色器写入一个值到gl_Position时,这个点要求必须在剪裁空间中,即它的x.y.z坐标必须在[-w,w]之间,任何这个范围之外的点都是不可见的. 这里需要注意以下,对于attribute类型的

  • OpenGL ES着色器使用详解(二)

    本文介绍了OpenGL ES着色器使用的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 1.着色器语言 着色器语言是一种高级图形编程语言,和C/C++语言很类似,但存在很大差别,比如,不支持double,byte ,short,不支持unin,enum,unsigned以及位运算等,但其加入了很多原生的数据类型,如向量,矩阵等. 数据类型可分为标量.向量.矩阵.采样器.结构体.数组等 向量 向量传递参数,如果只提供一个标量,这个值用于设置所有向量的值:如果输入是多个标量或者是矢量,从左到

  • OpenGL中的glutInitDisplayMode()函数的理解

    OpenGL中的glutInitDisplayMode()函数的作用主要是在创建窗口的时候,指定其显示模式的类型. 函数原型为:void glutInitDisplayMode(unsigned int mode); mode参数是一个GLUT库里预定义的可能的布尔组合.你使用mode去指定颜色模式,数量和缓冲区类型. 其中大部分情况下使用的参数为: GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL 颜色模式:GLUT_RGBA表示颜色模式,

  • OpenGL ES正交投影实现方法(三)

    本文实例为大家分享了OpenGL ES正交投影展示的具体代码,供大家参考,具体内容如下 绘制正方形 在最开始绘制的六边形里面好像看起来挺容易的,也没有出现什么问题,接下来不妨忘记前面绘制六边形的代码,让我们按照自己的理解来绘制一个简单的正方形. 按照我的理解,要想在屏幕中间显示一个正方形,效果如下图所示 应该创建的数据如下图所示 即传给渲染管线的顶点数据如下图: float[] vertexArray = new float[] { (float) -0.5, (float) -0.5, 0,

随机推荐