当前位置:网站首页>OpenGL ES 学习初识(1)
OpenGL ES 学习初识(1)
2022-07-06 07:01:00 【换元不配限】
1.认识OpenGL ES
OpenGL是跨平台2D/3D图形API,而OpenGL ES是在前者基础上扩展的版本,适用于手机等嵌入式设备。具有以下版本:
| 版本 | 解释 |
|---|---|
| OpenGL ES 1.0 | 2003年发布 |
| OpenGL ES 1.1 | 支持了多纹理,顶点缓冲对象等 |
| OpenGL ES 2.0 | 2007年发布,基于OpenGL 2.0,删除了1.x中的固定管线(pipeline),提供可编程的管线 |
| OpenGL ES 3.0 | 2012年发布,向后兼容2.x |
| OpenGL ES 3.1 | 2014年发布 |
| OpenGL ES 3.2 | 2015年发布 |
OpenGL ES 1.x 和OpenGL ES2.0不兼容的,是完全两种不同的实现。
OpenGL EX 1.x仅支持固定管线渲染,可以固件支持或软件模拟,但渲染能力有限。
OpenGL EX 2.X采用可编程的渲染管线,提高了渲染能力。但编程难度也提高了,且要求设备中必须有对应GPU硬件支持。


上面图3-16和图3-21分别是OpenGL 1.x和OpenGL 2.x渲染管线过程示意图。“变换和光照”---->“顶点着色器”
“纹理环境和颜色求和”、“雾”、“Alpha测速”---->“片元着色器”
本系列文章将主要介绍OpenGL ES2.x
2.初识OpenGL ES2.x程序面貌
在认识了OpenGL ES基础后,下面直接带来一个入门级Demo(本程序官网也有类似的可以学习)。代码中添加了注释,可以更好帮助入门学习。
2.1 效果图

2.2 工具类ShaderUtil.java
public class ShaderUtil {
private static final String TAG = "ShaderUtil";
/**
* 加载着色器编码进GPU并编译
*
* @param shaderType 着色器类型
* @param source 着色器脚本字符串
* @return
*/
public static int loadShader(int shaderType, String source) {
int shader = GLES20.glCreateShader(shaderType);
if (shader != 0) {
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
int[] compiled = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e(TAG, "loadShader: ES20_ERROR,Could not compile shader " + shaderType + ";");
Log.e(TAG, "loadShader: ES20_ERROR,shader = " + GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
shader = 0;
}
}
return shader;
}
/**
* 创建着色器程序
*
* @param vertexSource
* @param fragmentSource
* @return
*/
public static int createProgram(String vertexSource, String fragmentSource) {
//加载顶点着色器
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
if (vertexShader == 0) {
return 0;
}
//加载片元着色器
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if (pixelShader == 0) {
return 0;
}
int program = GLES20.glCreateProgram();
if (program != 0) {
GLES20.glAttachShader(program, vertexShader);
checkGLError("glAttachShader");
GLES20.glAttachShader(program, pixelShader);
checkGLError("glAttachShader");
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
Log.e(TAG, "createProgram: ES20_ERROR,Could not link program");
Log.e(TAG, "createProgram: ES20_ERROR,program = " + GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;
}
/**
* 检测每一步操作是否有错误的方法
*
* @param op
*/
public static void checkGLError(String op) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.d(TAG, ">>>>>> " + op + " :glError " + error);
throw new RuntimeException(op + ":glError " + error);
}
}
/**
* 从sh脚本中加载着色器内容
*
* @param fname
* @param resources
* @return
*/
public static String loadFromAssetsFile(String fname, Resources resources) {
String result = null;
try {
InputStream in = resources.getAssets().open(fname);
int ch = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((ch = in.read()) != -1) {
baos.write(ch);//获取的信息写入流
}
byte[] buffer = baos.toByteArray();
baos.close();
in.close();
result = new String(buffer, "UTF-8");
result = result.replaceAll("\\r\\n", "\n");
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, "loadFromAssetsFile: result = " + result);
return result;
}
}
2.3 三角形Triangle
public class Triangle {
public static float[] mProjMatrix = new float[16];//4x4投影矩阵
public static float[] mVMatrix = new float[16];//摄像机位置朝向的参数矩阵
public static float[] mMvPMatrix;//总变换矩阵
private int program;//自定义渲染管线着色器程序id
private int muMVPMatrixHandle;//总变换矩阵引用
private int maPositionHandle;//顶点位置属性引用
private int maColorHandle;//顶点颜色属性引用
private String mVertexShader;//顶点着色器代码脚本
private String mFragmentShader;//片元着色器代码脚本
private static float[] mMMatrix = new float[16];//具体物体的3D变换矩阵,包括旋转、平移、缩放
private FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
private FloatBuffer mColorBuffer;//顶点着色数据缓冲
private int vCount = 0;//顶点数量
public float xAngle = 0;//绕X轴旋转的角度
public Triangle(MyTDView myTDView) {
initVertexData();
initShader(myTDView);
}
/**
* 初始化着色器
* @param myTDView
*/
private void initShader(MyTDView myTDView) {
mVertexShader = ShaderUtil.loadFromAssetsFile("vertex.sh", myTDView.getResources());
mFragmentShader = ShaderUtil.loadFromAssetsFile("frag.sh", myTDView.getResources());
program = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
maPositionHandle = GLES20.glGetAttribLocation(program, "aPosition");
maColorHandle = GLES20.glGetAttribLocation(program, "aColor");
muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
}
/**
* 绘制三角形
*/
public void drawSelf() {
GLES20.glUseProgram(program);
Matrix.setRotateM(mMMatrix, 0, 0, 0, 1, 0);//初始化变换矩阵
Matrix.translateM(mMMatrix, 0, 0, 0, 1);//设置沿Z轴正向位移
Matrix.rotateM(mMMatrix, 0, xAngle, 1, 0, 0);//设置绕X轴旋转
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Triangle.getFinalMatrix(mMMatrix), 0);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer);
GLES20.glVertexAttribPointer(maColorHandle, 4, GLES20.GL_FLOAT, false, 4 * 4, mColorBuffer);
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glEnableVertexAttribArray(maColorHandle);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
}
/**
* 初始化顶点数据
*/
private void initVertexData() {
vCount = 3;
final float UNIT_SIZE = 0.2f;//设置单位长度
//顶点坐标数组
float vertices[] = new float[]{
-4 * UNIT_SIZE, 0, 0,
0, -4 * UNIT_SIZE, 0,
4 * UNIT_SIZE, 0, 0
};
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());//设置字节顺序为本地操作系统顺序
mVertexBuffer = vbb.asFloatBuffer();//转换为浮点型缓冲
mVertexBuffer.put(vertices);//在缓冲区内写入数据
mVertexBuffer.position(0);//设置缓冲区起始位置
//顶点颜色数组
float colors[] = new float[]{
1, 1, 1, 0,
0, 0, 1, 0,
0, 1, 0, 0
};
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());
mColorBuffer = cbb.asFloatBuffer();
mColorBuffer.put(colors);
mColorBuffer.position(0);
}
/**
* 最终变换矩阵
*
* @param spec
* @return
*/
public static float[] getFinalMatrix(float[] spec) {
//初始化总变换矩阵
mMvPMatrix = new float[16];
Matrix.multiplyMM(mMvPMatrix, 0, mVMatrix, 0, spec, 0);
Matrix.multiplyMM(mMvPMatrix, 0, mProjMatrix, 0, mMvPMatrix, 0);
return mMvPMatrix;
}
}
2.4 渲染类MyTDView
GLSurfaceView和GLSurfaceView.Render的使用
public class MyTDView extends GLSurfaceView {
private static final String TAG = "MyTDView";
//每次三角形旋转的角度
private final float ANGLE_SPAN = 0.375f;
//线程
private RotateThread mRotateThread;
//自定义渲染器
private SceneRenderer mSceneRenderer;
public MyTDView(Context context) {
super(context);
//使用OpenGLES2.0
this.setEGLContextClientVersion(2);
mSceneRenderer = new SceneRenderer();
this.setRenderer(mSceneRenderer);
this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
private class SceneRenderer implements GLSurfaceView.Renderer {
Triangle mTriangle;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0, 0, 0, 1.0f);//设置屏幕背景颜色
mTriangle = new Triangle(MyTDView.this);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
mRotateThread = new RotateThread();
mRotateThread.start();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);//设置视口
float ratio = width / height;
//设置透视投影
Matrix.frustumM(Triangle.mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 10);
//设置摄像机
Matrix.setLookAtM(Triangle.mVMatrix, 0, 0, 0, 3,
0f, 0f, 0f, 0f, 1.0f, 0.0f);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
mTriangle.drawSelf();
}
}
private class RotateThread extends Thread {
//设置循环标识位
public boolean flag = true;
@Override
public void run() {
super.run();
while (flag) {
mSceneRenderer.mTriangle.xAngle = mSceneRenderer.mTriangle.xAngle + ANGLE_SPAN;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
2.5 顶点着色器和片元着色器代码
顶点着色器和片元着色器资源放置在assets目录下。本案例使用的如下所示:
2.5.1 frag.sh
precision mediump float;
varying vec4 vColor;
void main(){
gl_FragColor = vColor;
}
2.5.2 vertex.sh顶点着色器
uniform mat4 uMVPMatrix;//总变换矩阵
attribute vec3 aPosition;//顶点位置
attribute vec4 aColor;//顶点颜色
varying vec4 vColor;//用于传递给片元着色器的易变变量
void main(){
gl_Position = uMVPMatrix * vec4(aPosition,1);//根据总变换矩阵计算此次绘制顶点的位置
vColor = aColor;
}
2.6 其他
public class MainActivity extends AppCompatActivity {
private MyTDView mTDView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mTDView = new MyTDView(this);
mTDView.requestFocus();
mTDView.setFocusableInTouchMode(true);
setContentView(mTDView);
}
@Override
protected void onResume() {
super.onResume();
mTDView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mTDView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
本示例程序可以直接运行,查看效果。
【参考】
- https://www.khronos.org/opengles/
- 《OpenGL ES应用开发实践指南 Android卷 Kevin Brothaler》
- https://en.wikipedia.org/wiki/OpenGL_ES
- https://developer.android.google.cn/guide/topics/graphics/opengl
- https://developer.android.google.cn/training/graphics/opengl
- Android3D游戏开发技术宝典OpenGL ES 2.0
边栏推荐
- 雲上有AI,讓地球科學研究更省力
- UniPro甘特图“初体验”:关注细节背后的多场景探索
- 万丈高楼平地起,每个API皆根基
- 中青看点阅读新闻
- SSO process analysis
- 将ue4程序嵌入qt界面显示
- LeetCode 78:子集
- 19. Actual memory management of segment page combination
- [Yu Yue education] flower cultivation reference materials of Weifang Vocational College
- Erreur de type résolue avec succès: type de données « catégorie» non sous - jacente
猜你喜欢

万丈高楼平地起,每个API皆根基

3. Business and load balancing of high architecture

Windows Server 2016 standard installing Oracle

作者已死?AI正用藝術征服人類
![[brush questions] how can we correctly meet the interview?](/img/89/a5b874ba4db97fbb3d330af59c387a.png)
[brush questions] how can we correctly meet the interview?

【软件测试进阶第1步】自动化测试基础知识

BUU的MISC(不定时更新)

呆错图床系统源码图片CDN加速与破解防盗链功能

leetcode35. 搜索插入位置(简单,找插入位置,不同写法)

Reflex WMS medium level series 3: display shipped replaceable groups
随机推荐
leetcode35. 搜索插入位置(简单,找插入位置,不同写法)
Arduino tutorial - Simon games
Huawei equipment configuration ospf-bgp linkage
NFT on fingertips | evaluate ambire on G2, and have the opportunity to obtain limited edition collections
Is it difficult for girls to learn software testing? The threshold for entry is low, and learning is relatively simple
18. Multi level page table and fast table
AI on the cloud makes earth science research easier
Successfully solved typeerror: data type 'category' not understood
Monotonic stack
软件测试外包到底要不要去?三年真实外包感受告诉你
树莓派3B更新vim
[server data recovery] case of offline data recovery of two hard disks of IBM server RAID5
18.多级页表与快表
A brief introduction of reverseme in misc in the world of attack and defense
Missing monitoring: ZABBIX monitors the status of Eureka instance
【Hot100】739. 每日温度
Embed UE4 program into QT interface display
Three methods of adding color to latex text
Redis Foundation
SAP SD发货流程中托盘的管理