当前位置: 首页 > news >正文

android数组的定义数组长度,Android OpenGLES3.0 入门教程(三)——顶点数组和统一变量...

上一章简单介绍了一下着色器的基础语法,复盘了一下第一章中讲到的两个着色器的代码。这一章主要讲述数据传递:Android 环境与顶点着色器的数据传递,顶点着色器与片元着色器的数据传递等。这篇文章还是以需求来驱动知识点的学习。

三个点

之前的demo,咱们是绘制了一个点。简单回顾一下这一个点的数据传递:

顶点着色器定义了一个顶点属性

通过顶点数组的赋值形式(glVertexAttribPointer)将点的坐标信息从Android环境传递到了顶点着色器

顶点着色器告诉OpenGL ES要绘制的点的位置

片元着色器告诉OpenGL ES绘制点的颜色(片元着色器中写死的色值)

通过上边四步,咱们就可以在手机屏幕上指定位置绘制一个指定颜色的点了。那么现在需求升级,咱们需要绘制三个点。

按着之前开发的思维惯性,很容易想到给顶点着色器定义三个顶点属性不就行了么。还真不行,在第一章中已经指出来了,顶点着色器只会负责一个顶点,也就是说不管你定义多少个顶点属性,用来控制OpenGL ES顶点位置的输出属性只有一个”gl_Position“

#version 300 es

layout (location = 0) in vec4 av_Position;

void main() {

gl_Position = av_Position;

gl_PointSize = 10.0;

}

也就是你定义100个av_Position,但最终只会有一个赋值给gl_Position。除非你把100个值同时赋予gl_Position让gl_Position处于一个100个状态的叠加态(手动狗头🐶)。

确定三个顶点位置的一步其实是告诉OpenGL ES你要绘制三个顶点,这个时候根据之前开发的思维惯性是不是觉得OpenGL ES应该有个setVertexCount的Api,哈 并没有。那么OpenGL ES是怎么确认顶点数量的呢,看回第一章的顶点属性赋值代码:

private val POSITION_VERTEX = floatArrayOf(

0.0f, 0.0f, 0.0f

)

init {

vertexBuffer = ByteBuffer.allocateDirect(POSITION_VERTEX.size * 4)

.order(ByteOrder.nativeOrder())

.asFloatBuffer()

.put(POSITION_VERTEX)

vertexBuffer.position(0)

}

GLES30.glVertexAttribPointer(avPosition, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer)

其实是把一个float数组按照指定规格赋值给了顶点属性avPosition,glVertexAttribPointer方法的参数中,avPosition代表了顶点属性的位置索引,第二参数”3"则是代表了赋值数组的长度,也就是把float数组POSITION_VERTEX中三个元素装成一个数组赋值给顶点属性四维向量avPosition。

这块其实就可以看出来一些问题的,我的POSITION_VERTEX数组就三个元素为什么还要指定传入的数组长度呢?盲生你发现了华点🤓🤓🤓🤓

其实这就是OpenGL ES指定顶点个数的方式。OpenGL ES的顶点数量=给顶点属性赋值的数组总长度/顶点属性需要的数组长度

上边代码的顶点数量就是POSITION_VERTEX.length/3 = 1,知道了这个三个点其实就很好画了,下边贴出关键代码

private val POSITION_VERTEX = floatArrayOf(

0.0f, 0.5f, 0.0f,

-0.25f, -0.25f, 0.0f,

0.25f, -0.25f, 0.0f

)

init {

vertexBuffer = ByteBuffer.allocateDirect(POSITION_VERTEX.size * 4)

.order(ByteOrder.nativeOrder())

.asFloatBuffer()

.put(POSITION_VERTEX)

vertexBuffer.position(0)

}

override fun onDrawFrame(gl: GL10?) {

GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)

GLES30.glUseProgram(pointProgram)

GLES30.glEnableVertexAttribArray(avPosition)

GLES30.glVertexAttribPointer(avPosition, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer)

GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3)

GLES30.glDisableVertexAttribArray(avPosition)

}

