WEBGL 2D游戏引擎研发系列 第四章 <感想以及矩阵>

来源:互联网 发布:淘宝指数官网 编辑:程序博客网 时间:2024/05/17 00:19

WEBGL 2D游戏引擎研发系列 第四章 <感想以及矩阵>

HTML5游戏开发者社区(群号:326492427)

转载请注明出处:http://html5gamedev.org/

 

 

  • HTML5 2D游戏引擎研发系列  第一章 <一切的开始>
  • HTML5 2D游戏引擎研发系列 第二章 <磨剑>
  • HTML5 2D游戏引擎研发系列 第三章 <Canvas技术篇-画布技术-显示图片>
  • HTML5 2D游戏引擎研发系列 第四章 <Canvas技术篇-画布技术-基于手动切片动画>
  • HTML5 2D游戏引擎研发系列 第五章 <Canvas技术篇-画布技术-纹理集复杂动画>
  • HTML5 2D游戏引擎研发系列 第六章 <Canvas技术篇-画布技术-混色特效和粒子>
  • HTML5 2D游戏引擎研发系列 第七章 <Canvas技术篇-画布技术-鼠标侦听器>
  • HTML5 2D游戏引擎研发系列 第八章 <Canvas技术篇-基于顶点绘制与变形>
  • WEBGL 2D游戏引擎研发系列 第一章 <新的开始>
  • WEBGL 2D游戏引擎研发系列 第二章 <显示图片>
  • WEBGL 2D游戏引擎研发系列 第三章 <正交视口>
  • WEBGL 2D游戏引擎研发系列 第四章 <感想以及矩阵>
  • WEBGL 2D游戏引擎研发系列 第五章 <操作显示对象>
  • WEBGL 2D游戏引擎研发系列 第六章 <第一次封装>
  • WEBGL 2D游戏引擎研发系列 第七章 <混色>
  • WEBGL 2D游戏引擎研发系列 第八章 <批处理(影分身之术)>
  • WEBGL 2D游戏引擎研发系列 第九章 <基于UV的模拟切片>
  • WEBGL 2D游戏引擎研发系列 第十章 <纹理集动画>
  • WEBGL 2D游戏引擎研发系列 第十一章 <着色器-shader>
  • WEBGL 2D游戏引擎研发系列 第十二章 <粒子发射器>
  • WEBGL 2D游戏引擎研发系列 第十三章 <Shader分享>
  • 游戏技法 2D游戏引擎研发系列 第一章 <优化技巧>
  • 游戏技法 2D游戏引擎研发系列 第二章 <计时器>
  • 游戏技法 2D游戏引擎研发系列 第三章 <基于UV的无缝图像滚动>
  • 游戏技法 2D游戏引擎研发系列 第四章 <基于形状的碰撞检测>

               HI,今天的章节我们不得不谈谈矩阵了,在之前的章节中它总是在关键的时刻出现,而我们总是忽略了它,因为如果要保持文章的内容简单,我们不得不规避它,现在,我需要花一章的时间来讲讲矩阵,而矩阵可以说是开发引擎里最难的部分,实际上我试过没有矩阵一样可以像矩阵一样去操作显示对象,但是太过于麻烦,在这里我想先偏离主题,谈谈我的一些感受,很早之前我的一个朋友自己做了一套骨骼编辑器,我当时看了非常惊奇,我说你开发这套骨骼编辑器需要用到反向运动学吧,他反而用一脸更加惊奇的表情看着我说,什么是反向运动学,我就是用三角函数让它们符合逻辑的去运动而已,他的这个回答让我思考了许久,其实我也一直想开发一套属于自己的骨骼编辑器,但是我不幸的是了解的反向运动这个概念,更加不幸的是了解他有多么复杂,所以我一直在阻止我自己去做方面的研究,这和我最早想开发自己的引擎的想法是一样的,因为我当时什么都不懂,不知道有openg,不知道有着色器,不知道固定管线还是可编程管线是什么意思,当然了,更加不知道矩阵是怎么用,我只有一个目标,就是希望利用原生的API写出自己的东西,记得最早学习的技术是J2ME,那会智能手机还没有流行,或者说,那会有方向键可以选择应用程序的就算是智手机了,要玩手机游戏你需要去论坛你找你相应的手机类型的游戏,所以那时候根本就没有太多的游戏引擎给你选择,你只能自己动手,从那时候开始接触的就是2D渲染技术canvas,因为之前在学校里自学过flash,我当时的认知就是显示图片只要2句话,new和addChild,但是接触canvas之后觉得他的绘图过程相当的复杂,并且难以修改,每次修改游戏逻辑块时都要去修改底层的canvas,所以当时我就做了一个决定,我要像使用flash一样去使用canvas,我要显示图片也只需要两句话,于是我就这么做了,效果很明显,当我完成这个可以说是框架的东西后,我进步神速,我已经不在关心底层如何去绘制了,我只需要关心我的游戏如何去实现,所以,当同学们还在研究怎么拼接地图,怎么滚动地图时,我就已经开始制作射击游戏,塔防游戏,拼图游戏了,下面你可以欣赏一下,当然了,素材是扒皮的.

