1、前言
选择绘制三角形作为OpenGL ES的第一个实例,是因为点、线、三角形是OpenGL ES世界的图形基础,无论多么复杂的几何物体,在OpenGL ES的世界里都可以用三角形拼成
2、步骤
依照官方文档中的说明,Android中利用OpenGL ES 2.0绘制三角形的步骤为:
2.1在AndroidManifest.xml文件中设置使用的OpenGL ES的版本:
GLSurfaceView glv = findViewById(R.id.glv);
//必须代码设置版本
glv.setEGLContextClientVersion(2);
2.2毫无疑问的,显示三角形,需要一个载体。创建显示三角形的Activity,利用GLSurfaceView作为显示三角形的View,图形的具体渲染工作都是在Render中完成的。
3. 实现GLSurfaceView的Render,在Render中完成三角形的绘制,具体行为有:
1、加载顶点和片元着色器
2、确定需要绘制图形的坐标和颜色数据
3、创建program对象,连接顶点和片元着色器,链接program对象。
4、设置视图窗口(viewport)。
5、将坐标数据颜色数据传入OpenGL ES程序中
6、使颜色缓冲区的内容显示到屏幕上。
3、具体实现
我们设置好OpenGL ES版本、创建入口Activity并设置好GLSurfaceView做为显示载体后,就进入了我们最主要的工作了。
3.1 第一步
首先,我们需要编写一个简单的顶点着色器和一个简单的片元着色器:
顶点着色器:
private final String vertextShaderCode =
"attribute vec4 vPosition;"+
"void main() {"+
" gl_Position = vPosition;"+
"}";
片元着色器:
private final String fragmentShaderCode =
"precision mediump float;"+
"uniform vec4 vColor;"+
"void main() {"+
" gl_FragColor = vColor;"+
"}";
gl_Position和gl_FragColor都是Shader的内置变量,分别为定点位置和片元颜色。
3.2 第二步
然后,我们确定要绘制的图形的顶点坐标和颜色:
我们现在需要绘制的是在一个三维空间中绘制一个三角形,三角形当然是三个顶点了。因为我们三角形只是一个平面图形。为了方便,我们现在在不设置相机(相机在后面讲)的情况下,三角形正对我们来呈现。所以我们打三个顶点的Z坐标都设置为0。OpenGL ES坐标映射到屏幕上,从屏幕中心垂直到上下左右边缘距离都是1.0,所以(-1.0,0,0)和(0,1.0,0)到原点的距离在屏幕上呈现出来的结果是不一样的,图解如下(左边是理想状态,右边是实际状态):
所以,为了不超出屏幕,我们的坐标数据设置为:
private float triangleCoors[] = {
0.5f , 0.5f , 0.0f,
-0.5f , -0.5f , 0.0f,
0.5f , -0.5f , 0.0f
};
颜色数据,我们设置为单一颜色:
private float color[] = {
1.0f , 1.0f , 1.0f , 1.0f
};
3.3 第三步
接着我们开始在Render中实现我们的三角形绘制了。Render接口有三个方法,分别为
onSurfaceCreated
onSurfaceChanged
onDrawFrame
在onSurfaceCreated方法中,我们来创建program对象,连接顶点和片元着色器,链接program对象。
//设置背景颜色
GLES20.glClearColor(0.5f,0.5f,0.5f,0.5f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
//申请底层空间
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(triangleCoors.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
//将坐标数据转换为FloatBuffer,用以传入给OpenGL ES程序
vertexBuffer = byteBuffer.asFloatBuffer();
//将三角形坐标传入FloatBuffer
vertexBuffer.put(triangleCoors);
vertexBuffer.position(0);
//创建顶点着色器程序
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertextShaderCode);
//创建片元着色器程序
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
if (vertexShader == 0 || fragmentShader == 0)
{
return;
}
//创建一个空的OpenGL ES程序
program = GLES20.glCreateProgram();
//将顶点着色器加入程序
GLES20.glAttachShader(program, vertexShader);
//将片元着色器加入程序
GLES20.glAttachShader(program, fragmentShader);
//连接到着色器程序中
GLES20.glLinkProgram(program);
//将程序加入到OpenGLES2.0环境
GLES20.glUseProgram(program);
public int loadShader(int type , String shaderCode)
{
//创建空的着色器
int shader = GLES20.glCreateShader(type);
//将着色器程序加到着色器中
GLES20.glShaderSource(shader,shaderCode);
//编译色器程序
GLES20.glCompileShader(shader);
return shader;
}
3.4 第四步
在onSurfaceChanged中设置视图窗口:
GLES20.glViewport(0,0,width,height);
3.5 第五步
最后在onDrawFrame中绘制
if(program == 0)
return;
//获取顶点着色器的vPosition成员句柄
int vPosition = GLES20.glGetAttribLocation(program, "vPosition");
//启用vPosition句柄
GLES20.glEnableVertexAttribArray(vPosition);
//传入但侥幸的坐标数据
GLES20.glVertexAttribPointer(vPosition,3,GLES20.GL_FLOAT,false,3*4, vertexBuffer);
//获取片元着色器的vColor成员句柄
int vColor = GLES20.glGetUniformLocation(program, "vColor");
//设置绘制三角形的颜色
GLES20.glUniform4fv(vColor,1,color,0);
//绘制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);
//禁止顶点数组的句柄
GLES20.glDisableVertexAttribArray(vPosition);