补充一下,GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3),这一句话并不是指明了OpenGL ES有三个顶点,而是指明了屏幕上要绘制三个点,这个三个点是OpenGL ES中前三个顶点。

看下手机绘制的效果

18618eacce46?utm_campaign=haruki

三个点.png

标题中的顶点数组指的就是POSITION_VERTEX这个用来指定顶点属性的关键数组。顶点数组的意义则是更加高效、快捷的指定顶点属性的值。

顶点数组指定每个顶点的属性,是保存在应用程序地址空间(OpenGL ES称为客户空间)的缓冲区。它们作为顶点缓冲对象的基础,提供指定顶点属性数据的一种高效、灵活的手段。顶点数组用glVertexAttribPointer或 glVertexAttribIPointer函数指定。

自定义点的颜色

现在咱们升级需求,画的点除了可以在Android层定义位置,咱们还要定义颜色。

在现有的代码中可以发现点的颜色时在片元着色器写死的,再次根据开发的思维惯性,有顶点属性,是不是也有片元属性,然后用片元数组赋值不就完了嘛!

18618eacce46?utm_campaign=haruki

yougedidi.jpg

哈,并没有片元属性,因为片元着色器的个数是不确定的。比如你画一个三角形,顶点三个,但是片元是三条线占用的像素数,最终生成多少个片元完全由OpenGL ES控制的。顶点数组的控制逻辑是需要明确顶点数量的,片元着色器显然不适用。

片元着色器的变量传递一般用使用顶点着色器的输出变量。还记得第二章中介绍的in 和out 两个修饰符吗,也就是将顶点着色器的一个变量用out修饰,片元着色器中一个变量用in修饰,且两个变量同名,这个时候顶点着色器的值就能传递到片元着色器来了。咱们的需求也就变成了将顶点的坐标和位置传入顶点着色器。

直接上代码,顶点着色器:

#version 300 es

layout (location = 0) in vec4 av_Position;

layout (location = 1) in vec4 point_Color;

out vec4 frag_point_Color;

void main() {

gl_Position = av_Position;

frag_point_Color = point_Color;

gl_PointSize = 10.0;

}

片元着色器

#version 300 es

precision mediump float;

out vec4 fragColor;

in vec4 frag_point_Color;

void main() {

fragColor = frag_point_Color;

}

可以看到顶点着色器其实是做了一个转发的操作,把通过顶点数组传下来的顶点属性用out修饰的frag_point_Color传到了片元着色器。这就是in 和 out 关键字的一个典型应用,只要记得in代表输入属性,out代表输出属性就可以了。然后再看kotlin代码

var pointProgram = -1

var vertexBuffer: FloatBuffer

var avPosition = -1

val POSITION_SIZE = 3

val COLOR_SIZE = 3

val VERTEX_ATTRIBUTES_SIZE = 4*(POSITION_SIZE+COLOR_SIZE)

private val POSITION_VERTEX = floatArrayOf(

0.0f, 0.5f, 0.0f, 0.0f, 0.1f, 1.0f,

-0.25f, -0.25f, 0.0f, 1.0f, 0.1f, 1.0f,

0.25f, -0.25f, 0.0f, 0.0f, 1.1f, 1.0f

)

init {

vertexBuffer = ByteBuffer.allocateDirect(POSITION_VERTEX.size * 4)

.order(ByteOrder.nativeOrder())

.asFloatBuffer()

.put(POSITION_VERTEX)

vertexBuffer.position(0)

}

override fun onDrawFrame(gl: GL10?) {

GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)

GLES30.glUseProgram(pointProgram)

GLES30.glEnableVertexAttribArray(avPosition)

GLES30.glEnableVertexAttribArray(1)

vertexBuffer.position(0)

GLES30.glVertexAttribPointer(0, POSITION_SIZE, GLES30.GL_FLOAT, false,VERTEX_ATTRIBUTES_SIZE, vertexBuffer)

vertexBuffer.position(3)

GLES30.glVertexAttribPointer(1, COLOR_SIZE, GLES30.GL_FLOAT, false, VERTEX_ATTRIBUTES_SIZE, vertexBuffer)

GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3)

GLES30.glDisableVertexAttribArray(0)

GLES30.glDisableVertexAttribArray(1)

}

override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {

GLES30.glViewport(0, 0, width, height)

}

override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {

pointProgram = ShaderUtil.loadProgramFromAssets(

"vertex_point_1.glsl",

"frag_point_1.glsl",

context.resources)

avPosition = GLES30.glGetAttribLocation(pointProgram, "av_Position")

}

这里的关注点主要在于怎样用一个数组给两个顶点属性赋值。

现在咱们要处理的数据是分别给三个顶点着色器的两个属性传输一组值,两个属性分别是位置和颜色,位置需要用一组三个元素的float数组标识(x,y,z),颜色也是一样的(r,g,b)。所以现在咱们把一个顶点着色器中的两组数组糅合成一组数组,也就是用一个6个元素的数组同时来标识位置和颜色。

18618eacce46?utm_campaign=haruki

array.png

所以生成了新的数组,每一行是一个顶点的数据,前三位代表点的位置,后三位是点的颜色

private val POSITION_VERTEX = floatArrayOf(

0.0f, 0.5f, 0.0f, 0.0f, 0.1f, 1.0f,

-0.25f, -0.25f, 0.0f, 1.0f, 0.1f, 1.0f,

0.25f, -0.25f, 0.0f, 0.0f, 1.1f, 1.0f

)

然后再看一下赋值的代码

vertexBuffer.position(0)

GLES30.glVertexAttribPointer(0, POSITION_SIZE, GLES30.GL_FLOAT, false, VERTEX_ATTRIBUTES_SIZE, vertexBuffer)

vertexBuffer.position(3)

GLES30.glVertexAttribPointer(1, COLOR_SIZE, GLES30.GL_FLOAT, false, VERTEX_ATTRIBUTES_SIZE, vertexBuffer)

这种混合数组的赋值方式,关键就是告诉OpenGL ES指定每个顶点着色器所占用的数据总长度,以及这组数据中哪段数据对应着那个属性。

结合上文对glVertexAttribPointer api的介绍,glVertexAttribPointer api中的第四个参数,就是用来描述顶点属性的总长度,也就是(三位位置数据+三位颜色数据)*(folat类型数据长度),告诉了OpenGL ES每组数据有六个元素,glVertexAttribPointer api的第二个参数,则表示了该顶点属性使用的数据个数(这里不用计算数据占位长度 ),vertexBuffer.position(0)这表示了赋值时数组的游标定位。

好了介绍完基础知识在翻译上面的代码:

游标定位到0

给索引位置0的顶点属性(av_Position)赋值,需要数据长度为3,一个顶点着色器需要的完整数据总长度为24字节(6个float类型)

OpenGL ES 就会从零个元素读起,把读到的前三个赋值给av_Position属性,然后跳过三个值,循环三次。

游标定位到3

给索引位置0的顶点属性(point_Color)赋值,需要数据长度为3,一个顶点着色器需要的完整数据总长度为24字节(6个float类型)

OpenGL ES 就会从第四个元素开始读,把读到的前三个赋值给point_Color属性,然后跳过三个值,循环三次。

这样就完成使用一个数组,给两个顶点属性赋值的过程。咱们现在看一下效果:

18618eacce46?utm_campaign=haruki

Screenshot_2020-09-17-16-55-32-1656217187.png

ok,三个不同颜色的点就完成了。这个时候可能有的同学会问了,一个数组赋值有点麻烦我使用文章最上边的那种指定属性值的方式,分别用两个数组给两个属性赋值不可以吗?当然可以。用一组数组指定所有属性的方式叫做结构数组,多个数组指定多个属性的方式叫做数组结构........🤢🤢🤢🤢🤢🤢

