OpenGLES2.0原理浅析

2023-12-22 08:18
文章标签 原理 浅析 opengles2.0

本文主要是介绍OpenGLES2.0原理浅析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.        OpenGLES通过获取物体的控件顶点信息, 可以实现3维物体到2维物体的坐标转换输出到屏幕,并且可以对物体实现平移,旋转,缩放,而且利用着色器可编程渲染通道实现多种光学作用, 特殊形状变换等效果。从而能实现丰富的物体再现功能。

2.        通过模拟人眼观察物体, 可能引起屏幕图像改变的几种行为和分别对应的几种OpenGL变换:

每种变换都可以由相应的Matrix静态方法生成相应的变换矩阵。 坐标系原点在屏幕中央,z轴正方向垂直屏幕向外。

行为

变换

记录变换方式的放法

记录变换方式的[4*4]矩阵

 

 

眼睛相对物体的位置改变

 

 

视图变换

Matrix.setLookAtMmVMatrix,

 0,//偏移量

cx, cy, cz,//相机位置,

tx, ty, tz,//观察点位置

upx, upy, upz//顶部朝向

 

 

 

 

mVMatrix[16]

 

 

物体平移

 

 

 

 

 

 

 

模型变换

Matrix.translateM(

mMMatrix,

0,//偏移量

x, y, z//平移量

)

 

 

 

 

 

 

 

mMMatrix[16]

 

物体按坐标缩放比例缩放

Matrix.scaleM(

mMMatrix,

sx,sy, sz//缩放因子

)

 

 

物体旋转

Matrix.rotateM(

mMMatrix,

0,//偏移量

angle,//旋转角度

x, y, z//需要旋转的轴

)

 

 

凸透镜眼睛

 

 

 

 

 

 

投影变换

Matrix.frustumM(

mPMatrix,

0,//偏移量

left,right,

buttom,top,

near,far//near>0

)

 

 

 

 

 

mPMatrix[16]

平面透镜眼睛

Matrix.orthoM(

mPMatrix,

0,//偏移量

left,right,

buttom,top,

near,far//near>0

)

PS: 如果眼睛不是凸透镜而是平面透镜, 则不会产生近小远大的效果, 视图变换可由人眼模拟。函数参数都是float

