233 lines
6.1 KiB
C
233 lines
6.1 KiB
C
|
|
#include <BH/Math.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <math.h>
|
||
|
|
|
||
|
|
|
||
|
|
#define EPSILON 0.00001f
|
||
|
|
#define PI 3.14159265358979323846f
|
||
|
|
|
||
|
|
|
||
|
|
int BH_Ray3fIntersectPlane(const float *start,
|
||
|
|
const float *direction,
|
||
|
|
const float *plane,
|
||
|
|
float *t,
|
||
|
|
float *out)
|
||
|
|
{
|
||
|
|
float tmp1[3];
|
||
|
|
float denom, time;
|
||
|
|
|
||
|
|
/* Calculate intersection time */
|
||
|
|
denom = BH_Vec3fDot(direction, plane);
|
||
|
|
time = (plane[3] - BH_Vec3fDot(plane, start)) / denom;
|
||
|
|
|
||
|
|
/* Check for ray/plane parallel to each other or point is behing the ray. */
|
||
|
|
if (fabsf(denom) < EPSILON || time < 0.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
/* Compute intersection point */
|
||
|
|
BH_Vec3fScale(direction, time, tmp1);
|
||
|
|
BH_Vec3fAdd(start, tmp1, out);
|
||
|
|
*t = time;
|
||
|
|
return BH_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int BH_Ray3fIntersectTriangle(const float *start,
|
||
|
|
const float *direction,
|
||
|
|
const float *a,
|
||
|
|
const float *b,
|
||
|
|
const float *c,
|
||
|
|
float *t,
|
||
|
|
float *out)
|
||
|
|
{
|
||
|
|
float plane[4];
|
||
|
|
float tmp1[3], tmp2[3], tmp3[3];
|
||
|
|
float time;
|
||
|
|
|
||
|
|
/* Compute plane */
|
||
|
|
if (BH_PlaneFromPoints(a, b, c, plane))
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
/* Compute intersection point in ray against plane */
|
||
|
|
if (BH_Ray3fIntersectPlane(start, direction, plane, &time, tmp3))
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
/* Check if point inside rectangle */
|
||
|
|
BH_Vec3fSub(b, a, tmp1);
|
||
|
|
BH_Vec3fSub(tmp3, a, tmp2);
|
||
|
|
BH_Vec3fCross(tmp2, tmp1, tmp1);
|
||
|
|
if (BH_Vec3fDot(tmp1, plane) < 0.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
BH_Vec3fSub(c, b, tmp1);
|
||
|
|
BH_Vec3fSub(tmp3, b, tmp2);
|
||
|
|
BH_Vec3fCross(tmp2, tmp1, tmp1);
|
||
|
|
if (BH_Vec3fDot(tmp1, plane) < 0.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
BH_Vec3fSub(a, c, tmp1);
|
||
|
|
BH_Vec3fSub(tmp3, c, tmp2);
|
||
|
|
BH_Vec3fCross(tmp2, tmp1, tmp1);
|
||
|
|
if (BH_Vec3fDot(tmp1, plane) < 0.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
/* Copy intersection point */
|
||
|
|
memcpy(out, tmp3, sizeof(tmp3));
|
||
|
|
*t = time;
|
||
|
|
return BH_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int BH_Segment3fIntersectPlane(const float *start,
|
||
|
|
const float *end,
|
||
|
|
const float *plane,
|
||
|
|
float *t,
|
||
|
|
float *out)
|
||
|
|
{
|
||
|
|
float tmp[3];
|
||
|
|
float denom, time;
|
||
|
|
|
||
|
|
/* Calculate intersection time */
|
||
|
|
BH_Vec3fSub(end, start, tmp);
|
||
|
|
denom = BH_Vec3fDot(tmp, plane);
|
||
|
|
time = (plane[3] - BH_Vec3fDot(plane, start)) / denom;
|
||
|
|
|
||
|
|
/* Check for ray/plane parallel to each other or point is behing the ray. */
|
||
|
|
if (fabsf(denom) < EPSILON || time < 0.0f || time > 1.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
/* Compute intersection point */
|
||
|
|
BH_Vec3fScale(tmp, time, tmp);
|
||
|
|
BH_Vec3fAdd(start, tmp, out);
|
||
|
|
*t = time;
|
||
|
|
return BH_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int BH_Segment3fIntersectTriangle(const float *start,
|
||
|
|
const float *end,
|
||
|
|
const float *a,
|
||
|
|
const float *b,
|
||
|
|
const float *c,
|
||
|
|
float *t,
|
||
|
|
float *out)
|
||
|
|
{
|
||
|
|
float plane[4];
|
||
|
|
float tmp1[3], tmp2[3], tmp3[3];
|
||
|
|
float time;
|
||
|
|
|
||
|
|
/* Compute plane */
|
||
|
|
if (BH_PlaneFromPoints(a, b, c, plane))
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
/* Compute intersection point in ray against plane */
|
||
|
|
if (BH_Segment3fIntersectPlane(start, end, plane, &time, tmp3))
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
/* Check if point inside rectangle */
|
||
|
|
BH_Vec3fSub(b, a, tmp1);
|
||
|
|
BH_Vec3fSub(tmp3, a, tmp2);
|
||
|
|
BH_Vec3fCross(tmp2, tmp1, tmp1);
|
||
|
|
if (BH_Vec3fDot(tmp1, plane) < 0.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
BH_Vec3fSub(c, b, tmp1);
|
||
|
|
BH_Vec3fSub(tmp3, b, tmp2);
|
||
|
|
BH_Vec3fCross(tmp2, tmp1, tmp1);
|
||
|
|
if (BH_Vec3fDot(tmp1, plane) < 0.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
BH_Vec3fSub(a, c, tmp1);
|
||
|
|
BH_Vec3fSub(tmp3, c, tmp2);
|
||
|
|
BH_Vec3fCross(tmp2, tmp1, tmp1);
|
||
|
|
if (BH_Vec3fDot(tmp1, plane) < 0.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
/* Copy intersection point */
|
||
|
|
memcpy(out, tmp3, sizeof(tmp3));
|
||
|
|
*t = time;
|
||
|
|
return BH_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int BH_Ray3fIntersectBox3f(const float *aStart,
|
||
|
|
const float *aDirection,
|
||
|
|
const float *bMin,
|
||
|
|
const float *bMax,
|
||
|
|
float *t,
|
||
|
|
float *out)
|
||
|
|
{
|
||
|
|
float timeNear, timeFar, hitNear, hitFar, denom, tmp;
|
||
|
|
int i;
|
||
|
|
|
||
|
|
timeNear = -1.0f / 0.0f;
|
||
|
|
timeFar = 1.0f / 0.0f;
|
||
|
|
|
||
|
|
/* Check if origin inside box */
|
||
|
|
if (!BH_Box3fContains(bMin, bMax, aStart))
|
||
|
|
{
|
||
|
|
memcpy(out, aStart, sizeof(float) * 3);
|
||
|
|
*t = 0.0f;
|
||
|
|
return BH_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Check each axis for the minimal and maximum intersection time */
|
||
|
|
for (i = 0; i < 3; i++)
|
||
|
|
{
|
||
|
|
if (fabsf(aDirection[i]) < EPSILON)
|
||
|
|
{
|
||
|
|
if (aStart[i] < bMin[i] || aStart[i] > bMax[i])
|
||
|
|
return BH_ERROR;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
denom = 1.0f / aDirection[i];
|
||
|
|
hitNear = (bMin[i] - aStart[i]) * denom;
|
||
|
|
hitFar = (bMax[i] - aStart[i]) * denom;
|
||
|
|
|
||
|
|
if (hitNear > hitFar)
|
||
|
|
{
|
||
|
|
tmp = hitNear;
|
||
|
|
hitNear = hitFar;
|
||
|
|
hitFar = tmp;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (hitNear > timeNear)
|
||
|
|
timeNear = hitNear;
|
||
|
|
if (hitFar < timeFar)
|
||
|
|
timeFar = hitFar;
|
||
|
|
|
||
|
|
if (timeNear > timeFar || timeFar < 0.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
out[0] = aStart[0] + aDirection[0] * timeNear;
|
||
|
|
out[1] = aStart[1] + aDirection[1] * timeNear;
|
||
|
|
out[2] = aStart[2] + aDirection[2] * timeNear;
|
||
|
|
*t = timeNear;
|
||
|
|
|
||
|
|
return BH_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int BH_Segment3fIntersectBox3f(const float *aStart,
|
||
|
|
const float *aEnd,
|
||
|
|
const float *bMin,
|
||
|
|
const float *bMax,
|
||
|
|
float *t,
|
||
|
|
float *out)
|
||
|
|
{
|
||
|
|
float tmp[3];
|
||
|
|
float time;
|
||
|
|
|
||
|
|
BH_Vec3fSub(aEnd, aStart, tmp);
|
||
|
|
if (BH_Ray3fIntersectBox3f(aStart, tmp, bMin, bMax, &time, out))
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
if (time > 1.0f)
|
||
|
|
return BH_ERROR;
|
||
|
|
|
||
|
|
*t = time;
|
||
|
|
return BH_OK;
|
||
|
|
}
|