game

                在那个时代,不管你喜欢还是不喜欢,多数情况下你只有2个选择,要么每个游戏都从0代码开始编写,让绘图参与游戏逻辑,要么你写一个属于自己的引擎来封装这一切,当然了,至少我接触的人中,多数选择前者,这样导致了开发工作量的难度提升,和修改难度增加,最终导致了很多人放弃,在我的同学中,多数放弃的人都去做策划了,好吧,我没有其他意思,接着往下说,和现在对比,不管你在哪个语言领域开发游戏,最先送到你面前的就是各种第三方引擎和工具库,工作招聘也是需要使用某个引擎或者框架为审核条件,所以,如果现在把你硬盘上的女神和所有第三方引擎和文档删除掉,放在当时那个年代,你是否还会坚持你的游戏梦想?你是否还能完成游戏的开发工作呢?回想一下,我们现在做为一名游戏开发工程师,究竟是使用者,还是开发者,现在游戏开发的配套工具越来越强大,流程越来越规范,渐渐的让我们失去了对底层的原理探究的心态,也开始了排斥心里,我听得最多的一句话就是,不要重复造轮子,这句话没错,重复的工作是无意义的,但是这个轮子是别人造的,试想一下你乘坐的马车轮子坏了,你是去修复这个轮子还是等待造轮子的工匠过来,再等待的期间你是愿意做一个修复轮子的工匠还是一个盲目等待的人,我觉得重复工作是需要条件的,如果每次开发游戏你都是从底层渲染开始写起这就是重复劳动没有意义,但是用着别人写好的轮子来告诉自己不要重复劳动这无异于给自己日后留下了大大的一个坑,一个自己无法弥补的坑,j接着来谈谈我是如何开始接触opengl的,人的追求是无法满足的,当时安卓系统出来了,我开始使用canvas去开发游戏,我已经不需要去关注如何使用API了,但是新的问题来了,效率,当时canvas的效率已经不能满足我了, 我需要制作60帧率的游戏,于是我开始寻找方法,在网上搜寻中,我发现了一个之前没怎么接触过的技术,opengl es,当时我的理解是,这是开发高级3D游戏程序用的,而且是GPU硬件加速,其他的我没记住,反正我就记住了2个词,高级,硬件加速,于是之后就是我在本系列教程的第一章里写的一样,当时教程非常非常的难找,我花了200多块钱买了一套视频教程,我只看了前八章,因为我花钱买教程的目的不是为了学习而学习,我只是有目标的在寻找,我的目标很简单,像使用canvas一样去使用opengl es,他们是否有共同点,我需要掌握一套显示图片的原理和API的解决方案,因为前八章是基础篇,而基础篇正好有我需要的内容,于是,就这样我开始了在新的领域里的探索,每当我有新想法时,我会再去寻找,而不是跑马灯一样的去学习,所以这个过程是不停的探索,不停的验证,我没有退路,没有第三方提供可靠的引擎给我使用,所以所有的一些不管懂还是不懂只有自己动手写,但是给我的感觉是,当年的技术是很简单的,没有复杂的框架限制,也没有所谓的理论,但是现在看来,我觉得很多技术都越来越复杂,这也是我一直在思考的问题,我问过很多人,你为什么不自己写一套引擎呢?回答多数是自己写?没可能的,原因是现在的第三方提供的引擎非常强大,一个人的力量是无法完成的,而且需要大量的数学运算,还需要对底层架构有一定的了解,所以从这个结论来看,自己写=没可能,而且难度极大,现在让我们回想一下,所谓的难度是如何在人类的思维里定义的,难通常是描述一个没有把握的事情,而且多数是不了解的事情,新手觉得某个问题很难解决,老手在你问他时他就已经在脑海里有一套解决方案了,所以简单,我们或许可以再深入一些,没有把握的事情和不了解的事情是如何发生的,因为对于某个事情不明白缘由,起始,害怕失败,好了,这就是我们深入的关键,不明白事情的起始就是我们觉得难的关键所在,我们习惯了第三方提供的工具来实现某个目的,但是不明白它的缘由,所以认为自己写一套一样的很难,我们已经习惯了把图片地址传入给引擎就能简单的去显示这个图片,但是不明白图片为何能显示的缘由,所以认为自己写一套一样很难,我们已经习惯了使用各种各样的插件引擎工具来实现某个目的,但是我们不了解他们底层的逻辑所以,觉得要自己实现很难,所以,当我了解到这个真理之后,我学习任何技术都习惯性的去了解它的本质,它如何产生的,因什么而产生,最后才是如何使用,但是你要知道掌握原理的人是少数,多数是使用者,即使一个很常用的技术,你在网上寻找到的多数也是如何使用,久而久之让我们的思维固态化,觉得自己实现很难,但是你一旦掌握了它的缘由本质,你就不会再觉得难,顶多就是你写得没有别人的好,效率没有别人的高,但这是另外一个问题了,至少你不会再觉得它很难,好了,我偏题偏得太厉害了,所以我都把文章的标题给改了,本来叫矩阵,现在想想还是叫感想以及矩阵比较好,现在,我们要回到正确的话题了,矩阵,因为矩阵多数人认为它是很难的东西,并且这是自己开发引擎的关键部分,所以我需要花大量的文字来让你做好心里准备。

            我最早接触矩阵的时候,也觉得它非常的难,难在他的写法,我不懂他为何要这么写,更加不懂一些变换的操作和矩阵有什么关系,他为什么要这么做,所以理解起来非常非常的困难,现在我告诉你矩阵为何要这么样,好吧,现在幻想一下你是一个魔法师,你需要让一个人从A点瞬间移动到B点,你需要画一个魔法阵,可能是这样

QQ截图20131002013824

我们现在假设小人的头是坐标点,黄色小人是开始点,蓝色小人是目标点,你很容易算出他们之间的坐标相差多少,然后你可以很简单的让黄色小人的坐标加上这个值就可以到达蓝色小人的位置,当然了,这是初级魔法,不需要用到矩阵,我们来看看高级一点的,现在我们需要移动多个黄色小人,并且条件是黄色小人的相对位置不能改变,不能变形,比如这样

QQ截图20131002014333

好吧,难道这样你还希望按照上面的方式去计算吗?或者,可以再加上旋转,比如这样

QQ截图20131002014456

                 我觉得这样你应该没有办法计算出蓝色小人究竟在什么位置了,这时候就需要用到矩阵了,现在,为了保持简单,你可以把矩阵当作一个魔法,它能实现你的目的,那么这个矩阵需要一个模版,和黄色小人的坐标,你只需要往模版里输入你要操作的数据,比如位移多少,旋转多少,然后让黄色小人的坐标和这个模版魔法一下那么这个魔法就会帮你算出最终蓝色小人的位置,矩阵的模版看起来是这样

?
1
2
3
4
5
6
7
8
9
10
11
12
13
//旋转
spinArray=[
[Math.cos(rotation * Math.PI /180),Math.sin(rotation * Math.PI /180),0],
[-Math.sin(rotation * Math.PI /180),Math.cos(rotation * Math.PI /180),0],
[0,0,1]
];
  
//平移,缩放,倾斜
translationArray=[
[scaleX,biasY,0],
[biasX,scaleY,0],
[x,y,1]
]

这个模版现在看起来就是一个二维数组,并且把你的输入参数按照一定的规律去放在了这个矩阵的位置上,在这之后你可能会遇到各式各样的矩阵模版,你可以存储起来,当作你的魔法工具,如果你需要明白这个参数为何要这么排列,你可以看看我的canvas系列的第二章,那里有介绍一本书,里面有非常非常详细的算法论证过程,但是算法类的论证你可以去探究,或者你也可以选择记住这个公式,但这个方式只限于数学公式,现在,我们剩下最后一步,不过在此之前,我们一直用黄色小人坐标这个来表述坐标点,现在我们需要一个新的名词,叫向量,从字面上理解就是方向和大小(量),比如[2,2]这可以说是一个向量,从原点0,0到2,2的向量,或者图片更加容易理解

QQ截图20131002020736

 

蓝色的剪头指向的坐标点是2.2你也可以说蓝色的剪头是2,2的向量,很容易理解不是吗,在2D中它的向量一般是[x,y],3D中一般是[x,y,z],但一般情况下你需要保留多余,方便我们的矩阵模版,这个多余的一位一般叫齐次坐标,所以一般是[x,y,w]和[x,y,z,w],在2D中w一般为1,或者可以理解为在它看上去是在3D坐标系里Z轴为1的情况下,现在我们所谓的魔法,就是让黄色小人的向量乘以矩阵的模版,比如这样

