3D坐标系统

五个空间

要把游戏模型显示到屏幕需要经历五个空间。

  1. 局部空间 (Local Space,模型空间)
  2. 世界空间 (Wolrd Space,游戏空间)
  3. 观察空间 (View Space,视觉空间)
  4. 裁剪空间 (Clip Space)
  5. 屏幕空间 (Screen Space)

局部空间 (Local Space)

指模型对象所在的坐标空间,即建模软件的空间。

一般在导出创建的模型时,将模型的的坐标设为(0,0,0),目的是为了保持和世界坐标重合,方便调整其在世界坐标中的位置。

世界空间 (Wolrd Space)

游戏所在的场景就是世界空间。

将模型放到世界空间之后,可以对模型对象进行平移,缩放,旋转等操作,本质上就是通过矩阵的转换算法实现的。(模型举证

观察空间 (View Space)

通过虚拟摄像机观察世界空间。

在游戏中,可以操作视角看到周围的物体。本质就是操作虚拟摄像机,将视线内的物体转换到摄像机的坐标系中。

观察空间也就是摄像机所观察的空间,是将物体对象的世界空间坐标转换为观察视觉内的坐标。

观察空间的计算需要使用观察矩阵

裁剪空间(Clip Space)

不能将所有的物体都移动到观察空间中,没有在视线范围内的物体需要被裁剪掉。

平截头体:由投影矩阵创建的观察区域。出现在其区域内的物体都会出现在屏幕中。

将场景中的物体从观察空间转换到裁剪空间,需要定义投影矩阵

将一定范围内的坐标转化到标准设备坐标系的过程叫投影

两种投影矩阵:

  1. 正交投影矩阵 ======> 正交投影
  2. 透视投影矩阵 ======> 透视投影

正交投影

正交投影矩阵定义了一个类似立方体的平截头体。在立方体外的物体都会被裁剪掉。

在创建一个正交投影矩阵的时候,需要指定平截头体的宽度、高度和长度的远近。

摄像机的可视坐标系由这个平截头体的宽、高、深来决定。

由此可以看到,正交投影的矩阵由宽和高来决定,和深度无关。即不管远近,所显示的部分和近裁剪面是一致的。

作用:由于正交投影没有远近之分,一般作用于UI的摄像机上。

bool Camera::initOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane)
{_zoom[0] = zoomX;_zoom[1] = zoomY;_nearPlane = nearPlane;_farPlane = farPlane;Mat4::createOrthographicOffCenter(0, _zoom[0], 0, _zoom[1], _nearPlane, _farPlane, &_projection);_viewProjectionDirty = true;_frustumDirty = true;_type = Type::ORTHOGRAPHIC;return true;
}

zoomX : 平截头体的宽

zoomY : 平截头体的高

nearPlane :近裁剪面

farPlane : 远裁剪面

然后调用函数createOrthographicOffCenter

void Mat4::createOrthographicOffCenter(float left, float right, float bottom, float top,float zNearPlane, float zFarPlane, Mat4* dst)
{GP_ASSERT(dst);GP_ASSERT(right != left);GP_ASSERT(top != bottom);GP_ASSERT(zFarPlane != zNearPlane);memset(dst, 0, MATRIX_SIZE);dst->m[0] = 2 / (right - left);dst->m[5] = 2 / (top - bottom);dst->m[10] = 2 / (zNearPlane - zFarPlane);dst->m[12] = (left + right) / (left - right);dst->m[13] = (top + bottom) / (bottom - top);dst->m[14] = (zNearPlane + zFarPlane) / (zNearPlane - zFarPlane);dst->m[15] = 1;
}

正交投影的平截头体为一个长方体[left,right][bottom,top][far,near]

那么需要把这个长方体转换到[-1,1][-1,1][-1,1]中

那么就需要两步。

平移
算出上面的长方体的中心点。``[(left+right) / 2,(bottom+top) / 2,(far+near) / 2] ``那么将这个点移动到原点。平移公式为:

∣ 1 0 0 T x 0 1 0 T y 0 0 1 T z 0 0 0 1 ∣ ⋅ { x y z 1 } = { x 1 y 1 z 1 1 } \left| \begin{matrix} 1 & 0 & 0 & T_x \\ 0 & 1 & 0 & T_y \\ 0 & 0 & 1 & T_z \\ 0 & 0 & 0 & 1 \end{matrix} \right| \cdot \left\{ \begin{matrix} x \\ y \\ z \\ 1 \end{matrix} \right\} = \left\{ \begin{matrix} x_1 \\ y_1 \\ z_1 \\ 1 \end{matrix} \right\} ∣ ∣​1000​0100​0010​Tx​Ty​Tz​1​∣ ∣​⋅⎩ ⎨ ⎧​xyz1​⎭ ⎬ ⎫​=⎩ ⎨ ⎧​x1​y1​z1​1​⎭ ⎬ ⎫​