我们已经描述了两种最常用的顶点属性存储方法∶结构数组和数组结构。问题是,对于OpenGLES3.0硬件实现,哪种分配方法最高效?在大部分情况下,答案是结构数组(一个数组方式)。原因是,每个顶点的属性数据可以顺序方式读取,这最有可能造成高效的内存访问模式。使用结构数组的缺点在应用程序需要修改特定属性时变得很明显。如果顶点属性数据的一个子集需要修改(例如,纹理坐标),这将造成顶点缓冲区的跨距更新。当顶点缓冲区以缓冲区对象的形式提供时,需要重新加载整个顶点属性缓冲区。可以通过将动态的顶点属性保存在单独的缓冲区来避免这种效率低下的情况。

顶点缓冲区对象(VBO)

上边描述了如何用glVertexAttribPointer指定这3个顶点属性。注意,我们在此介绍如何使用客户端顶点数组,以便解释逐顶点数据指定的概念。我们建议应用程序使用顶点缓冲区对象,避免使用客户端顶点数组,以实现最佳性能。在OpenGL ES 3.0 中支持客户端顶点数组只是为了与OpenGLES 2.0兼容。在OpenGLES3.0中,总是建议使用顶点缓冲区对象。

使用顶点数组指定的顶点数据保存在客户内存中。在进行绘图调用时,这些数据必须从客户内存复制到图形内存。但是,如果我们没有必要在每次绘图调用时都复制顶点数据,而是在图形内存中缓存这些数据,那就好得多了。这种方法可以显著地改进渲染性能,也会降低内存带宽和电力消耗需求,对于移动设备相当重要。这是顶点缓冲区对象发挥作用的地方。顶点缓冲区对象使OpenGL ES 3.0应用程序可以在高性能的图形内存中分配和缓存顶点数据,并从这个内存进行渲染,从而避免在每次绘制图元的时候重新发送数据。不仅是顶点数据,描述图元顶点索引、作为 glDrawElements 参数传递的元素索引也可以缓存。

OpenGL ES 3.0支持两类缓冲区对象,用于指定顶点和图元数据∶数组缓冲区对象和元素数组缓冲区对象。GL_ARRAY_BUFFER标志指定的数组缓冲区对象用于创建保存顶点数据的缓冲区对象。GL_ELEMENT ARRAY BUFFER标志指定的元素数组缓冲区对象用于创建保存图元索引的缓冲区对象。

简单介绍一下数组缓冲区对象使用方式。

override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {

pointProgram = ShaderUtil.loadProgramFromAssets(

"vertex_point_1.glsl",

"frag_point_1.glsl",

context.resources

)

GLES30.glGenBuffers(1, vboIds, 0);

GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboIds[0])

GLES30.glBufferData(

GLES30.GL_ARRAY_BUFFER,

POSITION_VERTEX.size * 4,

vertexBuffer,

GLES30.GL_STATIC_DRAW

);

GLES30.glEnableVertexAttribArray(0);

GLES30.glVertexAttribPointer(0, POSITION_SIZE, GLES30.GL_FLOAT, false, LENGTH * 4, 0);

GLES30.glEnableVertexAttribArray(1);

GLES30.glVertexAttribPointer(1, POSITION_SIZE, GLES30.GL_FLOAT, false, LENGTH * 4, POSITION_SIZE*4);

}

override fun onDrawFrame(gl: GL10?) {

GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)

GLES30.glUseProgram(pointProgram)

GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3);

GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);

}

我们可以看到其实和顶点数组方式基本流程差不多,只不过是多了一个生成缓冲区对象,并绑定的流程。有一点需要注意的是glVertexAttribPointer api中最后一个参数变成了一个int型变量,他设置了缓冲区数据偏移量,作用和顶点数组的数组结构方式中的vertexBuffer.position(3) 效果是一样的。还有一个需要注意的是这个偏移量的单位是字节,也就是数据偏移量*数据类型所占字节数。

顶点数组对象(VAO)

除了顶点缓冲区对象,OPENGL ES还提供了一种性能更高的方式∶顶点数组对象(VAO)。

正如我们已经看到的,使用顶点缓冲区对象设置绘图操作可能需要多次调用glBindBuffr、glVertexAtribPointer和glEnableVertexAtribAray。为了更快地在顶点数组配置之间切换,OpenGL ES3.0推出了顶点数组对象。VAO提供包含在顶点数组/顶点缓冲区对象配置之间切换所需要的所有状态的单一对象。

