WEBGL 2D游戏引擎研发系列 第三章 <正交视口>
作者:HTML5游戏开发者社区-白泽
转载请注明出处: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,朋友,上一个章节怎么样了?是不是感觉进入了新的一个领域,而且复杂度一下就上升了呢?当然了,要做高品质高帧率的游戏当然就得付出更多的努力了,教你一个小技巧,把第一章的内容背下来,这样可以在你脑海里形成一个思维体系,某一些API还不理解不要紧,经验在于实战,用多了就会感悟了,今天本章的内容是2D游戏很关键的一部分,没有这一步,就没有2D游戏,这也是2D和3D开始分解的关键点,正交视口,通常在这里你使用的引擎或者看到的教程都会告诉你需要导入一个外部库,因为这里需要矩阵的计算,在3D教程中,和本章类似的部分通常会告诉你一个3D空间的坐标系,还有一个透视的投影原理等等,不过我建议你最好还是提前了解一个大概,网上已经有很多教程了,在3D空间中,物体遵循近大远小的规律,但是在2D游戏是没有Z轴的,所以没有这个概念,并且你也不希望你的显示对象上下左右移动时会越来越小吧,所以我们会使用一个叫正交的投影原理,正交也就是除去近大远小的规律,物体投影的点始终以水平线投影到目标上,这正好符合我们2D游戏的规律,那么,你现在最需要的什么,就是一段4*4的正交视口转换的矩阵模型,下面是公式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* 正交视口模型矩阵
* @param m 正交的一维数组
* @param left 左边界
* @param right 右边界
* @param bottom 底边界
* @param top 上边界
* @param near 近截面
* @param far 远截面
*/
function
orthoM(m,left,right,bottom,top,near,far)
{
m[0] = 2.0*1.0/(right - left);
m[5] = 2.0*1.0/(top - bottom);
m[10] = 1.0/(far - near);
m[12] = (right + left)/(right - left);
m[13] = (bottom + top)/(bottom - top);
m[14] = near/(near - far);
m[1] = m[2] = m[3] = m[4] =m[6] = m[7] = m[8] = m[9] = m[11] = 0;
m[15] = 1.0;
}
|
实际上4*4的矩阵是二维的,为什么我们要使用一维的呢,因为如果你考虑跨平台通用性,就必须考虑使用一维的数组,有一些平台是只支持一维数组,现在你需要创建这么一个数组
打开DisplayerObjectGL.js
加入新的变量
1
2
|
//正交矩阵
var
oRMatrixList=[];
|
为了使用正交矩阵的公式,你还需要一个场景的宽度和高度的比例
1
|
var
ratio=1024/768;
|
然后在刷新函数里去调用这个函数
1
|
orthoM(oRMatrixList,-ratio,ratio,-1,1, -10, 1000);
|
第一个参数我们把刚才初始化的一维数组传递进来,第二个参数是左右的缩放的系数,通常我们使用场景的高度为确定值,宽度则是利用场景的宽度/高度这样的系数动态改变,通常的参数分为左边和右边,后面的-1,1是高度比,上面和下面,这里有一个小技巧你可以同时给这4个参数加上一个值来做镜头的移动,最后2个参数是近截面和远截面,什么意思呢?因为我们人类观察物体是有一个盲区的,比如,你可以把你的手机近距离的靠近你的眼睛,这时候你是看不清楚手机的,你甚至无法分辨它是一个手机还是一个其他的物体,并且会产生重影,如果你把手机放远了看,你一样是看不清,所以我们人类观察任何物体都是在离人眼一定距离和范围之内的,在3D中,小于这个范围的为了节省性能会被删除掉不显示,远了也一样,否则显示器不像人眼,你永远无法让你的手机无限的靠近你的眼球,因为你有鼻梁,有骨骼,而在显示器里则会无限制的放大,但其实这是无意义的,所以你在玩某个3D游戏穿越某个物体时它在一定的距离后会消失不见就是这个原因.现在,正交视口通过我们的公式已经处理完毕了,我们需要上传到顶点着色器 :
1
2
3
|
//上传正交矩阵,先在着色器中查询对应的矩阵寄存器名称然后把结果上传,后面的参数是否转置矩阵,默认吧,最后的参数是接受
//一个一维数组,也就是我们计算4*4的矩阵,长度为16的一维数组
gl.uniformMatrix4fv(gl.getUniformLocation(shaderProgram,
"oRMatrix"
),
false
,oRMatrixList);
|
我们把矩阵信息传递给一个叫oRMatrix的寄存器,我们最终需要让这个矩阵寄存器和我们的坐标向量相乘,比如这样
1
2
3
4
5
6
7
8
9
10
11
12
|
//正交矩阵,注意了,类型不同了,这里是mat4,也就是4*4的矩阵意思
uniform mat4 oRMatrix;
//执行的代码片段放这里
void main(void) {
//gl_Position是内置寄存器,它是一个4维的寄存器,但实际上我们的2D游戏只用到了2维,所以我们可以强制转换类型,
//把前面2维的寄存器丢进去,因为还有剩下的2维,所以你可以填入默认值,1,1
//把矩阵和坐标向量相乘得出了最终的坐标
gl_Position = oRMatrix*vec4(aVertexPosition,1.0,1.0);
//这是一个神奇的过程,你看不到插值计算你只要把UV信息给这个寄存去,它传递到像素着色器时再获取就是插值后的坐标了
vTextureCoord = aTextureUv;
}
|
如果你的代码没有出现问题的话,现在你的画面应该是这个样子了
发现区别了吗,我们的图像不再填充整个画面,而是显示出了正确的宽度高度比,这就是正交视口的功能,但是还是不对,我们上传的图片是512*512的,这里明显大了哦,那是因为我们的顶点坐标还没有改变,我们现在的四角形的高也就是2,2是等于场景的高度的,也就算是768,所以我们需要计算出512实际在768的比例是多少,比如512/768,然后让顶点坐标都乘以这个比例系数
1
2
3
4
5
6
|
var
vertices = [
-1.0*512/768, -1.0*512/768,
//左下角
1.0*512/768, -1.0*512/768,
//右下角
1.0*512/768, 1.0*512/768,
//右上角
-1.0*512/768, 1.0*512/768
//左上角
];
|
看到了吗,很简单,为了方便你的观看,我就直接写在这里了,但实际上在引擎中,这里的只是需要交给一个矩阵去代理的,因为你最终需要通过顶点对这个显示对象去旋转缩放倾斜等等,加入这段代码之后你现在显示的图片应该就是正常的大小了
因为本教程是以最简短的方式呈现的代码,所以里面的结构不代表最终的引擎结构,有很多细节是需要优化的,而这些优化是直接关系到你的引擎效率问题,但是目前来看,我们暂时不需要关注,重要的是你是否掌握了使用方法呢?下一章节,我们需要自己写一个矩阵类,来操作这个图片了,有了它就可以实现游戏的基本功能了,下面是DEMO和源码地址,演示地址建议用谷歌浏览器打开.