光线跟踪之 物体表示方式

2016-04-30
渲染场景中的物体主要有两种表示方式:
  1. 类似于数学中几何的表达方式。如一条直线由一点和通过该点的向量组成。我们想表现一个球体,可以使用 
  2. 我们也可以使用3d max,maya,blender这类建模工具制作一个球体,输出一个数据文件,导入程序。常用格式:obj,ply。一般而言,3d max 类似的工具导出的物体都是三角形或者四边形网格。当然,还有其他的表现方式,就需要你自己手动实现渲染算法了。

            http://leonardo.wotaneage.com/attachments/sphere_triangle.png

  此篇中,我们尝试展示常见的物体:平面,三角形,长方体,球体,长方体,不规则立体。我们的示例程序只进行一次光线追踪,亦即视线与物体相交一次后不再反射。
  我们还是把光源放在 坐标原点 正上方,Point light = { 0, 5, 0 }, 这样方便计算。
平面 :
  实际上,这种物体只能在示例程序中出现,因为真实世界中是不存在无穷平面的,所以,根本无需模拟。我们需要指定平面的法向,我们需要判断眼睛、光源是否在同一侧,否则,就什么都看不到了。
长方形、三角形:
  我们需要知道长方形、三角形的正反面,这样的话才知道该如何正确的渲染指定一面,因为两面的颜色可能不同。 
// 仔细选择p, v1, v2 需保证rectangle 法向对外
typedef struct {
    Point p;  //
    Vector v1;
    Vector v2;
} Rectangle;  
球体: 
typedef struct {
    Point center;
    double radius;
} Sphere;
  把球体圆心放在坐标系原点上方y=3, 半径为1, 那么,应该在下方会形成一个原型的阴影区域。问题是会看到一个完整的球体吗?不会的,球体的下半部分没有收到光照,应该看不到的, 球体与光源形成的阴影应该是黑色的,应该没有光线照射过去。
长方体:
  长方体由六个四边形组成, 

// 只需要指定底部的长宽,剩下的类似y轴,只指定长度即可,
// 底部面序号1,逆时针, 顶部为3,  前面5, 后面 6,  
typedef struct {
    Point p;   
    Vector wVector;   // widht  = x 
    Vector hVector;   // z
    double yLenth;      // y

    Rectangle rects[6];
} Cuboid;

不规则立体:
  随着不规则的程度的增加,我们很难使用数学的表达方式来计算了。一般而言,渲染器处理的都是mesh 数据,物体的mesh都是三角形构成的。以三角形为最小基础单元做渲染。再精细的模型,都可以用三角形表示出来,只是面片的个数会很大。例如简单的长方体只需要12个triangle来表示,一个人物的精细模型可能会有数十万个triangle。这样的话,模拟真实物体和场景这种需求下,我们只需处理triangle即可,简单吧。
 
如果场景中有多个物体,那么该如何计算呢?
     foreach (ray in rays)
          obj = firstHitObj(objs)
          color = intersect(ray, obj) 
  这就有一个问题,obj 是有多种类型的,对应的算法不一样,intersect 函数该如何接受参数呢? 如果是C++语言,我们可以重载该函数,每个重载函数中书写不同的逻辑就可以了,如果使用C 语言来写,那么只能在obj 内部标识其类型,然后再分别使用其对应的函数来计算。  
 
  把这些常见物体的相交测试方法都实现一遍,其实也并没有什么难度。而且,这部分内容也并不是渲染程序的重难点,所占比不大,窗口系统、各种透视方式等都不重要,渲染器的重点是如何建立更加真实的光照模型、如何解决从连续的三维世界到离散的二维世界(像素屏幕)带来的锯齿、反射折射效果。
  
  本文对应实例代码在https://github.com/cloudqiu1110/tinyrt.git的 objects 分支上。
     
ref:
  1. https://www.douban.com/note/142379570/
  2.      
如果有任何意见,欢迎留言讨论。


[ 主页 ]
COMMENTS
POST A COMMENT

(optional)



(optional)