6.7 使用投影矩阵(Switching to a Projection Matrix)

我们现在开始使用透视投影矩阵,打开AirHockeyRenderer并且移除onSurfaceChanged()方法中除了调用glViewport()的所有代码。添加如下代码:

//AirHockey3D/src/com/airhockey/android/AirHockeyRenderer.java
MatrixHelper.perspectiveM(projectionMatrix, 45, (float) width/ (float) height, 1f, 10f);

这将会创建一个视角为45度的透视投影矩阵,相应的z轴坐标开始于-1终止于-10处。

当导入MatrixHelper类并且正确编译运行后,你会发现桌面不见了!因为我们没有为桌面指定z轴位置,它的默认位置是0,而我们的视锥体开始于z轴的-1处,所以我们是不会看到桌面的,除非我们把桌面移入到视锥体范围内。
    这里为了不把z的位置写死,我们在使用投影矩阵之前先用平移矩阵把桌面移入视锥体中,按照约定,我们称这个矩阵为模型矩阵。

6.7.1 使用模型矩阵移动物体(Moving Objects Around with a Model Matrix)

在AirHockeyRenderer类的顶部增加如下定义:

//AirHockey3D/src/com/airhockey/android/AirHockeyRenderer.java
private final float[] modelMatrix = new float[16];

我们将会使用这个矩阵把桌面移入到视锥体范围内,在onSurfaceChanged()函数最后添加如下代码:

//AirHockey3D/src/com/airhockey/android/AirHockeyRenderer.java
setIdentityM(modelMatrix, 0);
translateM(modelMatrix, 0, 0f, 0f, -2f);

上面的代码将会把模型矩阵重置为单位矩阵,然后向z轴平移-2个单位;当我们把桌面的顶点坐标与这个矩阵相乘的时候,这些顶点坐标将会向着z轴负方向平移两个单位;这样就可以将会桌面移入视锥体范围内了。

6.7.2 乘一次VS乘两次(Multiplying Once Versus Multiplying Twice)

我们现在有一个选择:我们仍然需要把这个矩阵与每一个顶点相乘,因此我们的第一个选择是把这个矩阵添加到顶点着色器中。首先每一个顶点与模型矩阵相乘,这样的话每个顶点都会沿着z轴负方向平移两个单位,然后再把每一个顶点与投影矩阵相乘以便OpenGL可以做透视分割并且把顶点转化为规范化设备坐标。
    上面的方法可行,但是比较麻烦;这里有一个比较好的方法,我们把把模型矩阵与投影矩阵相乘得到一个新的矩阵,然后把这个新矩阵传递给顶点着色器,这样的话顶点着色器还是只有一个矩阵而我们也不需要修改顶点着色器。

6.7.3 矩阵相乘(Matrix Multiplication)

矩阵、矩阵相乘与矩阵、向量相乘相似,假如我们有如下两个矩阵:

我们把第一个矩阵的第一行元素与第二个矩阵的第一列元素相乘相加得到结果矩阵的第一个元素,如下所示:


    然后把第一个矩阵的第二行元素与第二个矩阵的第一列元素相乘相加得到结果矩阵的第二个元素,如下所示:


    依此类推计算结果矩阵的每一个元素。

6.7.4 矩阵相乘顺序(Order of Multiplication)

我们现在知道如何将两个矩阵相乘,但是我们需要确保两个矩阵是以正确的顺序相乘的;我们可以将投影矩阵放在左边而将模型矩阵放在右边或者将模型矩阵放在左边而将投影矩阵放在右边。
    不像普通的乘法,这个顺序非常重要!如果我们把顺序搞错了,那么结果会很奇怪或者我们把什么看不到!下面的例子是两个矩阵相乘的一种顺序:


    下面是两个相同矩阵不同相乘顺序:


    由此可知,使用不同的顺序结果也不一样。

6.7.5 选择正确的相乘顺序(Selecting the Appropriate Order)

为了确定正确的相乘顺序,我们来看看仅仅使用投影矩阵时的情况:


     代表与投影矩阵相乘前的场景中坐标,一旦我们使用模型矩阵移动桌面,运算将会如下所示:

 代表使用模型矩阵将其移动到场景中之前的坐标,将这两个表达式联合起来将得到如下表达式:


    为了将这两个矩阵替换为一个矩阵,我们把投影矩阵与模型矩阵相乘,投影矩阵在左边而模型矩阵在右边。

6.7.6 使用单个矩阵实现投影(Updating the Code to Use One Matrix)

在onSurfaceChanged()中 translateM()调用的后面添加如下代码:

//AirHockey3D/src/com/airhockey/android/AirHockeyRenderer.java
final float[] temp = new float[16];
multiplyMM(temp, 0, projectionMatrix, 0, modelMatrix, 0);
System.arraycopy(temp, 0, projectionMatrix, 0, temp.length);

当我们将两个矩阵相乘的时候,我们需要一个临时存储区域存储结果,如果直接将他们相乘,那结果将会是未定义的。
    我们首先创建了一个临时一维float类型数组来储存计算结果,然后调用multiplyMM()将投影矩阵与模型矩阵相乘并储存到临时数组中。下一步调用System.arraycopy()把临时结果存储到projectionMatrix中,这时该矩阵包含了模型矩阵与投影矩阵的变换功能了。
    现在运行我们的运用,将会看到如下效果:

现在已经把桌面绘制出来了,但却是从一个垂直角度看上去的效果;现在我们简单复习下这一节学了些什么,在下一节中我们将学习如何旋转桌面使得视角有一个角度而不是垂直的。

