Android Studio + OpenGL ES 学习记录
OpenGL是一种应用程序编程接口,它是一种可以对图形硬件设备特性进行访问的软件库,而OpenGL ES是OpenGL的子集,针对手机、PDA和游戏主机嵌入式设备而设计。OpenGL ES 是从 OpenGL 裁剪定制而来的,去除了 glBegin/glEnd,四边形(GL_QUADS)、多边形(GL_POLYGONS)等复杂图元等许多非绝对必要的特性,剩下最核心有用的部分。
简介
OpenGL是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API),而在嵌入式和移动平台的版本是OpenGL ES。Android最初就支持OpenGL ES的1.0版本,到现在已经支持到最新的3.2版本,下面的支持变化图:
版本支持声明
可以在AndroidManifet.xml中加入下面这行使用特性的声明,Google Play将会过滤掉不支持指定OpenGL ES版本的用户,拒绝他们安装。
<!-- 需要OpenGL ES 2.0 -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
也可以在代码中判断gles的版本,version同样传入版本号即可(例如0x20000)
public static boolean checkOpenGL(Activity activity, int version) {
ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
if (am != null) {
return am.getDeviceConfigurationInfo().reqGlEsVersion >= version;
}
return false;
}
OpenGL ES的名词解释 图元 官方的解释是图形软件用来描述各种图形的函数,可以理解为图元就是组成图像的基本单元。
顶点数据 在计算机中图元的位置是通过x,y,z,w来存储或颜色数据是通过RGBA的数组格式存储的,然后通过多个点来进行图元装配和光栅化出图形。
片元 元是光栅化过程的产物,光栅化是将一个图元转变为一个二维图象。
光栅化 光栅化是处理区域内的图元并生成片元数据。
OpenGL渲染管线 是显卡芯片内部处理图形信号相互独立的并行处理单元。也就是把数据转化到openGL并且生成最终图像的一个过程。
GLSL是什么 GLSL是一门专门为图形开发设计的编程语言。
可编程管线的编程阶段
基础
两个基本的类GLSurfaceView和GLSurfaceView.Renderer。 GLSurfaceView:继承自SurfaceView,用来显示渲染的图像。如果想操作你的图像,需要扩展触摸监听事件来处理。 GLSurfaceView.Renderer:GLSurfaceView的内部接口类,主要负责渲染图像。
GLSurfaceView主要方法: setEGLContextClientVersion:设置OpenGL ES的版本,只能设置主要版本(例如:1,2,3),不能设置次要版本。 setEGLContextFactory:设置OpenGL ES的版本构建器,默认的构建器是根据版本设置的,可以自定义成版本自适应。 setRenderer:设置Renderer,如果不设置,那么界面显示的就是一片空白。 setRenderMode:设置Renderer的模式,有这么两种:1、RENDERMODE_WHEN_DIRTY(仅在创建时或调用requestRender时才会渲染内容);RENDERMODE_CONTINUOUSLY(不停的渲染)。 onPause:暂停渲染,在页面不再显示时可以调用,减少性能开销,例如在Activity的onStop时。 onResume:恢复渲染,类似onPause。 requestRender:请求渲染,通常是RENDERMODE_WHEN_DIRTY模式时使用,必须在setRenderer后才能使用。 queueEvent:插入一个Runnable任务到后台渲染线程上执行,必须在setRenderer后才能使用。 setDebugFlags:设置debug模式,主要有两种:1、DEBUG_CHECK_GL_ERROR(当GL调用glError()方法后如果发生异常会打印。主要用来跟踪OpenGL错误。);2、DEBUG_LOG_GL_CALLS(打印所有GL的verbose级别的日志) 2.GLSurfaceView.Renderer的主要方法:
onSurfaceCreated(GL10 gl, EGLConfig config):当Surface创建或重新创建时,这时可以进行初始化。 onSurfaceChanged(GL10 gl, int width, int height):Surface尺寸改变时,返回当前surface宽高,可以进行下一步操作。 onDrawFrame(GL10 gl):渲染绘制当前一帧时会调用。 OpenGL类:在包android.opengl下,主要有GLES20(OpenGL ES 2.0版本),GLES30,GLES31,GLES32和。
public class BaseGLView extends GLSurfaceView {
public BaseGLView(Context context) {
this(context, null);
}
public BaseGLView(Context context, AttributeSet attrs) {
super(context, attrs);
setDebug();
init();
}
protected void setDebug() {
setDebugFlags(BuildConfig.DEBUG ? DEBUG_LOG_GL_CALLS : DEBUG_CHECK_GL_ERROR);
}
protected void init() {
// 设置版本
setEGLContextClientVersion(2);
// 设置Renderer
setRenderer(new BaseRenderer());
// 设置渲染模式(默认RENDERMODE_CONTINUOUSLY)
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
}
新建一个自定义的Renderer类
public class BaseRenderer implements GLSurfaceView.Renderer {
private int bg = Color.BLACK;
public BaseRenderer() {
}
public BaseRenderer(int bg) {
this.bg = bg;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 设置背景色
GLES20.glClearColor(Color.red(bg) / 255.0f, Color.green(bg) / 255.0f,
Color.blue(bg) / 255.0f, Color.alpha(bg) / 255.0f);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 设置显示范围
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
// 清屏
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}
}
安卓手机下的坐标系
三维坐标系,原点在中间,x 轴向右,y 轴向上,z 轴朝向我们,x y z 取值范围都是 [-1, 1]:
OpenGL 纹理(texture)坐标系 二维坐标系,原点在左下角,s(x)轴向右,t(y)轴向上,x y 取值范围都是 [0, 1]:
绘制一个最简单的三角形
主程序:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GLSurfaceView glSurfaceView =
(android.opengl.GLSurfaceView) findViewById(R.id.mGLSurfaceView);
glSurfaceView.setEGLContextClientVersion(2);
glSurfaceView.setRenderer(new MyRenderer());
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
static class MyRenderer implements GLSurfaceView.Renderer {
private static final String VERTEX_SHADER = "attribute vec4 vPosition;\n"
+ "void main() {\n"
+ " gl_Position = vPosition;\n"
+ "}";
private static final String FRAGMENT_SHADER = "precision mediump float;\n"
+ "void main() {\n"
+ " gl_FragColor = vec4(0.5,0,0,1);\n"
+ "}";
private static final float[] VERTEX = { // in counterclockwise order:
0, 1, 0.0f, // top
-0.5f, -1, 0.0f, // bottom left
1f, -1, 0.0f, // bottom right
};
private final FloatBuffer mVertexBuffer;
private int mProgram;
private int mPositionHandle;
MyRenderer() {
mVertexBuffer = ByteBuffer.allocateDirect(VERTEX.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(VERTEX);
mVertexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
mProgram = GLES20.glCreateProgram();
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER);
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
}
@Override
public void onDrawFrame(GL10 unused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(mProgram);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false,
12, mVertexBuffer);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
static int loadShader(int type, String shaderCode) {
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
}
运行效果:
原文链接
fjnu 116052019030 huangyuxuan
|