All checks were successful
CI / build-and-analyze (push) Successful in 41s
244 lines
6.6 KiB
C
244 lines
6.6 KiB
C
#include "CgeMath.h"
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#define EPSILON 0.00001f
|
|
#define PI 3.14159265358979323846f
|
|
|
|
int CgeRay3fIntersectPlane(const float start[3], const float direction[3],
|
|
const float plane[4], float *t, float out[3]) {
|
|
float tmp1[3];
|
|
float denom, time;
|
|
|
|
/* Calculate intersection time */
|
|
denom = CgeVec3fDot(direction, plane);
|
|
time = (plane[3] - CgeVec3fDot(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 0;
|
|
|
|
/* Compute intersection point */
|
|
CgeVec3fScale(direction, time, tmp1);
|
|
CgeVec3fAdd(start, tmp1, out);
|
|
*t = time;
|
|
return 1;
|
|
}
|
|
|
|
int CgeRay3fIntersectTriangle(const float start[3], const float direction[3],
|
|
const float a[3], const float b[3],
|
|
const float c[3], float *t, float out[3]) {
|
|
float plane[4];
|
|
float tmp1[3], tmp2[3], tmp3[3];
|
|
float time;
|
|
|
|
/* Compute plane */
|
|
if (!CgePlaneFromPoints(a, b, c, plane))
|
|
return 0;
|
|
|
|
/* Compute intersection point in ray against plane */
|
|
if (!CgeRay3fIntersectPlane(start, direction, plane, &time, tmp3))
|
|
return 0;
|
|
|
|
/* Check if point inside rectangle */
|
|
CgeVec3fSub(b, a, tmp1);
|
|
CgeVec3fSub(tmp3, a, tmp2);
|
|
CgeVec3fCross(tmp2, tmp1, tmp1);
|
|
if (CgeVec3fDot(tmp1, plane) < 0.0f)
|
|
return 0;
|
|
|
|
CgeVec3fSub(c, b, tmp1);
|
|
CgeVec3fSub(tmp3, b, tmp2);
|
|
CgeVec3fCross(tmp2, tmp1, tmp1);
|
|
if (CgeVec3fDot(tmp1, plane) < 0.0f)
|
|
return 0;
|
|
|
|
CgeVec3fSub(a, c, tmp1);
|
|
CgeVec3fSub(tmp3, c, tmp2);
|
|
CgeVec3fCross(tmp2, tmp1, tmp1);
|
|
if (CgeVec3fDot(tmp1, plane) < 0.0f)
|
|
return 0;
|
|
|
|
/* Copy intersection point */
|
|
memcpy(out, tmp3, sizeof(tmp3));
|
|
*t = time;
|
|
return 1;
|
|
}
|
|
|
|
int CgeSegment3fIntersectPlane(const float start[3], const float end[3],
|
|
const float plane[4], float *t, float out[3]) {
|
|
float tmp[3];
|
|
float denom, time;
|
|
|
|
/* Calculate intersection time */
|
|
CgeVec3fSub(end, start, tmp);
|
|
denom = CgeVec3fDot(tmp, plane);
|
|
time = (plane[3] - CgeVec3fDot(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 0;
|
|
|
|
/* Compute intersection point */
|
|
CgeVec3fScale(tmp, time, tmp);
|
|
CgeVec3fAdd(start, tmp, out);
|
|
*t = time;
|
|
return 1;
|
|
}
|
|
|
|
int CgeSegment3fIntersectTriangle(const float start[3], const float end[3],
|
|
const float a[3], const float b[3],
|
|
const float c[3], float *t, float out[3]) {
|
|
float plane[4];
|
|
float tmp1[3], tmp2[3], tmp3[3];
|
|
float time;
|
|
|
|
/* Compute plane */
|
|
if (!CgePlaneFromPoints(a, b, c, plane))
|
|
return 0;
|
|
|
|
/* Compute intersection point in ray against plane */
|
|
if (!CgeSegment3fIntersectPlane(start, end, plane, &time, tmp3))
|
|
return 0;
|
|
|
|
/* Check if point inside rectangle */
|
|
CgeVec3fSub(b, a, tmp1);
|
|
CgeVec3fSub(tmp3, a, tmp2);
|
|
CgeVec3fCross(tmp2, tmp1, tmp1);
|
|
if (CgeVec3fDot(tmp1, plane) < 0.0f)
|
|
return 0;
|
|
|
|
CgeVec3fSub(c, b, tmp1);
|
|
CgeVec3fSub(tmp3, b, tmp2);
|
|
CgeVec3fCross(tmp2, tmp1, tmp1);
|
|
if (CgeVec3fDot(tmp1, plane) < 0.0f)
|
|
return 0;
|
|
|
|
CgeVec3fSub(a, c, tmp1);
|
|
CgeVec3fSub(tmp3, c, tmp2);
|
|
CgeVec3fCross(tmp2, tmp1, tmp1);
|
|
if (CgeVec3fDot(tmp1, plane) < 0.0f)
|
|
return 0;
|
|
|
|
/* Copy intersection point */
|
|
memcpy(out, tmp3, sizeof(tmp3));
|
|
*t = time;
|
|
return 1;
|
|
}
|
|
|
|
int CgeRay3fIntersectBox3f(const float aStart[3], const float aDirection[3],
|
|
const float bMin[3], const float bMax[3], float *t,
|
|
float out[3]) {
|
|
float timeNear, timeFar, hitNear, hitFar, denom, tmp;
|
|
int i;
|
|
|
|
timeNear = -1.0f / 0.0f;
|
|
timeFar = 1.0f / 0.0f;
|
|
|
|
/* 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 0;
|
|
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 0;
|
|
}
|
|
|
|
out[0] = aStart[0] + aDirection[0] * timeNear;
|
|
out[1] = aStart[1] + aDirection[1] * timeNear;
|
|
out[2] = aStart[2] + aDirection[2] * timeNear;
|
|
*t = timeNear;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CgeSegment3fIntersectBox3f(const float aStart[3], const float aEnd[3],
|
|
const float bMin[3], const float bMax[3],
|
|
float *t, float out[3]) {
|
|
float tmp[3];
|
|
float time;
|
|
|
|
CgeVec3fSub(aEnd, aStart, tmp);
|
|
if (!CgeRay3fIntersectBox3f(aStart, tmp, bMin, bMax, &time, out))
|
|
return 0;
|
|
|
|
if (time > 1.0f)
|
|
return 0;
|
|
|
|
*t = time;
|
|
return 1;
|
|
}
|
|
|
|
int CgeRay3fIntersectSphere(const float start[3], const float direction[3],
|
|
const float center[3], float radius, float *t,
|
|
float out[3])
|
|
{
|
|
float v[3], tmp[3];
|
|
float tCa, d2, th, t1, t2;
|
|
|
|
CgeVec3fSub(center, start, v);
|
|
tCa = CgeVec3fDot(v, direction);
|
|
d2 = CgeVec3fDot(v, v) - tCa * tCa;
|
|
|
|
if (d2 > radius * radius)
|
|
return 0;
|
|
|
|
th = (float)sqrt(radius * radius - d2);
|
|
t1 = tCa - th;
|
|
t2 = tCa + th;
|
|
|
|
if (t2 < EPSILON) return 0;
|
|
|
|
*t = (t1 > EPSILON) ? t1 : t2;
|
|
CgeVec3fScale(direction, *t, tmp);
|
|
CgeVec3fAdd(start, tmp, out);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CgeSegment3fIntersectSphere(const float start[3], const float end[3],
|
|
const float center[3], float radius, float *t,
|
|
float out[3]) {
|
|
float dir[3], lenSq, len;
|
|
float norm[3];
|
|
|
|
CgeVec3fSub(end, start, dir);
|
|
lenSq = CgeVec3fDot(dir, dir);
|
|
|
|
if (lenSq == 0.0f)
|
|
return 0;
|
|
|
|
len = (float)sqrt(lenSq);
|
|
CgeVec3fScale(dir, 1.0f / len, norm);
|
|
|
|
if (!CgeRay3fIntersectSphere(start, norm, center, radius, t, out)) {
|
|
return 0;
|
|
}
|
|
|
|
*t = *t / len;
|
|
if (*t > len)
|
|
return 0;
|
|
|
|
CgeVec3fScale(dir, *t, out);
|
|
CgeVec3fAdd(start, out, out);
|
|
return 1;
|
|
}
|