Android OpenGL ES(三)----编程框架(二)

简介: Android OpenGL ES(三)----编程框架(二)

5.把着色器一起链接进OpenGL的程序


既然我们已经加载并编译了一个顶点着色器和一个片段着色器,下一步就是把它们绑定在一起放入一个单个的程序里。


5.1理解OpenGL的程序:


简单来说,一个OpenGL程序就是把一个顶点着色器和一个片段着色器链接在一起变成单个对象。顶点着色器和片段着色器总是一起工作的。没有片段着色器,OpenGL就不知道怎么绘制那些组成的每个点,直线和三角形片段;如果没有顶点着色器,OpenGL就不知道在哪里绘制这些片段。


虽然顶点着色器和片段着色器总是要一起工作的,但并不意味着它们必须是一对一匹配的,我们可以同时在多个程序中使用同一个着色器。


让我们打开ShaderHelper,并在类的末尾加入如下代码:

public static int linkProgram(int vertexShaderId, int fragmentShaderId) {


下面我们将构建这个方法。


新建程序并附着上着色器,我们要做的第一件事就是调用glCreateProgram()新建程序对象,并把那个对象的ID存进programObjectId。如下:

final int programObjectId = GLES20.glCreateProgram();
         if (programObjectId == 0) {
             if (LoggerConfig.ON) {
                 Log.w(TAG, "Could not create new Program");
             }
             return 0;
         }


和上面的代码类似就不过多的解释了,下一步就是附上着色器:

GLES20.glAttachShader(programObjectId, vertexShaderId);
         GLES20.glAttachShader(programObjectId, fragmentShaderId);

使用glAttachShader()方法把顶点着色器和片段着色器附加到程序对象上。


5.2链接程序


现在准备把这些着色器联合起来了,为此,将调用

glLickProgram(programObjectId):
GLES20.glLinkProgram(programObjectId);


为了检查这个链接是成功还是失败,我们遵循编译着色器时所使用的步骤:

final int[] linkStatus = new int[1];
         GLES20.glGetProgramiv(programObjectId, GLES20.GL_LINK_STATUS, linkStatus, 0);


最后验证链接状态并返回程序对象ID,代码如下:

if (linkStatus[0]==0) {
             GLES20.glDeleteProgram(programObjectId);
             if(LoggerConfig.ON){
                 Log.w(TAG,"linking of program failed");
             }
             return 0;
         }
         return programObjectId;


给渲染类LYJRenderer加入代码,先定义成员变量:

private int program;


然后在onSurfaceCreated()结尾处加入如下代码把着色器链接起来:

program = ShaderHelper.linkProgram(vertexShader, fragmentShader);


6.最后的拼接


6.1验证OpenGL程序的对象


在开始使用OpenGL的程序之前,我们首先应该验证一下它,看看这个程序对于当前的OpenGL状态是不是有效的。根据OpenGL ES2.0的文档,它也给OpenGL提供了一种方法让我们知道为什么当前程序可能是低效率的,无法运行的,等等。



让我们在ShaderHelper加入如下代码:

public static boolean validateProgram(int programObjectId){
         GLES20.glValidateProgram(programObjectId);
         final int[] validateStatus=new int[1];
         GLES20.glGetProgramiv(programObjectId,GLES20.GL_VALIDATE_STATUS,validateStatus,0);
         Log.v(TAG,GLES20.glGetProgramInfoLog(programObjectId));
         return validateStatus[0]!=0;
     }


这段代码与上面验证类似就不过多的阐述了,然后在onSurfaceView()结尾处加入如下代码:

ShaderHelper.validateProgram(program);


然后调用glUseProgram(program);


调用glUseProgram()告诉OpenGL在绘制任何东西到屏幕上的时候要使用这个定义的程序。


获取属性的位置


在使用属性之前我们要获取它们的位置。我们可以让OpenGL自动给这些属性分配位置编号,或者在着色器被链接到一起之前,可以通过调用glBindAttrribLocation()由我们自己给它们分配位置编号。我们要让OpenGL自动分配这些位置,因为它使代码容易管理。


在LYJRenderer顶部加入如下定义:

private static final String A_POSITION="a_Position";
private int aPositionLocation;
private static final int POSITION_COMPONENT_COUNT = 2;


一旦着色器被链接起来了,我们就只需要加入一些代码去获取属性位置。在onSurfaceCreated() 结尾处加入如下代码:

this.aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);


