1
\$\begingroup\$

I'm trying to implement the Fast Voxel Traversal Algorithm on a uniform grid of axis-aligned rectangles. Having read the paper, I understand how the traversing works, but not the initialization. I've looked around and I did find a readme that overviews the algorithm, but I fail to see how the derive how to determine the index in a data structure (such as an array) that corresponds to the first voxel the ray intersects.

Using the construct presented in the readme, assuming the grid is 2x2 and stored in (going to use Python) an list like so:

+--------+--------+ | | | | | | | 0, 1 | 1, 1 | | | | | | | +--------+--------+ | | | | | | | 0, 0 | 1, 0 | | | | | | | +--------+--------+ grid = [[(0, 0), (1, 0)], [(0, 1), (1, 1)]] 

In the overview, the compute r2 = r and resolve t = 27/32, but I fail to see how they translate that to the index grid[0].

Some other resources I've used to try and understand:

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Short answer: rounding down.

Long answer:

2 by 2 grid of unit cells, with a corner on the origin, and extending on the positive x and y axis. Also a ray with positive slope enters the grid from the lower part of the cell closer to the origin.

The ray in the image above might be represented as r = u + tv where u = <0,-3/4> and v = <1, 8/9>, i.e. r follows the line y = (3/4)+ (9/8)x.

Note: that is a typo, it should read y = (3/4)+ (8/9)x.

Thus, ray.origin.x = 0 and ray.origin.y = -3/4.

We can start from these terms: y = y₀ + mx. The ray crosses the vertical axis at y₀, and has a slope of m. Now, the vector u would be (0, y₀) which is the point where the ray crosses the vertical axis. And the vector v would be (1, m).

Constructing the ray in this fashion we would always have 1 on the horizontal axis of v. Which would prevent us from representing a vertical ray. Also, v is not normalized. However, this poses no problem for our purposes.


Based on grid (given at initialization) we know that

grid.corners = [(0,0),(0,2), (2,2),(2,0)]; 

Here we are defining a rectangle that contains the whole grid. We want to know where the ray enters the rectangle.

Thus, we can determine the boundary at which r intersects the grid. In particular, we see the y = 0 boundary of the grid is represented by the vector r2 = <0,0> + <1,0>t;

At y = 0, there is a boundary of the rectangle that contains the grid. That boundary starts at (0, 0) and ends at (2, 0). We can create a second ray line that corresponds to the boundary. That second ray line r2. The second ray starts at u2 = (0, 0), and v2 would be (1, 0).

solving for r2 = r yields t = 27/32.

That is, we find the point where the two rays intersect. We can easily check the particular solution:

r2 = r <0,0> + <1,0>t = <0, -3/4> + <1, 8/9>t <0,0> - <0, -3/4> = <1, 8/9>t - <1,0>t => 0 = 0t 3/4 = (8/9)t => 3*9 = (4*8)t 27 = 32t 27/32 = t 

Note: We discarded the not useful 0 = 0t.

This is not a general approach. It works thanks to both rays using the horizontal axis as parameter. And we were able to discard 0 = 0t, which is not always the case.


I'll go ahead and find a general solution:

r(t) = r2(t2) u + tv = u2 + t2v2 u.x + tv.x = u2.x + t2v2.x u.y + tv.y = u2.y + t2v2.y u.x + tv.x = u2.x + t2v2.x u.x - u2.x + tv.x = t2v2.x (u.x - u2.x + tv.x)/v2.x = t2 (u.x/v2.x) - (u2.x/v2.x) + t(v.x/v2.x) = t2 u.y + tv.y = u2.y + t2v2.y u.y + tv.y = u2.y + ((u.x/v2.x) - (u2.x/v2.x) + t(v.x/v2.x))v2.y u.y + tv.y = u2.y + (u.x*v2.y/v2.x) - (u2.x*v2.y/v2.x) + t(v.x*v2.y/v2.x) u.y + tv.y - t(v.x*v2.y/v2.x) = u2.y + (u.x*v2.y/v2.x) - (u2.x*v2.y/v2.x) tv.y - t(v.x*v2.y/v2.x) = u2.y + (u.x*v2.y/v2.x) - (u2.x*v2.y/v2.x) - u.y t(v.y - (v.x*v2.y/v2.x)) = u2.y + (u.x*v2.y/v2.x) - (u2.x*v2.y/v2.x) - u.y t = (u2.y + (u.x*v2.y/v2.x) - (u2.x*v2.y/v2.x) - u.y)/(v.y - (v.x*v2.y/v2.x)) t = (u.x*v2.y - u.y*v2.x - u2.x*v2.y + u2.y*v2.x)/(v.y*v2.x - v.x*v2.y) 

Thus:

t = (u.x*v2.y - u.y*v2.x - u2.x*v2.y + u2.y*v2.x)/(v.y*v2.x - v.x*v2.y) t = (0*0 - (-3/4)*1 - 0*0 + 0*1)/((8/9)*1 - 1*0) t = (3/4)/(8/9) t = (3/4)*(9/8) t = (3*9/4*8) t = 27/32 

let us figure out the coordinates:

p = r(t) p = <0,-3/4> + <1, 8/9>t p = <0,-3/4> + <1, 8/9>(27/32) p = <0,-3/4> + <27/32, (8/9)*(27/32)> p = <0,-3/4> + <27/32, 3/4> p = <27/32,0> 

Since we had constructed the ray with v = (1, m) the solution point is simply (t, 0). The approach above is not limited to such cases.

On the other hand, if we construct vertical rays with v = (0, 1) we will find other optimizations for such case.


Thus, at the annoying value of t = 27/32, the ray r will intersect the boundary of the grid. Note that this value of t is the least such value of t for all boundary crossings.

Note: 27/32 = 0.84375. Thus, the entry point on the grid is <0.84375, 0>which is on the cell (0, 0), as depicted on the image. We find that simply by rounding down (assuming the cell size is 1).

Now that you have a general formula, you can apply it for all the boundaries and find the one that yields the lowest t (tMin). The corresponding point is the point where the ray enters the grid.

You can define the four boundaries of the rectangle as follows:

r2(t) = <0, 0> + <1, 0>t r3(t) = <0, h> + <1, 0>t r4(t) = <0, 0> + <0, 1>t r5(t) = <w, 0> + <0, 1>t 

Assuming the grid has a corner at the origin, and w, h define the size of the grid (not the number of cells, but the length of the sides of the rectangle that contains the gird).

As you can see we have a lot of 0s, which will result in a lot of cancellations, which is room for optimization.

\$\endgroup\$
4
  • \$\begingroup\$ "We find that simply by rounding" to be more precise, we find it by "flooring", rounding down to the next integer less than or equal to our value. (Rather than rounding up or to the nearest integer) \$\endgroup\$ Commented Jan 6, 2021 at 19:46
  • \$\begingroup\$ Did you mean that the boundary for y=0 starts at (0, 0) and ends at (2, 0) and not (0, 2)? \$\endgroup\$ Commented Jan 7, 2021 at 19:10
  • \$\begingroup\$ @datta fixed, I think. \$\endgroup\$ Commented Jan 7, 2021 at 20:05
  • \$\begingroup\$ Correct me if I am wrong, but this is not considered the "slab" method, because we are checking each border plane. We could optimize this check by determining direction of the ray and only using incident planes, but the slab method would be faster and doesn't require checking each border. \$\endgroup\$ Commented Jan 8, 2021 at 14:36

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.