一、绘制点
前面讲了一些关于OpenGL ES相关的知识,接下来就开始利用OpenGL ES在Android平台上实现各种效果。首先介绍利用OpenGL ES2.0实现点的绘制。首先看下效果图:
image.png
通过该效果图,可以看出,是在黑色的背景上绘制了两个红色的点。
实现
1.Activity实现
/**
* @Description: 点
* @Author: dzh
* @CreateDate: 2020-06-16 17:03
*/
public class PointActivity extends Activity {
private GLSurfaceView mGLSurfaceView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
//设置使用OpenGL2.0版本
mGLSurfaceView.setEGLContextClientVersion(2);
mGLSurfaceView.setRenderer(new PointRenderer(this));
//设置渲染模式:requestRender方法触发会渲染
mGLSurfaceView.setRenderMode(DGLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mGLSurfaceView);
}
}
把创建的GLSurfaceView设置给Activity,并且设置OpenGL ES的版本号为2,渲染模式为手动触发,渲染器为PointRenderer。
2.PointRenderer实现
2.1 编写顶点着色器
attribute vec4 av_Position;
uniform float p_Size;
void main(){
gl_Position = av_Position;
gl_PointSize = p_Size;
}
备注:顶点着色器会把av_Position赋值给gl_Position,把p_Size赋值给gl_PointSize。
2.2 编写片元着色器
precision mediump float;
uniform vec4 af_Color;
void main(){
gl_FragColor = af_Color;
}
备注:片元着色器会把af_Color赋值给gl_FragColor。
2.3 设置顶点坐标
上图两个红点的位置是:(0,0),(0.5,0.5),在OpenGL ES中,顶点坐标的值是float类型,用数组标示即为:
private float[] vertexData = {
0f, 0f,
0.5f, 0.5f
};
上面数组是加载在jvm中,为了提供效率需要把顶点坐标存放到内存数组中:
vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
备注:vertexData.length * 4是因为float占4个字节
2.4 加载着色器
1、创建shader(着色器:顶点或片元)
int shader = GLES20.glCreateShader(shaderType);
2、加载shader源码并编译shader
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
3、检查是否编译成功:
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
4、创建一个渲染程序:
int program = GLES20.glCreateProgram();
5、将着色器程序添加到渲染程序中:
GLES20.glAttachShader(program, vertexShader);
6、链接源程序:
GLES20.glLinkProgram(program);
7、检查链接源程序是否成功
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
8、得到着色器中的属性:
int vPosition = GLES20.glGetAttribLocation(program, "v_Position");
9、使用源程序:
GLES20.glUseProgram(program);
10、使顶点属性数组有效:
GLES20.glEnableVertexAttribArray(vPosition);
11、为顶点属性赋值:
GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
12、绘制图形:
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 2);
但是我后面又把上面的步骤进行了一次封装,使用相对简单了些:
package com.stormdzh.openglanimation.util.shader;
import android.content.Context; import android.opengl.GLES20; import android.util.Log;
import [java.io](http://java.io/).BufferedReader; import [java.io](http://java.io/).InputStream; import [java.io](http://java.io/).InputStreamReader;
/** * @Description: ShaderUtil * @Author: dzh * @CreateDate: 2020-06-16 19:45 */ public class ShaderUtil {
public static String readRawText(Context context, int rawId) { InputStream inputStream = context.getResources().openRawResource(rawId); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer sb = new StringBuffer(); String line; try { while ((line = reader.readLine()) != null) {
sb.append(line).append("\n"); } reader.close(); } catch (Exception e) { e.printStackTrace(); }
return sb.toString(); }
public static int loadShader(int shaderType, String source) {
int shader = GLES20.glCreateShader(shaderType); if (shader != 0) { GLES20.glShaderSource(shader, source); GLES20.glCompileShader(shader); int[] compile = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compile, 0); if (compile[0] != GLES20.GL_TRUE) { Log.i("DzhShaderUtil", " compile 失败"); GLES20.glDeleteShader(shader); shader = 0; }
} return shader;
}
public static int creteProgram(String vertexSource, String fragmentSource) {
int vettexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vettexShader == 0) {
return 0; }
int fragmentShaper = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if (fragmentShaper == 0) {
return 0; }
int program = GLES20.glCreateProgram();
if (program != 0) { GLES20.glAttachShader(program, vettexShader); GLES20.glAttachShader(program, fragmentShaper); GLES20.glLinkProgram(program); int[] linsStatus = new int[1]; GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linsStatus, 0); if (linsStatus[0] != GLES20.GL_TRUE) { Log.i("DzhShaderUtil", " linsStatus 失败"); GLES20.glDeleteProgram(program); program = 0;
} }
return program; } }
这个类有三个方法,分别是读取raw目录下着色器脚本,加载着色器、和创建渲染程序。
那么绘制点的三行核心代码是:
//给颜色赋值
GLES20.glUniform4f(afColor, 1f, 0, 0, 1);
//设置点的大小
GLES20.glUniform1f(pSize, 20.0f);
//绘制
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, vertexData.length / 2);
二、绘制线
首先看一下线条的预览图:
image.png
绘制步骤和点的步骤几乎是一样的,只是绘制的图元需要修改下:
//绘制
GLES20.glDrawArrays(GLES20.GL_LINES, 0, 2);
三、绘制三角形
首先看一下三角形的预览图:
image.png
绘制三角形和绘制点和直线的区别,在于顶点坐标的格式,和绘制方式,所以必须定义三个顶点:
//顶点数据
private float[] vertexData = {
0f, 1f,
-1f, -1f,
1f, -1f
};
之后需要修改绘制方式:
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 3);
网友评论