调用glGetAttribLocation()获取属性的位置。 有了这个位置,就能告诉OpenGL到哪里去找到这个属性对应的数据了。


6.2关联属性与顶点数据的数组


下一部就是要告诉OpenGL到哪里找到属性a_Position对应的数据。

this.vertexData.position(0);
         GLES20.glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, this.vertexData);


在我们告诉OpenGL从这个缓冲区中读取数据之前,需要确保它会从开头处开始读取数据,而不是中间或者结尾处。每个缓冲区都有一个内部指针,可以通过调用position(int)移动它,并且当OpenGL从缓冲区读取时,它会从这个位置开始读取。


下面是参数的解析:


aPositionLocation:这个是属性位置。


POSITION_COMPONENT_COUNT:这个属性有多少分量


GLES20.GL_FLOAT:这是数据的类型


false:只有使用整型数组时候,这个数据才有意义。


STRIDE:多于一个属性时候,就要告诉取下个数据要跳过多少分量。


vertexData:这个参数告诉OpenGL去哪里读取数据。


尽管我们已经把数据属性链接起来了,在开始绘制之前,我们还需要调用glEnableVertexAttribArray()使用这个属性。代码如下:

GLES20.glEnableVertexAttribArray(aPositionLocation);

同理颜色分量的代码如下:

private static final int COLOR_COMPONENT_COUNT=3;
private static final String A_COLOR = "a_Color";
     private int aColorLocation;
private static final int STRIDE=(POSITION_COMPONENT_COUNT+COLOR_COMPONENT_COUNT)*BYTES_PER_FLOAT;
this.vertexData.position(POSITION_COMPONENT_COUNT);
        GLES20.glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, this.vertexData);
        GLES20.glEnableVertexAttribArray(aColorLocation);


7.在屏幕上绘制


在onDrawFrame() 方法的结尾添加如下代码:

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
         GLES20.glDrawArrays(GLES20.GL_LINES, 6, 2);
         GLES20.glDrawArrays(GLES20.GL_POINTS, 8, 1);
         GLES20.glDrawArrays(GLES20.GL_POINTS, 9, 1);


第一个语句告诉OpenGL绘制三角扇形,什么是三角扇形后面讲解,第二个语句告诉OpenGL绘制直线,第三,四条语句告诉OpenGL绘制点。


这七个步骤就是开发OpenGL程序的基本流程。如图

7.png

相关文章
|
1月前
|
Ubuntu 网络协议 Java
【Android平板编程】远程Ubuntu服务器code-server编程写代码
【Android平板编程】远程Ubuntu服务器code-server编程写代码
|
19天前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
21 1
Android开发之使用OpenGL实现翻书动画
|
19天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
15 1
Android开发之OpenGL的画笔工具GL10
|
1月前
|
Ubuntu 网络协议 Java
在Android平板上使用code-server公网远程Ubuntu服务器编程
在Android平板上使用code-server公网远程Ubuntu服务器编程
|
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
|
7月前
|
Android开发
Android获取已连接wifi的热点信息(上位机开发学习之多个界面切换编程)
Android获取已连接wifi的热点信息(上位机开发学习之多个界面切换编程)
188 0
|
8月前
|
IDE Java 开发工具
在Android Studio中进行JNI编程
在Android Studio中进行JNI编程
|
12月前
|
缓存 监控 Linux
Android C++系列:Linux Socket编程(四)多路IO转接服务器
select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开 的文件描述符个数并不能改变select监听文件个数
94 0