绘制时绘制的圆形中有许多(可能80-90%)被后续绘制覆盖。因此,我怀疑通过预处理可以显着提高绘制循环的速度,消除覆盖的圆形。是否有一种算法可以以合理的效率识别它们?
我可以容忍相当大数量的假阴性(即绘制了实际上被覆盖的某些圆形),只要它们不会太多以至于绘制效率受到影响即可。我也可以容忍假阳性,只要它们几乎是真阳性(例如删除仅被覆盖99%的某些圆形)。只要看起来还可以,我也可以接受圆形分布方式的更改。
每个圆的遮挡区域必须得到维护(随着处理更多圆,它通常会增长),直到扫描线到达其底部。如果遮挡区域在任何时候覆盖整个圆,则可以将其删除并永远不绘制。
记录遮挡区域的详细程度越高,算法的效果就越好。矩形区域的联合是一种可能性(例如,请参见Android的Region代码)。另一个选择是单个矩形,尽管这可能会导致许多错误结果。
同样,需要快速的数据结构来查找可能遮挡和被遮挡的圆形。包含BIALB的间隔树可能是一个好选择。
请注意,在实践中,像这样的算法只有在基元数量巨大时才能产生胜利,因为快速的图形硬件是如此之快。quadtree T
for each circle c
add(T,c)
for each pixel p
draw color of top_circle(T,p)
def add(quadtree T, circle c)
if leaf(T)
append four children to T, split along center(c)
T.circle = c
else
quadtree U = child of T containing center(c)
add(U,c)
def top_circle(quadtree T, pixel p)
if not leaf(T)
if intersects(T.circle, p)
c = T.circle
quadtree U = child of T containing p
c = top_circle(U,p) if not null
return c
O(Nd)
,其中d
是四叉树的深度,并且您假设O(M log N)
循环支配了这个循环,对吗?我只是想知道这是否可能更快:为每个像素初始化一个布尔数组并将其设置为false。对于每个圆,从顶部开始,设置它覆盖的每个像素的布尔值,并仅在它设置先前未设置的布尔值时保留该圆。 - CosmologiconFor each circle from closest to farthest
if all squares overlapped (even partially) by the circle are painted
eliminate the circle
else
paint the squares totally overlapped by the circle
然后,您可以使用Z缓冲算法(即让GPU完成其余工作)来呈现剩余的圆形。
CPU方法
这假设您将网格实现为内存位图,没有GPU的帮助。
要确定要绘制的正方形,您可以使用基于圆心与网格距离(示例图像中的红色十字)和实际圆半径的预计算模式。
如果直径的相对变化足够小,则可以定义一个二维表,该表由圆半径和距离最近网格点的中心索引。
检索到正确的模式后,您可以使用简单的对称性将其应用于适当的位置。
相同的原理也可用于检查圆是否适合已涂面。
基于GPU方法
我很久以前就开始从事计算机图形学了,但是如果当前的技术允许,您可以让GPU为您绘制。
将网格绘制出来可以通过渲染每个圆并按比例缩放以适应网格来实现
检查消除需要读取包含圆的所有像素值(按网格尺寸缩放)。
效率
网格尺寸应该有一个最佳点。更密集的网格将覆盖更高比例的圆面积,从而消除更多圆(减少误判),但计算成本将以o(1/grid_step²)增长。
当然,如果渲染的圆可以缩小到大约1像素直径,那么你也可以放弃整个算法,让GPU来处理。但与基于GPU像素的方法相比,效率随着网格步长的平方增长。
在我的示例中使用网格,您可以预期对于完全随机的圆集合,大约有1/3的误判。
对于您的图片,似乎定义了体积,应该消除2/3的前景圆和(几乎)所有后向圆。消除超过80%的圆可能值得努力。
话虽如此,在暴力计算竞赛中很难击败GPU,因此我只有最模糊的想法关于实际性能收益。不过尝试一下可能很有趣。
float distanceBetweenCentres = sqrt((topCircle.centre.x - bottomCircle.centre.x) * (topCircle.centre.x - bottomCircle.centre.x) + (topCircle.centre.y - bottomCircle.centre.y) * (topCircle.centre.y - bottomCircle.centre.y));
if((bottomCircle.radius + distanceBetweenCentres) <= topCircle.radius){
// The bottom circle is covered by the top circle.
}
您没有提及Z分量,因此我假设它们按Z顺序列在列表中并从后向前绘制(即绘图算法)。
正如之前的张贴者所说,这是一种遮挡剔除练习。
除了所述的物体空间算法之外,我还建议研究屏幕空间算法,例如分层Z-缓冲。您甚至不需要z值,只需位标志指示是否存在某些内容。
请参见:http://www.gamasutra.com/view/feature/131801/occlusion_culling_algorithms.php?print=1