[x,y,w]*[[x,y,z],[x,y,z],[x,y,z]]

关键的地方来了,向量和矩阵相乘是把向量的列元素乘以矩阵的行元素然后相加,假设我们有一个向量坐标为a和一个矩阵模版为b,最终得出结果是一个向量c

a=[2,2,1]

b=[
[Math.cos(45*Math.PI/180),Math.sin(45*Math.PI/180),0],
[-Math.sin(45*Math.PI/180),Math.cos(45*Math.PI/180),0],
[0,0,1]
];

相乘就是

c=[
a[0]*b[0][0]+a[1]*b[1][0]+a[2]*b[2][0],
a[0]*b[0][1]+a[1]*b[1][1]+a[2]*b[2][1],
a[0]*b[0][2]+a[1]*b[1][2]+a[2]*b[2][2]
];

别看错拉,c是一个一维的向量,而这个c就是通过矩阵变换后的蓝色小人的位置,是不是很简单?最后回顾一下,A向量与B矩阵模版相乘得出一个C向量,而这个C向量就是A向量通过矩阵模版变换后的向量也就是最终的坐标点,除了向量和矩阵相乘之外还有矩阵和矩阵相乘,你还记得上面有2个矩阵模版吗?一个用于旋转一个用于位移,而且更多时候是这样,A矩阵模版有一系列的操作,B矩阵模版也有一些列的操作,如此下来,你会有N个矩阵,在2D中,你可以利用这个特性做图层嵌套操作,比如把显示对象a放在b中,再把b放入c中,那么实际上你移动c也就是移动了a和b,或者你先移动c,再缩放b,再旋转a,那么实际a的位置是基于它的父级和爷级的操作,所以你可以理解为a有一个自己的矩阵,b也有一个自己的矩阵,c同样,而最终的的矩阵是a的矩阵*b的矩阵*c的矩阵得出一个最终的变换矩阵,然后再用这个最终的变换矩阵和a的实际坐标向量相乘得出了最终的坐标,接下来看看矩阵和矩阵是如何相乘的,假设有a1和a2两个矩阵,对新矩阵里的任意元素取a1的第N行和a2的第N列,将行和列中的对应元素相乘然后相加,还是看下面的过程吧,我用颜色标记出来

d = [
[a1[0][0]*a2[0][0]+a1[0][1]*a2[1][0]+a1[0][2]*a2[2][0],a1[0][0]*a2[0][1]+a1[0][1]*a2[1][1]+a1[0][2]*a2[2][1],a1[0][0]*a2[0][2]+a1[0][1]*a2[1][2]+a1[0][2]*a2[2][2]],
[a1[1][0]*a2[0][0]+a1[1][1]*a2[1][0]+a1[1][2]*a2[2][0],a1[1][0]*a2[0][1]+a1[1][1]*a2[1][1]+a1[1][2]*a2[2][1],a1[1][0]*a2[0][2]+a1[1][1]*a2[1][2]+a1[1][2]*a2[2][2]],
[a1[2][0]*a2[0][0]+a1[2][1]*a2[1][0]+a1[2][2]*a2[2][0],a1[2][0]*a2[0][1]+a1[2][1]*a2[1][1]+a1[2][2]*a2[2][1],a1[2][0]*a2[0][2]+a1[2][1]*a2[1][2]+a1[2][2]*a2[2][2]]
];

别看错了,d是一个矩阵也就是一个二维数组,矩阵和矩阵相乘最终也是得到一个矩阵,现在你只需要理解这个规律在之后的章节中,我们需要自己去实现一个矩阵类,因为我们实际上是用矩阵对4个顶点做变换操作,也就是说让这个4个向量分别乘以模版矩阵来实现4个顶点的变换,并且保持相对坐标不变,比如这样

QQ截图20131002025113

 

现在,你明白了矩阵了吗,它唯一的目的就是让N个顶点做同样的变换操作,我们是用4个顶点来描述一个图像,所以需要4个顶点做统一的变换才能保持图像不会被变形并且看起来就好像是这个图像做了变换,其实是每个顶点都运算了一次矩阵操作,好了,本章到这里就结束了,下一章节我们会利用矩阵的知识开始实际操作显示对象了,很期待呢。

 

 

0 0
原创粉丝点击