We are coding a small game from scratch using Qt, OpenGL (as well as glm library for CPU-side code) and C++.
Our code handling collision detection does most of its math with floating points. It seems to work perfectly fine when compiled on an ArchLinux distribution, but freezes / doesn't work on a Windows machine. (Underlying hardware of both machines unknown). However, none of the math is extremely precise; when checking floating point equality, we always check whether the absolute difference of the two floats are below some threshold, and that threshold is usually around 0.0001. Furthermore, we use a lot of floor operations.
Since we never check for huge precision though, I'm wondering why the result is so vastly different on our machines (ie non working on one)? I tried reading up on the topic, but what would be the best way to make floating point operations behave the same way across systems? Would trying to somehow make sure we use fixed-sized ints and floats be enough?
In particular, this part of our ray-casting code seems to be troublesome (it used to be a while loop without limit, but that made it freeze on my machine - adding a limit of 10 iterations made it still work accurately on the linux distribution, but completely inaccurately on my windows machine.) (The code is a bit out of context so not sure how helpful providing it will be, but without it the question would have been a bit too general)
while (abs(ray_dist) < proposed_dist) {
max_iterations--;
if (max_iterations <= 0) {
break;
}
float min_dist = 2; //greater than root(3)
//for each "plane"
for (int i=0; i<3; i++) {
if (ray_dir[i] != 0) {
//get new distance from ray origin to cell
float new_dist = ((current_cell[i] + ray_sign[i])
- current_ray_orig[i]) / ray_dir[i];
if (abs(new_dist) < min_dist) {
min_dist = abs(new_dist);
axis = i;
}
}
}
ray_dist += min_dist;
current_ray_orig += (ray_dir * min_dist);
//calculate main direction
glm::vec3 offset(0,0,0);
offset[axis] = opp_ray_sign[axis];
//get the current cell and the blocktype at the current cell
current_cell = glm::floor(current_ray_orig) + offset;
BlockType type_at_cell = terrain->getBlockAt((int) current_cell[0],
(int) current_cell[1],
(int) current_cell[2]);
//check if cell is considered to be empty
if (type_at_cell != EMPTY && type_at_cell != UNLOADED) {
//set position
if (ray_dist < shortest_dist) {
//to avoid floating pt clipping, set actual ray dist below possible ray dist
shortest_dist = abs(ray_dist) * .999f;
}
}
}