6.7.7 小节(A Quick Recap)

现在简单复习下在这一节中我们学习了些什么:
    1) 在把顶点转递给投影矩阵之前如何使用另外一个矩阵------模型矩阵把桌面移动到视锥体范围内。
    2) 两个矩阵如何相乘
    3) 如何把模型矩阵与投影矩阵整合起来,这样我们就不需要修改着色器来接收另外一个矩阵(并且避免了着色器运行时两个矩阵都会相乘的计算开销)

Part I 空气曲棍球 Chapter6(6.7 Switching to a Projection Matrix)相关推荐

  1. Part I 空气曲棍球 Chapter6(6.5 Defining a Perspective Projection)

    6.5 定义一个透视投影(Defining a Perspective Projection) 透视投影矩阵需要与透视分割配合才能构造出3D效果,投影矩阵并没有透视分割的能力,透视分割也需要其它因素一 ...

  2. Part I 空气曲棍球 Chapter6(6.1 The Art of 3D)

    6.1 3D的艺术(The Art of 3D) 几个世纪以来,艺术家们通过他们特殊的技巧在2D的纸张上画出3D场景,其实他们只是使用了线性映射这样一种技术而已,想像下一些平行的直线,当你从一端看去的 ...

  3. Part I 空气曲棍球 Chapter6(6.8 Adding Rotation)

    6.8 增加旋转(Adding Rotation) 前面我们使用投影矩阵配合模型矩阵把桌面移入了我们的视野,现在我们要做的是给桌面增加一个旋转角度使得桌面看上去有一个角度以便增加立体感.使用旋转矩阵我 ...

  4. Part I 空气曲棍球 Chapter6(6.4 Moving to a Perspective Projection)

    6.4 创建透视投影(Moving to a Perspective Projection) 在学习透视投影背后的矩阵运算之前,我们先来看看一个例子.在前一章节中,我们使用正交投影来适配视口在进行规范 ...

  5. 空气曲棍球 由哪几部分组成_Excel中的曲棍球运动员数据分析

    空气曲棍球 由哪几部分组成 Congratulations to the USA Women's Hockey team, who won the Olympic gold medal. They b ...

  6. 《OpenGL ES应用开发实践指南:Android卷》—— 2.1 为什么选择空气曲棍球

    本节书摘来自华章出版社<OpenGL ES应用开发实践指南:Android卷>一 书中的第2章,第2.1节,作者:(美)Kevin Brothaler ,更多章节内容可以访问云栖社区&qu ...

  7. Part I 空气曲棍球 Chapter8(Building Simple Objects)

    我们的空气曲棍球项目已经捣鼓好久了,现在绘制出来的桌面也是呈现出了一个好视角并且配合纹理映射后看起来更好了:然而由于球棍只是一个点所以看起来并不像真正的球棍,你能想象下使用像一个点一样的球棍打球会是什 ...

  8. 《OpenGL ES应用开发实践指南:Android卷》—— 2.3 定义空气曲棍球桌子的结构...

    本节书摘来自华章出版社<OpenGL ES应用开发实践指南:Android卷>一 书中的第2章,第2.3节,作者:(美)Kevin Brothaler ,更多章节内容可以访问云栖社区&qu ...

  9. Part I 空气曲棍球 Chapter9(Adding Touch Feedback)

    通过支持触控反馈获得好的用户交互体验是很多应用和游戏的基石,这样会让用户觉得他们能真正使用一些真实的东西,即使用户只是对着空白的屏幕也是如此.一些手机游戏之所以非常流行只是因为增加了一些触控而已:此时 ...

最新文章

  1. oracle安装清单过不去,oracle 11g(二)安装过程
  2. cube、rollup及exec的用法实例
  3. discuz mysql_搭建Discuz! (mysql+apache+Discuz! )
  4. 小白的奇幻数学课堂(part3)--你能把一张纸对折7次以上吗
  5. java控制图片移动_多线程控制图片移动
  6. 什么是换码符(escape character)?
  7. pytorch的nn.CrossEntropyLoss()函数使用方法
  8. 关于经典机器学习算法的一个总结
  9. 监控摄像机的区别和分类
  10. 在windows实现和smtp交互发送邮件
  11. SonicWall宣布推出全新渠道伙伴计划,为中小型企业的网络安全提供可靠防护
  12. 现控笔记(三):状态空间表达式的解
  13. TCP实现原理(三次握手与四次挥手)
  14. conda安装tensorflow-GPU出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url错误
  15. php 跨域 session,php session 跨域的解决办法
  16. 一起写RPC框架(七)RPC网络模块的搭建五 Netty模块
  17. 计算机备品备件如何管理,备品备件管理系统
  18. 网站怎么被搜索引擎快速收录?
  19. 干货分享:Windows资源管理器无限重启?解决方法竟然是…
  20. 六、Hystrix详解三:Hystrix的健康监测

热门文章

  1. 如何在linux运行spawn,expect spawn、linux expect 用法
  2. Fidder Script
  3. 2020年中国互联网之大事件(一)
  4. 计算机网络安全混合加密算法,计算机网络安全中数据加密技术的应用研究
  5. 关于HttpEntity的用法
  6. opencv 二值化 matlab,opencv-python图像二值化函数cv2.threshold函数详解及参数cv2.THRESH...
  7. linux定时python,linux 中定时执行python脚本
  8. 伤不起的戴尔台式机XPS8700脆弱的蓝牙
  9. STM32F103在线升级程序
  10. 互联网黑话,我忍你很久了!