anchor.diff:  
   对于栅格化，投影在场景中的点找到它们各自在图像平面上的位置。我们可以换个角度看这个问题。不再是从点到像素，而是从像素开始转换成图像平面上的一点（取像素的中心点，从栅格空间转换到屏幕空间）。给定P'，然后从眼睛出发追踪一条光线，透过P'一直到场景（默认我们假设P'就是像素中心）。如果发现光线和物体相交，那么得到的交点P，就是该像素的可见点。简单的说，光线追踪解决可见性问题的意思，就是追踪一条从眼睛出发到场景的光线。
   
  -image::http://www.scratchapixel.com/images/upload/rendering-3d-scene-overview/raytracing.png[caption="图4：", title="对于光线追踪，光线从眼睛直到场景。如果和某个几何体相交，像素值就是该交点处物体的颜色值", alt="光线追踪"]
  +image::http://www.scratchapixel.com/images/upload/rendering-3d-scene-overview/raytracing.png[alt="光线追踪"]
  +^图4：对于光线追踪，光线从眼睛直到场景。如果和某个几何体相交，像素值就是该交点处物体的颜色值^
   
   注意的是，光线追踪和栅格化是相反的。他们基于同样的原则，只是光线追踪是从眼睛到物体，而栅格化是从物体到眼睛。给定图像中任意像素都可以找出可见点（两者的结果是一致的），他们分别解决不同的问题。光线追踪更复杂一点，因为他需要解决光线几何的交点问题。我们有办法找到一条光线和几何图形的交点么？一条光线和一个球体的交点可能容易计算，那么光线和圆锥的交点能找到么？对于任意形状、NURBS、细分表面以及隐式表面呢？可见，光线追踪是一种用来计算光线在场景中可能会碰到的任意几何体的技术（你得渲染器可能已经支持）。
   
  -好几年来，一大堆研究投入在更有效的计算光线和三角形——最简单的图形的交点上，但也有直接追踪在其他几何体：NURBS，隐式表面等等。不管怎样，一种至此所有几何类型的可行方案，就是在渲染过程开始前，把所有几何体转换成单一一种几何体，之后渲染器只测试光线和一种几何体的相交。因为三角形在大多数时候是最基本的图形，所以所有几何体都先转成三角形网格。也就是说不用实现一个光线对象来和每一种几何体进行相交测试，只需要测试光线和三角形即可。这么做有几大好处：
  +好几年来，一大堆研究投入在更有效的计算光线和三角形——最简单的几何图形——的交点上，但也有直接追踪在其它几何体：NURBS，隐式表面等等。不管怎样，一种针对所有几何形状的可行方案，就是在渲染过程开始前，把所有几何体转换成单一几何体，之后渲染器只测试光线和该几何体的相交。因为三角形在大多数时候是最基本的图形，所有几何体都应该先转成三角形网格。也就是说不用实现一个光线对象来和每一种几何体进行相交测试，只需要测试光线和三角形即可。这么做有几大好处：
   
  -* 第一，像之前提到的，三角形的很多属性使其成为最基本的几何体。三点共面使得三角形是不可分割的（通过连接各个顶点创建更多面，至少会需要4个或者更多顶点），但却很容易的分解出更多的三角形。最终，用数学计算三角形的重心坐标（用于贴图）也很简单而且强大。
  +* 第一，正如之前提到的，三角形的很多属性使其成为最基本的几何体。三点共面使得三角形是不可分割的（通过连接各个顶点可以创建更多面），但却很容易的分解出更多的三角形。最终，用数学计算三角形的重心坐标（用于贴图）也很简单而且强大。
   
   * 因为三角形是一个基本几何形状，所以很多研究已经完成了光线和三角形相交的最佳测试方法。什么是最好的相交算法？快速（得到结果所用的操作越少越好），省内存（一些算法由于要存储预先计算的三角形，所以非常吃资源），强大（避免浮点数问题）。
   
  
