线光栅化:覆盖所有像素,无论线梯度如何?
基本上,我想使用直线算法来确定哪些单元格要检查我的光线投射器的碰撞。
Bresenham 不太适合这种情况,因为它使用统一厚度的方法,这意味着它忽略至少未覆盖该线一半的单元格。一点都不好,因为这意味着我的线的某些段没有被检查与单元格的相交,从而导致错误。
我似乎找不到任何“粗线”算法,有人可以帮我找到一个吗?
绿色:我想要什么。
红色:我目前拥有的和不想要的。
Basically, I want to use a line algo to determine which cells to check for collisions for my raycaster.
Bresenham isn't great for this as it uses a unified-thickness approach, meaning that it ignores cells that aren't at least half-covering the line. Not great at all, because it means that some segments of my line aren't being checked for intersections with the cells, leading to errors.
I can't seem to find any "thick-line" algorithms, can anyone help me find one?
Green: What I would like.
Red: What I currently have and don't want.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我遇到了和你完全相同的问题,并找到了一个非常简单的解决方案。通常,Bresenham 有两个连续的 if 来确定是否应该增加两个维度的坐标:
现在您所要做的就是在第二个
if
之前插入一个else
:现在该算法不再同时更改两个坐标。
我还没有彻底测试过这个,但它似乎工作得很好。
I had exactly the same problem as you and found an very simple solution. Usually, Bresenham has two consecutive if's to determine whether it should increase the coordinate for the two dimensions:
Now all you have to do is to insert an
else
before the secondif
:Now the algorithm doesn't change both coordinates at once anymore.
I haven't thoroughly tested this but it seems to work pretty well.
这个线程很旧,但我认为值得将其放在互联网上:
This thread old, but I thought it'd be worth putting this on the Internet:
不失一般性,假设 x2 >= x1,则
发言权可能可以写成强制转换为整数。
Without loss of generality, assume x2 >= x1, then
The floor calls can probably be written just as a cast-to-integer.
GPU Gems 中有一篇有趣的文章,也许可以帮助您:第 22 章. 快速预过滤行
There is an interesting article available in GPU Gems, maybe it can help you: Chapter 22. Fast Prefiltered Lines
Bresenham 有一个附加约束,不允许对角移动:使用传统算法生成点,然后作为后处理步骤插入仅进行正交移动所需的额外步骤。
What about Bresenham with an additional constraint that no diagonal moves are allowed: Generate the points with the traditional algorithm, then as a post-processing step insert extra steps needed to make only orthogonal movements.
您可以找到光线与水平网格线的所有交点,然后标记一行上的所有单元格,这些单元格要么在一侧有交点,要么位于该行上有交点的两个单元格之间。
找到交点可以通过以下方式完成:从原点开始,将点推进到第一个交点(并标记过程中的单元格),找出从一个交点到下一个交点的向量(这两个操作都是基本的相似三角形) (或 trig)),然后逐列前进,直到走得足够远。逐列前进涉及每列一次向量加法,以及一个小循环来填充具有交叉点的单元格之间的单元格。如果您正在动态处理单元格,请将“标记”替换为“处理” - 该算法保证仅标记每个单元格一次。
垂直线也可以做同样的事情,但网格通常存储在水平切片中,所以我选择了它。如果您使用三角函数,则需要使用特殊情况来处理水平直线。
顺便说一句,据我所知,这就是旧的基于网格的光线投射器“3D”游戏(如德军总部 3D)的制作方式。我第一次读到这个算法是在很久以前的这本书中。
You could find all the intersections your ray has with the horizontal grid lines, and then mark all the cells on a row that either have an intersection point on one side, or are between the two cells with the intersections on the row.
Finding the intersections can be done by starting from the origin, advancing the point to the first intersection (and marking the cells in the process), finding out the vector that takes you from an intersection to the next (both these operations are basic similar triangles (or trig)) and then advancing column by column until you've gone far enough. Advancing column by column involves one vector addition per column, and a small loop to fill in the cells between the ones with intersections. Replace "mark" with "process" if you're processing the cells on the fly - this algorithm is guaranteed to mark each cell only once.
The same could be done with the vertical lines, but grids are generally stored in horizontal slices so I chose that. If you're using trig, you'll need to handle straight horizontal lines with a special case.
By the way, as far as I know, this is how old grid-based raycaster "3D" games (like Wolfenstein 3D) were done. I first read about this algorithm from this book, eons ago.