mirror of
https://github.com/ZDoom/ZDRay.git
synced 2025-02-03 13:11:04 +00:00
- improve speed by saving some calculations
This commit is contained in:
parent
d3d7174c77
commit
e21679a4d7
2 changed files with 68 additions and 41 deletions
|
@ -23,8 +23,6 @@
|
||||||
#include "collision.h"
|
#include "collision.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#undef min
|
|
||||||
#undef max
|
|
||||||
|
|
||||||
TriangleMeshShape::TriangleMeshShape(const kexVec3 *vertices, int num_vertices, const unsigned int *elements, int num_elements, const int *surfaces)
|
TriangleMeshShape::TriangleMeshShape(const kexVec3 *vertices, int num_vertices, const unsigned int *elements, int num_elements, const int *surfaces)
|
||||||
: vertices(vertices), num_vertices(num_vertices), elements(elements), num_elements(num_elements), surfaces(surfaces)
|
: vertices(vertices), num_vertices(num_vertices), elements(elements), num_elements(num_elements), surfaces(surfaces)
|
||||||
|
@ -68,7 +66,7 @@ bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape1, SphereShape *sha
|
||||||
|
|
||||||
bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end)
|
bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end)
|
||||||
{
|
{
|
||||||
return find_any_hit(shape, ray_start, ray_end, shape->root);
|
return find_any_hit(shape, RayBBox(ray_start, ray_end), shape->root);
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceHit TriangleMeshShape::find_first_hit(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end)
|
TraceHit TriangleMeshShape::find_first_hit(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end)
|
||||||
|
@ -85,7 +83,7 @@ TraceHit TriangleMeshShape::find_first_hit(TriangleMeshShape *shape, const kexVe
|
||||||
float segstart = t / tracedist;
|
float segstart = t / tracedist;
|
||||||
float segend = std::min(t + segmentlen, tracedist) / tracedist;
|
float segend = std::min(t + segmentlen, tracedist) / tracedist;
|
||||||
|
|
||||||
find_first_hit(shape, ray_start + ray_dir * segstart, ray_start + ray_dir * segend, shape->root, &hit);
|
find_first_hit(shape, RayBBox(ray_start + ray_dir * segstart, ray_start + ray_dir * segend), shape->root, &hit);
|
||||||
if (hit.fraction < 1.0f)
|
if (hit.fraction < 1.0f)
|
||||||
{
|
{
|
||||||
hit.fraction = segstart * (1.0f - hit.fraction) + segend * hit.fraction;
|
hit.fraction = segstart * (1.0f - hit.fraction) + segend * hit.fraction;
|
||||||
|
@ -186,32 +184,32 @@ bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape1, TriangleMeshShap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end, int a)
|
bool TriangleMeshShape::find_any_hit(TriangleMeshShape *shape, const RayBBox &ray, int a)
|
||||||
{
|
{
|
||||||
if (overlap_bv_ray(shape, ray_start, ray_end, a))
|
if (overlap_bv_ray(shape, ray, a))
|
||||||
{
|
{
|
||||||
if (shape->is_leaf(a))
|
if (shape->is_leaf(a))
|
||||||
{
|
{
|
||||||
return intersect_triangle_ray(shape, ray_start, ray_end, a) < 1.0f;
|
return intersect_triangle_ray(shape, ray, a) < 1.0f;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (find_any_hit(shape, ray_start, ray_end, shape->nodes[a].left))
|
if (find_any_hit(shape, ray, shape->nodes[a].left))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return find_any_hit(shape, ray_start, ray_end, shape->nodes[a].right);
|
return find_any_hit(shape, ray, shape->nodes[a].right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleMeshShape::find_first_hit(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end, int a, TraceHit *hit)
|
void TriangleMeshShape::find_first_hit(TriangleMeshShape *shape, const RayBBox &ray, int a, TraceHit *hit)
|
||||||
{
|
{
|
||||||
if (overlap_bv_ray(shape, ray_start, ray_end, a))
|
if (overlap_bv_ray(shape, ray, a))
|
||||||
{
|
{
|
||||||
if (shape->is_leaf(a))
|
if (shape->is_leaf(a))
|
||||||
{
|
{
|
||||||
float t = intersect_triangle_ray(shape, ray_start, ray_end, a);
|
float t = intersect_triangle_ray(shape, ray, a);
|
||||||
if (t < hit->fraction)
|
if (t < hit->fraction)
|
||||||
{
|
{
|
||||||
hit->fraction = t;
|
hit->fraction = t;
|
||||||
|
@ -220,18 +218,18 @@ void TriangleMeshShape::find_first_hit(TriangleMeshShape *shape, const kexVec3 &
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
find_first_hit(shape, ray_start, ray_end, shape->nodes[a].left, hit);
|
find_first_hit(shape, ray, shape->nodes[a].left, hit);
|
||||||
find_first_hit(shape, ray_start, ray_end, shape->nodes[a].right, hit);
|
find_first_hit(shape, ray, shape->nodes[a].right, hit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TriangleMeshShape::overlap_bv_ray(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end, int a)
|
bool TriangleMeshShape::overlap_bv_ray(TriangleMeshShape *shape, const RayBBox &ray, int a)
|
||||||
{
|
{
|
||||||
return IntersectionTest::ray_aabb(ray_start, ray_end, shape->nodes[a].aabb) == IntersectionTest::overlap;
|
return IntersectionTest::ray_aabb(ray, shape->nodes[a].aabb) == IntersectionTest::overlap;
|
||||||
}
|
}
|
||||||
|
|
||||||
float TriangleMeshShape::intersect_triangle_ray(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end, int a)
|
float TriangleMeshShape::intersect_triangle_ray(TriangleMeshShape *shape, const RayBBox &ray, int a)
|
||||||
{
|
{
|
||||||
const int start_element = shape->nodes[a].element_index;
|
const int start_element = shape->nodes[a].element_index;
|
||||||
|
|
||||||
|
@ -249,8 +247,8 @@ float TriangleMeshShape::intersect_triangle_ray(TriangleMeshShape *shape, const
|
||||||
|
|
||||||
kexVec3 triangleNormal = kexVec3::Cross(e1, e2);
|
kexVec3 triangleNormal = kexVec3::Cross(e1, e2);
|
||||||
float dist = kexVec3::Dot(p[0], triangleNormal);
|
float dist = kexVec3::Dot(p[0], triangleNormal);
|
||||||
float distA = kexVec3::Dot(ray_start, triangleNormal) - dist;
|
float distA = kexVec3::Dot(ray.start, triangleNormal) - dist;
|
||||||
float distB = kexVec3::Dot(ray_end, triangleNormal) - dist;
|
float distB = kexVec3::Dot(ray.end, triangleNormal) - dist;
|
||||||
|
|
||||||
if (distA * distB >= 0.0f)
|
if (distA * distB >= 0.0f)
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
@ -265,7 +263,7 @@ float TriangleMeshShape::intersect_triangle_ray(TriangleMeshShape *shape, const
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
|
||||||
float edgeTolerance = triangleNormal.LengthSq() * -0.0001f;
|
float edgeTolerance = triangleNormal.LengthSq() * -0.0001f;
|
||||||
kexVec3 point = ray_start * (1.0f - distance) + ray_end * distance;
|
kexVec3 point = ray.start * (1.0f - distance) + ray.end * distance;
|
||||||
|
|
||||||
kexVec3 v0p = p[0] - point;
|
kexVec3 v0p = p[0] - point;
|
||||||
kexVec3 v1p = p[1] - point;
|
kexVec3 v1p = p[1] - point;
|
||||||
|
@ -287,7 +285,7 @@ float TriangleMeshShape::intersect_triangle_ray(TriangleMeshShape *shape, const
|
||||||
#else
|
#else
|
||||||
// Moeller–Trumbore ray-triangle intersection algorithm:
|
// Moeller–Trumbore ray-triangle intersection algorithm:
|
||||||
|
|
||||||
kexVec3 D = ray_end - ray_start;
|
kexVec3 D = ray.end - ray.start;
|
||||||
|
|
||||||
// Find vectors for two edges sharing p[0]
|
// Find vectors for two edges sharing p[0]
|
||||||
kexVec3 e1 = p[1] - p[0];
|
kexVec3 e1 = p[1] - p[0];
|
||||||
|
@ -308,7 +306,7 @@ float TriangleMeshShape::intersect_triangle_ray(TriangleMeshShape *shape, const
|
||||||
float inv_det = 1.0f / det;
|
float inv_det = 1.0f / det;
|
||||||
|
|
||||||
// Calculate distance from p[0] to ray origin
|
// Calculate distance from p[0] to ray origin
|
||||||
kexVec3 T = ray_start - p[0];
|
kexVec3 T = ray.start - p[0];
|
||||||
|
|
||||||
// Calculate u parameter and test bound
|
// Calculate u parameter and test bound
|
||||||
float u = kexVec3::Dot(T, P) * inv_det;
|
float u = kexVec3::Dot(T, P) * inv_det;
|
||||||
|
@ -340,11 +338,10 @@ bool TriangleMeshShape::sweep_overlap_bv_sphere(TriangleMeshShape *shape1, Spher
|
||||||
{
|
{
|
||||||
// Convert to ray test by expanding the AABB:
|
// Convert to ray test by expanding the AABB:
|
||||||
|
|
||||||
kexBBox aabb = shape1->nodes[a].aabb;
|
CollisionBBox aabb = shape1->nodes[a].aabb;
|
||||||
aabb.min -= shape2->radius;
|
aabb.Extents += shape2->radius;
|
||||||
aabb.max += shape2->radius;
|
|
||||||
|
|
||||||
return IntersectionTest::ray_aabb(shape2->center, target, aabb) == IntersectionTest::overlap;
|
return IntersectionTest::ray_aabb(RayBBox(shape2->center, target), aabb) == IntersectionTest::overlap;
|
||||||
}
|
}
|
||||||
|
|
||||||
float TriangleMeshShape::sweep_intersect_triangle_sphere(TriangleMeshShape *shape1, SphereShape *shape2, int a, const kexVec3 &target)
|
float TriangleMeshShape::sweep_intersect_triangle_sphere(TriangleMeshShape *shape1, SphereShape *shape2, int a, const kexVec3 &target)
|
||||||
|
@ -579,7 +576,7 @@ bool TriangleMeshShape::is_leaf(int node_index)
|
||||||
|
|
||||||
float TriangleMeshShape::volume(int node_index)
|
float TriangleMeshShape::volume(int node_index)
|
||||||
{
|
{
|
||||||
kexVec3 extents = nodes[node_index].aabb.Extents();
|
const kexVec3 &extents = nodes[node_index].aabb.Extents;
|
||||||
return extents.x * extents.y * extents.z;
|
return extents.x * extents.y * extents.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -851,15 +848,12 @@ IntersectionTest::Result IntersectionTest::frustum_obb(const FrustumPlanes &frus
|
||||||
return inside;
|
return inside;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntersectionTest::OverlapResult IntersectionTest::ray_aabb(const kexVec3 &ray_start, const kexVec3 &ray_end, const kexBBox &aabb)
|
IntersectionTest::OverlapResult IntersectionTest::ray_aabb(const RayBBox &ray, const CollisionBBox &aabb)
|
||||||
{
|
{
|
||||||
kexVec3 c = (ray_start + ray_end) * 0.5f;
|
const kexVec3 &v = ray.v;
|
||||||
kexVec3 w = ray_end - c;
|
const kexVec3 &w = ray.w;
|
||||||
kexVec3 h = aabb.Extents();
|
const kexVec3 &h = aabb.Extents;
|
||||||
|
auto c = ray.c - aabb.Center;
|
||||||
c -= aabb.Center();
|
|
||||||
|
|
||||||
kexVec3 v(std::abs(w.x), std::abs(w.y), std::abs(w.z));
|
|
||||||
|
|
||||||
if (std::abs(c.x) > v.x + h.x || std::abs(c.y) > v.y + h.y || std::abs(c.z) > v.z + h.z)
|
if (std::abs(c.x) > v.x + h.x || std::abs(c.y) > v.y + h.y || std::abs(c.z) > v.z + h.z)
|
||||||
return disjoint;
|
return disjoint;
|
||||||
|
|
|
@ -41,6 +41,39 @@ struct TraceHit
|
||||||
int surface = -1;
|
int surface = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CollisionBBox : public kexBBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CollisionBBox() = default;
|
||||||
|
|
||||||
|
CollisionBBox(const kexVec3 &aabb_min, const kexVec3 &aabb_max) : kexBBox(aabb_min, aabb_max)
|
||||||
|
{
|
||||||
|
auto halfmin = aabb_min * 0.5f;
|
||||||
|
auto halfmax = aabb_max * 0.5f;
|
||||||
|
Center = halfmax + halfmin;
|
||||||
|
Extents = halfmax - halfmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
kexVec3 Center;
|
||||||
|
kexVec3 Extents;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RayBBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RayBBox(const kexVec3 &ray_start, const kexVec3 &ray_end) : start(ray_start), end(ray_end)
|
||||||
|
{
|
||||||
|
c = (ray_start + ray_end) * 0.5f;
|
||||||
|
w = ray_end - c;
|
||||||
|
v.x = std::abs(w.x);
|
||||||
|
v.y = std::abs(w.y);
|
||||||
|
v.z = std::abs(w.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
kexVec3 start, end;
|
||||||
|
kexVec3 c, w, v;
|
||||||
|
};
|
||||||
|
|
||||||
class TriangleMeshShape
|
class TriangleMeshShape
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -65,7 +98,7 @@ public:
|
||||||
Node(const kexVec3 &aabb_min, const kexVec3 &aabb_max, int element_index) : aabb(aabb_min, aabb_max), element_index(element_index) { }
|
Node(const kexVec3 &aabb_min, const kexVec3 &aabb_max, int element_index) : aabb(aabb_min, aabb_max), element_index(element_index) { }
|
||||||
Node(const kexVec3 &aabb_min, const kexVec3 &aabb_max, int left, int right) : aabb(aabb_min, aabb_max), left(left), right(right) { }
|
Node(const kexVec3 &aabb_min, const kexVec3 &aabb_max, int left, int right) : aabb(aabb_min, aabb_max), left(left), right(right) { }
|
||||||
|
|
||||||
kexBBox aabb;
|
CollisionBBox aabb;
|
||||||
int left = -1;
|
int left = -1;
|
||||||
int right = -1;
|
int right = -1;
|
||||||
int element_index = -1;
|
int element_index = -1;
|
||||||
|
@ -85,12 +118,12 @@ private:
|
||||||
|
|
||||||
static bool find_any_hit(TriangleMeshShape *shape1, TriangleMeshShape *shape2, int a, int b);
|
static bool find_any_hit(TriangleMeshShape *shape1, TriangleMeshShape *shape2, int a, int b);
|
||||||
static bool find_any_hit(TriangleMeshShape *shape1, SphereShape *shape2, int a);
|
static bool find_any_hit(TriangleMeshShape *shape1, SphereShape *shape2, int a);
|
||||||
static bool find_any_hit(TriangleMeshShape *shape1, const kexVec3 &ray_start, const kexVec3 &ray_end, int a);
|
static bool find_any_hit(TriangleMeshShape *shape1, const RayBBox &ray, int a);
|
||||||
|
|
||||||
static void find_first_hit(TriangleMeshShape *shape1, const kexVec3 &ray_start, const kexVec3 &ray_end, int a, TraceHit *hit);
|
static void find_first_hit(TriangleMeshShape *shape1, const RayBBox &ray, int a, TraceHit *hit);
|
||||||
|
|
||||||
inline static bool overlap_bv_ray(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end, int a);
|
inline static bool overlap_bv_ray(TriangleMeshShape *shape, const RayBBox &ray, int a);
|
||||||
inline static float intersect_triangle_ray(TriangleMeshShape *shape, const kexVec3 &ray_start, const kexVec3 &ray_end, int a);
|
inline static float intersect_triangle_ray(TriangleMeshShape *shape, const RayBBox &ray, int a);
|
||||||
|
|
||||||
inline static bool sweep_overlap_bv_sphere(TriangleMeshShape *shape1, SphereShape *shape2, int a, const kexVec3 &target);
|
inline static bool sweep_overlap_bv_sphere(TriangleMeshShape *shape1, SphereShape *shape2, int a, const kexVec3 &target);
|
||||||
inline static float sweep_intersect_triangle_sphere(TriangleMeshShape *shape1, SphereShape *shape2, int a, const kexVec3 &target);
|
inline static float sweep_intersect_triangle_sphere(TriangleMeshShape *shape1, SphereShape *shape2, int a, const kexVec3 &target);
|
||||||
|
@ -157,5 +190,5 @@ public:
|
||||||
static OverlapResult aabb(const kexBBox &a, const kexBBox &b);
|
static OverlapResult aabb(const kexBBox &a, const kexBBox &b);
|
||||||
static Result frustum_aabb(const FrustumPlanes &frustum, const kexBBox &box);
|
static Result frustum_aabb(const FrustumPlanes &frustum, const kexBBox &box);
|
||||||
static Result frustum_obb(const FrustumPlanes &frustum, const kexOrientedBBox &box);
|
static Result frustum_obb(const FrustumPlanes &frustum, const kexOrientedBBox &box);
|
||||||
static OverlapResult ray_aabb(const kexVec3 &ray_start, const kexVec3 &ray_end, const kexBBox &box);
|
static OverlapResult ray_aabb(const RayBBox &ray, const CollisionBBox &box);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue