当前位置:网站首页>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
边栏推荐
- 26岁从财务转行软件测试,4年沉淀我已经是25k的测开工程师...
- Development of entity developer database application
- Attributeerror successfully resolved: can only use cat accessor with a ‘category‘ dtype
- 1189. Maximum number of "balloons"
- 首发织梦百度推送插件全自动收录优化seo收录模块
- Entity Developer数据库应用程序的开发
- What is the difference between int (1) and int (10)? Senior developers can't tell!
- C语言_双创建、前插,尾插,遍历,删除
- Establishment and operation of cloud platform open source project environment
- BUU的MISC(不定时更新)
猜你喜欢
Oracle数据库11gr2使用tde透明数据加密报错ora28353,如果运行关闭wallet会报错ora28365,运行打开wallet就报错ora28353无法打开wallet
云上有AI,让地球科学研究更省力
Introduction to ros2 installation and basic knowledge
At the age of 26, I changed my career from finance to software testing. After four years of precipitation, I have been a 25K Test Development Engineer
[brush questions] how can we correctly meet the interview?
Missing monitoring: ZABBIX monitors the status of Eureka instance
leetcode1020. 飞地的数量(中等)
Pallet management in SAP SD delivery process
ROS2安装及基础知识介绍
19. Actual memory management of segment page combination
随机推荐
Monotonic stack
Apache DolphinScheduler源码分析(超详细)
AttributeError: Can‘t get attribute ‘SPPF‘ on <module ‘models.common‘ from ‘/home/yolov5/models/comm
【每日一题】729. 我的日程安排表 I
《从0到1:CTFer成长之路》书籍配套题目(周更)
Bitcoinwin (BCW): 借贷平台Celsius隐瞒亏损3.5万枚ETH 或资不抵债
Missing monitoring: ZABBIX monitors the status of Eureka instance
C language_ Double create, pre insert, post insert, traverse, delete
这个高颜值的开源第三方网易云音乐播放器你值得拥有
pymongo获取一列数据
3. Business and load balancing of high architecture
Call, apply, bind rewrite, easy to understand with comments
The psychological process from autojs to ice fox intelligent assistance
Brief introduction to the curriculum differences of colleges and universities at different levels of machine human major -ros1/ros2-
Supporting title of the book from 0 to 1: ctfer's growth road (Zhou Geng)
【Hot100】739. 每日溫度
中青看点阅读新闻
Simple use of MySQL database: add, delete, modify and query
[advanced software testing step 1] basic knowledge of automated testing
基于PyTorch和Fast RCNN快速实现目标识别