片段着色器操作
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);指定将颜色缓冲清空为什么颜色,参数为对应的RGBA值,该步骤只是设置属性
glClear(GL_COLOR_BUFFER_BIT);真正将颜色缓冲设置为glClearColor指定的值,该步骤才是真正的改变颜色缓冲为设置属性的值
glClear方法的参数为指定要设置的缓冲区,可以传入的数值为:GL_COLOR_BUFFER_BIT、GL_DEPTH_BUFFER_BIT 和 GL_STENCIL_BUFFER_BIT,分别表示颜色缓冲、深度缓冲、模板缓冲。
**关于这三个缓冲:
**前面说过光栅化后形成的片段包含绘制一个像素的所有信息,包含颜色、深度、模板等,所有这些信息会缓存在3个缓冲区中,分别就是颜色缓冲(color buffer)、深度缓冲(depth buffer)、模板缓冲(stencil buffer)。
uniform代表着色器程序的常量,类似于Final,着色器程序会执行很多次,一个片段执行一次片段着色器,有多少个片段就会执行多少次片段着色器
和顶点着色器不同,顶点数据比如坐标每次执行顶点着色器都是变化的
uniform常量的赋值:
glUniform4fv是OpenGL中对uniform变量赋值全家桶的其中一个方法,最后的v表示uniform变量类型为向量vec,对于全家桶中修改向量的方法系列,其基本格式为:
glUniform + n维向量 + 向量元素数据类型 + v
代码实战
只需创建该对象实例调用draw方法即可绘制
uniform的作用和final的作用相似,代表不可变。uniform的不可变指的是在渲染关系中该着色器被多次调用的时候其值都为常量
package com.example.glsurfacedemo
import android.opengl.GLES20
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.util.*
import javax.microedition.khronos.opengles.GL10.GL_COLOR_BUFFER_BIT
class Triangle {
//VAO数组中存放顶点,VBO数组中存放顶点的数据。
// 顶点数组对象【用于存放顶点数组】Vertex Array Object,VAO
// 三角形三个点的坐标值(逆时针方向,在3D坐标系中,方向决定了哪面是正面)
//VAO用于存放各个顶点的坐标(X,Y,Z)
private var triangleCoords = floatArrayOf(
0.0f, 1.0f, 0.0f, // top
1.0f, -1.0f, 0.0f, // bottom left
-1f,-1f, 0.0f , // bottom right
)
// 设置颜色(分别代表red, green, blue and alpha)
private val color = floatArrayOf(1f, 0.4f, 0.3f, 0.1f)
//存放顶点缓冲的数据 Vertex Buffer Object,VBO
private var vertexBuffer: FloatBuffer =
// 坐标点的数目 * float所占字节
ByteBuffer.allocateDirect(triangleCoords.size * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer().apply {
// 把坐标添加到FloatBuffer
put(triangleCoords)
// 设置buffer的位置为起始点0
position(0)
}
// 每个顶点的坐标数
val COORDS_PER_VERTEX = 3
/**
* 顶点着色器代码;
*/
private val vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}"
/**
* 片段着色器代码
*/
private val fragmentShaderCode =
"precision highp float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}"
/**
* 着色器程序ID引用
*/
private var mProgram: Int
init {
// 编译顶点着色器和片段着色器
val vertexShader: Int = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader: Int = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
// glCreateProgram函数创建一个着色器程序,并返回新创建程序对象的ID引用
mProgram = GLES20.glCreateProgram().also {
// 把顶点着色器添加到程序对象
GLES20.glAttachShader(it, vertexShader)
// 把片段着色器添加到程序对象
GLES20.glAttachShader(it, fragmentShader)
// 连接并创建一个可执行的OpenGL ES程序对象
GLES20.glLinkProgram(it)
}
}
private fun loadShader(type: Int, shaderCode: String): Int {
// glCreateShader函数创建一个顶点着色器或者片段着色器,并返回新创建着色器的ID引用
val shader = GLES20.glCreateShader(type)
// 把着色器和代码关联,然后编译着色器
GLES20.glShaderSource(shader, shaderCode)
GLES20.glCompileShader(shader)
return shader
}
private val vertexCount: Int = triangleCoords.size / COORDS_PER_VERTEX
private val vertexStride: Int = COORDS_PER_VERTEX * 4 // 4 bytes per vertex
/**
* 实际绘制时执行的方法
**/
fun draw() {
// 激活着色器程序,把程序添加到OpenGL ES环境
GLES20.glUseProgram(mProgram)
// 获取顶点着色器中的vPosition变量(因为之前已经编译过着色器代码,所以可以从着色器程序中获取);用唯一ID表示
val position = GLES20.glGetAttribLocation(mProgram, "vPosition")
// 允许操作顶点对象position
GLES20.glEnableVertexAttribArray(position)
// 将顶点数据传递给position指向的vPosition变量;将顶点属性与顶点缓冲对象关联
//第四个参数是VBO代表的是数组缓冲对象如FloatBuffer,而VAO数组是数组数据,是FloatArray、区别是VBO会被缓冲在GPU内部,使用的时候CPU告知如何去取GPU中的缓冲数据,而VAO每次都需要和GPU通信传递数据,性能太差
//因此VBO和VAO的差别就是顶点属性数组信息是否缓存在GPU内部缓冲区中还是CPU每次都携带顶点信息和GPU通信
GLES20.glVertexAttribPointer(
position, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
false, 0, vertexBuffer
)
// 获取片段着色器中的vColor变量
val colorHandle = GLES20.glGetUniformLocation(mProgram, "vColor")
// 通过colorHandle设置绘制的颜色值
GLES20.glUniform4fv(colorHandle, 1, color, 0)
// 绘制顶点数组;
// GLES20.glClear(GL_COLOR_BUFFER_BIT)
// GLES20.glClearColor(1.0f, 1.0f, 0.2f, 0.2f);
//使用的图元链接图形,从第几个顶点元素绘制,需要绘制多少个顶点
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 3)
// 操作完后,取消允许操作顶点对象position
GLES20.glDisableVertexAttribArray(position)
}
//首先获取顶点着色器中的glposition属性,接着从0开始取,步长为12,区三个顶点。将这三个顶点信息绘制成指定图形
}
标签:实战,val,OpenGl,缓冲,着色器,顶点,GL,绘制,GLES20
From: https://blog.51cto.com/u_14689064/5788620