Android OpenGL ES 开发:绘制图形 (2)

尝试画一个三角定,定义三个顶点,每个顶点包含三个坐标 x,y,z。手机屏幕中心坐标系(0,0,0),左上角坐标(-1, 1, 0)。

private val points = floatArrayOf( 0.0f, 0.0f, 0.0f, //屏幕中心 -1.0f, -1.0f, 0.0f, //左下角 1.0f, -1.0f, 0.0f //右下角 ) private val sizePerPoint = 3 //每个顶点三个坐标 private val byteSize = sizePerPoint * 4 //每个顶点之前字节偏移量,float 四个字节 private val pointNum = points.size / sizePerPoint //顶点数量 private var vertexBuffer: FloatBuffer? = null //顶点数据浮点缓冲区

OpenGL 修改顶点属性时接受的数据类型为缓冲区类型 Buffer,因此还需要将数组类型转为 Buffer:

fun createFloatBuffer(array: FloatArray): FloatBuffer { val bb = ByteBuffer.allocateDirect(array.size * 4);//float 四个字节 bb.order(ByteOrder.nativeOrder()) //使用本机硬件设备的字节顺序 val buffer = bb.asFloatBuffer() //创建浮点缓冲区 buffer.put(array) //添加数据 buffer.position(0);//从第一个坐标开始读取 return buffer } 为顶点属性赋值

顶点着色器代码:

attribute vec4 vPosition; void main() { gl_Position = vPosition; }

顶点着色器的每个输入变量叫顶点属性,着色器中定义了 vPosition 用于存放顶点数据,先使用 GLES20.glGetAttribLocation 获取 vPosition 句柄,再使用 GLES20.glVertexAttribPointer 为 vPosition 添加我们定义好的顶点数据。

public static void glVertexAttribPointer( int indx, int size, int type, boolean normalized, int stride, java.nio.Buffer ptr )

该方法接收六个参数,分别代表:

indx:要修改的顶点属性的句柄

size:每个顶点的坐标数,如果只有 x、y 两个坐标值就传 2

type:坐标数据类型

normalized:指定在访问定点数据值时是应将其标准化(true)还是直接转换为定点值(false)

stride:每个顶点之间的字节偏移量

ptr:顶点坐标 Buffer

val vPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition") //获取 vPosition 句柄 GLES20.glVertexAttribPointer(vPositionHandle, sizePerPoint, GLES20.GL_FLOAT, false, byteSize, vertexBuffer) //为 vPosition 添加顶点数据

如果 glGetAttribLocation 返回值为 -1 代表获取失败,可能 program 对象或着色器对象里没有对应的属性。

还需要注意的是,为顶点属性赋值时,glVertexAttribPointer 建立了 CPU 和 GPU 之前的逻辑连接,实现了 CPU 数据上传到 GPU。但 GPU 数据是否可见,也就是顶点着色器能否读到数据,则由是否启用了对应的属性决定。默认情况下顶点属性都是关闭的,可以通过 glEnableVertexAttribArray 启用属性,允许着色器读取 GPU 数据。

定义片元颜色

OpenGL 定义色值使用 float 数组,可以使用色值转换在线工具将十六进制色值转换为 float 值

private val colors = floatArrayOf( 0.93f, 0.34f, 0.16f, 1.00f ) 为颜色属性赋值

片元着色器代码:

precision mediump float; uniform vec4 zColor; void main() { gl_FragColor = zColor; }

颜色属性定义为 uniform 变量,为颜色属性赋值一样需要先获取属性句柄,再向属性添加数据:

mColorHandle = GLES20.glGetUniformLocation(mProgram, "zColor"); //获取 zColor 句柄 GLES20.glUniform4fv(zColorHandle, 1, color, 0); //为 zColor 添加数据 绘制 GLES20.glEnableVertexAttribArray(vPositionHandle) //启用顶点句柄 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, pointNum) //渲染图元 GLES20.glDisableVertexAttribArray(vPositionHandle) //禁用顶点句柄

绘制三角形

当当当当,三角形出现了。上次只是绘制了背景色,今天又向前迈一步绘制出图形。但是显而易见这并不是一个等边三角形,和我们定义的坐标有所出入,这是因为 OpenGL 屏幕坐标系是一个正方形并且分布均匀的坐标系,因此将图形绘制到非正方形屏幕上时图形会被压缩或者拉伸。下一篇文章我们会使用投影变换来解决这个问题。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgwyxs.html