热门标签 | 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


推荐阅读
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • PBO(PixelBufferObject),将像素数据存储在显存中。优点:1、快速的像素数据传递,它采用了一种叫DMA(DirectM ... [详细]
  • 普通树(每个节点可以有任意数量的子节点)级序遍历 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • C++ 开发实战:实用技巧与经验分享
    C++ 开发实战:实用技巧与经验分享 ... [详细]
  • 可参照github代码:https:github.comrabbitmqrabbitmq-tutorialsblobmasterjavaEmitLogTopic.ja ... [详细]
  • 第14周实践项目(4)-验证平衡二叉树
    问题**Copyright(c)2015,烟台大学计算机学院*Allrightsreserved.*文件名称:test.cpp*作者:王敏*完成日 ... [详细]
  • PHP-Casbin v3.20.0 已经发布,这是一个使用 PHP 语言开发的轻量级开源访问控制框架,支持多种访问控制模型,包括 ACL、RBAC 和 ABAC。新版本在性能上有了显著的提升。 ... [详细]
  • Java设计模式详解:解释器模式的应用与实现
    本文详细介绍了Java设计模式中的解释器模式,包括其定义、应用场景、优缺点以及具体的实现示例。通过音乐解释器的例子,帮助读者更好地理解和应用这一模式。 ... [详细]
  • 传统上,Java 的 String 类一直使用 char 数组来存储字符数据。然而,在 Java 9 及更高版本中,String 类的内部实现改为使用 byte 数组。本文将探讨这一变化的原因及其带来的好处。 ... [详细]
  • 本文详细介绍如何使用Netzob工具逆向未知通信协议,涵盖从基本安装到高级模糊测试的全过程。通过实例演示,帮助读者掌握Netzob的核心功能。 ... [详细]
  • Android 自定义 RecycleView 左滑上下分层示例代码
    为了满足项目需求,需要在多个场景中实现左滑删除功能,并且后续可能在列表项中增加其他功能。虽然网络上有很多左滑删除的示例,但大多数封装不够完善。因此,我们尝试自己封装一个更加灵活和通用的解决方案。 ... [详细]
  • com.sun.javadoc.PackageDoc.exceptions()方法的使用及代码示例 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 在使用 SQL Server 时,连接故障是用户最常见的问题之一。通常,连接 SQL Server 的方法有两种:一种是通过 SQL Server 自带的客户端工具,例如 SQL Server Management Studio;另一种是通过第三方应用程序或开发工具进行连接。本文将详细分析导致连接故障的常见原因,并提供相应的解决策略,帮助用户有效排除连接问题。 ... [详细]
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社区 版权所有