Android音视频开发-OpenGL ES正交投影实现方法

news/2024/4/20 21:30:32/文章来源:https://blog.csdn.net/m0_70749039/article/details/130331572

本文实例为大家分享了OpenGL ES正交投影展示的具体代码,供大家参考,具体内容如下

绘制正方形

在最开始绘制的六边形里面好像看起来挺容易的,也没有出现什么问题,接下来不妨忘记前面绘制六边形的代码,让我们按照自己的理解来绘制一个简单的正方形。

按照我的理解,要想在屏幕中间显示一个正方形,效果如下图所示

image.png

应该创建的数据如下图所示

image.png

即传给渲染管线的顶点数据如下图:

float[] vertexArray = new float[] {(float) -0.5, (float) -0.5, 0,(float) 0.5, (float) -0.5, 0,(float) -0.5, (float) 0.5, 0,(float) 0.5, (float) 0.5, 0};

于是代码大概是这样子的,这里省略掉与主题无关的代码,颜色用纯色填充,因此在片元着色器中指定颜色,也省略掉一系列矩阵变换。顶点着色器中直接将顶点传给渲染管线,片元着色器中给片元设置固定颜色红色。

Rectangle.java

public class Rectangle {private FloatBuffer mVertexBuffer;private int mProgram;private int mPositionHandle;public Rectangle(float r) {initVetexData(r);}public void initVetexData(float r) {// 初始化顶点坐标float[] vertexArray = new float[] {(float) -0.5, (float) -0.5, 0,(float) 0.5, (float) -0.5, 0,(float) -0.5, (float) 0.5, 0,(float) 0.5, (float) 0.5, 0};ByteBuffer buffer = ByteBuffer.allocateDirect(vertexArray.length * 4);buffer.order(ByteOrder.nativeOrder());mVertexBuffer = buffer.asFloatBuffer();mVertexBuffer.put(vertexArray);mVertexBuffer.position(0);int vertexShader = loaderShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);int fragmentShader = loaderShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);mProgram = GLES20.glCreateProgram();GLES20.glAttachShader(mProgram, vertexShader);GLES20.glAttachShader(mProgram, fragmentShader);GLES20.glLinkProgram(mProgram);mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");}public void draw() {GLES20.glUseProgram(mProgram);// 将顶点数据传递到管线,顶点着色器GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexBuffer);GLES20.glEnableVertexAttribArray(mPositionHandle);// 绘制图元GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);}private int loaderShader(int type, String shaderCode) {int shader = GLES20.glCreateShader(type);GLES20.glShaderSource(shader, shaderCode);GLES20.glCompileShader(shader);return shader;}private String vertexShaderCode = "attribute vec3 aPosition;"+ "void main(){"+ "gl_Position = vec4(aPosition,1);"+ "}";private String fragmentShaderCode = "precision mediump float;"+ "void main(){"+ "gl_FragColor = vec4(1,0,0,0);"+ "}";}

RectangleView.java

public class RectangleView extends GLSurfaceView{public RectangleView(Context context) {super(context);setEGLContextClientVersion(2);setRenderer(new MyRender());}class MyRender implements GLSurfaceView.Renderer {private Rectangle rectangle;@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1);rectangle = new Rectangle(0.5f);GLES20.glEnable(GLES20.GL_DEPTH_TEST);}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {GLES20.glViewport(0, 0, width, height);}@Overridepublic void onDrawFrame(GL10 gl) {GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);rectangle.draw();}}}

然后出来的效果是这样子的,实际上屏幕上的坐标并不是这样子的,后面可以知道上面画的这个样子其实只是一个归一化的设备坐标。归一化设备坐标可以通过公式映射到实际的手机屏幕,后面会学到。

image.png

咦,实际效果好像和想象中的不太一样呀。我的本意是显示一个正方形,但实际上现实的却是一个矩形了,y轴上被拉伸了,并且横屏状态下也是类似的情况。但比较巧的是,如果以屏幕中心做一个坐标轴,就会发现,这个矩形的四个顶点在这个坐标轴x、y范围为[-1,1]的中间。

