return length_squared(a - b);
}
+inline float distance(const glm::vec3 &a, const glm::vec3 &b) noexcept {
+ return length(a - b);
+}
+
template <class T>
inline bool iszero(const T &v) noexcept {
return length_squared(v) < std::numeric_limits<typename T::value_type>::epsilon();
glm::vec3 Center() const noexcept {
return min + (max - min) * 0.5f;
}
+
+ /// return distance between origin and farthest vertex
+ float OriginRadius() const noexcept {
+ glm::vec3 high(glm::max(abs(min), abs(max)));
+ return length(high);
+ }
};
struct Ray {
static constexpr int size = side * side * side;
static AABB Bounds() noexcept { return AABB{ { 0.0f, 0.0f, 0.0f }, ExactLocation::FExtent() }; }
+ static glm::vec3 Center() noexcept { return glm::vec3(8.0f); }
+ static float Radius() noexcept { return 27.71281292110203669632f; /* 16 * √3 */ }
static constexpr bool InBounds(const ExactLocation::Fine &pos) noexcept {
return
void Name(const std::string &n) { name = n; }
const AABB &Bounds() const noexcept { return bounds; }
- void Bounds(const AABB &b) noexcept { bounds = b; }
+ // get distance between local origin and farthest vertex
+ float Radius() const noexcept { return radius; }
+ void Bounds(const AABB &b) noexcept { bounds = b; radius = b.OriginRadius(); }
bool WorldCollidable() const noexcept { return world_collision; }
void WorldCollidable(bool b) noexcept { world_collision = b; }
std::string name;
AABB bounds;
+ float radius;
EntityState state;
/// chunk to model space
const glm::mat4 &Mchunk,
std::vector<WorldCollision> &col
) noexcept {
+ // box's origin relative to the chunk
+ const glm::vec3 box_coords(Mbox[3] - Mchunk[3]);
+ const float box_rad = box.OriginRadius();
+
+ if (distance_squared(box_coords, Center()) > (box_rad + Radius()) * (box_rad + Radius())) {
+ return false;
+ }
+
bool any = false;
float penetration;
glm::vec3 normal;
- if (!blank::Intersection(box, Mbox, Bounds(), Mchunk, penetration, normal)) {
- return false;
- }
+ // assume a bounding radius of 2 for blocks
+ constexpr float block_rad = 2.0f;
for (int idx = 0, z = 0; z < side; ++z) {
for (int y = 0; y < side; ++y) {
for (int x = 0; x < side; ++x, ++idx) {
if (!type.collision || !type.shape) {
continue;
}
- if (type.shape->Intersects(Mchunk * ToTransform(RoughLocation::Fine(x, y, z), idx), box, Mbox, penetration, normal)) {
+ const RoughLocation::Fine block_pos(x, y, z);
+ const ExactLocation::Fine block_coords(ToCoords(block_pos));
+ if (distance_squared(box_coords, block_coords) <= (box_rad + block_rad) * (box_rad + block_rad)
+ && type.shape->Intersects(Mchunk * ToTransform(block_pos, idx), box, Mbox, penetration, normal)
+ ) {
col.emplace_back(this, idx, penetration, normal);
any = true;
}
, id(-1)
, name("anonymous")
, bounds()
+, radius(0.0f)
, state()
, heading(0.0f, 0.0f, -1.0f)
, max_vel(5.0f)
}
bool World::Intersection(const Entity &e, const EntityState &s, std::vector<WorldCollision> &col) {
+ // TODO: make special case for entities here and in Chunk::Intersection so entity's bounding radius
+ // doesn't have to be calculated over and over again (sqrt)
AABB box = e.Bounds();
glm::ivec3 reference = s.pos.chunk;
glm::mat4 M = s.Transform(reference);
- return Intersection(box, M, reference, col);
+
+ bool any = false;
+ for (Chunk &cur_chunk : chunks) {
+ if (manhattan_radius(cur_chunk.Position() - reference) > 1) {
+ // chunk is not one of the 3x3x3 surrounding the entity
+ // since there's no entity which can extent over 16 blocks, they can be skipped
+ continue;
+ }
+ if (cur_chunk.Intersection(box, M, cur_chunk.Transform(reference), col)) {
+ any = true;
+ }
+ }
+ return any;
}
bool World::Intersection(