[6.837]A6:网格加速和固态纹理

来源:互联网 发布:ojad日语发音软件 编辑:程序博客网 时间:2024/04/27 23:16

任务概述

本次实验中,我们将修改光线追踪器,使用网格加速。我们将使用光线行进法的代码来与Cell中存储的所有物体求交。一定要注意在当前cell外求交的情况并且当我们发现一个有效的求交之后提前终止光线行进。为了测试程序性能,我们将会分析光线追踪器的不同状态。
最后,我们将添加材质效果,使用固态纹理来实现材质随空间变化的效果。我们将会渲染棋盘平面,并且完全满足之前的光线追踪的原则。固态纹理使用中获得物体纹理变化的简单方式。不同的材质属性通过空间位置函数来变化。
1.使用已有的静态RayTracingStats类来计算不同的统计量。包括像素点的个数,追踪的光线数,光线与物体的求交次数,网格的细分维度,光线行进法遍历的cell数,程序的运行时间。在代码中添加如下的timing和计数函数:

//Before beginning computation, call:   RayTracingStats::Initialize(int _width, int _height, BoundingBox *_bbox, int nx, int ny, int nz);//For each non-shadow ray cast (a call to RayTracer::TraceRay()), call:   RayTracingStats::IncrementNumNonShadowRays();//For each shadow ray cast, call:   RayTracingStats::IncrementNumShadowRays();//For each ray/primitive intersection operation (each call to intersect for non-group and non-transform objects), call: RayTracingStats::IncrementNumIntersections(); //For each cell traversed (a call to MarchingInfo::nextCell()), call:   RayTracingStats::IncrementNumGridCellsTraversed();

通过这些数字,我们可以计算出每个像素的平均光线数量,每条光线调用的求交函数次数,每条光纤经过的网格数,每秒渲染的光线等等。命令行参数中添加-stats。在绘制循环的末尾,打印统计量,调用函数:

RayTracingStats::PrintStatistics();

注意到这个统计量对于简单的没有网格的、阴影开/关的场景都适用。通过之前作业中的几个例子测试这个部分。注意到光线的总数和与物体求交的次数可以通过图片的分辨率和场景中的物体总数提前获得。
2.接下来适用网格加速光线投射。实现两种光线投射的方法:RayCast and RayCastFast .如果没有在命令行中声明网格,网格将会是空指针,我们将使用不加速的光线投射方法(RayCast),简单的遍历场景中的所有物体。如果在命令行中声明了 grid的维度但是没有声明 visualize_grid,使用加速的光线投射方法,沿着当前光线行进网格,仅检测当前cell中有相交的光线。
确保我们正确的实现了光线求交的加速过程,尤其是不要忽略阴影光线。注意一些物体与许多cell相交,不要错误的返回当前cell之外的相交。避免重复计算的标记策略是可以选择实现的。
3.因为平面不能被存储在网格中,我们需要单独处理。我们会向Grid类中添加Object3dVector类中添加指向无穷物体的指针。我们总是需要计算光线与这些无穷物体的相交,并且和最近的网格相交位置进行比较。
4.完成我们的光栅化场景继承实现包括仿射变换。我们需要为每一个对象存储一个累积的仿射变换矩阵。我们可以为Object3D类创建一个新的Transformation成员,作为
5.接下来我们要用程序生成一些固态纹理。从Material类中派生一个Checkerboard类。CheckerBoard类将会存储两个Material指针,并且存储一个矩阵来描述世界坐标空间式如何映射到三维纹理空间的。我们的固体纹理实现将会描述一个单位长度的轴对齐棋盘,两种材质分别对应表示棋盘的黑白格,矩阵将会控制棋盘格的大小和朝向。通过实现glSetMaterial方法来交互显示。OpenGL并不能实现普通的程序纹理,我们可以简单的对第一个材质指针调用glSetMaterial。
实现CheckerBoard类的shade方法。使用浮点数到整数的转换函数floor和odd,生成一个对应三维棋盘的布尔函数。

实现细节

1.对无限物体(Plane平面)的处理
我们首先要向Grid类中添加一个Object3DVector来指向场景中的所有无限物体:

Object3DVector *m_pInfObjects;//指向无限物体的容器

2.处理仿射变换的策略
由于Grid中并不会存储Transform类的指针,因此在我们目前的实现中,指针容器只有如下两种:
a.无穷物体的指针容器:指向Plane对象
b.有穷物体的指针容器:指向Sphere\Triangle对象
由于以上三种对象都可能接受仿射变换,因此他们的仿射变换矩阵与材质类似,作为父类Object3D对象的成员存储即可。因此我们首先向Object3D类添加一个仿射变换矩阵成员:

Matrix* m_pTransform;//仿射变换矩阵

3.3D棋盘纹理生成算法

我们首先将单位正方体划分为八块,如果用黑白棋盘来表示,那么我们将(0,0,0)(1,0,1)(1,1,0)(0,1,1)涂黑,其余四块涂白,可以保证在空间上黑白间隔。
给定三维空间一个pos,如何判定其对应到单位正方体的哪一块呢?根据上述思路,可以发现相同颜色的索引之和分别为偶数(0或2)或奇数。因此可以根据这一特性,首先使用floor函数将pos的三个分量分别向下取整,再求和,即可计算出当前点对应棋盘格的哪种颜色。
实现这一过程的函数getPosMat如下:

bool getPosMat(Vec3f pos)const{        Vec3f hitpos = pos;        this->m_pMatrix->Transform(hitpos);        int x = floor(hitpos.x());        int y = floor(hitpos.y());        int z = floor(hitpos.z());        return !((x%2+y%2+z%2)%2);    }

4.柏林噪声纹理的生成方法:

实验结果