其中 x1,y1,z1为新移动的点。

那么就可以得到,平移矩阵为

T − 1 ( t ) = T ( − t ) = ∣ 1 0 0 − T x 0 1 0 − T y 0 0 1 − T z 0 0 0 1 ∣ T^{-1}(t) = T(-t)= \left| \begin{matrix} 1 & 0 & 0 & -T_x \\ 0 & 1 & 0 & -T_y \\ 0 & 0 & 1 & -T_z \\ 0 & 0 & 0 & 1 \end{matrix} \right | T−1(t)=T(−t)=∣ ∣​1000​0100​0010​−Tx​−Ty​−Tz​1​∣ ∣​

所以,该长方体的平移矩阵为:

M t r a n s l a t e = ∣ 1 0 0 − l e f t + r i g h t 2 0 1 0 − b o t t o m + t o p 2 0 0 1 − f a r + n e a r 2 0 0 0 1 ∣ M_{translate} = \left| \begin{matrix} 1 & 0 & 0 & -\frac{left+right}{2} \\ 0 & 1 & 0 & -\frac{bottom+top}{2} \\ 0 & 0 & 1 & -\frac{far+near}{2} \\ 0 & 0 & 0 & 1 \end{matrix} \right | Mtranslate​=∣ ∣​1000​0100​0010​−2left+right​−2bottom+top​−2far+near​1​∣ ∣​

缩放

设缩放因子为s,则沿着坐标轴的缩放变换矩阵为:

S ( s ) = S ( s x , s y , s z ) = ∣ s x 0 0 0 0 s y 0 0 0 0 s z 0 0 0 0 1 ∣ S(s) = S(s_x,s_y,s_z)= \left| \begin{matrix} s_x & 0 & 0 & 0 \\ 0 & s_y & 0 & 0 \\ 0 & 0 & s_z & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right | S(s)=S(sx​,sy​,sz​)=∣ ∣​sx​000​0sy​00​00sz​0​0001​∣ ∣​

缩放矩阵的逆为:

S − 1 ( s ) = S ( 1 s x , 1 s y , 1 s z ) = ∣ 1 s x 0 0 0 0 1 s y 0 0 0 0 1 s z 0 0 0 0 1 ∣ S^{-1}(s) = S(\frac{1}{s_x},\frac{1}{s_y},\frac{1}{s_z})= \left| \begin{matrix} \frac{1}{s_x} & 0 & 0 & 0 \\ 0 & \frac{1}{s_y} & 0 & 0 \\ 0 & 0 & \frac{1}{s_z} & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right | S−1(s)=S(sx​1​,sy​1​,sz​1​)=∣ ∣​sx​1​000​0sy​1​00​00sz​1​0​0001​∣ ∣​

要将 [ l e f t , r i g h t ] [left,right] [left,right]缩放到 [ − 1 , 1 ] [-1,1] [−1,1],那么它的缩放因子就为 2 r i g h t − l e f t \frac{2}{right-left} right−left2​。

所以,该长方体的缩放变换矩阵为:

M s c a l e = ∣ 2 r i g h t − l e f t 0 0 0 0 2 t o p − b o t t o m 0 0 0 0 2 n e a r − f a r 0 0 0 0 1 ∣ M_{scale} = \left| \begin{matrix} \frac{2}{right-left} & 0 & 0 & 0\\ 0 & \frac{2}{top-bottom} & 0 & 0 \\ 0 & 0 & \frac{2}{near-far} &0 \\ 0 & 0 & 0 & 1 \end{matrix} \right | Mscale​=∣ ∣​right−left2​000​0top−bottom2​00​00near−far2​0​0001​∣ ∣​

最后的正交投影矩阵就为:

M o r t h o = M s c a l e ∗ M t r a n s l a t e Mortho = M_{scale} * M_{translate} Mortho=Mscale​∗Mtranslate​

即:

M O r t h o g r a p h i c = ∣ 2 r i g h t − l e f t 0 0 0 0 2 t o p − b o t t o m 0 0 0 0 2 n e a r − f a r 0 0 0 0 1 ∣ ∗ ∣ 1 0 0 − l e f t + r i g h t 2 0 1 0 − b o t t o m + t o p 2 0 0 1 − f a r + n e a r 2 0 0 0 1 ∣ M_{Orthographic} = \left| \begin{matrix} \frac{2}{right-left} & 0 & 0 & 0\\ 0 & \frac{2}{top-bottom} & 0 & 0 \\ 0 & 0 & \frac{2}{near-far} &0 \\ 0 & 0 & 0 & 1 \end{matrix} \right | * \left| \begin{matrix} 1 & 0 & 0 & -\frac{left+right}{2} \\ 0 & 1 & 0 & -\frac{bottom+top}{2} \\ 0 & 0 & 1 & -\frac{far+near}{2} \\ 0 & 0 & 0 & 1 \end{matrix} \right| MOrthographic​=∣ ∣​right−left2​000​0top−bottom2​00​00near−far2​0​0001​∣ ∣​∗∣ ∣​1000​0100​0010​−2left+right​−2bottom+top​−2far+near​1​∣ ∣​

起作用就是将正交投影的物体变换成标准视体。

这里保持一个疑惑 :cocos2dx的代码中,矩阵最后的数不是算出来的。由于知识有限,不明白为啥那么写。即:

dst->m[12] = (left + right) / (left - right);
dst->m[13] = (top + bottom) / (bottom - top);
dst->m[14] = (zNearPlane + zFarPlane) / (zNearPlane - zFarPlane);

所以正交投影一般用在UI上。

透视投影

它的特点是近大远小。这跟我们的眼睛是一样的。

Near Plane : 近裁剪面
Far Plane :远裁剪面
FOV :视口的夹角

因为有远近之分,所以一般运用于3D场景中。

bool Camera::initPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
{_fieldOfView = fieldOfView;_aspectRatio = aspectRatio;_nearPlane = nearPlane;_farPlane = farPlane;Mat4::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection);_viewProjectionDirty = true;_frustumDirty = true;_type = Type::PERSPECTIVE;return true;
}

fieldOfView : 即FOV,视野的夹角
aspectRatio :屏幕视口的宽高比
nearPlane : 近裁剪面
farPlane :远裁剪面

创建透视投影矩阵的函数:

void Mat4::createPerspective(float fieldOfView, float aspectRatio,float zNearPlane, float zFarPlane, Mat4* dst)
{GP_ASSERT(dst);GP_ASSERT(zFarPlane != zNearPlane);float f_n = 1.0f / (zFarPlane - zNearPlane);float theta = MATH_DEG_TO_RAD(fieldOfView) * 0.5f;if (std::abs(std::fmod(theta, MATH_PIOVER2)) < MATH_EPSILON){CCLOGERROR("Invalid field of view value (%f) causes attempted calculation tan(%f), which is undefined.", fieldOfView, theta);return;}float divisor = std::tan(theta);GP_ASSERT(divisor);float factor = 1.0f / divisor;memset(dst, 0, MATRIX_SIZE);GP_ASSERT(aspectRatio);dst->m[0] = (1.0f / aspectRatio) * factor;dst->m[5] = factor;dst->m[10] = (-(zFarPlane + zNearPlane)) * f_n;dst->m[11] = -1.0f;dst->m[14] = -2.0f * zFarPlane * zNearPlane * f_n;
}

需要把视锥体压缩成长方体,有三个原则:

  1. near plane上的所有坐标不变
  2. far plane上的所有点坐标的z值不变,都是far
  3. far plane的中心点不变,即永远为(0,0,far)

M p r e s s M_{press} Mpress​的推算方法,就是要找到一个使得下面的成立。

∣ x y z 1 ∣ = > ∣ n x / z n y / z u n k n o w n 1 ∣ \left| \begin{matrix} x \\ y \\ z \\ 1 \end{matrix} \right| => \left| \begin{matrix} nx/z \\ ny/z \\ unknown \\ 1 \end{matrix} \right| ∣ ∣​xyz1​∣ ∣​=>∣ ∣​nx/zny/zunknown1​∣ ∣​

Cocos2d-x 3D渲染技术 (二)相关推荐

  1. 下一代3d渲染技术,体素光线投射

    原文地址http://www.tomshardware.com/reviews/voxel-ray-casting,2423.html 强烈推荐看原英文,由于本人英语水平有限,对于图形学领悟有限,又借 ...

  2. 3D渲染技术分享:实时3D水面渲染(反射、折射、水深与水岸柔边)

    一.开篇 自从上次写了**<用实时反射Shader增强画面颜值>** 后,不少开发者开始尝试用它来渲染水面,但效果都差强人意. 这是因为,水面除了反射,还有许多细节需要考虑. 在此之前,也 ...

  3. 3D建模和3D渲染技术专题一: 热身篇,光线追踪(path Tracing),环境光阴影(ambient occlusion),焦距效果(effect focus)介绍

    相比大家都看到过美国迪斯尼或者梦工厂制作的一些动画片,其中很多都是使用3D图像技术来实现的,也就是说根本不用使用摄像机就能拍出一部很好的动画片.现在想开个专题主要介绍一些3D建模和3D渲染. 我之前在 ...

  4. 3D渲染技术分享:基于PBR的车漆Shader

    如今,许多曾经应用在游戏开发中的技术开始愈发频繁地在工业和商业领 域出现. 无论是在建筑.医疗.工业制造等高技术密度的行业,还是在零售.导航.人机互动等与普罗大众人间烟火息息相关的领域,即时渲染技术都 ...

  5. Cocos2d-x 3D渲染技术 (一)

    最近因为工作需要阅读<Cocos2D-X 3.X 3D图形学渲染技术讲解>这本书所做的笔记. GPU 语言 OpenGL : GLSL DirectX : HLSL Nvidia :CG ...

  6. 3D渲染技术分享:3D游戏开发渲染调试高级技巧

    零.本文主要知识点 友情劝退:全文7400+字 如果知识点里没有你想要的,那可以直接拉到底,与评论区大神一战. 最初的计划是想写一篇关于KylinsGraphicsDebugger实现原理的文章,但感 ...

  7. 3D渲染技术分享:用实时反射Shader增强画面颜值

    自制Shader免费分享:实时反射技术实现与3D领域中的应用示例 一个离谱的开始 细心的小伙伴可能已经发现了,最近麒麟子关于 3D 图形渲染方面的文章输出比之前多了许多. 灵感来源于生活,却更有可能是 ...

  8. Cocos2d-x 3D渲染技术 (三)

    包围盒算法 说白了就是给物体装进一个盒子里,该盒子可以装下物体.目的是为了进行碰撞检测. 种类: 球状碰撞体 立方体碰撞体 胶囊碰撞体 Mesh碰撞体 实现原理是OBB包围盒. 经常使用的两种碰撞算法 ...

  9. 增强现实和3D渲染技术是如何应用在SAP产品里的

    要获取更多Jerry的原创文章,请关注公众号"汪子熙":

最新文章

  1. 小学计算机课计划,小学信息技术教学工作计划
  2. Java学习之路(七):泛型
  3. 添加文件然后自动打开
  4. OpenFOAM边界类型(终极详细介绍)
  5. mmap父子进程间通信
  6. Javascript特效:动态获取鼠标位置
  7. 【openjudge 计算概论(A)】[函数递归练习(3)]
  8. mysql 自定义函数 找不到表,mysql判断表记录是否存在,不存在则插入新纪录
  9. python opencv视频流_python – PyQt显示来自opencv的视频流
  10. 计算机网络第七版课后答案(谢希仁版)
  11. 邓仰东专栏|机器学习的那些事儿(二):机器学习简史
  12. ALTREA cyclone IV e系列程序固化方法
  13. 【整理】关于Android图形系统的一些事实真相
  14. 微博数据:如何在西瓜微数平台使用「热门话题分析」功能?
  15. scheduled一分钟执行一次_Spring 中使用 @Scheduled 创建定时任务
  16. Win XP系统无法关机时如何强制软关机
  17. 艰涩难懂,不存在的,消息队列其实很简单
  18. XEN-libvirt札记
  19. 可以跟着你浪迹天涯的咖啡机,比星巴克还方便的“续命良药” | 钛空舱
  20. 夺命雷公狗---Smarty NO:02 几个常用属性

热门文章

  1. 国内openstack桌面云领跑者机敏云桌面GPU性能评测
  2. 猫咪panda新Android,《我的世界:Win10版》迎来1.8更新:熊猫和猫重新设计,全新竹子...
  3. c语言 float 精度,C语言float的精度为什么是6~7位
  4. ldconfig 命令用法
  5. VS Code配置python运行环境
  6. 有没有免费/便宜好用的云服务器推荐?
  7. 中国有哪些开源社区?
  8. php实现token验证,PHP如何实现Token验证
  9. redis 哨兵集群搭建
  10. PHP生成随机字符串