COSC-3P93-Project/Step 3/include/engine/math/colliders.h

245 lines
10 KiB
C
Raw Normal View History

2022-10-20 11:30:15 -04:00
/*
* Created by Brett Terpstra 6920201 on 17/10/22.
* Copyright (c) 2022 Brett Terpstra. All Rights Reserved.
*/
#ifndef STEP_2_COLLIDERS_H
#define STEP_2_COLLIDERS_H
#include "vectors.h"
2022-10-20 11:30:15 -04:00
namespace Raytracing {
// 3D Axis Aligned Bounding Box for use in a BVH
2022-11-15 16:23:37 -05:00
struct AABBHitData {
bool hit;
PRECISION_TYPE tMin, tMax;
2022-11-15 16:23:37 -05:00
};
2022-11-16 17:34:17 -05:00
enum AABBAxis {
X = 0, Y = 1, Z = 2
};
2022-12-13 01:33:31 -05:00
/**
* Simple minimal Axis Aligned Bounding Box implementation. Based on my C++ Game Engine's AABB which is based on my Java Game Engine's AABB
* which is based on my Minecraft Clone v2's AABB which is based on a decompiled AABB class from Minecraft Beta 1.7.3
*/
2022-10-20 11:30:15 -04:00
class AABB {
protected:
Vec4 min;
Vec4 max;
public:
2022-12-13 01:33:31 -05:00
/**
* Creates an empty AABB. Not useful for anything.
*/
AABB(): min({0, 0, 0}), max({0, 0, 0}) {};
/**
* Creates an AABB using the provided min/max coords
*/
2022-10-20 11:30:15 -04:00
AABB(PRECISION_TYPE minX, PRECISION_TYPE minY, PRECISION_TYPE minZ, PRECISION_TYPE maxX, PRECISION_TYPE maxY, PRECISION_TYPE maxZ):
min{minX, minY, minZ}, max{maxX, maxY, maxZ} {
}
2022-12-13 01:33:31 -05:00
/**
* Creates an AABB using the provided min/max vector coords
*/
2022-10-20 11:30:15 -04:00
AABB(const Vec4& min, const Vec4& max): min(min), max(max) {}
2022-12-13 01:33:31 -05:00
/**
* creates an AABB extending of size centered on x, y, z
* @param size radius of the AABB
*/
2022-10-20 11:30:15 -04:00
AABB(PRECISION_TYPE x, PRECISION_TYPE y, PRECISION_TYPE z, PRECISION_TYPE size):
min{x - size, y - size, z - size}, max{x + size, y + size, z + size} {
}
2022-12-13 01:33:31 -05:00
/**
* translates the AABB to position x,y,z for world collision detection
* This creates a copy AABB.
* @return a copy of this AABB translated by Vec4{x,y,z}
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] AABB translate(PRECISION_TYPE x, PRECISION_TYPE y, PRECISION_TYPE z) const {
Vec4 pos = {x, y, z};
return {min + pos, max + pos};
}
2022-12-13 01:33:31 -05:00
/**
* Translates this AABB using a vector instead of individual coords
* @return a copy of this AABB translated by vec
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] AABB translate(const Vec4& vec) const {
Vec4 pos = {vec.x(), vec.y(), vec.z()};
return {min + pos, max + pos};
}
2022-12-13 01:33:31 -05:00
/**
* returns an expanded version of this AABB is the other AABB is larger then this AABB
* @param other other AABB to expand against
* @return a AABB which includes this AABB and the other AABB. If this AABB is empty it will return other.
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] AABB expand(const AABB& other) const {
// terrible hack
// a 0 init AABB was having issues when being "expanded" to a place which is larger
// this should prevent that by side stepping the issue. Which is a TODO:
if (isEmpty())
return other;
2022-10-20 11:30:15 -04:00
PRECISION_TYPE minX = std::min(min.x(), other.min.x());
PRECISION_TYPE minY = std::min(min.y(), other.min.y());
PRECISION_TYPE minZ = std::min(min.z(), other.min.z());
PRECISION_TYPE maxX = std::max(max.x(), other.max.x());
PRECISION_TYPE maxY = std::max(max.y(), other.max.y());
PRECISION_TYPE maxZ = std::max(max.z(), other.max.z());
return {minX, minY, minZ, maxX, maxY, maxZ};
}
2022-12-13 01:33:31 -05:00
/**
* Checks if this AABB interests with the AABB described in individual coordinates
* @return true if intersection occurs
*/
[[nodiscard]] inline bool intersects(
PRECISION_TYPE minX, PRECISION_TYPE minY, PRECISION_TYPE minZ, PRECISION_TYPE maxX, PRECISION_TYPE maxY, PRECISION_TYPE maxZ
) const {
2022-10-20 11:30:15 -04:00
return min.x() <= maxX && max.x() >= minX && min.y() <= maxY && max.y() >= minY && min.z() <= maxZ && max.z() >= minZ;
}
2022-12-13 01:33:31 -05:00
/**
* Checks if this AABB interests with the AABB described in vector coordinates
* @return true if intersection occurs
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] inline bool intersects(const Vec4& minV, const Vec4& maxV) const {
return intersects(minV.x(), minV.y(), minV.z(), maxV.x(), maxV.y(), maxV.z());
}
2022-12-13 01:33:31 -05:00
/**
* Checks if this AABB intersects with the other AABB
* @return true if intersection
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] inline bool intersects(const AABB& other) const {
return intersects(other.min, other.max);
}
2022-12-13 01:33:31 -05:00
/**
* Checks if the provided ray intersects with this AABB between tmin and tmax using an implementation defined method.
* @return true if intersected
*/
2022-11-15 16:23:37 -05:00
AABBHitData intersects(const Ray& ray, PRECISION_TYPE tmin, PRECISION_TYPE tmax);
2022-12-13 01:33:31 -05:00
/**
* Slap method of checking for intersection, see the comment in the cpp file. DO NOT USE OUTSIDE THIS CLASS.
*/
2022-11-15 16:23:37 -05:00
AABBHitData simpleSlabRayAABBMethod(const Ray& ray, PRECISION_TYPE tmin, PRECISION_TYPE tmax);
2022-12-13 01:33:31 -05:00
/**
* Creates a transform matrix using information contained within the AABB, done to prevent repeating code.
* @return a transform (model) matrix for this AABB.
*/
2022-11-16 16:15:08 -05:00
[[nodiscard]] Mat4x4 getTransform() const;
2022-12-13 01:33:31 -05:00
/**
* @return the exact center of the AABB
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] inline Vec4 getCenter() const {
return {min.x() + (max.x() - min.x()) * 0.5, min.y() + (max.y() - min.y()) * 0.5, min.z() + (max.z() - min.z()) * 0.5};
}
2022-12-13 01:33:31 -05:00
/**
* @return the longest axis distance from the center point of the AABB
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] PRECISION_TYPE longestDistanceFromCenter() const;
2022-12-13 01:33:31 -05:00
/**
* 0 - x
* 1 - y
* 2 - z
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] int longestAxis() const;
2022-12-13 01:33:31 -05:00
/**
* @return the complete length from min to max of the longest axis
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] PRECISION_TYPE longestAxisLength() const;
2022-12-13 01:33:31 -05:00
/**
* @return a pair of AABB which are subsets of this AABB split by the longest axis of this AABB
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] std::pair<AABB, AABB> splitByLongestAxis();
2022-12-13 01:33:31 -05:00
/**
* @param axis axis to split on
* @return a pair of AABB which are subsets of this AABB split along the axis provided
*/
2022-11-16 17:34:17 -05:00
[[nodiscard]] std::pair<AABB, AABB> splitAlongAxis(AABBAxis axis);
2022-12-13 01:33:31 -05:00
/**
* Splits the AABB by a rotating axis. Not recommended to use. Not thread safe across ALL AABB objects.
*/
[[nodiscard]] std::pair<AABB, AABB> splitAlongAxis();
2022-12-13 01:33:31 -05:00
/**
* @return average distance to the center of this object, subject to axis bias (really small or really big)
*/
2022-10-20 11:30:15 -04:00
[[nodiscard]] PRECISION_TYPE avgDistanceFromCenter() const;
2022-12-13 01:33:31 -05:00
/**
* Returns true if the min and max are equal, which tells us this AABB wasn't assigned
* or was properly created. Either way it isn't responsible to use the AABB in said case.
*/
[[nodiscard]] inline bool isEmpty() const { return min == max; }
2022-12-13 01:33:31 -05:00
2022-10-20 11:30:15 -04:00
[[nodiscard]] Vec4 getMin() const { return min; }
2022-12-13 01:33:31 -05:00
2022-10-20 11:30:15 -04:00
[[nodiscard]] Vec4 getMax() const { return max; }
2022-12-13 01:33:31 -05:00
[[nodiscard]] inline PRECISION_TYPE getXRadius(const Vec4& center) const {
return max.x() - center.x();
}
2022-12-13 01:33:31 -05:00
[[nodiscard]] inline PRECISION_TYPE getYRadius(const Vec4& center) const {
return max.y() - center.y();
}
2022-12-13 01:33:31 -05:00
[[nodiscard]] inline PRECISION_TYPE getZRadius(const Vec4& center) const {
return max.z() - center.z();
}
2022-12-13 01:33:31 -05:00
/*
* Minecraft code below this
*/
[[nodiscard]] inline bool isInside(PRECISION_TYPE x, PRECISION_TYPE y, PRECISION_TYPE z) const {
return x >= min.x() && x <= max.x() && y >= min.y() && y <= max.y() && z >= min.z() && z <= max.z();
}
[[nodiscard]] inline bool intersectsWithYZ(PRECISION_TYPE y, PRECISION_TYPE z) const {
return y >= min.y() && y <= max.y() && z >= min.z() && z <= max.z();
}
[[nodiscard]] inline bool intersectsWithXZ(PRECISION_TYPE x, PRECISION_TYPE z) const {
return x >= min.x() && x <= max.x() && z >= min.z() && z <= max.z();
}
[[nodiscard]] inline bool intersectsWithXY(PRECISION_TYPE x, PRECISION_TYPE y) const {
return x >= min.x() && x <= max.x() && y >= min.y() && y <= max.y();
}
2022-10-20 11:30:15 -04:00
};
2022-11-15 11:45:50 -05:00
2022-12-13 01:33:31 -05:00
inline bool operator==(const AABB& a, const AABB& b) {
2022-11-15 11:45:50 -05:00
const auto& aMax = a.getMax();
const auto& aMin = a.getMin();
const auto& bMax = b.getMax();
const auto& bMin = b.getMin();
return aMax == bMax && aMin == bMin;
}
2022-10-20 11:30:15 -04:00
inline std::ostream& operator<<(std::ostream& out, const AABB& v) {
auto max = v.getMax();
auto min = v.getMin();
auto center = v.getCenter();
return out << "AABB {\n\t min{" << min.x() << ", " << min.y() << ", " << min.z() << "},\n\t max{" << max.x() << ", " << max.y()
<< ", " << max.z() << "},\n\t diff{" << max.x() - min.x() << ", " << max.y() - min.y() << ", " << max.z() - min.z() << "},\n\t "
<< "center{" << center.x() << ", " << center.y() << ", " << center.z() << "},\n\t "
<< "radi{" << v.getXRadius(center) << ", " << v.getYRadius(center) << ", " << v.getZRadius(center) << "}\n};\n";
2022-10-20 11:30:15 -04:00
}
}
#endif //STEP_2_COLLIDERS_H