【问题标题】:Access a circle of rays efficiently (find closest obstacle contours)有效地访问一圈光线(找到最近的障碍物轮廓)
【发布时间】:2020-05-02 06:16:34
【问题描述】:

有一个二元网格(例如黑色和白色像素,黑色 = 空白,白色 = 障碍物)。 从黑色的给定点开始,我想向各个方向发射“射线”。这些光线应该在达到给定长度(例如 100)或击中白色像素时中止(在这种情况下,应标记该像素的位置,也就是障碍物轮廓)。 那些标记的像素导致从给定点“可见”的所有障碍物轮廓的视图(没有被其他障碍物阻挡)。

到目前为止,我的想法是简单地调用足够数量的 bresenham 行。在半径为 100 的情况下,这意味着 100*2*pi = 628 行来覆盖最外圈上的所有像素。 然而,这会导致对靠近中心的相同像素进行多次多次检查。现在我可以将支票分成多个环,每个环都有不同密度的 bresenham 线,但这似乎也相当低效。

有人碰巧对此有更有效的算法想法吗? 非常感谢提前!

【问题讨论】:

  • 通常一个好的方法是只发射可以给你相关结果的光线:例如在一个有直墙的迷宫场景中,你只需要知道两个给定的角是否可见就可以确定是否整面墙都是可见的。也许这可以帮助你:ncase.me/sight-and-light
  • 为了增加问题与本网站的相关性(这对我来说似乎并不明显),也许你可以添加一些数字和代码 sn-p 显示你的想法(即使是伪代码也会比没有代码好完全)。
  • @Liuka 有趣的工作,但不幸的是,这种优化不适用于我的情况,因为障碍像素可以有效地看起来好像是随机的。 @kebs 好主意,我会做点什么。
  • 如果您正在寻找更“像素完美的方法”,有这样的东西:github.com/mattdesl/lwjgl-basics/wiki/2D-Pixel-Perfect-Shadows,但是,如果我没记错的话,需要移动到 GPU 着色器才能获得良好的性能结果,您获得的只是图像而不是“逻辑数据”。这种方法虽然很酷,但可能满足您的需求就足够了
  • 基本上,您将相机周围的空间(网格)转换为极坐标(我认为,但请看文章),然后您只需从下到上滑动每个像素列,看看哪个是最前面的像素。这样,您只检查每个像素一次。即使您需要应用额外的转换,肯定不会产生像素完美的图像(但可能是实现部分可见性的一种很酷的方法),我认为您正在减少检查的总数

标签: c++ algorithm bresenham


【解决方案1】:

不幸的是,图形处理技术的提示虽然引人入胜,但不适用于我的情况,因为我无法使用着色器或相机等。

现在我自己找到了一个足够有效的解决方案。基本思想是从轮廓发射光线,而不是从原点发射。此外,使用名为“可达”的辅助网格,其中标记了从原点成功可见的所有像素。这种方式只有少数像素被读取两次,大多数只被读取一次,一些最多被写入一次。代码比较乱,这里只写伪代码:

Have desired origin O.x/O.y
Have obstacle bool grid Obstacle

Define bool grid Reachable[w][h]    
Clear Reachable with false

Reachable[O.x][O.y] = true

For each Point C on all obstacle Contours // if not available, compute contours by finding all pixels adjacent to non-obstacle    
    For all Pixels A on Bresenham line from C to O

        If Obstacle[A.x][A.y]    
            Continue with outer loop on contours // abort this line due to obstacle hit

        If Reachable[A.x][A.y]
            For all Pixels B on Bresenham line from C to A
                Reachable[B.x][B.y] = true // mark all pixels on this line as Reachable
            Mark C as a desired result pixel
            Continue with outer loop on contours

【讨论】:

    【解决方案2】:

    令 (x1,y1) 和 (x2,y2) 两点之间的“平方距离”为 max(|x1-x2|,|y1-y2|),使得周围“平方距离”增加的点越来越大的广场的中心。

    现在,对于距您的中心点的每平方距离 d,按照递增顺序,跟踪中心点可以通过距离

    对于 d=0,您可以使用从 [(0,360)] 开始的角度区间列表。

    对于每个新距离,您可以检查列表,检查给定角度内的新像素,并在遇到障碍物时从间隔中删除角度。从中心点可以看到导致您修改间隔的每个障碍物,因此您可以将其标记为这样。

    此方法仅检查一次像素,并且仅检查您可以看到的像素。然而,我上面写的方式需要三角函数,这很慢。对于实际实现,不要实际使用角度,而是使用斜率,这只需要简单的数学运算,并分别处理每个八分圆。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-15
      • 2015-05-28
      • 2020-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多