本节我们继续来看一下《OPENGL ES 3.0编程指南 原书第2版(中文版)》书中第6章的内容,PDF下载地址:OPENGL ES 3.0编程指南 原书第2版(中文版),代码下载地址:Opengl ES Source Code。本书中第3、4、5章讲解的是Opengl ES着色器语言的语法知识,没有实例,不过这些语法也是我们掌握Opengl ES的硬功底,万丈高楼平地起,只有基础扎实,才能往上实现出更炫丽的效果。

第6章一共两个实例,分别对应代码中Example63Renderer、Example66Renderer两个类,先来看一下实现效果。

效果很简单,就是两个三角形。我们先来看一下Example63Renderer类,该小节主要讲的是通过Opengl ES 3.0的新语法指定顶点属性,然后通过API赋值,其他方法就不看了,主要是onDrawFrame方法,源码如下:

    public void onDrawFrame(GL10 glUnused) {// Set the viewportGLES30.glViewport(0, 0, mWidth, mHeight);// Clear the color bufferGLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);// Use the program objectGLES30.glUseProgram(mProgramObject);// Set the vertex color to redGLES30.glVertexAttrib4f(0, 1.0f, 0.0f, 0.0f, 1.0f);// Load the vertex position
//        mVertices.position(0);GLES30.glVertexAttribPointer(1, 3, GLES30.GL_FLOAT,false,0, mVertices);GLES30.glEnableVertexAttribArray(1);GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 3);GLES30.glDisableVertexAttribArray(1);}

该方法中主要有两句:GLES30.glVertexAttrib4f(0, 1.0f, 0.0f, 0.0f, 1.0f)、GLES30.glVertexAttribPointer(1, 3, GLES30.GL_FLOAT, false, 0, mVertices),这两句代码用来给着色器中的顶点数据赋值,第一个参数就是要赋值的目标对象的ID,为什么分别是0和1呢?上一节我们已经讲过,可以通过调用GLES30.glGetAttribLocation来获取顶点属性的ID值,这就是3.0的新语法,我们来看一下app\src\main\assets\chapter63目录下的顶点着色器,源码如下:

#version 300 es
layout(location = 0) in vec4 a_color;
layout(location = 1) in vec4 a_position;
out vec4 v_color;
void main()
{v_color = a_color;gl_Position = a_position;
}

第二行、第三行是通过location来定义a_color、a_position两个属性的,所以我们在Application中才可以通过0、1来给顶点属性赋值,其他的代码都基本相同,我们就不分析了。

继续看一下Example66Renderer,源码如下:

public class Example66Renderer implements GLSurfaceView.Renderer {private static final String TAG = Example66Renderer.class.getSimpleName();private Context mContext;///// Constructor//public Example66Renderer(Context context) {mContext = context;mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();mVertices.put(mVerticesData).position(0);mColors = ByteBuffer.allocateDirect(mColorData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();mColors.put(mColorData).position(0);mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2).order(ByteOrder.nativeOrder()).asShortBuffer();mIndices.put(mIndicesData).position(0);}///// Initialize the shader and program object//public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {String vShaderStr = ESShader.readShader(mContext, "chapter66/vertexShader.vert");String fShaderStr = ESShader.readShader(mContext, "chapter66/fragmentShader.frag");// Load the shaders and get a linked program objectmProgramObject = ESShader.loadProgram(vShaderStr, fShaderStr);mVBOIds[0] = 0;mVBOIds[1] = 0;mVBOIds[2] = 0;GLES30.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);}// /// Draw a triangle using the shader pair created in onSurfaceCreated()//public void onDrawFrame(GL10 glUnused) {// Set the viewportGLES30.glViewport(0, 0, mWidth, mHeight);// Clear the color bufferGLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);// Use the program objectGLES30.glUseProgram(mProgramObject);drawPrimitiveWithVBOs();}private void drawPrimitiveWithVBOs() {int numVertices = 3;int numIndices = 3;// mVBOIds[0] - used to store vertex position// mVBOIds[1] - used to store vertex color// mVBOIds[2] - used to store element indicesif (mVBOIds[0] == 0 && mVBOIds[1] == 0 && mVBOIds[2] == 0) {// Only allocate on the first drawGLES30.glGenBuffers(3, mVBOIds, 0);Log.e(TAG, "0: " + mVBOIds[0] + ", 1: " + mVBOIds[1] + ", 2: " + mVBOIds[2]);mVertices.position(0);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBOIds[0]);GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vtxStrides[0] * numVertices,mVertices, GLES30.GL_STATIC_DRAW);mColors.position(0);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBOIds[1]);GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vtxStrides[1] * 3,mColors, GLES30.GL_STATIC_DRAW);mIndices.position(0);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[2]);GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, 2 * numIndices,mIndices, GLES30.GL_STATIC_DRAW);}GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBOIds[0]);GLES30.glEnableVertexAttribArray(VERTEX_POS_INDX);GLES30.glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,GLES30.GL_FLOAT, false, vtxStrides[0], 0);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBOIds[1]);GLES30.glEnableVertexAttribArray(VERTEX_COLOR_INDX);GLES30.glVertexAttribPointer(VERTEX_COLOR_INDX, VERTEX_COLOR_SIZE,GLES30.GL_FLOAT, false, vtxStrides[1], 0);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, mVBOIds[2]);GLES30.glDrawElements(GLES30.GL_TRIANGLES, numIndices,GLES30.GL_UNSIGNED_SHORT, 0);GLES30.glDisableVertexAttribArray(VERTEX_POS_INDX);GLES30.glDisableVertexAttribArray(VERTEX_COLOR_INDX);GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0);}///// Handle surface changes//public void onSurfaceChanged(GL10 glUnused, int width, int height) {mWidth = width;mHeight = height;}// Handle to a program objectprivate int mProgramObject;// Additional member variablesprivate int mWidth;private int mHeight;private FloatBuffer mVertices;private FloatBuffer mColors;private ShortBuffer mIndices;// VertexBufferObject Idsprivate int[] mVBOIds = new int[3];// 3 vertices, with (x,y,z) ,(r, g, b, a) per-vertexprivate final float[] mVerticesData ={0.0f, 0.5f, 0.0f, // v0-0.5f, -0.5f, 0.0f, // v10.5f, -0.5f, 0.0f  // v2};private final short[] mIndicesData ={0, 1, 2};private final float[] mColorData ={1.0f, 0.0f, 0.0f, 1.0f,   // c00.0f, 1.0f, 0.0f, 1.0f,   // c10.0f, 0.0f, 1.0f, 1.0f    // c2};final int VERTEX_POS_SIZE = 3; // x, y and zfinal int VERTEX_COLOR_SIZE = 4; // r, g, b, and afinal int VERTEX_POS_INDX = 0;final int VERTEX_COLOR_INDX = 1;private int vtxStrides[] ={VERTEX_POS_SIZE * 4,VERTEX_COLOR_SIZE * 4};
}

先来看成员变量:mProgramObject表示编译链接完成的program id;mWidth、mHeight表示视窗口的宽度和高度;mVertices存储顶点位置数据;mColors存储顶点颜色数据;mIndices存储顶点的索引数据;mVBOIds存储顶点缓冲区分配到的ID值,因为我们要使用顶点缓冲区、颜色缓冲区、索引缓冲区三个,所以它的size为3;mVerticesData存储的三角形三个顶点的位置数据,v0(0.0f, 0.5f, 0.0f)位于Y轴正方向上0.5距离处,也就是最上面那个点,v1(-0.5f, -0.5f, 0.0f)位于X、Y轴都是负方向0.5距离处,就是数学上所说的第三象限,也就是左下角那个点,v2(0.5f, -0.5f, 0.0f)位于X轴正方向0.5距离、Y轴负方向0.5距离处,也就是第四象限,右下角那个点;mIndicesData存储索引数据,一共只有三个点,所以就只有0、1、2了,索引值我们在Opengl ES系列学习--增加地形一节已经详细讲解过了,如果还有疑问,请回头先搞清楚;mColorData存储了三个顶点的颜色值,分别是红、绿、蓝三元色,透明度全部为1,而所有中间的片段都是经过插值计算出来的,所以大家就会看到一个渐变过度的彩色三角形了,我们在Opengl ES系列学习--序一节中利用插值画了一个很简单的线条,也是用的这样的原理;VERTEX_POS_SIZE表示描述顶点位置需要3个size,分别对应X、Y、Z;VERTEX_COLOR_SIZE表示描述顶点颜色需要4个size,分别对应R、G、B、A;VERTEX_POS_INDX表示着色器中定义的顶点位置属性的ID值为0,我们后面看到顶点着色器的代码就可以看到了,不过总是感觉这样的方式不友好,代码可读性差,个人建议大家不要使用这样的方式;VERTEX_COLOR_INDX表示着色器中定义的顶点颜色属性的ID值为1,和上一个位置属性相同,都是在着色器程序中通过location关键字来指定的;vtxStrides定义了位置属性、颜色属性的跨距,这个我们应该已经非常熟悉了。

6-6小节主要讲解的就是如何使用顶点缓冲区,代码实现和Opengl ES系列学习--增加地形中的顶点缓冲区基本是一样的,主要就是在drawPrimitiveWithVBOs方法当中了,根据if (mVBOIds[0] == 0 && mVBOIds[1] == 0 && mVBOIds[2] == 0)判断条件,如果之前没有分配过,那就执行一次分配,分配时调用GLES30.glGenBuffers(3, mVBOIds, 0),分配成功的三个缓冲区ID会存储在mVBOIds数组当中,接下来调用GLES30.glBindBuffer、GLES30.glBufferData系统API给缓冲区填充数据就可以了,最后不要忘了调用GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)、GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, 0)分别解除绑定。

