Reputation: 38
Given a 3D voxel grid where each voxel is SIZE * SIZE * SIZE (width * height * length) for some integer SIZE and a line passing through some of the voxels in the grid, is there a decently efficient way of computing a line of sight algorithm to detect all voxels that the line passes through?
Algorithm Constraints:
Upvotes: 1
Views: 2702
Reputation: 17955
First, Bresenham is not that good at line-of-sight: as your drawing shows, the resulting selection of cells/voxels will not allow the source to "see" the target due to all those jagged edges.
However, if you are willing to consider Bresenham good for your problem in 2d, it is easy to extend to 3d: given a line from p0 = {x0, y0, z0} to p1 = {x1, y1, z1}, you can run 2d Bresenham twice from {x0, y0} to {x1, y1} and from {x0, z0} to {x1, z1}. Use the x and y values from the 1st run, and the z values from the 2nd run.
Alternatively, you can just do the full generalization:
// adapted from https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
// expects x to be the fastest-changing dimension; replace
// with fastest-changing dimension otherwise, and fix plot() accordingly
function line(float x0, float y0, float x1, float y1, float z1, float y1) {
float dx = x1 - x0;
float dy = y1 - y0;
float dz = z1 - z0;
float deltaErrorY := abs(dy / dx);
float deltaErrorZ := abs(dz / dx);
float errorY = 0;
float errorZ = 0;
int y = y0;
int z = z0;
for (int x = x0; x<x1; x++) {
plot(x,y,z);
errorY += deltaErrorY;
while (errorY >= 0.5) {
y += sign(dy);
errorY --;
}
errorZ += deltaErrorZ;
while (errorZ >= 0.5) {
z += sign(dz);
errorZ --;
}
}
}
The idea behind Brensenham can be generalized to any dimension: simply keep track of accumulated errors, and jump when needed to keep them under control
Upvotes: 2