- improve speed by saving some calculations

This commit is contained in:
Magnus Norddahl 2018-11-05 00:54:25 +01:00
parent d3d7174c77
commit e21679a4d7
2 changed files with 68 additions and 41 deletions

View file

@ -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
// MoellerTrumbore ray-triangle intersection algorithm: // MoellerTrumbore 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;

View file

@ -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);
}; };