6-6小节的两个着色器程序和6-3完全相同,我们就不分析了,相信大家都能理解着色器的代码原理。

回头来总结一下,本节主要就是介绍如何使用缓冲区的概念来实现一个效果,缓冲区能很好的提高我们程序的执行效率,也是Opengl ES的基本操作,以后我们要实现什么效果的话,也要基于缓冲区来实现,而不要再使用顶点数组了,那样效率太低,而且浪费内存。使用的流程都是非常规范的API调用操作,也没有什么难度,大家直接照着复制就可以了。

好了,让我们继续开车!!

Opengl ES系列学习--顶点属性、顶点数组和缓冲区对象相关推荐

  1. OpenGL ES之离屏渲染的帧缓冲区对象FBO的说明和使用

    一.什么是 FBO ? FBO(Frame Buffer Object)即帧缓冲区对象,实际上是一个可添加缓冲区的容器,可以为其添加纹理或渲染缓冲区对象(RBO). FBO 本身不能用于渲染,只有添加 ...

  2. Opengl ES系列学习--顶点着色器

    本节我们继续来看一下<OPENGL ES 3.0编程指南 原书第2版(中文版)>书中第8章的内容,PDF下载地址:OPENGL ES 3.0编程指南 原书第2版(中文版),代码下载地址:O ...

  3. es6删除对象的属性_javascript - 按对象属性从数组中删除对象

    javascript - 按对象属性从数组中删除对象 var listToDelete = ['abc', 'efg']; var arrayOfObjects = [{id:'abc',name:' ...

  4. opengles 顶点数组 android,OpenGLES顶点属性、顶点数组和缓冲区对象

    顶点属性数据可以用一个顶点数组对每个顶点指定,也可以将一个常量值用于一个图元的所有顶点 OpenGLES支持最少16个顶点属性.准确查询顶点数量方法如下: GLint maxVertexAttribs ...

  5. Opengl ES系列学习--glViewport API使用

    去年有分析了一些Opengl ES的实例,但是后面在实际的工作中,发现根基不牢,工作中使用的一些复杂场景还是理解的不够透彻,所以回过心来,必须把基础把扎实.从这节开始,我们后面对一些非常基础普通的Op ...

  6. Opengl ES系列学习--颜色

    本节我们来学习一下颜色的知识,在看完原作者讲解的颜色的知识的基础上,只要我们理解了,应该就能提取出重点,其实本节的重点就是下面这一句话. 所以我们要作的就是计算出物体颜色和光源颜色,然后把它们两个相乘 ...

  7. Opengl ES系列学习--莫比乌斯带

    一个莫比乌斯带的shader,效果如下: Java类为GlMobiusRender,完整源码如下: package com.opengl.learn.aric;import android.conte ...

  8. Opengl ES系列学习--太阳

    继续积累Shadertoy,大家也可去Shader女神的CSDN逛逛:Shader女神.使用别人写好的shader实现的一个太阳的效果,太漂亮了!!! 该效果实现是GlSunRender类,完整源码如 ...

  9. android平台下OpenGL ES 3.0实例详解顶点属性、顶点数组

    OpenGL ES 3.0学习实践 android平台下OpenGL ES 3.0从零开始 android平台下OpenGL ES 3.0绘制纯色背景 android平台下OpenGL ES 3.0绘 ...

最新文章

  1. linux下vim编辑器的基本使用
  2. jquery点击页面其他位置隐藏div
  3. 你想被推荐系统毁掉么?
  4. mysql 复杂统计_MYSQL复杂查询
  5. 科技行业风投日趋谨慎:VR、机器学习和汽车值得关注
  6. html页面取js里面的值,如何在javascript中获取HTML元素的样式值?
  7. 在Silverlight+WCF中应用以角色为基础的安全模式(一)基础篇之角色为基础的安全模式简介...
  8. VT-x/AMD-V 硬件加速器已被启动,但当前处于无效状态
  9. SQL SERVER 中 GO 的用法2
  10. php 模板解析,关于模板的原理和解析
  11. window2008 64位系统无法调用Microsoft.Office.Interop组件进行文件另存的解决办法
  12. 2020各大网站rss订阅源地址_2020-20-18——DJANGO复习
  13. keycode值列表
  14. 【数据结构】八种常见数据结构介绍
  15. 【信息安全技术】期末复习考点汇总
  16. Android小知识- LayoutInflater
  17. 湿敏电阻HR202L使用记录
  18. 【古代文学论文】酒文化传播中唐代文学的作用分析(节选)
  19. Unity3D的3D音效的实现
  20. linux gem安装软件,安装gem报错

热门文章

  1. 工业机器人的特点有哪些
  2. 最小生成树-Prime
  3. AP1272 LDO 线性稳压IC 而压18V 电路原理图
  4. 实验二利用MATLAB工具箱对混杂噪声的音频信号进行滤波
  5. Kafka的 acks 的三种机制是什么?
  6. Oracle EBS MRP Forecast预测删除实例脚本
  7. Camera elements
  8. nodejs03中间件 -3 ejs consolidate router
  9. Java实现对局域网内PC的监控
  10. 如何打印计算机合格证,合格证打印机怎么安装