Starting work on capsules.
This commit is contained in:
71
src/dawn/physics/3d/AABB3D.cpp
Normal file
71
src/dawn/physics/3d/AABB3D.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "AABB3D.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
bool_t Dawn::aabb3dIntersect(struct AABB3D cube1, struct AABB3D cube2) {
|
||||
return (
|
||||
(cube1.min.x <= cube2.max.x && cube1.max.x >= cube2.min.x) &&
|
||||
(cube1.min.y <= cube2.max.y && cube1.max.y >= cube2.min.y) &&
|
||||
(cube1.min.z <= cube2.max.z && cube1.max.z >= cube2.min.z)
|
||||
);
|
||||
}
|
||||
|
||||
bool aabbSweep(
|
||||
const glm::vec3& pos1, const glm::vec3& size1, const glm::vec3& vel1,
|
||||
const glm::vec3& pos2, const glm::vec3& size2, const glm::vec3& vel2,
|
||||
float& fraction
|
||||
) {
|
||||
glm::vec3 relVel = vel1 - vel2;
|
||||
glm::vec3 relPos = pos1 - pos2;
|
||||
|
||||
// If the relative velocity is zero, the cubes are already intersecting
|
||||
i (glm::length2(relVel) == 0.0f) {
|
||||
fraction = 0.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Expand the size of the cubes by the magnitude of the relative velocity
|
||||
glm::vec3 size1exp = size1 + glm::abs(relVel);
|
||||
glm::vec3 size2exp = size2 + glm::abs(relVel);
|
||||
|
||||
// Compute the times at which the cubes first and last overlap on each axis
|
||||
float tminx = (size1exp.x + size2exp.x - glm::abs(relPos.x)) / glm::abs(relVel.x);
|
||||
float tmaxx = (size1.x + size2.x - glm::abs(relPos.x)) / glm::abs(relVel.x);
|
||||
float tminy = (size1exp.y + size2exp.y - glm::abs(relPos.y)) / glm::abs(relVel.y);
|
||||
float tmaxy = (size1.y + size2.y - glm::abs(relPos.y)) / glm::abs(relVel.y);
|
||||
float tminz = (size1exp.z + size2exp.z - glm::abs(relPos.z)) / glm::abs(relVel.z);
|
||||
float tmaxz = (size1.z + size2.z - glm::abs(relPos.z)) / glm::abs(relVel.z);
|
||||
|
||||
// Find the earliest and latest times of overlap
|
||||
float tmin = glm::max(glm::max(glm::min(tminx, tmaxx), glm::min(tminy, tmaxy)), glm::min(tminz, tmaxz));
|
||||
float tmax = glm::min(glm::min(glm::max(tminx, tmaxx), glm::max(tminy, tmaxy)), glm::max(tminz, tmaxz));
|
||||
|
||||
// If the earliest time of overlap is greater than the length of the timestep, the cubes
|
||||
// will not collide during the timestep
|
||||
if (tmin > 1.0f) {
|
||||
fraction = 1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the latest time of overlap is less than or equal to zero, the cubes are already
|
||||
// colliding and will collide throughout the timestep
|
||||
if (tmax <= 0.0f) {
|
||||
fraction = 0.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compute the fraction of the timestep at which the collision occurs
|
||||
fraction = glm::clamp(tmin, 0.0f, 1.0f);
|
||||
|
||||
// Check if the two AABB cubes are intersecting at the time of collision
|
||||
glm::vec3 min1 = pos1 + vel1 * fraction - size1 / 2.0f;
|
||||
glm::vec3 max1 = pos1 + vel1 * fraction + size1 / 2.0f;
|
||||
glm::vec3 min2 = pos2 + vel2 * fraction - size2 / 2.0f;
|
||||
glm::vec3 max2 = pos2 + vel2 * fraction + size2 / 2.0f;
|
||||
return aabbIntersect(min1, max1, min2, max2);
|
||||
}
|
@ -1,14 +1,25 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct AABB3D {
|
||||
glm::vec3 min;
|
||||
glm::vec3 max;
|
||||
};
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct AABB3D {
|
||||
glm::vec3 min;
|
||||
glm::vec3 max;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether two 3D AABB are intersecting or not.
|
||||
*
|
||||
* @param cube1 First cube.
|
||||
* @param cube2 Second cube.
|
||||
* @return True if the two cubes are intersecting, otherwise false.
|
||||
*/
|
||||
bool_t aabb3dIntersect(struct AABB3D cube1, struct AABB3D cube2);
|
||||
|
||||
|
||||
}
|
15
src/dawn/physics/3d/PhysicsCapsule.hpp
Normal file
15
src/dawn/physics/3d/PhysicsCapsule.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct PhysicsCapsule {
|
||||
float_t height;
|
||||
float_t radius;
|
||||
glm::vec3 origin;
|
||||
};
|
||||
}
|
@ -200,4 +200,58 @@ bool_t Dawn::raytestQuad(
|
||||
*normal = glm::normalize(glm::vec3(transform * glm::vec4(0.0f, 0.0f, 1.0f, 0.0f)));
|
||||
|
||||
return true; // intersection found
|
||||
}
|
||||
|
||||
bool_t Dawn::raytestCapsule(
|
||||
struct Ray3D ray,
|
||||
struct PhysicsCapsule capsule,
|
||||
glm::vec3 *point,
|
||||
glm::vec3 *normal,
|
||||
float_t *distance
|
||||
) {
|
||||
// Calculate the axis and length of the capsule
|
||||
glm::vec3 axis = glm::normalize(glm::vec3(0.0f, capsule.height, 0.0f));
|
||||
float length = capsule.height - 2 * capsule.radius;
|
||||
|
||||
// Calculate the closest point on the capsule axis to the ray origin
|
||||
glm::vec3 originToCenter = -capsule.origin;
|
||||
float proj = glm::dot(originToCenter, axis);
|
||||
glm::vec3 closestPointOnAxis = capsule.origin + axis * proj;
|
||||
|
||||
// Calculate the distance between the closest point on the axis and the ray origin
|
||||
float distToClosestPoint = glm::length(closestPointOnAxis - capsule.origin);
|
||||
|
||||
// If the distance is greater than the capsule radius, the ray misses the capsule
|
||||
if (distToClosestPoint > capsule.radius) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate the distance between the closest point on the axis and the capsule end points
|
||||
float distToCapsuleEnds = glm::length(originToCenter - axis * proj) - length * 0.5f;
|
||||
|
||||
// Calculate the distance along the ray to the point of intersection with the capsule
|
||||
float t1 = glm::dot(-capsule.origin, ray.direction);
|
||||
float t2 = glm::dot(closestPointOnAxis - capsule.origin, ray.direction);
|
||||
float t3 = glm::sqrt(capsule.radius * capsule.radius - distToClosestPoint * distToClosestPoint);
|
||||
float t4 = glm::sqrt(distToCapsuleEnds * distToCapsuleEnds + t3 * t3);
|
||||
float tEnter = t1 + (t2 - t4);
|
||||
float tExit = t1 + (t2 + t4);
|
||||
|
||||
// If the intersection point is behind the ray origin or beyond the ray endpoint, the ray misses the capsule
|
||||
if (tEnter < 0 || tEnter > tExit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the output parameters
|
||||
*distance = tEnter;
|
||||
|
||||
// Calculate the hit point and normal
|
||||
*point = capsule.origin + ray.direction * tEnter;
|
||||
if (tEnter < 0 || tEnter > tExit) {
|
||||
*normal = glm::normalize(*point);
|
||||
} else {
|
||||
*normal = glm::normalize(*point - closestPointOnAxis);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
#include "assert/assert.hpp"
|
||||
#include "PhysicsTriangle.hpp"
|
||||
#include "PhysicsSphere.hpp"
|
||||
#include "PhysicsCapsule.hpp"
|
||||
#include "AABB3D.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
@ -57,4 +58,12 @@ namespace Dawn {
|
||||
glm::vec3 *normal,
|
||||
float_t *distance
|
||||
);
|
||||
|
||||
bool_t raytestCapsule(
|
||||
struct Ray3D ray,
|
||||
struct PhysicsCapsule capsule,
|
||||
glm::vec3 *point,
|
||||
glm::vec3 *normal,
|
||||
float_t *distance
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user