实际上,要显示的所有物体映射到手机屏幕上,都是要映射到x、y、z轴上的[-1,1]范围内,这个范围内的坐标称为归一化设备坐标,独立于屏幕的实际尺寸和形状。

因此按照这样的规定,我们要创建一个正方形就非常困难了,因为要创建正方形就必须考虑手机的宽高比,传入数据的时候就比较复杂了:不能仅仅站在要绘制物体的自身角度来看了。也就是说,上面的例子中要绘制一个正方形,传入的顶点数据的y坐标要按照比例进行一点转换,比如对16:9的屏幕,将上面传入的顶点数据的y坐标都乘以9/16即可。但同时会发现当处于横屏时,又要处理传入的x坐标的值,显然这不是一个好的方案。

引入投影

实际上,对于一个物体来说它有它自身的坐标,这个空间称为物体空间,也就是设计物体的时候采用的一个坐标空间,物体的几何中心在坐标原点上,归一化后坐标范围在[-1,1]之间,x和y轴分度是一致的。

将在这个空间的物体直接往手机屏幕的归一化坐标绘制时,由于屏幕的宽高比的问题,就会出现和预料结果不一样。所以只需要对物体空间的坐标做一个映射即可。

正交投影就是为了解决这个问题的,

public static void orthoM(float[] m, int mOffset,float left, float right, float bottom, float top,float near, float far)

正交投影背后的数学

orthoM函数产生的矩阵会把所有的左右之间、上下之间,远近之间的点映射到归一化设备坐标中。

各参数的含义如图所示

image.png

正交投影是一种平行投影,投影线是平行的,其视景体是一个长方体,坐标位于视景体中的物体才有效,视景体里面的物体投影到近平面上的部分最终会显示到屏幕的视口中,关于视口后面会降到。

会产生下面的矩阵,z轴的负值会反转z坐标,这是因为归一化设备坐标是左手系统,而OpenGL ES中的坐标系统都是右手系统,这里还涉及到顶点坐标的w分量,目前暂时用不到。

image.png

利用矩阵的就可以将物体空间[-1,1]之间的坐标映射到屏幕归一化设备坐标的[-1,1]之间。归一化屏幕坐标是右手坐标系统,原点在屏幕正中心,向右为x轴正方向,向上为y轴正方向,z轴垂直屏幕向外。以竖屏为例,比如设置left=-1,right=1,bottom=-hight/width,top=hight/width,比如我的手机分辨率为1920*1080 =1.8 对上面的正方形点(0.5,0.5)坐标而言经过变化就成了(0.5,0.3)

image.png

在屏幕的归一化设备坐标中来看就是一个正方形了,因为y轴范围显然比x轴大,0.3对应的实际长度和x轴的0.5长度是一样的。

上面的代码需要做如下修改,在onSurfaceChanged里面增加如下代码

@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {GLES20.glViewport(0, 0, width, height);// 根据屏幕方向设置投影矩阵float ratio= width   height ? (float)width / height : (float)height / width;if (width   height) {// 横屏 Matrix.orthoM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 0, 5);} else {Matrix.orthoM(mProjectionMatrix, 0, -1, 1, -ratio, ratio, 0, 5);}}

接着在顶点着色器中对顶点乘以投影矩阵

private String vertexShaderCode = "uniform mat4 uProjectionMatrix;" // 增加这一行+ "attribute vec3 aPosition;"+ "void main(){"+ "gl_Position = uProjectionMatrix * vec4(aPosition,1);" // 不是直接赋值而是乘以投影矩阵+ "}";

最后增加获取着色器中uProjectionMatrix以及传入值的代码部分即可。最终的效果不论横屏还是竖屏,显示的都是我们期望的正方形。

摄像机设置

需要补充的是,上面的参数near、far的含义指的是和视点的距离,视点貌似到目前还未接触到,它指的是摄像机的位置,和实际生活中用相机看物体一样,从不同的角度和位置拍摄同一个物体获得的照片肯定是不一样的,摄像机位置用setLookAtM函数指定。

 public static void setLookAtM(float[] rm, // 生成的摄像机矩阵int rmOffset,float eyeX, float eyeY, float eyeZ, // 摄像机的位置float centerX, float centerY, float centerZ, // 观察目标点的位置// 摄像机位置和观察目标点的位置确定了观察方向float upX, float upY,float upZ // up向量在x、y、z轴上的分量,我觉得一般应该是和观察方向垂直的)

前面提到的确定的视景体就和上面函数指定的摄像机位置和观察方向有关。摄像机默认位置在(0,0,0)处,在上面的设置下,如果将改正方形沿z轴正方向平移1个单位,屏幕上就显示不了,因为已经跑到了设置的视景体外面了。

关于摄像机的参数和投影near和far参数的设置需要注意,肯定不是胡乱设置的!摄像机的位置、方向和投影矩阵定义的视景体最终确定了视景体的位置,如果设置不当就会导致物体没有显示在屏幕上,因为物体的坐标可能位于视景体外面。

视口

前面说过在视景体中的物体最终会投影到近平面上,最终显示到视口上,正如前面在onSurfaceChanged设置的那样。

public static native void glViewport(int x,int y,int width,int height);

视口中各参数的含义

image.png

视口用的屏幕坐标系原点并不在屏幕左上角而是在左下角,x轴向右,y轴向上。其实还不是很准确,准确的说,视口的坐标原点位于该View的左下角,因为GLSurfaceView并不总是占据整个屏幕的。

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_102422.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu下打开QtCreator,环境变量(PATH、LD_LIBRARY_PATH等)与预期不一致的问题

现象展示 在Ubuntu中,安装好Qt之后,可以在系统桌面的左下角找到启动图标 但是,这种方式启动的QtCreator所读取到的环境变量和我们从命令行读取到的不一致: 可以看到,明显少了这个:/opt/ros/humble/bin 因…

很合适新手入门使用的Python游戏开发包pygame实例教程-02[如何控制飞行]

前面一篇博文,我们让飞机动起来了,但不是那么完美,我们继续来完善我们的游戏代码,本篇博文主要介绍获取按键的方式已经飞行的控制。 文章目录 一、获取按键的三种方式1、通过event.get配合pygame.key枚举2、通过event.get配合ord…

微积分入门

文章目录 前言初期积分微分微积分问题 后期极限 ε \varepsilon ε- δ \delta δ极限勒贝格积分 结语 前言 微积分总共走过了两个时期。首先是牛顿和莱布尼茨利用无穷小量定义微分和积分,并且发现了微分和积分的关系,这是第一个时期,这时的…

设计模式——组件协作模式之模板方法模式

文章目录 前言一、“组件协作” 模式二、模板方法模式1、动机2、源码分析讲解①、结构化软件设计②、面向对象软件设计 三、模板方法模式定义四、结构要点总结 前言 一、“组件协作” 模式 现代软件专业分工之后的第一个结果是 “框架与应用程序的划分”,“组件协作…

Cuckoo Filter

其他判重数据结构 Bloom Filter 无法支持删除和计数的功能,需要更多的存储空间来存储数据 因为在CS中,删除和计数是常见的操作,但是这会对布隆过滤器的存储空间产生影响,同样为了实现这一操作,需要更多的存储空间 数…

ArcGIS Pro导航工具

主要导航工具为浏览工具 、屏幕导航器 、书签 、转到XY工具 。 其它还包括链接视图、地图比例(2D)、场景高度(3D)、暂停并刷新绘制、照相机属性、在3D模式下导航、键盘快捷键等。 1 主要导航工具 地图和场景的默认工具为浏览工具…

C++ “类与对象”

类与对象的概念 类相当于是结构体的声明,是结构体的设计图,而对象是利用设计图的创造的产物. (1).类的大小计算 类的大小计算时与结构体类似,但函数是不计入大小的(函数放在单独的公共空间). 在…

Unity API详解——Object类

Object类是Unity中所有对象的基类,例如GameObject、Component、Material、Shader、Texture、Mesh、Font等都是Object的子类。本博客介绍Object类的一些实例方法和静态方法。 一、Object类实例方法 在Object类中,涉及的实例方法主要有GetInstanceID方法…

8. 优先队列

8. 优先队列 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在某些情况下,我们可能需要找出队列中的最大值或者最小值,例如使用一个队列保存计算机的任务,一般情况下计算机的任务都是有优先级…

ROS1学习笔记:常用可视化工具的使用(ubuntu20.04)

参考B站古月居ROS入门21讲:常用可视化工具的实现 基于VMware Ubuntu 20.04 Noetic版本的环境 文章目录 一、日志输出工具:rqt_console二、绘制数据曲线:rqt_plot三、 图像渲染工具:rqt_image_view四、图形界面总接口:r…

kong(4):限流配置

Kong 提供了 Rate Limiting 插件,实现对请求的限流功能,避免过大的请求量过大,将后端服务打挂。 Rate Limiting 支持秒/分/小时/日/月/年多种时间维度的限流,并且可以组合使用。例如说:限制每秒最 多 100 次请求&…

初识Android内存优化

一、简介 Android 内存优化是指优化 Android 应用程序的内存使用,以减少可用内存的消耗,提高应用程序的性能和可靠性。Android 内存优化可以通过减少内存使用量,减少对资源的消耗,以及提高内存利用率来实现。 安卓系统对每个应用…

什么才是好CDN

选择一种领先于网络和移动技术不断进步以及不断演变的威胁格局的CDN,将使您能够始终如一地为客户提供尽可能好的在线体验,同时最大限度地降低运营复杂性和管理成本。 但问题来了:什么才是最好的CDN? 这个问题的唯一答案是&#x…

Tomcat概述以及部署与优化

一、Tomcat概述 1、Tomcat的概念 Tomcat是Java语言开发的,服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。一般来说&am…

Flutter开发日常练习-小猫咪杂货店(新增动画和跳转抖音)

之前的练习加了个详情页面,然后跳转第三方页面抖音用户详情页面 跳转详情页添加了Hero的动画,共享元素过度 一个 标准 hero 动画 使 hero 从一页飞至新页面,通常以不同大小到达不同的目的地。 设定好每个图片的id,通过id作为 Hero 组件的标识,id不能重,否则会报错&…

OSCP-Medjed(重置用户密码、mysql写webshell、可写文件替换提权)

目录 扫描 FTP WEB 提权 扫描 FTP 尝试登录到FTP服务器,该服务器位于端口30021 使用Filezilla,并能够浏览文件。那里有一些配置文件,但找不到任何值得注意的东西,不能写入目录。

算法--前缀和技巧 (蓝桥杯123-灵能传输)

文章目录 什么是前缀和用途什么时候用例题[蓝桥杯 2021 国 ABC] 123题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示 思路代码 灵能传输(蓝桥杯96%,洛谷ac)[蓝桥杯 2019 省 B] 灵能传输题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1…

【Leetcode -21.合并两个有序链表 -83.删除排序链表中的重复元素】

Leetcode Leetcode-21.合并两个有序链表Leetcode-83.删除排序链表中的重复元素 Leetcode-21.合并两个有序链表 题目:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 输入:l1 […

【Web3.0大势所趋】我看到了互联网未来的模样

前言 Web3.0 是一个越来越受到关注的话题,它被认为将会带来天翻地覆的变化。本文我们一起来谈谈 Web3.0 的概念、特点和优势,并探讨它为什么如此重要和具有革命性的。 文章目录 前言Web3.0是什么Web3.0的技术Web3.0的优势总结 Web3.0是什么 Web3.0: 是下…

MATLAB实现图像滤波及噪声消除

图像增强是指根据特定的需要突出一幅图像中的某些信息,同时削弱或去除某些不需要的信息的处理方法。其主要目的是使处理后的图像对某种特定的应用来说,比原始图像更适用。因此,这类处理是为了某种应用目的而去改善图像质量的。处理的结果使图…