aliens

Author Topic: Question about: TileEngine::calculateLine is bresenham 3D skipping over voxels ?  (Read 1162 times)

Offline Skybuck

  • Colonel
  • ****
  • Posts: 223
    • View Profile
How confident are you that the bresenham line 3d algorithm checks all voxels ? I have my doubts about this algorithm and it could be the cause of some missed shots.

A better/more accurate but still fast algorithm is described here:

https://github.com/cgyurgyik/fast-voxel-traversal-algorithm

(Check the overview and the md file for a description of the algorithm)

And my fork here in case it goes missing:

https://github.com/SkybuckFlying/fast-voxel-traversal-algorithm/blob/master/overview/FastVoxelTraversalOverview.md

There are also PDFs on the internet describing it in it's original paper.

Free download:

https://www.researchgate.net/publication/2611491_A_Fast_Voxel_Traversal_Algorithm_for_Ray_Tracing

It might take a bit to wrap your head around it, but it helps to draw vertical lines only and then see how a line intersects it, once you understand how a diagonal line hops/intersects from vertical line to vertical line then you basically get the algorithm.

The algorithm switches between hopping from vertical line to vertical line, and horizontal line to horizontal line and depth line to depth line to a mix of each.

Which ever line is closest it will switch to which is the genius of this algorithm and then it "shifts/moves" the T to that line intersection, which basically means it's now on the start of the next voxel.

The setup is the most difficult part, and the end can also be a bit tricky.

So far this C/C++ code is untested, but it's worth trying to implement it into OpenXCom to see how it performs.

Offline Skybuck

  • Colonel
  • ****
  • Posts: 223
    • View Profile
BIG SUCCESS,

This code below was first translated to Delphi, then tested, then slighty adjusted and I can confirm it works flawlessly, one problems remains, no clipping yet.

This C code was then integrated into the OpenXCom game, tested a few times, made some changes until it works, pretty cool !

(Perhaps if the swapping of xy is not done and such it might be even more accurate, that's kinda the feeling I got first time I did it, but I am going to keep this swapping in there for now ;))
(Later I will examine the original code, to see how accurate that one was):

Here is original algorithm, slightly modified to process first and last voxel too,

This code expects the coordinates to be scaled down to grid space, it may be floating points, the game already does that, but in case people want to use this code for other purposes then you know how to use it, divide x,y,z coordinates by cell width, height, depth and such.

Code has been integrated into game in this branch:

https://github.com/SkybuckFlying/OpenXcom/tree/FastVoxelTraversalAttempt2


The one that worked for me in 3D for both positive and negative directions (in CUDA C):

#define SIGN(x) (x > 0 ? 1 : (x < 0 ? -1 : 0))
#define FRAC0(x) (x - floorf(x))
#define FRAC1(x) (1 - x + floorf(x))

float tMaxX, tMaxY, tMaxZ, tDeltaX, tDeltaY, tDeltaZ;
int3 voxel;

float x1, y1, z1; // start point   
float x2, y2, z2; // end point   

int dx = SIGN(x2 - x1);
if (dx != 0) tDeltaX = fmin(dx / (x2 - x1), 10000000.0f); else tDeltaX = 10000000.0f;
if (dx > 0) tMaxX = tDeltaX * FRAC1(x1); else tMaxX = tDeltaX * FRAC0(x1);
voxel.x = (int) x1;

int dy = SIGN(y2 - y1);
if (dy != 0) tDeltaY = fmin(dy / (y2 - y1), 10000000.0f); else tDeltaY = 10000000.0f;
if (dy > 0) tMaxY = tDeltaY * FRAC1(y1); else tMaxY = tDeltaY * FRAC0(y1);
voxel.y = (int) y1;

int dz = SIGN(z2 - z1);
if (dz != 0) tDeltaZ = fmin(dz / (z2 - z1), 10000000.0f); else tDeltaZ = 10000000.0f;
if (dz > 0) tMaxZ = tDeltaZ * FRAC1(z1); else tMaxZ = tDeltaZ * FRAC0(z1);
voxel.z = (int) z1;

while (true) {
    // process first and subsequent voxels here

    if (tMaxX < tMaxY) {
        if (tMaxX < tMaxZ) {
            voxel.x += dx;
            tMaxX += tDeltaX;
        } else {
            voxel.z += dz;
            tMaxZ += tDeltaZ;
        }
    } else {
        if (tMaxY < tMaxZ) {
            voxel.y += dy;
            tMaxY += tDeltaY;
        } else {
            voxel.z += dz;
            tMaxZ += tDeltaZ;
        }
    }
    if (tMaxX > 1 && tMaxY > 1 && tMaxZ > 1)
   {
    // process last voxel here
  break;
  }
}
« Last Edit: March 12, 2022, 10:38:45 am by Skybuck »

Offline Skybuck

  • Colonel
  • ****
  • Posts: 223
    • View Profile
Translated the OpenXCOM c/c++ bresenham line 3d algorithm to Delphi, tested it, examine and:

I CAN CONFIRM THE FAST VOXEL TRAVERSAL ALGORITHM IS A LOT MORE ACCURATE THEN THE BRESENHAM 3D LINE ALGORITHM, AT LEAST WHEN doVoxelCheck := false;

EVEN WITH doVoxelCheck := True; THE BRESENHAM 3D LINE ALGORITHM WILL STILL MISS SOME CELLS !

VERY INTERESTING DISCOVERY !