热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

opengles透视矩阵投影原理

学习本文前建议先学习前文opengles相关矩阵知识:解决androidopengles绘制物体屏幕横竖屏切换物体压扁形变以及矩阵相关知识在上文中我们知道要把空间物体(下图传给顶点着色

学习本文前建议先学习前文opengl es相关矩阵知识:
解决android opengl es绘制物体屏幕横竖屏切换物体压扁形变以及矩阵相关知识
在上文中我们知道要把空间物体(下图传给顶点着色器的gl_position坐标)最终显示在二维屏幕需要经过归一化设备坐标(在[-1,1]范围),实际opengl经过了具体过程可以用如下流程图来表示:
这里写图片描述
即两个变换和三个不同坐标空间。
可见从gl_position到归一化设备坐标之间的透视除法是很关键的,opengl具体是怎么做的呢,见下文?

透视除法:

回到我们的初心,opengl要解决的问题是在二维平面显示三维图像,这怎么做到尼?这其实是利用了人们大脑的幻象。
我们可以把相对较远的物体在二维屏幕上显示的小一点,比较近的物体我们在屏幕上呈现大一点,比如看铁路,近的看上去大一点,远了小一点这样就有空间感。那么具体多远多大才合适尼?在解决android opengl es绘制物体屏幕横竖屏切换物体压扁形变以及矩阵相关知识一文中我们提出了w坐标分量,这个w分量就是来解决这个问题的。比如有两个点(1,1,1,1)和(1,1,1,2)只是在w的分量不同,这样用x,y,z分别除以w得到x,y,z如下新坐标(1,1,1)和(0.5,0.5,0.5)这样有较大的w分量就离中心(0,0,0)更近了,也就在屏幕的中间了,可见越远的物体w越大,离屏幕中心越近。这也符合我们之前铁路越远越小,越在屏幕中间的效果。

视口变换:
视口(viewport)概念我们已经在之前很多文章提过了,不熟悉可以参考
openGL 3D图形和openGL简介和android studio上第一个opengl es程序相关基础文章里面的概念。

在这个过程opengl做坐标映射的时候,会把从(-1,-1,-1)到(1,1,1)范围映射到为显示而预留的二维窗口中,这个范围之外的会被归一化坐标裁剪到,不会显示在屏幕上。
扯远了,回到上文我们怎么精确确定w分量?opengl给出了透视投影矩阵:
这里写图片描述
在Android中代码层面,在Matrxi类提供了Matrix.frustumM()和Matrix.perspectiveM();方法,但是frustumM有缺陷对某些类型投影,perspectiveM是Android4.x才提出的故有兼容版本问题为此,本文代码给出了自己的实现见MatrixHelper类的perspectiveM方法,值得注意的是透视投影矩阵上的值是按照列坐标映射到float[] m的。代码如下:

public class MatrixHelper {
public static void perspectiveM(float[] m, float yFovInDegrees, float aspect,
float n, float f) {
final float angleInRadians = (float) (yFovInDegrees * Math.PI / 180.0);

final float a = (float) (1.0 / Math.tan(angleInRadians / 2.0));
m[0] = a / aspect;
m[1] = 0f;
m[2] = 0f;
m[3] = 0f;

m[4] = 0f;
m[5] = a;
m[6] = 0f;
m[7] = 0f;

m[8] = 0f;
m[9] = 0f;
m[10] = -((f + n) / (f - n));
m[11] = -1f;

m[12] = 0f;
m[13] = 0f;
m[14] = -((2f * f * n) / (f - n));
m[15] = 0f;
}
}

可以比较上图透视投影矩阵截图和这里的代码,坐标对应关系。
在AirHockeyRenderer类的onSurfaceChanged中可以看到使用了该方法 MatrixHelper.perspectiveM(projectionMatrix, 45, (float) width
/ (float) height, 1f, 10f);即从45度的视野创建一个视景体,视景体的z从-1到-10范围。但是其实此时是看不到的,因为视景体在[-1,-10]而桌子默认z在0不在视景体范围内,为此,我们利用模型矩阵移动物体在这个范围。
模型矩阵:
在 onSurfaceChanged方法中我们接着使用 setIdentityM(modelMatrix, 0);
translateM(modelMatrix, 0, 0f, 0f, -2f);方法,setIdentityM是将模型矩阵modelMatrix初始化为单位矩阵,translateM是将其在沿z轴移动-2单位,接着我们把 投影矩阵和模型矩阵相乘放进临时矩阵final float[] temp,即源码中的final float[] temp = new float[16];
multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0); (这相当于对投影矩阵做了这个z轴-2移动), 然后使用 System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);将临时矩阵里面的值在拷贝到投影矩阵projectionMatrix,这是projectionMatrix包含了原来的投影和现在z轴移动-2单位两个效果,之后把这个矩阵传给顶点着色器,完成投影位移。
同时,代码中 translateM(modelMatrix, 0, 0f, 0f, -2.5f);
rotateM(modelMatrix, 0, -60f, 1f, 0f, 0f);
是沿z轴-2.5个单位移动,然后使用旋转函数rotateM沿x轴旋转-60度,即物体在y-z平面发生旋转,这样更加有空间感。
本文代码:
https://github.com/pangrui201/OpenGlesProject/tree/master/OpenGlesProject_lesson5


推荐阅读
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • Android 渐变圆环加载控件实现
    本文介绍了如何在 Android 中创建一个自定义的渐变圆环加载控件,该控件已在多个知名应用中使用。我们将详细探讨其工作原理和实现方法。 ... [详细]
  • andr ... [详细]
  • 本文介绍了如何使用JQuery实现省市二级联动和表单验证。首先,通过change事件监听用户选择的省份,并动态加载对应的城市列表。其次,详细讲解了使用Validation插件进行表单验证的方法,包括内置规则、自定义规则及实时验证功能。 ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 本文介绍如何使用阿里云的fastjson库解析包含时间戳、IP地址和参数等信息的JSON格式文本,并进行数据处理和保存。 ... [详细]
  • 本文详细介绍如何在VSCode中配置自定义代码片段,使其具备与IDEA相似的代码生成快捷键功能。通过具体的Java和HTML代码片段示例,展示配置步骤及效果。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 本文探讨了在Java中实现系统托盘最小化的两种方法:使用SWT库和JDK6自带的功能。通过这两种方式,开发者可以创建跨平台的应用程序,使窗口能够最小化到系统托盘,并提供丰富的交互功能。 ... [详细]
author-avatar
甘文靖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有