Skip to content

Instantly share code, notes, and snippets.

@jflipts
Forked from Philipp-M/TriangleBoxIntersection.hpp
Last active January 27, 2023 19:00
Show Gist options
  • Save jflipts/fc68d4eeacfcc04fbdb2bf38e0911850 to your computer and use it in GitHub Desktop.
Save jflipts/fc68d4eeacfcc04fbdb2bf38e0911850 to your computer and use it in GitHub Desktop.
Forked from https://gist.github.com/Philipp-M/e5747bd5a4e264ab143824059d21c120 , fixed several typos. Triangle Box Intersection, adapted to c++ with glm from http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/
#pragma once
#include <cmath>
#include <glm/glm.hpp>
inline void findMinMax(float x0, float x1, float x2, float &min, float &max) {
min = max = x0;
if (x1 < min)
min = x1;
if (x1 > max)
max = x1;
if (x2 < min)
min = x2;
if (x2 > max)
max = x2;
}
inline bool planeBoxOverlap(glm::vec3 normal, glm::vec3 vert, glm::vec3 maxbox) {
glm::vec3 vmin, vmax;
float v;
for (size_t q = 0; q < 3; q++) {
v = vert[q];
if (normal[q] > 0.0f) {
vmin[q] = -maxbox[q] - v;
vmax[q] = maxbox[q] - v;
} else {
vmin[q] = maxbox[q] - v;
vmax[q] = -maxbox[q] - v;
}
}
if (glm::dot(normal, vmin) > 0.0f)
return false;
if (glm::dot(normal, vmax) >= 0.0f)
return true;
return false;
}
/*======================== X-tests ========================*/
inline bool axisTestX01(float a, float b, float fa, float fb, const glm::vec3 &v0,
const glm::vec3 &v2, const glm::vec3 &boxhalfsize, float &rad, float &min,
float &max, float &p0, float &p2) {
p0 = a * v0.y - b * v0.z;
p2 = a * v2.y - b * v2.z;
if (p0 < p2) {
min = p0;
max = p2;
} else {
min = p2;
max = p0;
}
rad = fa * boxhalfsize.y + fb * boxhalfsize.z;
if (min > rad || max < -rad)
return false;
return true;
}
inline bool axisTestX2(float a, float b, float fa, float fb, const glm::vec3 &v0,
const glm::vec3 &v1, const glm::vec3 &boxhalfsize, float &rad, float &min,
float &max, float &p0, float &p1) {
p0 = a * v0.y - b * v0.z;
p1 = a * v1.y - b * v1.z;
if (p0 < p1) {
min = p0;
max = p1;
} else {
min = p1;
max = p0;
}
rad = fa * boxhalfsize.y + fb * boxhalfsize.z;
if (min > rad || max < -rad)
return false;
return true;
}
/*======================== Y-tests ========================*/
inline bool axisTestY02(float a, float b, float fa, float fb, const glm::vec3 &v0,
const glm::vec3 &v2, const glm::vec3 &boxhalfsize, float &rad, float &min,
float &max, float &p0, float &p2) {
p0 = -a * v0.x + b * v0.z;
p2 = -a * v2.x + b * v2.z;
if (p0 < p2) {
min = p0;
max = p2;
} else {
min = p2;
max = p0;
}
rad = fa * boxhalfsize.x + fb * boxhalfsize.z;
if (min > rad || max < -rad)
return false;
return true;
}
inline bool axisTestY1(float a, float b, float fa, float fb, const glm::vec3 &v0,
const glm::vec3 &v1, const glm::vec3 &boxhalfsize, float &rad, float &min,
float &max, float &p0, float &p1) {
p0 = -a * v0.x + b * v0.z;
p1 = -a * v1.x + b * v1.z;
if (p0 < p1) {
min = p0;
max = p1;
} else {
min = p1;
max = p0;
}
rad = fa * boxhalfsize.x + fb * boxhalfsize.z;
if (min > rad || max < -rad)
return false;
return true;
}
/*======================== Z-tests ========================*/
inline bool axisTestZ12(float a, float b, float fa, float fb, const glm::vec3 &v1,
const glm::vec3 &v2, const glm::vec3 &boxhalfsize, float &rad, float &min,
float &max, float &p1, float &p2) {
p1 = a * v1.x - b * v1.y;
p2 = a * v2.x - b * v2.y;
if (p1 < p2) {
min = p1;
max = p2;
} else {
min = p2;
max = p1;
}
rad = fa * boxhalfsize.x + fb * boxhalfsize.y;
if (min > rad || max < -rad)
return false;
return true;
}
inline bool axisTestZ0(float a, float b, float fa, float fb, const glm::vec3 &v0,
const glm::vec3 &v1, const glm::vec3 &boxhalfsize, float &rad, float &min,
float &max, float &p0, float &p1) {
p0 = a * v0.x - b * v0.y;
p1 = a * v1.x - b * v1.y;
if (p0 < p1) {
min = p0;
max = p1;
} else {
min = p1;
max = p0;
}
rad = fa * boxhalfsize.x + fb * boxhalfsize.y;
if (min > rad || max < -rad)
return false;
return true;
}
bool triBoxOverlap(glm::vec3 boxcenter, glm::vec3 boxhalfsize, glm::vec3 tv0, glm::vec3 tv1,
glm::vec3 tv2) {
/* use separating axis theorem to test overlap between triangle and box */
/* need to test for overlap in these directions: */
/* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
/* we do not even need to test these) */
/* 2) normal of the triangle */
/* 3) crossproduct(edge from tri, {x,y,z}-directin) */
/* this gives 3x3=9 more tests */
glm::vec3 v0, v1, v2;
float min, max, p0, p1, p2, rad, fex, fey, fez;
glm::vec3 normal, e0, e1, e2;
/* This is the fastest branch on Sun */
/* move everything so that the boxcenter is in (0,0,0) */
v0 = tv0 - boxcenter;
v1 = tv1 - boxcenter;
v2 = tv2 - boxcenter;
/* compute triangle edges */
e0 = v1 - v0;
e1 = v2 - v1;
e2 = v0 - v2;
/* Bullet 3: */
/* test the 9 tests first (this was faster) */
fex = fabsf(e0.x);
fey = fabsf(e0.y);
fez = fabsf(e0.z);
if (!axisTestX01(e0.z, e0.y, fez, fey, v0, v2, boxhalfsize, rad, min, max, p0, p2))
return false;
if (!axisTestY02(e0.z, e0.x, fez, fex, v0, v2, boxhalfsize, rad, min, max, p0, p2))
return false;
if (!axisTestZ12(e0.y, e0.x, fey, fex, v1, v2, boxhalfsize, rad, min, max, p1, p2))
return false;
fex = fabsf(e1.x);
fey = fabsf(e1.y);
fez = fabsf(e1.z);
if (!axisTestX01(e1.z, e1.y, fez, fey, v0, v2, boxhalfsize, rad, min, max, p0, p2))
return false;
if (!axisTestY02(e1.z, e1.x, fez, fex, v0, v2, boxhalfsize, rad, min, max, p0, p2))
return false;
if (!axisTestZ0(e1.y, e1.x, fey, fex, v0, v1, boxhalfsize, rad, min, max, p0, p1))
return false;
fex = fabsf(e2.x);
fey = fabsf(e2.y);
fez = fabsf(e2.z);
if (!axisTestX2(e2.z, e2.y, fez, fey, v0, v1, boxhalfsize, rad, min, max, p0, p1))
return false;
if (!axisTestY1(e2.z, e2.x, fez, fex, v0, v1, boxhalfsize, rad, min, max, p0, p1))
return false;
if (!axisTestZ12(e2.y, e2.x, fey, fex, v1, v2, boxhalfsize, rad, min, max, p1, p2))
return false;
/* Bullet 1: */
/* first test overlap in the {x,y,z}-directions */
/* find min, max of the triangle each direction, and test for overlap in */
/* that direction -- this is equivalent to testing a minimal AABB around */
/* the triangle against the AABB */
/* test in X-direction */
findMinMax(v0.x, v1.x, v2.x, min, max);
if (min > boxhalfsize.x || max < -boxhalfsize.x)
return false;
/* test in Y-direction */
findMinMax(v0.y, v1.y, v2.y, min, max);
if (min > boxhalfsize.y || max < -boxhalfsize.y)
return false;
/* test in Z-direction */
findMinMax(v0.z, v1.z, v2.z, min, max);
if (min > boxhalfsize.z || max < -boxhalfsize.z)
return false;
/* Bullet 2: */
/* test if the box intersects the plane of the triangle */
/* compute plane equation of triangle: normal*x+d=0 */
normal = glm::cross(e0, e1);
if (!planeBoxOverlap(normal, v0, boxhalfsize))
return false;
return true; /* box and triangle overlaps */
}
@nimryf
Copy link

nimryf commented Apr 24, 2019

Hello, I have the indices and vertices of a 3D mesh, and I want to voxelise it using this header. However, I'm not sure how to actually implement it... What I have in mind so far is that I make a 3 dimensional array that represents the object, where each element is a boolean indicating whether the voxel is part of the object and its index in the array being the relative location of the voxel. Inside a triple nested loop, I would be using the header to test for the presence of the object in the voxel, but I'm really confused as to how I'm meant to use it. Am I going about this the wrong way? If not, how am I meant to use it? Any help would be really appreciated...

@jjpepper
Copy link

Awesome... thanks for fixing that other code. I got bitten by trying it.

@charlesrwest
Copy link

If I may ask, what is the license covering these two gists? Is it public domain like the original C code?

Thanks,
Charlie West

@jflipts
Copy link
Author

jflipts commented Nov 9, 2020

If I may ask, what is the license covering these two gists? Is it public domain like the original C code?

My changes are public domain without any warranties, but I have no idea about the other gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment