本文主要想介绍一下3D渲染的基本流程,及怎样把一个三角形(0,1,0),(1,0,1),(0,0,1)最终渲染到屏幕上来。文章的目的是对3D渲染流程作一个简单的介绍,其中不涉及任何语言的APIhtml
参考资料算法
局部坐标和世界坐标编程
接触Flash的人应该不太难理解这个概念吧,好比在库中创建一个边长为50的正方形,设置其左上角为原点,局部坐标的(0,0)为原点测试
而后将其拖入Flash的主舞台上面之后,就会获得一个全局坐标(84,110).net
那刚才拖动的一下操做,完成的是怎样的一个运算呢?3d
抛开填充的蓝色先不谈,那么几何上面来讲,正方形是由4个点构成的,A(0,0) B(0,50) C(50,0) D(50,50)htm
刚才作的操做能够理解把该正方形拖放到舞台的(84,100)位置。对应的获得ABCD四点坐标分别为A’(0+81,0+100) B’(0+84,0+50) C’(50+84,0+100) D’(50+84,50+100)blog
这样也就是完成了一次局部坐标到世界坐标的转换游戏
那一样的道理,对于一个3D坐标点A(0,0,0) 也能够执行一次坐标变换,好比(84,100,37),这样也能获得一个对应的3D坐标点A’(0+81,0+100,0+37)游戏开发
为什么要进行局部坐标到世界坐标转换
在日常咱们作Flash时候也同样,好比要作一个小人站在房子边上的图,那确定是单独创建两个元件 元件::小人 元件::房子 ,而后将其拖入主舞台拼凑在一块儿。3D中也是同样的各类物体也是如今本身的坐标系内制做好,
最后放入场景内进行的拼接
了解矩阵
在进一步介绍3D以前,首先须要了解一下矩阵。原本想给出一些本身的例子,不过参考了一下现有资料,发现没有太多好补充的东西。若是对矩阵的基本改变还不是很了解
(好比矩阵是作什么用的,矩阵相乘,旋转矩阵,平移矩阵等)
请参考以下部分
《3D游戏编程大师技巧》 P161~P165
《3D数学基础:图形与游戏开发》 P85~P107
摄像机&视景体
在把全部物体完成了从局部坐标系到全局坐标系的转化,及完成了构建一个3D场景,只是这个场景中所有是由点构成的。这个时候就须要引入摄像机的概念,摄像机就像一双在这3D世界中的眼睛,眼睛的位置不一样,
看的方向不一样,那最终看到的景象也就不一样.
和现实世界中的摄像机稍微有些不一样,在于须要给这个摄像空间定义一个区域,及近剪裁面和远剪裁面。也就是小于近剪裁面和大于远剪裁面的物体将不会被渲染
在远剪裁面以外的物体: 能够理解为即便渲染了该物体也会是一个点,因此不进行渲染。在玩儿一些早期的3D游戏时候有时候会出现这种状况,一直向前走,前方的建筑物会忽然从远处出现,我想也是这种缘由吧
在近剪裁面以外的物体: 若是渲染的话会是一个很是大的物体,因此也不进行渲染。(近剪裁面若是用现实中的相机作比喻彷佛不是很容易理解,当时若吧这个放入数学定义中去理解,反而容易一些)
世界坐标到相机坐标的转换
当肯定好视景体后,也就能够肯定了哪些物体最终能够见,哪些是不能够见。剔除这些不可见的物体后,须要将其他物体进行世界坐标到相机坐标的转换。
在一种极端状况下是不须要进行该步骤的,就是相机在原点(0,0,0)且方向和坐标轴的方向是一致的,此时不须要再进行转换
可是大部分时候,相机实际上是不在原点的,且所朝的方向也不是坐标轴方向。
此时就要对这些物体(物体的每一个顶点)进行世界坐标到相机坐标的变换。
变换一共分为几个步骤,
第一步 平移
如图,也就是假设相机的坐标点为(cam_x,cam_y,cam_z),那对全部剩余物体的顶点均执行平移操做(world_x-cam_x,world_y-cam_y,world_z-cam_z)
第二步 旋转
此时相机已经处于坐标原点处了,不过相机镜头仍旧是歪的,仍旧须要对其进行x,y,z三方向旋转才能够将相机还原为最开始那张图所画的样子。
对于先旋转哪一个,后旋转哪一个是无所谓的。及按xyz仍是zyx方向旋转都是同样
最终流程:
为什么要进行相机坐标转换
若是还不是很理解为什么要进行相机坐标转换,能够再回到2D世界,仍是最先的例子,那个正方形A(0,0) B(0,50) C(50,0) D(50,50) 通过的局部到世界坐标的转换是A'(0+81,0+100) B'(0+84,0+50) C'(50+84,0+100) D'(50+84,50+100)
A'点也就是为(0+81,0+100)->(81,100)
此时若是假设你本身就是相机,眼睛和舞台的0,0点对齐,眼部和显示器距离为300,那么A'点在你眼中的三维坐标也就是(81,100,300)
此时也就是以前所说的极端状况,摄像机和全局坐标同轴且共相。那A'点(81,100,300) 也就是最终渲染到屏幕上面的坐标点,可是
若是此时你离开显示器一段距离,且歪一下脑壳,再看A'点(81,100,300),这时候其所在你本身眼睛(摄像机)中的位置就不是原来那个位置了,
假设此时你看到的景象是M,
那你能够想象此时你回到原位,而后有另一我的,抱起你的显示器放在另一个位置且稍微转一个角度
此时你看到的景象仍旧是M,
那我的对那个物体进行的操做(抱起来放边上且转了一个角度)就是相机坐标变换
物体剔除&背面消除
这块知识我想简单的说一下,在《3D游戏编程大师技巧》 里面有很是详细的说明
物体剔除:
物体剔除在2D中也是存在的,对一个物体进行包围盒测试,若是再也不场景内则不显示该物体,3D中也是作一样的操做,只不过包围盒是三维的,且探测范围也再也不是一个平面,而是整个视景体。
背面消除:
当一个物体确实是在视景体内部时候,也不是全部面均须要最终渲染出来,此时要作的就是背面剔除,将那些被彻底挡住的平面剔除出去
为什么要进行剔除
在渲染流程的前段步骤,全部操做均是针对点的,好比坐标转换,剔除等.当最终肯定了一个面确实要被渲染之后。后半段的操做及要对该面进行着色(设置纹理),光照处理等。
因此若是能够在前期多剔除掉一个面,就应该多剔除一个。
透视变换
当完成了一切剔除操做后,对于剩下的平面(此时剩余的仅为一个个平面了),还须要进行透视变换。也就是将一个三维点A'(81,100,300) 变换为一个二维的坐标点。
这里面的转换涉及两种
正交投影
来源 http://baike.baidu.com/view/3153027.htm
这种投影比较简单,及直接去除z点的值便可,通常用在工业制图上面(AutoCAD),对于Starling(Flash上面使用Stage3D技术加速2D游戏的引擎),目前我还不是很了解。不过为本身写的一个Demo,投影选择的就是
正交投影。由于本来须要渲染的就是一个2D平面,只要其在视景体内,其大小就和所在位置无关了
透视投影
来源 http://baike.baidu.com/view/1318206.htm
透视投影及实现了近大远小的投影,及离摄像机距离较远的物体看起来会相对小一些,离摄像机进的物体看起来更大一些。和真实世界中看到的是同样的。在三维游戏中用到的均为这种投影
二者的区别下面这张图很好的标示出来
左面的为透视投影,右面的为正交投影
总体流程概览
3D渲染流程上面大致就是这样了
图中在背面消除后采起了两种方式,
B路线为画家算法(http://baike.baidu.com/view/2020287.htm),
A路线为在常规的物体消除后再进行一次空间剪裁(及把那些不是彻底在视景体内部的元件再剪裁,及AABB测试压线的物体)
可是不管是通过A路线,仍是B路线 最终剩余的平面就会开始光栅化(忽略屏幕坐标变化,具体的请看书)。及真正的对其进行着色,打光等操做了
本文和Stage3D的关系
首先请阅读两篇文章
GPU大百科全书第二章 凝固生命的光栅化 http://vga.zol.com.cn/236/2366808.html
How Stage3D works http://www.adobe.com/devnet/flashplayer/articles/how-stage3d-works.html
看完这两篇文章之后能够看出,本文其实只是大致上面说明了一下3D渲染的基本过程,可是和目前真正的技术(我参考的资料已是十几年前的东西了吧)仍是有必定出入的,
Stage3D最相关的东西也就是这张图中的
VertexShader 还有 FragmentShader(也就是Pixel shaders)
我在初探Stage3D(二) 了解AGAL中作了一些说明,
VertexShader 主要做用就是3D流程中的前半段操做(对顶点进行一系列的矩阵变换)
FragmentShader 操做是对这些变换后的顶点(及流程中的光栅化部分)进行渲染