您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 广告经营 > 第04章体素和求交加速
第4章体素和求交加速上一章所介绍的类专注于如何表达3D物体的几何性质。虽然Shape类对于象求交和求包围盒之类的几何操作是很方便的抽象,但它并不包括描述一个场景中物体的足够的信息。例如,我们必须把材质信息和形体加在一起才可以说明形体的外观。为了达到这些目标,本章介绍Primitive类及其几个实现。直接用来渲染的形体用GeometricPrimitive类来表达。这个类把一个Shape和关于其外观性质的描述结合起来。这样做的目的是把pbrt的几何部分和渲染部分清楚地分离开来,这些外观性质被封装在Material类中,具体见第10章。有些场景包含许多同一个体素在不同位置上的拷贝。对关联拷贝(instancing)的支持可以极大地减少场景对内存的需求,因为每一个拷贝只存放对体素的指针和一个变换。为此,pbrt提供了InstancePrimitive类。每一个InstancePrimitive对象有一个单独的变换用来把它放置在场景之中,但可以同其它InstancePrimitive对象共享同一个体素。本章还将介绍Aggregate基类,它表示一个可以包含许多Primitive的容器(container)。pbrt用这个类来实现加速结构--这是一个数据结构,它可以降低场景中n个物体和光线求交测试的复杂性。大多数光线只跟很少的体素相交。如果一个加速结构一次可以排除一组体素,那么这跟必须测试每个体素的情况相比较,将会有实质性的性能提升。这些加速结构重用了Primitive接口(加速结构是Aggregate的子类,而Aggregate也是Primitive的子类),这样做的好处是pbrt可以支持混合形的加速方法,也就是说一个类型的加速结构可以包含其它类型的加速结构。本章介绍两种加速结构:GridAccel结构,它基于一个覆盖场景的均匀网格;另一个是KdTreeAccel,它基于自适应递归式空间划分(adaptiverecursivespatialsubdivision)。4.1Primitive接口和几何体素抽象基类Primitive是pbrt几何处理子系统和着色子系统的桥梁。它继承了ReferenceCounted基类,可以自动地记录对象引用次数,当最后一个引用脱离作用域时,就释放对象所占用的内存。含有Primitive的其它的类不应该存放Primitive的指针,而应存放ReferencePrimitive,这样才可以保证正确的引用次数。除了这点不同外,ReferencePrimitive类的功能跟指向Primitive的指针没有什么不同。PrimitiveDeclarations=classCOREDLLPrimitive:publicReferenceCounted{public:PrimitiveInterface};因为Primitive类把几何操作和着色操作联系起来,它的接口也包括跟两者有关的函数。它有5个几何例程,它们都和Shape类中的函数很相似。第一个是Primitive::WorldBound(),返回体素在世界空间的包围盒。包围盒有很多用途,其中最重要的一个用途是用于把Primitive放入加速结构的过程中。PrimitiveInterface=virtualBBoxWorldBound()const=0;跟Shape类相似,所有的Primitive都能够决定是否可以直接求光线跟体素的交点,如果不能,还要能够把它细分成一个或多个新的primitive。跟Shape相似,Primitive有一个函数Primitive::CanIntersect(),用来决定它的体素是否可以直接求交点。跟Shape接口的一个不同之处是,Primitive求交函数返回一个Intersection结构,而不是一个DifferentialGeometry结构。这些Intersection结构除了包括交点的局部几何信息外,还有诸如材料性质等其它信息。另一个不同是Shape::Intersect()只返回沿光线上到交点的参数距离,而Primitive::Intersect()还要更改光线的Ray::maxt值。这样做的好处是上一章所介绍的几何例程没必要关心系统的其它部分如何使用这个参数距离。PrimitiveInterface+=virtualboolCanIntersect()const;virtualboolIntersect(constRay&r,Intersection*in)const=0;virtualboolIntersect(constRay&r)const=0;virtualvoidRefine(vectorReferencePrimitive&refined)const;Intersection结构包含关于光线和体素交点的信息,包括点在表面上的微分几何信息,指向Primitive的指针,还要一个世界空间到物体空间的变换。PrimitiveDeclaration+=structCOREDLLIntersection{IntersectionPublicMethodsDifferentialGeometrydg;constPrimitive*primitive;TransformWorldToObject;};有时候我们需要不断地细化一个体素,直到所返回的新体素都可以求交为止。Primitive::FullyRefine()就是做这项工作的。它的实现很简单。它保持一个要细化的Primitive队列(todo队列),然后不断地从队列中取出Primitive,对之调用Primitive::Refine()。由Primitive::Refine()返回的那些可求交的体素被加入到输出队列中,而不可求交的体素被到todo队列中,这样一直处理下去,直到todo队列空为止。PrimitiveInterface+=voidFullyRefine(vectorReferencePrimitive&refined)const;PrimitiveMethodDefinitions=voidPrimitive::FullyRefine(vectorReferencePrimitive&refined)const{vectorReferencePrimitivetodo;todo.push_back(const_castPrimitive*(this));while(todo.size()){Refinelastprimitiveintodolist}}Refinelastprimitiveintodolist=ReferencePrimitiveprim=todo.back();todo.pop_back();if(prim-CanIntersect())refined.push_back(prim);elseprim-Refine(todo);除了几何操作函数以外,Primitive还有两个跟材料性质相关的函数。第一个是Primitive::GetAreaLight(),它返回一个指向AreaLight的指针,AreaLight类用来描述体素(如果它本身是光源的话)的发射光分布。另一个函数是Primitive::GetBSDF(),返回一个BSDF指针(见第10.1节)。BSDF用来描述表面上的点的光散射的材料性质。该函数的参数是交点处的微分几何信息,和一个世界空间到物体空间的变换。这个变换将会后面讲的InstancePrimitive类中用到。PrimitiveInterface+=virtualconstAreaLight*GetAreaLight()const=0;virtualBSDF*GetBSDF(constDifferentialGeometry&dg,constTransform&WorldToObject)const=0;4.1.1几何体素(GeometricPrimitives)GeometricPrimitive类用来表示场景中的单个的形体(如一个球)。对于用户所提供的场景描述文件中的每个形体,pbrt都会为它创建一个GeometricPrimitive对象。PrimitiveDeclarations+=classGeometricPrimitive:publicPrimitive{public:GeometricPrimitivePublicMethodsprivate:GeometricPrimitivePrivateData}每个GeometricPrimitive都保存一个对Shape的引用和Material的引用。另外,由于pbrt中的体素可以是面光源,它还有一个指向描述发光特性的AreaLight的指针(如果体素不发光,则设为NULL)。GeometricPrimitivePrivateData=ReferenceShapeshape;ReferenceMaterialmaterial;AreaLight*areaLight;GeometricPrimitive的构造器初始化这些变量,这里就不列出具体实现了。GeometricPrimitivePublicMethods=GeometricPrimitive(constReferenceShape&s,constReferenceMaterial&m,AreaLight*a);Primitive接口中和几何处理相关的大多数函数只是调用Shape中相应的函数而已。例如,GeometricPrimitive::Intersect()调用Shape::Intersect()来做实际的几何求交运算,再用所得到的交点初始化一个Intersection对象。还有,它还要把Ray::maxt的成员更新为所返回的交点参数距离。这样把最近的交点参数距离保存在Ray::maxt的主要好处是,如果发现体素处于光线的给定范围(mint,maxt)之外,就不必做进一步的求交测试了。GeometricPrimitiveMethodDefinitions=boolGeometricPrimitive::Intersect(constRay&r,Intersection*isect)const{floatthit;if(!shape-Intersect(r,&thit,&isect-dg))returnfalse;isect-primitive=this;isect-WorldToObject=shape-WorldToObject;r.maxt=thit;returntrue;}我们不再把GeometricPrimitive的WorldBound(),IntersectP(),CanIntersect(),Refine()函数的实现列在这里,它们只是调用Shape类中相应的函数而已。类似地,GetAreaLight()只是返回GeometricPrimitive::areaLight成员变量。最后,GetBSDF()函数调用Shape中的函数求得着色信息,并用Material中的函数计算BSDF值。GeometricPrimitiveMethodDefinitions+=BSDF*GeometricPrimitive::GetBSDF(constDifferentialGeometry&dg,constTransform&WorldToObject)const{DifferentialGeometrydgs;shape-GetShadingGeometry(WorldToObject.GetInverse(),dg,&dgs);returnmaterial-GetBSDF(dg,dgs);4.1.2物体关联拷贝(ObjectInstancing)物体关联拷贝是一项很经典的技术:一个体素可以被变换到场景中的多个位置中。例如,一个音乐
本文标题:第04章体素和求交加速
链接地址:https://www.777doc.com/doc-2152721 .html