positive.code: = 可见性问题
  :hp-tags: graphic
  :hp-alt-title: The Visibility Problem
  
  http://www.scratchapixel.com/lessons/3d-basic-rendering/rendering-3d-scene-overview/visibility-problem[原文出处]
  
  在前一章节里，我们已经解释了什么事可见性问题。为了创建一个逼真的图像，我们需要从给定的观察点来决定一个对象的哪些部分是可见的。问题就是当我们按例去投影一个盒子的所有顶点，并且连接所有投影点绘制成盒子边，则盒子的所有面都是可见的。不管怎么说，真实情况下只有盒子的正面是可见的，其他面应该看不到。
  
  在图形学中，解决可见性问题主要有两个方法：*光线追踪*和*栅格化*。我们会快速的解释他们是如何工作的。如今已很难搞清楚哪个方法更古老，只不过在图形学早期，栅格化更流行点。光线追踪比栅格化计算量大（使用内存多）是出了名的，比较下来会慢很多。以前的电脑也不快（内存也少），所以渲染图像基本不考虑使用光线追踪，至少在生产环境下如此（比如制作电影）。因此，几乎每个渲染器使用的都是栅格化（光线追踪一般仅限于研究项目）。但是，光线追踪在类似反射、柔和阴影等效果模拟上比栅格化好，原因我们下一章节解释。总的来说，用光线追踪比较容易创建逼真的图像，比起栅格化适用于渲染几何图形，光线追踪更适合模拟真实的着色和光阴效果。我们会在下一章节解释为什么。即时渲染API和显卡通畅使用栅格化，因为速度才是选择算法的决定因素。不过对于光线追踪的说法，80、90年代正确的，在今天就不一定是正确的。现如今电脑非常强大，光线追踪经常用于离线渲染器（至少，两种算法的混合方法已经被实现了）。为什么？还是因为对于模拟类似刺眼的光泽的反射，柔和的阴影等效果，光线追踪是最简单的方法。当速度不再是问题，那么在很多地方都比栅格化来的卓越（让光线追踪有效率的运作仍需要大量的工作）。Pixar的PhotoRealistic RenderMan，是Pixar开发的一个基于栅格化算法的渲染器（该算法被称为REYES，是Renders Everything You Ever Saw【渲染一切所见】的缩写，其构思深远，几乎是最好的可见面判定算法，连显卡的渲染管线都诸多类似REYES），制作过很多早期的电影(玩具总动员、海底总动员、虫虫特工队)。但目前Pixar的渲染器RIS是一个纯粹的光线追踪器。引入光线追踪使得工作室这几年内，极大的推动了写实化以及复杂图像的制作。
  
  == 栅格化如何解决可见性问题？
  
  我们已经把栅格化和光线追踪的区别清晰的解释过了（阅读上一章节）。让我们回顾一下，栅格化可以看作是，位于几何图形表面的一点P，沿着连接到眼睛的一条直线移动，直到碰到画布表面为止。当然，这条直线是隐藏的，实际上根本不需要去构造它，在此，我们是为了可以直观的去解释投影过程。
  
  image::http://www.scratchapixel.com/images/upload/rendering-3d-scene-overview/projection3.png[caption="图1：", title="投影过程可以被看成是一个点沿着它和眼睛的连线一直向下移动，当碰到画布所在平面时停止移动。显然我们不必真的去滑动这个点，只是以此解释投影过程。", alt="投影过程"]
  
  我们需要解决的是可见性问题。换句话说，在场景上可能会有很多点P,P1,P2等等，它们都投影在画布的同一点P'上（画布即是场景）。而在连接到眼睛的同一条直线上的所有点里，只有一个点能被摄影机看到，就是离眼睛最近的那个，参考图2.
  
  image::http://www.scratchapixel.com/images/upload/rendering-3d-scene-overview/projection2.png[caption="图2：", title="场景上多个点可能会投影在场景的同一点上。摄影机能看到的是对齐的店中，离眼睛最近的那个点", alt="可见点"]
  
  要解决可见性问题，首先要找出图中P'所在位置的表达式，即图像的像素坐标是什么，P'落在哪里？还记得投影一个点到画布表面，给定另一个点P'的实数坐标么。P'必须落在最终图像给定的像素上。因此，如何通过画布表面上一点P'的表达式，来定义其在最终图像上的位置（像素坐标）？这里涉及一个简单的坐标系变换。
  
  * 首先定义的坐标系称为*场景空间*（或图像空间），其原点在画布中心。这个2D坐标系的所有轴都是单位长度（长度为1）。注意x或y轴上的点可以是负数，x轴向左以及向y轴向上即为负。
  
  * 以格子形式定义的图像像素坐标系称为*栅格空间*，其原点通常位于图像的左上角，轴也是单位长度，一个像素为一单位长度。因此，画布在该坐标系中的实际尺寸由图像的垂直（高）和水平（宽）的维度决定（即像素表达式）。
  
  image::http://www.scratchapixel.com/images/upload/rendering-3d-scene-overview/screentoraster.png[caption="图3：", title="计算一个画布上的点所处的像素值，需要把点从场景空间转换到NDC空间后，再从NDC空间转换到栅格空间。", alt="空间转换"]
  
  将点从场景空间转换到栅格空间非常简单。因为在栅格空间中的点P'只会是正数，我们首先把P'归一化。换句话说，使其范围在0,1之间（当点被如此定义时，我们称点被定义在NDC空间中，NDC全称是Normalized Device Coordinates【归一设备空间】）。一旦转换到NDC空间，再把点转换到栅格空间就很简单了。只需乘以图像尺寸，然后四舍五入即可（像素坐标永远是整数）P'坐标的范围取决于场景中画布的尺寸。为了简单起见，假设画布的宽高都只有2个单位长度，也就是说P'在场景中的坐标范围是[-1,1]。以下是把P'坐标从场景空间转换到栅格空间的伪码：
  
  [source,linenums]
  int width = 64, height = 64; // 以像素为单位的图像尺寸
  
negative.code: ****
  *当不透明阻挡时*
  
  为什么我们需要对每个像素维持一个点的列表？储存到眼睛最短距离的就可以不用这个列表。事实上，还可以做的更好：
  
  * 对图像上每个像素，设置z为无穷大。
  * 对场景上每个点。
  ** 投影后计算栅格化坐标。
  ** 如果当前点到眼睛的距离小于储存的距离，更新z。
  
  你会发现，这和保存一个列表并排序的结果是一样的。那我们为何不这么做？因为这么做的前提是我们假设场景上所有的点都是完全不透明的。一旦碰到半透明的情况会怎么样呢？显然，如果有半透明的点出现在同一个像素上，他们都可能会被看到。对此，就必须保存每个像素上所有的点，然后排序，利用特殊的混合算法（我们会在REYES算法课程里学到）计算出正确的像素值。
  ****
  
  
  