OpenGL基本图形:点、线段、和三角形
如何开始?通过顶点聚合。
第一步 了解坐标系
图1:左手坐标系与右手坐标系
其中左手坐标系广泛应用于计算机图形学、D3D之中,而右手坐标系广泛应用于OpenGL、线性代数、3DSMax之中。
先从二维入手,画一个三角形。
第二步 定义顶点
以三角形为例,写下各个顶点数据(逆时针顺序,卷曲顺序):
private float[] mTrianglePoints = { -0.5f, -0.5f, 0.5f, -0.5f, 0f, 0.5f};
第三步 使数据可以被存取
OpenGL作为本地系统库是直接运行在硬件上的,在Android里,而我们的代码是运行在Dalvik(现在是ART)上,导致OpenGL无法去读取我们的数据。那么安卓虚拟机如何与OpenGL通信?
1. 使用Java本地接口(JNI) 直接调用android.opengl.GLES20
2. 把内存从Java堆复制到本地堆:改变内存分配方式
Java浮点数有32位精度,而一个字节是8位精度,每个浮点数占四个字节。
private static final int BYTES_PER_FLOAT = 4;
private final FloatBuffer mVertexData;
DrawTriangleRenderer() {
mVertexData = ByteBuffer
//分配本地内存,不会被垃圾回收器处理
.allocateDirect(mTrianglePoints.length * BYTES_PER_FLOAT)
//告诉字节缓冲区,按本地字节序组织内容
.order(ByteOrder.nativeOrder())
//得到反应底层字节实例
.asFloatBuffer();
mVertexData.put(mTrianglePoints);
}
第四步 OpenGL管道(pipeline)
显示流程:读取顶点数据->执行顶点着色器->组装图元->光栅化图元->执行片段着色器->写入帧缓冲区->显示在屏幕上
- 顶点着色器(Vertex Shader)顶点着色器是GPU上运行的小程序,通过它来处理顶点,他用于渲染图形顶点的OpenGL ES图形代码。顶点着色器可用来修改图形的位置,颜色,纹理坐标,不过不能用来创建新的顶点坐标。
- 片段着色器(Fragment Shader ) 用于呈现与颜色或纹理的形状的面。每个片段是单一颜色的长方形区域,类似屏幕像素。
//顶点着色器
private String mVertexShaderCode =
"attribute vec4 a_Position; \n" +
"void main() \n" +
"{ \n" +
" gl_Position = a_Position; \n" +
"} \n";
//片段着色器
private String mFragmentShaderCode =
"precision mediump float; \n" +
"uniform vec4 u_Color; \n" +
"void main() \n" +
"{ \n" +
" gl_FragColor = u_Color; \n" +
"}";
(上述代码可以保存在glsl文件中,放在res/raw目录下,然后用readTextFileFromResource()读取文本)
vec4是有四个分量的向量,可以认为是(X,Y,Z,W),XYZ对应三维坐标,W可以理解为用来透视的分量。
第五步 编译连接
创建了着色器的编译代码后,需要写个方法来执行这段代码,这里我们在渲染器中写一个如下方法来执行着色器代码
int vertexShader = compileShader(GL_VERTEX_SHADER, mVertexShaderCode);
int fragmentShader = compileShader(GL_FRAGMENT_SHADER, mFragmentShaderCode);
//连接顶点着色器和片段着色器
mShaderProgram = linkProgram(vertexShader,fragmentShader);
//告诉OpenGL绘制到屏幕上要 使用这里的程序
glUseProgram(mShaderProgram);
第六步 赋值绘制
对变量进行赋值绘制:
//获取u_Color这个uniform的位置,存入uColorLocation
uColorLocation = glGetUniformLocation(mShaderProgram, "u_Color");
//获取属性的位置
aPositionLocation = glGetAttribLocation(mShaderProgram, "a_Position");
// 关联属性与顶点数组
mVertexData.position(0);//内部指针从开头读取
glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT,
false, 0,mVertexData);
glEnableVertexAttribArray(aPositionLocation);
glUniform4f(uColorLocation, 1.0f, 1.0f, 1.0f, 1.0f);//白色
绘制:
@Override
public void onDrawFrame(GL10 glUnused) {
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);//从顶点数组下标0开始,绘制3个顶点
}
效果图
参考书籍:《OpenGL ES应用开发实践指南:Android卷》 刘力平,苏统华译