added the readme

This commit is contained in:
2026-06-08 17:07:34 -04:00
commit 6655fd2886
1001 changed files with 253651 additions and 0 deletions
+490
View File
@@ -0,0 +1,490 @@
#include "tFunctions.h"
#include "Debug.h"
glm::vec3 CalculateTriangleNormal(Triangle t) {
return glm::normalize(glm::cross(t.b - t.a, t.c - t.a));
}
float Magnitude2(const glm::vec3& v) {
return v.x*v.x + v.y*v.y + v.z*v.z;
}
float Magnitude(const glm::vec3& v) {
return pow(Magnitude2(v), 0.5f);
}
//SQUARED FOR PERFORMANCE REASONS
float SquaredPerpendicularMagnitude(glm::vec3 off, glm::vec3 line)
{
float offmag = Magnitude2(off);
return offmag * (glm::dot(off, line)/ (offmag + Magnitude2(line)));
}
float VolumeOfTriangle(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3) {
return glm::dot(p1, glm::cross(p2, p3)) / 6.0f;
}
std::optional<glm::vec3> RayIntersectsTriangle(const Ray& ray,
const Triangle triangle)
{
constexpr float epsilon = std::numeric_limits<float>::epsilon();
const glm::vec3 ray_origin = ray.origin;
const glm::vec3 ray_direction = ray.direction;
glm::vec3 edge1 = triangle.b - triangle.a;
glm::vec3 edge2 = triangle.c - triangle.a;
glm::vec3 ray_cross_e2 = cross(ray_direction, edge2);
float det = dot(edge1, ray_cross_e2);
if (det > -epsilon && det < epsilon)
return {}; // This ray is parallel to this triangle.
float inv_det = 1.0 / det;
glm::vec3 s = ray_origin - triangle.a;
float u = inv_det * dot(s, ray_cross_e2);
if ((u < 0 && abs(u) > epsilon) || (u > 1 && abs(u - 1) > epsilon))
return {};
glm::vec3 s_cross_e1 = cross(s, edge1);
float v = inv_det * dot(ray_direction, s_cross_e1);
if ((v < 0 && abs(v) > epsilon) || (u + v > 1 && abs(u + v - 1) > epsilon))
return {};
// At this stage we can compute t to find out where the intersection point is on the line.
float t = inv_det * dot(edge2, s_cross_e1);
if (t > epsilon) // ray intersection
{
return glm::vec3(ray_origin + ray_direction * t);
}
else // This means that there is a line intersection but not a ray intersection.
return {};
}
std::optional<glm::vec3> IsRayInT(const Ray& ray, t& t) {
const BoundingBox aabb = t.GetRotationlessAABB();
glm::mat4 inverse = glm::inverse(t.GetMatrix());
glm::vec3 ray_origin = glm::vec3(inverse * glm::vec4(ray.origin, 1.0f));
glm::vec3 ray_direction = glm::vec3(inverse * glm::vec4(ray.direction, 0.0f));
glm::vec3 dirfrac = glm::vec3(1.0f) / ray_direction;
// lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
// r.org is origin of ray
glm::vec3 lb = {-0.5f,-0.5f,-0.5f};
glm::vec3 rt = {0.5f,0.5f,0.5f };
float t1 = (lb.x - ray_origin.x) * dirfrac.x;
float t2 = (rt.x - ray_origin.x) * dirfrac.x;
float t3 = (lb.y - ray_origin.y) * dirfrac.y;
float t4 = (rt.y - ray_origin.y) * dirfrac.y;
float t5 = (lb.z - ray_origin.z) * dirfrac.z;
float t6 = (rt.z - ray_origin.z) * dirfrac.z;
float tmin = glm::max(glm::max(glm::min(t1, t2), glm::min(t3, t4)), glm::min(t5, t6));
float tmax = glm::min(glm::min(glm::max(t1, t2), glm::max(t3, t4)), glm::max(t5, t6));
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
if (tmax < 0)
{
return {};
}
// if tmin > tmax, ray doesn't intersect AABB
if (tmin > tmax)
{
return {};
}
return { glm::vec3(t.GetMatrix() * glm::vec4(ray_direction*tmin+ray_origin, 1.0f))};
}
bool IsRayInBool(const Ray& ray, t& t) {
const BoundingBox aabb = t.GetRotationlessAABB();
glm::mat4 inverse = glm::inverse(t.GetMatrix());
glm::vec3 ray_origin = glm::vec3(inverse * glm::vec4(ray.origin, 1.0f));
glm::vec3 ray_direction = glm::vec3(inverse * glm::vec4(ray.direction, 0.0f));
glm::vec3 dirfrac = glm::vec3(1.0f) / ray_direction;
// lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
// r.org is origin of ray
glm::vec3 lb = { -0.5f,-0.5f,-0.5f };
glm::vec3 rt = { 0.5f,0.5f,0.5f };
float t1 = (lb.x - ray_origin.x) * dirfrac.x;
float t2 = (rt.x - ray_origin.x) * dirfrac.x;
float t3 = (lb.y - ray_origin.y) * dirfrac.y;
float t4 = (rt.y - ray_origin.y) * dirfrac.y;
float t5 = (lb.z - ray_origin.z) * dirfrac.z;
float t6 = (rt.z - ray_origin.z) * dirfrac.z;
float tmin = glm::max(glm::max(glm::min(t1, t2), glm::min(t3, t4)), glm::min(t5, t6));
float tmax = glm::min(glm::min(glm::max(t1, t2), glm::max(t3, t4)), glm::max(t5, t6));
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
if (tmax < 0)
{
return false;
}
// if tmin > tmax, ray doesn't intersect AABB
if (tmin > tmax)
{
return false;
}
return true;
}
bool BoundingBoxInBoundingBox(const BoundingBox bb1, const BoundingBox bb2) {
glm::vec3 bb1min = bb1.min;
glm::vec3 bb1max = bb1.max;
glm::vec3 bb2min = bb2.min;
glm::vec3 bb2max = bb2.max;
return (bb1min[0] < bb2max[0] and bb2min[0] < bb1max[0] and bb1min[1] < bb2max[1] and bb2min[1] < bb1max[1] and bb1min[2] < bb2max[2] and bb2min[2] < bb1max[2]);
}
bool BoundingAxisInBoundingAxis(BoundingAxis ba1, BoundingAxis ba2) {
return ba1.min < ba2.max and ba2.min < ba1.max;
}
std::optional<std::pair<float,glm::vec3>> TAxisCollidesT(std::vector < glm::vec3 >& t1, std::vector < glm::vec3 >& t2, glm::vec3 axis) {
//FIRST RETURN IS OVERLAPPING AREA
//SECOND RETURN IS POINT OF COLLISION
float min1 = FLT_MAX;
float max1 = -FLT_MAX;
float min2 = FLT_MAX;
float max2 = -FLT_MAX;
for (glm::vec3& v : t1) {
float perpendicularmag = SquaredPerpendicularMagnitude(v,axis);
min1 = glm::min(min1,perpendicularmag);
max1 = glm::max(max1, perpendicularmag);
}
for (glm::vec3& v : t2) {
float perpendicularmag = SquaredPerpendicularMagnitude(v, axis);
min2 = glm::min(min2, perpendicularmag);
max2 = glm::max(max2, perpendicularmag);
}
if (min1 < max2 and min2 < max1) {
float overlap = glm::min(max1, max2) - glm::max(min1, min2);
float middle = (glm::min(max1, max2) + glm::max(min1, min2)) / 2.0f;
return { {overlap, middle * axis} };
}
else return {};
}
bool TAxisCollidesTNoInfo(std::vector < glm::vec3 >& t1, std::vector < glm::vec3 >& t2, glm::vec3 axis) {
//FIRST RETURN IS OVERLAPPING AREA
//SECOND RETURN IS POINT OF COLLISION
float min1 = FLT_MAX;
float max1 = -FLT_MAX;
float min2 = FLT_MAX;
float max2 = -FLT_MAX;
for (glm::vec3& v : t1) {
float perpendicularmag = SquaredPerpendicularMagnitude(v, axis);
min1 = glm::min(min1, perpendicularmag);
max1 = glm::max(max1, perpendicularmag);
}
for (glm::vec3& v : t2) {
float perpendicularmag = SquaredPerpendicularMagnitude(v, axis);
min2 = glm::min(min2, perpendicularmag);
max2 = glm::max(max2, perpendicularmag);
}
if (min1 < max2 and min2 < max1) {
return true;
}
return false;
}
std::optional<AxisCollisionCN> TAxisCollidesTCN(std::vector < glm::vec3 >& t1, std::vector < glm::vec3 >& t2, glm::vec3 axis) {
//FIRST RETURN IS OVERLAPPING AREA
//SECOND RETURN IS POINT OF COLLISION
float min1 = FLT_MAX;
float max1 = -FLT_MAX;
float min2 = FLT_MAX;
float max2 = -FLT_MAX;
for (glm::vec3& v : t1) {
float perpendicularmag = SquaredPerpendicularMagnitude(v, axis);
min1 = glm::min(min1, perpendicularmag);
max1 = glm::max(max1, perpendicularmag);
}
for (glm::vec3& v : t2) {
float perpendicularmag = SquaredPerpendicularMagnitude(v, axis);
min2 = glm::min(min2, perpendicularmag);
max2 = glm::max(max2, perpendicularmag);
}
if (min1 < max2 and min2 < max1) {
float overlap = glm::min(max1, max2) - glm::max(min1, min2);
float middle = (glm::min(max1, max2) + glm::max(min1, min2)) / 2.0f;
AxisCollisionCN accn;
accn.infront = (min1+max1)/2.0f > (min2+max2)/2.0f;
accn.POI = axis * middle;
accn.overlap = overlap;
return {accn};
}
return {};
}
bool TNearT(t& t1, t& t2)
{
glm::vec3 posdif = t1.GetTranslation() - t2.GetTranslation();
return t1.ScaleMagnitude2() + t2.ScaleMagnitude2() > (posdif.x* posdif.x+ posdif.y* posdif.y+ posdif.z* posdif.z) * 2.0f;
}
bool TInTNoInfo(t& t1, t& t2) {
std::vector < glm::vec3 > worldvertices1 = {
{0.5f,0.5f,0.5f},
{0.5f,-0.5f,0.5f},
{0.5f,0.5f,-0.5f},
{0.5f,-0.5f,-0.5f},
{-0.5f,0.5f,0.5f},
{-0.5f,-0.5f,0.5f},
{-0.5f,0.5f,-0.5f},
{-0.5f,-0.5f,-0.5f},
};
std::vector < glm::vec3 > worldvertices2 = {
{0.5f,0.5f,0.5f},
{0.5f,-0.5f,0.5f},
{0.5f,0.5f,-0.5f},
{0.5f,-0.5f,-0.5f},
{-0.5f,0.5f,0.5f},
{-0.5f,-0.5f,0.5f},
{-0.5f,0.5f,-0.5f},
{-0.5f,-0.5f,-0.5f},
};
glm::mat4 t1mat = t1.GetMatrix();
glm::mat4 t2mat = t2.GetMatrix();
for (glm::vec3& v : worldvertices1) {
v = glm::vec3(t1mat * glm::vec4(v, 1.0f));
}
for (glm::vec3& v : worldvertices2) {
v = glm::vec3(t2mat * glm::vec4(v, 1.0f));
}
//FIRST 6 AXES
glm::vec3 fv1 = t1.GetFrontVector();
glm::vec3 rv1 = t1.GetRightVector();
glm::vec3 uv1 = t1.GetUpVector();
glm::vec3 fv2 = t2.GetFrontVector();
glm::vec3 rv2 = t2.GetRightVector();
glm::vec3 uv2 = t2.GetUpVector();
std::vector<glm::vec3> axes = {
fv1,fv2,uv1,uv2,rv1,rv2,
glm::cross(fv1,fv2),
glm::cross(fv1, rv2),
glm::cross(fv1, uv2),
glm::cross(rv1, fv2),
glm::cross(rv1, rv2),
glm::cross(rv1, uv2),
glm::cross(uv1, fv2),
glm::cross(uv1, rv2),
glm::cross(uv1, uv2)
};
for (glm::vec3 axis : axes) {
if (not TAxisCollidesTNoInfo(worldvertices1, worldvertices2, axis)) return false;
}
//FINAL
return true;
}
std::optional<TInTInfo> TInT(t& t1, t& t2) {
std::vector<glm::vec3> worldvertices1 = {
{0.5f,0.5f,0.5f},{0.5f,-0.5f,0.5f},{0.5f,0.5f,-0.5f},{0.5f,-0.5f,-0.5f},
{-0.5f,0.5f,0.5f},{-0.5f,-0.5f,0.5f},{-0.5f,0.5f,-0.5f},{-0.5f,-0.5f,-0.5f},
};
std::vector<glm::vec3> worldvertices2 = worldvertices1;
glm::mat4 t1mat = t1.GetMatrix(), t2mat = t2.GetMatrix();
for (glm::vec3& v : worldvertices1) v = glm::vec3(t1mat * glm::vec4(v, 1.0f));
for (glm::vec3& v : worldvertices2) v = glm::vec3(t2mat * glm::vec4(v, 1.0f));
glm::vec3 fv1=t1.GetFrontVector(), rv1=t1.GetRightVector(), uv1=t1.GetUpVector();
glm::vec3 fv2=t2.GetFrontVector(), rv2=t2.GetRightVector(), uv2=t2.GetUpVector();
std::vector<glm::vec3> allAxes = {
fv1, uv1, rv1, fv2, uv2, rv2,
glm::cross(fv1,fv2), glm::cross(fv1,rv2), glm::cross(fv1,uv2),
glm::cross(rv1,fv2), glm::cross(rv1,rv2), glm::cross(rv1,uv2),
glm::cross(uv1,fv2), glm::cross(uv1,rv2), glm::cross(uv1,uv2)
};
TInTInfo tr;
float lowestoverlap = FLT_MAX;
bool bestInfront = false;
int bestIndex = 0;
for (int i = 0; i < (int)allAxes.size(); i++) {
glm::vec3 axis = allAxes[i];
if (i >= 6) {
float len = glm::length(axis);
if (len < 1e-6f) continue;
axis = axis / len;
allAxes[i] = axis;
}
std::optional<AxisCollisionCN> b = TAxisCollidesTCN(worldvertices1, worldvertices2, axis);
if (!b.has_value()) return {};
if (b->overlap < lowestoverlap) {
lowestoverlap = b->overlap;
bestInfront = b->infront;
bestIndex = i;
}
}
tr.overlap = lowestoverlap;
tr.CN = allAxes[bestIndex] * (bestInfront ? 1.0f : -1.0f);
// POI
glm::mat4 t1inv = glm::inverse(t1mat), t2inv = glm::inverse(t2mat);
std::vector<glm::vec3> contactPts;
for (const glm::vec3& v : worldvertices2) {
glm::vec3 local = glm::vec3(t1inv * glm::vec4(v, 1.0f));
if (glm::all(glm::lessThanEqual(glm::abs(local), glm::vec3(0.5f + 1e-4f))))
contactPts.push_back(v);
}
for (const glm::vec3& v : worldvertices1) {
glm::vec3 local = glm::vec3(t2inv * glm::vec4(v, 1.0f));
if (glm::all(glm::lessThanEqual(glm::abs(local), glm::vec3(0.5f + 1e-4f))))
contactPts.push_back(v);
}
if (contactPts.empty()) {
static const int edgeIdx[][2] = {
{0,1},{0,2},{1,3},{2,3},
{4,5},{4,6},{5,7},{6,7},
{0,4},{1,5},{2,6},{3,7}
};
float bestDist = FLT_MAX;
glm::vec3 bestPt(0.0f);
for (auto& e1 : edgeIdx) {
glm::vec3 p1 = worldvertices1[e1[0]], p2 = worldvertices1[e1[1]];
for (auto& e2 : edgeIdx) {
glm::vec3 p3 = worldvertices2[e2[0]], p4 = worldvertices2[e2[1]];
glm::vec3 d1=p2-p1, d2=p4-p3, r=p1-p3;
float a=glm::dot(d1,d1), e=glm::dot(d2,d2), f=glm::dot(d2,r);
float s, t;
if (a < 1e-10f && e < 1e-10f) { s=0.0f; t=0.0f; }
else if (a < 1e-10f) { s=0.0f; t=glm::clamp(f/e,0.0f,1.0f); }
else {
float c=glm::dot(d1,r), b=glm::dot(d1,d2), denom=a*e-b*b;
if (e < 1e-10f) { t=0.0f; s=glm::clamp(-c/a,0.0f,1.0f); }
else {
s = denom > 1e-10f ? glm::clamp((b*f-c*e)/denom,0.0f,1.0f) : 0.0f;
t = (b*s+f)/e;
if (t < 0.0f) { t=0.0f; s=glm::clamp(-c/a,0.0f,1.0f); }
else if (t > 1.0f) { t=1.0f; s=glm::clamp((b-c)/a,0.0f,1.0f); }
}
}
glm::vec3 c1=p1+s*d1, c2=p3+t*d2;
float dist = glm::length(c1-c2);
if (dist < bestDist) { bestDist=dist; bestPt=(c1+c2)*0.5f; }
}
}
tr.POI = bestPt;
} else {
tr.POI = glm::vec3(0.0f);
for (const glm::vec3& p : contactPts) tr.POI += p;
tr.POI /= (float)contactPts.size();
}
return tr;
}
glm::quat AngleAxis(glm::vec3 axis, float angle) {
float halfangle = angle * 0.5f;
glm::quat q;
float s = sin(halfangle);
q.x = axis.x * s;
q.y = axis.y * s;
q.z = axis.z * s;
q.z = 0.0f;
q.w = cos(halfangle);
return q;
}
glm::vec3 LookAtVector(glm::vec3 start, glm::vec3 end) {
return glm::normalize(end - start);
}
glm::quat RotationBetweenVectors(glm::vec3 start, glm::vec3 dest) {
start = glm::normalize(start);
dest = glm::normalize(dest);
float cosTheta = dot(start, dest);
glm::vec3 rotationAxis;
if (cosTheta < -1 + 0.001f) {
// special case when vectors in opposite directions:
// there is no "ideal" rotation axis
// So guess one; any will do as long as it's perpendicular to start
rotationAxis = cross(glm::vec3(0.0f, 0.0f, 1.0f), start);
if (glm::length(rotationAxis) < 0.01) // bad luck, they were parallel, try again!
rotationAxis = cross(glm::vec3(1.0f, 0.0f, 0.0f), start);
rotationAxis = normalize(rotationAxis);
return glm::angleAxis(glm::radians(180.0f), rotationAxis);
}
rotationAxis = cross(start, dest);
float s = sqrt((1 + cosTheta) * 2);
float invs = 1 / s;
return glm::quat(
s * 0.5f,
rotationAxis.x * invs,
rotationAxis.y * invs,
rotationAxis.z * invs
);
}
glm::quat LookAt(glm::vec3 direction) {
glm::vec3 normdir = glm::normalize(direction);
glm::quat rot1 = RotationBetweenVectors(glm::vec3(0.0f, 0.0f, 1.0f), normdir);
glm::vec3 desiredUp = { 0.0f,1.0f,0.0f };
glm::vec3 right = cross(normdir, desiredUp);
desiredUp = cross(right, normdir);
// Because of the 1rst rotation, the up is probably completely screwed up.
// Find the rotation between the "up" of the rotated object, and the desired up
glm::vec3 newUp = rot1 * glm::vec3(0.0f, 1.0f, 0.0f);
glm::quat rot2 = RotationBetweenVectors(newUp, desiredUp);
return rot2 * rot1;
}
glm::quat LookAt(glm::vec3 start, glm::vec3 end) {
return LookAt(end - start);
}