实际上,OpenGL ES3.0中总是有一个活动的顶点数组对象。本章目前为止的所有例子都在默认的顶点数组对象上操作(默认VAO的ID为0)。要创建新的顶点数组对象,可以使用 glGen VertexArays 函数。

override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {

pointProgram = ShaderUtil.loadProgramFromAssets(

"vertex_point_1.glsl",

"frag_point_1.glsl",

context.resources

)

GLES30.glGenBuffers(1, vaoIds, 0);

GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vaoIds[0])

GLES30.glBufferData(

GLES30.GL_ARRAY_BUFFER,

POSITION_VERTEX.size * 4,

vertexBuffer,

GLES30.GL_STATIC_DRAW

);

GLES30.glGenVertexArrays(1, vaoIds, 0)

GLES30.glBindVertexArray(vaoIds[0])

GLES30.glGenBuffers(1, vboIds, 0)

GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboIds[0])

GLES30.glBufferData(

GLES30.GL_ARRAY_BUFFER,

POSITION_VERTEX.size * 4,

vertexBuffer,

GLES30.GL_STATIC_DRAW

)

GLES30.glEnableVertexAttribArray(0);

GLES30.glVertexAttribPointer(0, POSITION_SIZE, GLES30.GL_FLOAT, false, LENGTH * 4, 0);

GLES30.glEnableVertexAttribArray(1);

GLES30.glVertexAttribPointer(1, POSITION_SIZE, GLES30.GL_FLOAT, false, LENGTH * 4, POSITION_SIZE*4);

GLES30.glBindVertexArray(0)

}

override fun onDrawFrame(gl: GL10?) {

GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)

GLES30.glUseProgram(pointProgram)

GLES30.glBindVertexArray(vaoIds[0])

GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3)

GLES30.glBindVertexArray(0)

}

可以看到使用方式上和顶点缓冲区对象是十分相似的,只是又多了一个顶点数组对象。

常量顶点属性和统一变量

上文介绍了OPENGL ES中最常用的指定顶点数组属性的方式。现在呢咱们把上文的需求稍微再改变一下,现在不是绘制三个不同位置不同颜色的点了,而是三个不同位置相同颜色的点。是不是感觉需求变简单了,新的需求只是上文中需求的一种特殊情况。所以用上面说的任何一种方式都可以完成这个需求的。只不过是顶点数组的原始数据变化一下:

private val POSITION_VERTEX = floatArrayOf(

0.0f, 0.5f, 0.0f, 0.1f, 0.1f, 1.0f,

-0.25f, -0.25f, 0.0f, 0.1f, 0.1f, 1.0f,

0.25f, -0.25f, 0.0f, 0.1f, 0.1f, 1.0f

)

代表颜色的数据全部变成了一种颜色。

现在咱们是绘制三个点,假如是三十个、三百个呢,相信大家都可以看出来这种方式会重复大量相同数值的数据。所以这个时候大家就需要一种新的赋值方式。也就是给所有着色器中统一值变量赋值。这种赋值方式有两种:常量顶点属性和统一变量。

常量顶点属性

常量顶点属性对于一个图元的所有顶点都相同,所以对一个图元的所有顶点只需指定一个值。可以用如下任何一个函数指定∶

void glvertexAttriblf (int index, float x);

void glVertexAttrib2f(int index, float x, float y);

void givertexattrib3f(int index, float x, float y, float z);

void g1Vertexλttrib4f(int index, float x, float y, float z, float w);

void glVertexttriblfv(int index, float[] values, int offset);

void glVertexAttrib2fv(int index, float[] values, int offset);

void glVertexAttrib3fv(int index, float[] values, int offset);

void g1Vertexttrib4fv(int index, float[] values, int offset);

gIVerexAtrib*命令用于加载index指定的通用顶点属性。glVertexAtriblf和glVertexAtriblfv 函数在通用顶点属性中加载(x,0.0,0.0,1.0)。glVerexAtrib2f和glVertexAtrib2v在通用顶点属性中加载(x,y,0.0,1.0)。glVertexAtri3f和glVertexAtrb3fv在通用顶点属性中加载(x,y,z,1.0)。glVertexAtrib4f和glVertexAtrib4fv在通用顶点属性中加载(x,y,z,w)。在实践中,常量顶点属性提供与使用标量/向量统一变量等价的功能,两者都是可以接受的选择。

统一变量

OpenGL ES着色语言中的变量类型限定符之一是统一变量。统一变量存储应用程序通过OpenGL ES3.0API传入着色器的只读值,对于保存着色器所需的所有数据类型(如变换矩阵、照明参数和颜色)都很有用。本质上,一个着色器的任何参数在所有顶点或者片段中都应该以统一变量的形式传入。在编译时已知值的变量应该是常量,而不是统一变量,这样可以提高效率。

统一变量在全局作用域中声明,只需要统一限定符。下面是统一变量的一些例子∶

uniform mat4 viewMatrix;

uniform vec3 lightPosition;

效果上统一变量和常量顶点属性基本上是差不多的,区别是同一变量是支持片元着色器。需要注意的是,统一变量的命名空间在顶点着色器和片段着色器中都是共享的。也就是说,如果顶点和片段着色器一起链接到一个程序对象,它们就会共享同一组统一变量。因此,如果在顶点着色器和片段着色器中都声明一个统一变量,那么两个声明必须匹配。应用程序通过API加载统一变量时,它的值在顶点和片段着色器中都可用。

上边简单介绍了一下两种全局统一变量的赋值方式,下边是实际代码应用。

顶点着色器:

#version 300 es

layout (location = 0) in vec4 av_Position;

layout (location = 1) in vec4 point_Size;

void main() {

gl_Position = av_Position;

gl_PointSize = 10.0;

}

片元着色器

#version 300 es

precision mediump float;

out vec4 fragColor;

uniform vec4 frag_point_Color;

void main() {

fragColor = frag_point_Color;

}

可以看到在之前的demo中固定大小的画笔这次变成了一个顶点属性,片元着色器的颜色值则变成了一个统一变量。同一变量基本使用形式类似顶点属性,有一套相应的Api,唯一不同的是同一变量不能用layout修饰符修饰,也就是只能用api来获取统一变量的index值。

kotlin代码:

class ThreePointColorUniformRenderer(var context: Context) : GLSurfaceView.Renderer {

var pointProgram = -1

var vertexBuffer: FloatBuffer

var fragPointColorIndex = -1

val POSITION_SIZE = 3

val COLOR_SIZE = 3

val VERTEX_ATTRIBUTES_SIZE = 4 * (POSITION_SIZE + COLOR_SIZE)

private val POSITION_VERTEX = floatArrayOf(

0.0f, 0.5f, 0.0f,

-0.25f, -0.25f, 0.0f,

0.25f, -0.25f, 0.0f

)

init {

vertexBuffer = ByteBuffer.allocateDirect(POSITION_VERTEX.size * 4)

.order(ByteOrder.nativeOrder())

.asFloatBuffer()

.put(POSITION_VERTEX)

vertexBuffer.position(0)

}

override fun onDrawFrame(gl: GL10?) {

GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)

GLES30.glUseProgram(pointProgram)

GLES30.glEnableVertexAttribArray(0)

GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer)

GLES30.glDrawArrays(GLES30.GL_POINTS, 0, 3)

GLES30.glDisableVertexAttribArray(0)

}

override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {

GLES30.glViewport(0, 0, width, height)

}

override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {

pointProgram = ShaderUtil.loadProgramFromAssets(

"vertex_point_2.glsl",

"frag_point_2.glsl",

context.resources

)

GLES30.glUseProgram(pointProgram)

fragPointColorIndex = GLES30.glGetUniformLocation(pointProgram, "frag_point_Color")

GLES30.glUniform4fv(fragPointColorIndex, 1, floatArrayOf(1.0f, 0.5f, 0.1f, 1.0f), 0)

GLES30.glVertexAttrib1f(1, 20.0f)

}

}

