首页 > 应用开发 > IT综合 > 最新的关于BSP技术的深入剖析与详解2(转)
在图中观察者的位置位于V,而初始的可视平截体为F1,当它通过一个portal多边形P1后被P1剪切产生新的可视平截体F2,接着当它通过portal多边形P2、P3后F2被剪切为F3、F4,而F3通过P4后被剪切为F5而F4被剪切为F6。观察这个过程我们可以发现portal技术非常适合进行递归调用。 接着需要考虑的是如何对物体进行拣选剔除,通常对于所有的3D引擎来说都需要通过一系列步骤来加速这个处理过程,回忆一下前面讲解的内容,这个过程首先要计算出物体的“最大包围球”或是“最大包围盒”,它是包含了物体所有顶点的最小包围体,接着用包围体来和“可视平截体”每一个剪切面进行碰撞检测,如果包围体位于每一个剪切面的“反面”那么物体将不会进行渲染,下图显示了这个过程:
图中物体1位于右剪切面的“正面”但位于左剪切面的“反面”因此它将不会被渲染,而物体2不仅位于左剪切面的“正面”而且有一部分位于右剪切面的“正面”因此将会被渲染出来。 Portal技术最初的想法是通过剪切多边形来保证只有物体可见的部分被渲染出来,也就是无效渲染的多边形数量为0。但是现在这种想法被认为不是很理想,因为它无谓的浪费了处理时间。但是由于一个多边形在递归循环过程中将被遍历多次因此我们需要知道在渲染场景时它是否已经被渲染过,一个较好的方法是使用一个帧数来标识这个多边形,这样可以很容易的来描述这个多边形在上一帧是否被渲染过。再看一下图中最右边的墙,它同时通过F5和F6来进行渲染,通过对它进行标识我们可以知道它是否被渲染过,否则就会产生Z缓冲错误。 为了便于在portal引擎中进行渲染我们需要对“可视平截体”进行一下定义,一个“可视平截体”是一个保存了多个剪切面的结构,每一个剪切面的法线都将指向“可视平截体”的内部,因此在它内部将产生一个闭合的锥体。下面的算法显示了如何计算一个多边形是否包含在“可视平截体”的内部。在这个算法中我们使用了一个函数CLASSIFY-POINT,它使用一个剪切面和一个点作为输入参数。 l 函数INSIDE-FRUSTUM l 参数: l Frustum ? 用于检测多边形是否位于其中的“可视平截体”。 l Polygon ? 用于检测的多边形。 l 返回值: l 多边形是否位于“可视平截体”的内部。 l 功能: l 使用“可视平截体”的每一个剪切面来对多边形的每一个顶点进行检测,如果所有的顶点都位于所有剪切面的“正面”,那么多边形处于“可视平截体”的内部。 INSIDE-FRUSTUM (Frustum, Polygon) 1 for each point Pt in Polygon 2 Inside = true 3 for each plane Pl in Frustum 4 if (CLASSIFY-POINT (Pl, Pt) <> INFRONT) 5 Inside f false 6 if (Inside) 7 return true 8 return false 在一个portal引擎中它的主渲染函数可以简单的用下面的方法来实现。 函数RENDER-PORTAL-ENGINE 参数: Sector ? 观察者所处的sector。 ViewFrustum ? 当前的“可视平截体”。 返回值: None 功能: 渲染portal引擎中的多边形,场景被描述为由多个portal连接的sectors所组成。 RENDER-PORTAL-ENGINE (Sector, ViewFrustum) 1 for each polygon P1 in Sector 2 if (P1是一个portal and INSIDE-FRUSTUM (ViewFrustum, P1)) 3 NewFrustum = CLIP-FRUSTUM (ViewFrustum, P1) 4 NewSector = 获得由当前sector通过portal P1相连接的sector 5 RENDER-PORTAL-ENGINE (NewSector, NewFrustum) 6 else if (P1任然没有被渲染) 7 draw P1 8 return 如何放置portal 正如我前面提到的在一个portal引擎中最大的问题就是如何放置portal,如果手工来放置它的话非常花费时间,同时要求地图的设计者有熟练的技巧。因此一个良好的自动放置portal的算法非常有必要,在这里我将要介绍一下关于这方面的几个解决方案,这些方案都使用了BSP。 我介绍的第一个解决方案是由瑞典DICE公司的Andreas Brinck提出的,它的原理非常简单,观察一下一个完整的BSP层次树,可以发现这样一个现象,对于每一个portal来说它必定与BSP层次树中由分割多边形定义的分割面位置相同,因此在相同的位置上我们可以在分割面之外建立一个portal多边形,portal多边形被初始化为一个矩形,这个矩形的大小将超过portal所处的BSP节点的“最大包围盒”的大小,接着将portal多边形放入包含它的节点所位于的子树中,当节点不是叶节点时,那么portal将继续被传送到节点的子树中,这样子节点中的分割面将对它进行分割,而当包含它的节点为叶节点时,它也会被节点中的多边形进行剪切,因为portal初始化的大小超过了节点的范围。当portal被分割后,被分割的两个部分会继续传送到最顶层的节点重复这个过程,而当portal不需要进行分割时,根据它所处于分割面的位置来放置到相应的子节点中,如果位于分割面的“正面”它将被放置在右子树中,而当它位于分割面的“反面”将被放置于左子树中。如果portal正好位于分割面之上它将同时放在左右子树中。 为了方便方便将所有的portal放置到BSP中我们需要定义如何对一个多边形进行分割,为了方便使用我们假设完成这个功能的函数为INTERSECTION-POINT,它将返回一个面与一个线段的交点。 l 函数CLIP-POLYGON l 参数: l Clipper ? 去分割其它多边形的多边形或面。 l Polygon ? 被分割的多边形。 l 返回值: l 被分割后的两个部分。 l 功能: l 由指定的分割面来分割多边形。如果多边形没有被分割将会返回一个空的多边形。 CLIP-POLYGON (Clipper, Polygon) 1 RightPart = {} 2 LeftPart = {} 3 for each point edge E in Polygon 4 Side1 = CLASSIFY-POINT (Clipper, E.Point1) 5 Side2 = CLASSIFY-POINT (Clipper, E.Point2) 6 if (Side1 <> Side2 and Side1 <> COINCIDING and Side2 <> COINCIDING) 7 Ip = INTERSECTION-POINT (Clipper, E) 8 if (Side1 = INFRONT) 9 RightPart = RightPart U E.Point1 10 RightPart = RightPart U Ip 11 LeftPart = LeftPart U Ip 12 LeftPart = L
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/8225414/viewspace-951989/ ,如需转载,请注明出处,否则将追究法律责任。