变换叠加: 可通过变换矩阵相乘得出想要的变换矩阵: Matrix.multiplyMM(

mMVPMatrix,             ///存放结果的总变换矩阵

0,    ///结果矩阵偏移量

              mMatrixLeft,

                                          0,          //左矩阵偏移量

              mMtrixRight,

                                          0            //右矩阵偏移量

                            变换技巧: 利用栈存储变换矩阵的算法可实现复杂场景的图形变换和提高渲染效率。

                            变换顺序: 矩阵相乘是讲究顺序的, 比如先平移再缩放  先缩放再平移的效果是不同的。

 

3.         绘制方式

GLES20.GL_POINTS

 

线

GLES20.GL_LINES

GLES20.GL_LINE_STRIP

GLES20.GL_LINE_LOOP

 

GLES20.TRIANGLES

GLES20.TRIANGLE_TRIP//条带,可间断

GLES20.TRIANGLE_FAN//扇面

非索引法: GLES20.glDrawArrays(GLES20.GL_POINTS, 0, vCount);

索引法 GLES20.glDrawElements(GLES20.GL_POINTS, iCount, GLES20.GL_UNSIGNED_BYTE,  mIndexBuffer);

 

 

二.androidopenGLES2.0程序设计框架浅析

1.主要实现流程有如下顺序的几点操作:

定义物体顶点信息 –> 编辑着色器代码 –> 编译连接着色器程序 -> 物体顶点信息传入着色器 –> GLSurfaceView加载Renderer –> Activity加载GLSurfaceView -> 渲染物体输出屏幕

操作名称

一般实现方法

定义物体顶点信息

*   顶点信息一般包括:

(1)三维坐标信息; (2)三维法向量信息;(3)颜色信息或二维贴图坐标信息;

*   复杂物体的坐标通常通过特定的软件绘制生成顶点信息文件,然后进行解读;

编辑着色器代码

*   着色器语言编写的代码, 通常后缀名.sh, 语法和C相似95%以上, OpenGLES2.0的可编程渲染通道, 增加了编程难度, 但是能实现更绚丽多彩的效果。

*   一般编写好的着色器代码放在android工程目录下的assets文件, assets常用轻量资源的读写。

编译连接着色器

*   assets获取着色器脚本, 并返回脚本字符串的过程:

主要方法:(1. InputStream in = rgetAssets .open(fname);

          (2. in 转化为 ByteArrayOutputStream out

          (3. byte[] bout = out.toByteArray(); 记得close in&out

          (4. String result = (new String(bout, “UTF-8”)).replaceAll(\\r\\n, “\n”);

*   加载片元着色器和顶点着色器的方法:

(1.       申请特定着色器

int shaderId = GLES20.glCreateShader(shaderType);// shaderType GLES20.GL_VERTEX_SHADER(顶点  GLES20.GL_FRAGMENT_SHADER(片元)

如果申请成功则返回的shaderId不为零

(2.   给申请成功的着色器加载脚本并编译,查错

GLES20.glShaderSource(shaderId, source);/// source是脚本字符串

GLES20.glCompileShader(shaderId);///编译

int compiles[1];

GLES20.glGetShaderiv(shaderId, GLES20._GL_COMPILE_STATUS, compiles, 0);///查看编译情况

if(compiles[0] == 0){//编译失败,释放申请的着色器

   GLES20.glDeleteShader(shaderId);

   shaderId = 0;

}

*   编译连接并生成着色器程序:

(1.       申请着色器程序:int program = GLES20.glCreateProgram();

(2.       加入两种着色器并查错(方法一样)

                GLES20.glAttachShader(programe, vertexShaderId);

                int error;

while((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR){

   throw (new RuntimeException(ShaderName + “attach Error”))

}

(3.       连接着色器程序,并查看连接情况

GLES20.glLinkProgram(program);

int LinkStatus[1];

GLES20.glGetPromgramiv(program, GLES20.GL_LINK_STATUS, LinkStatus, 0);

if(LinkStatus[0]!= GLES20.GL_TRUE){

  Log.e(“Link Error”, GLES20.glGetProgramInfoLog(program));

GLES20.glDeletePromgram(program);

program = 0;

}

*   至此可以利用program进行该着色器的利用。

物体顶点信息传入着色器

*   生成顶点信息, FloatBuffer类存储的一般方法:

         float vertexs[] = {1, 2, 3}

         ByteBuffer bbv = ByteBuffer.allocateDirect(vertexs.length * 4);//一个float 4个字节

         bbv.order(ByteOrder.nativeOrder());///前期设置

         vertexBuffer = bbv.asFloatBuffer();//作为中介开辟FloatBuffer

         vertexBuffer.put(vertexs);      //存入信息

         vertexBuffer.position(0);       //设置起始位置为0;

获取着色器参数ID

         int maPositionHandler = GLES20.glGetAttribLocation(program, “aPosition”);

传入数据

             GLES20.glVertexAttribPointer(

                      maPositionHandle,  

                      3,

                      GLES20.GL_FLOAT,

                      false,

                3*4,  

                mVertexBuffer

         );

使用数据:GLES20.glEnableVertexAttribArray(maPositionHandle); 

 

GLSurfaceView加载Renderer

*   初始化GLSurfaceView

setEGLContextClientVersion(2);//设置版本

setRanderer(new MyRenderer());//增添渲染器

setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//主动渲染模式

*   自定义渲染器,实现3个渲染接口,例如:

      private class MyRenderer implements GLSurfaceView.Renderer{

           Triangle tle;

                   public void onDrawFrame(GL10 gl)

                   {

                            //清除深度缓冲与颜色缓冲

            GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

            //绘制三角形对

            tle.drawSelf();   

                   }

                   public void onSurfaceChanged(GL10 gl, int width, int height)

                   {

                            //设置视窗大小及位置

             GLES20.glViewport(0, 0, width, height);

             //计算GLSurfaceView的宽高比

            float ratio = (float) width / height;

            //调用此方法计算产生透视投影矩阵

            Matrix.frustumM(Triangle.mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 100);

            //调用此方法产生摄像机9参数位置矩阵

            Matrix.setLookAtM(Triangle.mVMatrix, 0, 0,0,3,0f,0f,0f,0f,1.0f,0.0f);

                   }

                   public void onSurfaceCreated(GL10 gl, EGLConfig config)

                   {

                            //设置屏幕背景色RGBA

            GLES20.glClearColor(0,0,0,1.0f); 

            //创建三角形对对象

            tle=new Triangle(MyTDView.this);       

            //打开深度检测

            GLES20.glEnable(GLES20.GL_DEPTH_TEST);

                rthread=new RotateThread();

                rthread.start();

                  }

 

}

              

 

 

这篇关于OpenGLES2.0原理浅析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/523231

相关文章

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代

Golang HashMap实现原理解析

《GolangHashMap实现原理解析》HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作,:本文主要介绍GolangH... 目录HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

C#中async await异步关键字用法和异步的底层原理全解析

《C#中asyncawait异步关键字用法和异步的底层原理全解析》:本文主要介绍C#中asyncawait异步关键字用法和异步的底层原理全解析,本文给大家介绍的非常详细,对大家的学习或工作具有一... 目录C#异步编程一、异步编程基础二、异步方法的工作原理三、代码示例四、编译后的底层实现五、总结C#异步编程

浅析Java中如何优雅地处理null值

《浅析Java中如何优雅地处理null值》这篇文章主要为大家详细介绍了如何结合Lambda表达式和Optional,让Java更优雅地处理null值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录场景 1:不为 null 则执行场景 2:不为 null 则返回,为 null 则返回特定值或抛出异常场景

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

鸿蒙中@State的原理使用详解(HarmonyOS 5)

《鸿蒙中@State的原理使用详解(HarmonyOS5)》@State是HarmonyOSArkTS框架中用于管理组件状态的核心装饰器,其核心作用是实现数据驱动UI的响应式编程模式,本文给大家介绍... 目录一、@State在鸿蒙中是做什么的?二、@Spythontate的基本原理1. 依赖关系的收集2.

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2