总结

这一章主要是详细讲述了从应用层把参数值传递到OPENGL ES工作环境的几种方式。我在刚学这一块的时候书本上直接把这几种方式罗列了出来,也没有系统的讲解这几种方式的应用场景,我当时是看的一脸懵逼。在本章教程中从需求作为出发点展示了几种传值方式的异同。希望可以更好地帮到想学习OPENGL ES的同学们。然后就是OPENGL ES的api的设计方式有浓烈的C语言风格,写习惯了java代码的同学肯定是适应不过来的。java代码可能调用一个对象的一个方法就能方法完成的工作,在OPENGL ES中一般来说都是需要调用gen系列的api生成一个id,然后使用bind api绑定id,也就是确定调用对象,然后才是调用相关的方法api,最后还得解绑这个id。这个还是需要多多练习来适应。

18618eacce46?utm_campaign=haruki

swdt.png

一般来讲,每个顶点着色器都不一样的顶点属性,比如点位置可以使用顶点数组赋值,当点的位置恒定时就可以使用顶点缓冲区或者顶点数组对象方式来优化性能。当处理每个着色器都是统一值的属性时,比如说当所有点的颜色都一样时则需要考虑使用常量顶点属性或者统一变量的形式来进行赋值,这两个在使用上的区别则是是否支持片元着色器。

本章内容到这基本就结束了,下章会开始纹理部分的相关知识。

相关文章:

  • android mediastore.images.media.insertimage,尝试获取图像URI时,mediastore.images.media.insertImage返回空值...
  • android程序拍照内存溢出,彻底解决Android 拍照 内存溢出 Out of Memory的问题
  • 华为1120发布鸿蒙战略,华为发布智慧屏战略 首款产品搭载鸿蒙系统
  • Android备忘录github,Github备忘录
  • lua android异常捕获,使用lua实现try-catch异常捕获
  • 弹出自动消失html,用JS实现弹出div层过2秒自动消失的效果
  • html5主题标记是那个,网页文件主体标记 index.html是什么文件
  • html5走格子游戏,JS/HTML5游戏常用算法之碰撞检测 地图格子算法实例详解
  • html导航栏点击显示该栏内容,点击导航栏,实现下方内容改变
  • html 安卓 web 页面布局,webApp 页面布局
  • 学 HTML5 开发 零基础 经验,零基础能不能学会HTML5开发技术?
  • html表示dom怎么设置,{HTML5}DOM 和 CSS 操作-第二节-设置元素及内容
  • 中职计算机应用基础教案1,中职计算机应用基础教案版.ppt
  • 计算机未来发展趋势多级化,计算机的未来发展趋势
  • 学城市轨道和计算机专业哪个好,2019湖南考生学城市轨道交通通信信号技术专业选什么大学好?...
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • FineReport中如何实现自动滚屏效果
  • Selenium实战教程系列(二)---元素定位
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 阿里研究院入选中国企业智库系统影响力榜
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 构建二叉树进行数值数组的去重及优化
  • 欢迎参加第二届中国游戏开发者大会
  • 前端学习笔记之观察者模式
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (ros//EnvironmentVariables)ros环境变量
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (四)Controller接口控制器详解(三)
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)EOS中账户、钱包和密钥的关系
  • (转)winform之ListView
  • (转)负载均衡,回话保持,cookie
  • (转)树状数组
  • .cn根服务器被攻击之后
  • .libPaths()设置包加载目录
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .NET单元测试
  • .NET构架之我见
  • .Net中wcf服务生成及调用
  • ?
  • @31省区市高考时间表来了,祝考试成功
  • @Autowired注解的实现原理
  • @ComponentScan比较
  • @Transactional注解下,循环取序列的值,但得到的值都相同的问题
  • [ linux ] linux 命令英文全称及解释
  • [ 蓝桥杯Web真题 ]-布局切换
  • [1204 寻找子串位置] 解题报告