Upgrade bounce

This commit is contained in:
Luke Benstead
2020-01-30 18:42:47 +00:00
parent 1509b9bd0e
commit e5897d433d
459 changed files with 98378 additions and 48427 deletions

View File

@@ -41,7 +41,7 @@ public:
~b3BroadPhase();
// Create a proxy and return a index to it.
u32 CreateProxy(const b3AABB3& aabb, void* userData);
u32 CreateProxy(const b3AABB& aabb, void* userData);
// Destroy a given proxy and remove it from the broadphase.
void DestroyProxy(u32 proxyId);
@@ -49,13 +49,13 @@ public:
// Update an existing proxy AABB with a given AABB and a displacement.
// displacement = dt * velocity
// Return true if the proxy has moved.
bool MoveProxy(u32 proxyId, const b3AABB3& aabb, const b3Vec3& displacement);
bool MoveProxy(u32 proxyId, const b3AABB& aabb, const b3Vec3& displacement);
// Force move the proxy
void TouchProxy(u32 proxyId);
// Get the AABB of a given proxy.
const b3AABB3& GetAABB(u32 proxyId) const;
const b3AABB& GetAABB(u32 proxyId) const;
// Get the user data attached to a proxy.
void* GetUserData(u32 proxyId) const;
@@ -68,7 +68,7 @@ public:
// Notify the client callback the AABBs that are overlapping with the passed AABB.
template<class T>
void QueryAABB(T* callback, const b3AABB3& aabb) const;
void QueryAABB(T* callback, const b3AABB& aabb) const;
// Notify the client callback the AABBs that are overlapping the
// passed ray.
@@ -114,7 +114,7 @@ private :
u32 m_pairCount;
};
inline const b3AABB3& b3BroadPhase::GetAABB(u32 proxyId) const
inline const b3AABB& b3BroadPhase::GetAABB(u32 proxyId) const
{
return m_tree.GetAABB(proxyId);
}
@@ -130,7 +130,7 @@ inline u32 b3BroadPhase::GetProxyCount() const
}
template<class T>
inline void b3BroadPhase::QueryAABB(T* callback, const b3AABB3& aabb) const
inline void b3BroadPhase::QueryAABB(T* callback, const b3AABB& aabb) const
{
return m_tree.QueryAABB(callback, aabb);
}
@@ -174,7 +174,7 @@ inline void b3BroadPhase::FindPairs(T* callback)
continue;
}
const b3AABB3& aabb = m_tree.GetAABB(m_queryProxyId);
const b3AABB& aabb = m_tree.GetAABB(m_queryProxyId);
m_tree.QueryAABB(this, aabb);
}

View File

@@ -19,25 +19,24 @@
#ifndef B3_COLLISION_H
#define B3_COLLISION_H
#include <bounce/common/geometry.h>
#include <bounce/collision/shapes/aabb3.h>
#include <bounce/common/math/vec3.h>
// Input for a ray cast.
struct b3RayCastInput
{
b3Vec3 p1; // first point on segment
b3Vec3 p2; // second point on segment
float32 maxFraction; // maximum intersection
scalar maxFraction; // maximum intersection
};
// Output of a ray cast.
struct b3RayCastOutput
{
float32 fraction; // time of intersection on ray-segment
scalar fraction; // time of intersection on ray-segment
b3Vec3 normal; // surface normal of intersection
};
// Perform a ray-cast on a triangle.
// Perform a ray-cast against a triangle.
bool b3RayCast(b3RayCastOutput* output, const b3RayCastInput* input,
const b3Vec3& v1, const b3Vec3& v2, const b3Vec3& v3);

View File

@@ -31,7 +31,7 @@ struct b3SimplexVertex
b3Vec3 point1; // support vertex on proxy 1
b3Vec3 point2; // support vertex on proxy 2
b3Vec3 point; // minkowski vertex
float32 weight; // barycentric coordinate for point
scalar weight; // barycentric coordinate for point
u32 index1; // support 1 vertex index
u32 index2; // support 2 vertex index
};
@@ -56,7 +56,7 @@ struct b3Simplex
void WriteCache(b3SimplexCache* cache) const;
float32 GetMetric() const;
scalar GetMetric() const;
};
// The output of the GJK algorithm.
@@ -67,13 +67,13 @@ struct b3GJKOutput
{
b3Vec3 point1; // closest point on proxy 1
b3Vec3 point2; // closest point on proxy 2
float32 distance; // euclidean distance between the closest points
scalar distance; // euclidean distance between the closest points
u32 iterations; // number of GJK iterations
};
// Find the closest points and distance between two proxies.
b3GJKOutput b3GJK(const b3Transform& xf1, const b3GJKProxy& proxy1,
const b3Transform& xf2, const b3GJKProxy& proxy2);
const b3Transform& xf2, const b3GJKProxy& proxy2, bool applyRadius);
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -84,7 +84,7 @@ b3GJKOutput b3GJK(const b3Transform& xf1, const b3GJKProxy& proxy1,
// for the first time.
struct b3SimplexCache
{
float32 metric; // distance or area or volume
scalar metric; // lenght or area or volume
u32 iterations; // number of GJK iterations
u16 count; // number of support vertices
u8 index1[4]; // support vertices on proxy 1
@@ -114,18 +114,4 @@ b3GJKOutput b3GJK(const b3Transform& xf1, const b3GJKProxy& proxy1,
const b3Transform& xf2, const b3GJKProxy& proxy2,
bool applyRadius, b3SimplexCache* cache);
// The output of the GJK-based shape cast algorithm.
struct b3GJKShapeCastOutput
{
float32 t; // time of impact
b3Vec3 point; // contact point at t
b3Vec3 normal; // contact normal at t
u32 iterations; // number of iterations
};
// Find the time of impact between two proxies given the relative target translation vector.
bool b3GJKShapeCast(b3GJKShapeCastOutput* output,
const b3Transform& xf1, const b3GJKProxy& proxy1,
const b3Transform& xf2, const b3GJKProxy& proxy2, const b3Vec3& translation2);
#endif

View File

@@ -26,7 +26,7 @@ struct b3GJKProxy
{
const b3Vec3* vertices; // vertices in this proxy
u32 vertexCount; // number of vertices
float32 radius; // proxy radius
scalar radius; // proxy radius
b3Vec3 vertexBuffer[3]; // vertex buffer for convenience
// Get the number of vertices in this proxy.
@@ -57,10 +57,10 @@ inline const b3Vec3& b3GJKProxy::GetVertex(u32 index) const
inline u32 b3GJKProxy::GetSupportIndex(const b3Vec3& d) const
{
u32 maxIndex = 0;
float32 maxProjection = b3Dot(d, vertices[maxIndex]);
scalar maxProjection = b3Dot(d, vertices[maxIndex]);
for (u32 i = 1; i < vertexCount; ++i)
{
float32 projection = b3Dot(d, vertices[i]);
scalar projection = b3Dot(d, vertices[i]);
if (projection > maxProjection)
{
maxIndex = i;

View File

@@ -28,10 +28,10 @@ struct b3Hull;
struct b3FaceQuery
{
u32 index;
float32 separation;
scalar separation;
};
float32 b3Project(const b3Hull* hull, const b3Plane& plane);
scalar b3Project(const b3Hull* hull, const b3Plane& plane);
b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Hull* hull1,
const b3Transform& xf2, const b3Hull* hull2);
@@ -42,12 +42,12 @@ struct b3EdgeQuery
{
u32 index1;
u32 index2;
float32 separation;
scalar separation;
};
bool b3IsMinkowskiFace(const b3Vec3& A, const b3Vec3& B, const b3Vec3& B_x_A, const b3Vec3& C, const b3Vec3& D, const b3Vec3& D_x_C);
float32 b3Project(const b3Vec3& P1, const b3Vec3& E1, const b3Vec3& P2, const b3Vec3& E2, const b3Vec3& C1);
scalar b3Project(const b3Vec3& P1, const b3Vec3& E1, const b3Vec3& P2, const b3Vec3& E2, const b3Vec3& C1);
b3EdgeQuery b3QueryEdgeSeparation(const b3Transform& xf1, const b3Hull* hull1,
const b3Transform& xf2, const b3Hull* hull2);
@@ -94,13 +94,13 @@ struct b3FeatureCache
// Read the current state of the cache.
// Return e_unkown if neither a separation or penetration was detected.
b3SATCacheType ReadState(const b3Transform& xf1, const b3Hull* hull1,
const b3Transform& xf2, const b3Hull* hull2, float32 totalRadius);
const b3Transform& xf2, const b3Hull* hull2, scalar totalRadius);
b3SATCacheType ReadEdge(const b3Transform& xf1, const b3Hull* hull1,
const b3Transform& xf2, const b3Hull* hull2, float32 totalRadius);
const b3Transform& xf2, const b3Hull* hull2, scalar totalRadius);
b3SATCacheType ReadFace(const b3Transform& xf1, const b3Hull* hull1,
const b3Transform& xf2, const b3Hull* hull2, float32 totalRadius);
const b3Transform& xf2, const b3Hull* hull2, scalar totalRadius);
b3SATFeaturePair m_featurePair;
};

View File

@@ -16,8 +16,8 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_EDGE_HULL_SAT_H
#define B3_EDGE_HULL_SAT_H
#ifndef B3_HULL_AND_EDGE_SAT_H
#define B3_HULL_AND_EDGE_SAT_H
#include <bounce/collision/sat/sat.h>
@@ -25,16 +25,16 @@ struct b3Capsule;
///////////////////////////////////////////////////////////////////////////////////////////////////
float32 b3ProjectEdge(const b3Capsule* hull, const b3Plane& plane);
scalar b3ProjectEdge(const b3Capsule* hull, const b3Plane& plane);
b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Capsule* hull1,
const b3Transform& xf2, const b3Hull* hull2);
b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Hull* hull1,
const b3Transform& xf2, const b3Capsule* hull2);
///////////////////////////////////////////////////////////////////////////////////////////////////
float32 b3ProjectEdge(const b3Vec3& P1, const b3Vec3& E1, const b3Vec3& P2, const b3Vec3& E2, const b3Vec3& C2);
scalar b3ProjectEdge(const b3Vec3& P1, const b3Vec3& E1, const b3Vec3& P2, const b3Vec3& E2, const b3Vec3& C2);
b3EdgeQuery b3QueryEdgeSeparation(const b3Transform& xf1, const b3Capsule* hull1,
const b3Transform& xf2, const b3Hull* hull2);
b3EdgeQuery b3QueryEdgeSeparation(const b3Transform& xf1, const b3Hull* hull1,
const b3Transform& xf2, const b3Capsule* hull2);
#endif

View File

@@ -16,8 +16,8 @@
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_VERTEX_HULL_SAT_H
#define B3_VERTEX_HULL_SAT_H
#ifndef B3_HULL_AND_VERTEX_SAT_H
#define B3_HULL_AND_VERTEX_SAT_H
#include <bounce/collision/sat/sat.h>
@@ -25,9 +25,9 @@ struct b3Sphere;
///////////////////////////////////////////////////////////////////////////////////////////////////
float32 b3ProjectVertex(const b3Sphere* hull, const b3Plane& plane);
scalar b3ProjectVertex(const b3Sphere* hull, const b3Plane& plane);
b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Sphere* hull1,
const b3Transform& xf2, const b3Hull* hull2);
b3FaceQuery b3QueryFaceSeparation(const b3Transform& xf1, const b3Hull* hull1,
const b3Transform& xf2, const b3Sphere* hull2);
#endif

View File

@@ -0,0 +1,370 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_AABB_H
#define B3_AABB_H
#include <bounce/common/math/transform.h>
#include <bounce/collision/collision.h>
// A min-max representation of a three-dimensional AABB.
struct b3AABB
{
// Constructor. Does nothing for performance.
b3AABB() { }
// Get the support vertex in a given direction.
b3Vec3 GetSupportVertex(const b3Vec3& direction) const
{
b3Vec3 support;
support.x = direction.x < scalar(0) ? lowerBound.x : upperBound.x;
support.y = direction.y < scalar(0) ? lowerBound.y : upperBound.y;
support.z = direction.z < scalar(0) ? lowerBound.z : upperBound.z;
return support;
}
// Set this AABB from a list of points.
void Set(const b3Vec3* points, u32 count)
{
lowerBound = upperBound = points[0];
for (u32 i = 1; i < count; ++i)
{
lowerBound = b3Min(lowerBound, points[i]);
upperBound = b3Max(upperBound, points[i]);
}
}
// Set this AABB from a list of points and a transform.
void Set(const b3Vec3* points, u32 count, const b3Transform& xf)
{
lowerBound = upperBound = b3Mul(xf, points[0]);
for (u32 i = 1; i < count; ++i)
{
b3Vec3 v = b3Mul(xf, points[i]);
lowerBound = b3Min(lowerBound, v);
upperBound = b3Max(upperBound, v);
}
}
// Set this AABB from a list of points, a local scale, and a transform.
void Set(const b3Vec3* points, u32 count, const b3Vec3& scale, const b3Transform& xf)
{
lowerBound = upperBound = b3Mul(xf, b3MulCW(scale, points[0]));
for (u32 i = 1; i < count; ++i)
{
b3Vec3 v = b3Mul(xf, b3MulCW(scale, points[i]));
lowerBound = b3Min(lowerBound, v);
upperBound = b3Max(upperBound, v);
}
}
// Set this AABB from two points.
void SetSegment(const b3Vec3& p1, const b3Vec3& p2)
{
lowerBound = b3Min(p1, p2);
upperBound = b3Max(p1, p2);
}
// Set this AABB from three points.
void SetTriangle(const b3Vec3& p1, const b3Vec3& p2, const b3Vec3& p3)
{
lowerBound = b3Min(p1, b3Min(p2, p3));
upperBound = b3Max(p1, b3Max(p2, p3));
}
// Set this AABB from a center point and a radius vector.
void Set(const b3Vec3& center, const b3Vec3& r)
{
lowerBound = center - r;
upperBound = center + r;
}
// Set this AABB from a center point and a radius value.
void Set(const b3Vec3& center, scalar radius)
{
b3Vec3 r(radius, radius, radius);
Set(center, r);
}
// Extend this AABB by a radius value.
void Extend(scalar s)
{
b3Vec3 r(s, s, s);
lowerBound -= r;
upperBound += r;
}
// Extend this AABB by a radius vector.
void Extend(const b3Vec3& r)
{
lowerBound -= r;
upperBound += r;
}
// Get the center of this AABB.
b3Vec3 GetCenter() const
{
return scalar(0.5) * (lowerBound + upperBound);
}
// Get the half-extents of this AABB.
b3Vec3 GetExtents() const
{
return scalar(0.5) * (upperBound - lowerBound);
}
// Get the width of this AABB.
scalar GetWidth() const
{
return upperBound.x - lowerBound.x;
}
// Get the height of this AABB.
scalar GetHeight() const
{
return upperBound.y - lowerBound.y;
}
// Get the depth of this AABB.
scalar GetDepth() const
{
return upperBound.z - lowerBound.z;
}
// Get the volume of this AABB.
scalar GetVolume() const
{
b3Vec3 d = upperBound - lowerBound;
return d.x * d.y * d.z;
}
// Get the surface area of this AABB.
scalar GetSurfaceArea() const
{
b3Vec3 d = upperBound - lowerBound;
return scalar(2) * (d.x * d.y + d.y * d.z + d.z * d.x);
}
// Get the index of the longest axis of this AABB.
u32 GetLongestAxisIndex() const
{
b3Vec3 d = upperBound - lowerBound;
scalar maxValue = d.x;
u32 maxIndex = 0;
if (d.y > maxValue)
{
maxValue = d.y;
maxIndex = 1;
}
if (d.z > maxValue)
{
maxValue = d.z;
maxIndex = 2;
}
return maxIndex;
}
// Test if this AABB contains a point.
bool Contains(const b3Vec3& point) const
{
return lowerBound.x <= point.x && point.x <= upperBound.x &&
lowerBound.y <= point.y && point.y <= upperBound.y &&
lowerBound.z <= point.z && point.z <= upperBound.z;
}
// Test if this AABB contains another AABB.
bool Contains(const b3AABB& aabb) const
{
return Contains(aabb.lowerBound) && Contains(aabb.upperBound);
}
// Perform a ray-cast against this AABB.
bool RayCast(b3RayCastOutput* output, const b3RayCastInput& input) const
{
b3Vec3 p1 = input.p1;
b3Vec3 p2 = input.p2;
b3Vec3 d = p2 - p1;
b3Vec3 normals[6];
normals[0].Set(scalar(-1), scalar(0), scalar(0));
normals[1].Set(scalar(1), scalar(0), scalar(0));
normals[2].Set(scalar(0), scalar(-1), scalar(0));
normals[3].Set(scalar(0), scalar(1), scalar(0));
normals[4].Set(scalar(0), scalar(0), scalar(-1));
normals[5].Set(scalar(0), scalar(0), scalar(1));
u32 index = B3_MAX_U32;
scalar lower = scalar(0);
scalar upper = input.maxFraction;
u32 planeIndex = 0;
for (u32 i = 0; i < 3; ++i)
{
scalar numerators[2], denominators[2];
numerators[0] = p1[i] - lowerBound[i];
numerators[1] = upperBound[i] - p1[i];
denominators[0] = -d[i];
denominators[1] = d[i];
for (u32 j = 0; j < 2; ++j)
{
scalar numerator = numerators[j];
scalar denominator = denominators[j];
if (denominator == scalar(0))
{
// s is parallel to this half-space.
if (numerator < scalar(0))
{
// s is outside of this half-space.
// dot(n, p1) and dot(n, p2) < 0.
return false;
}
}
else
{
if (denominator < scalar(0))
{
// s enters this half-space.
if (numerator < lower * denominator)
{
// Increase lower.
lower = numerator / denominator;
index = planeIndex;
}
}
else
{
// s exits the half-space.
if (numerator < upper * denominator)
{
// Decrease upper.
upper = numerator / denominator;
}
}
// Exit if intersection becomes empty.
if (upper < lower)
{
return false;
}
}
++planeIndex;
}
}
B3_ASSERT(lower >= scalar(0) && lower <= input.maxFraction);
if (index != B3_MAX_U32)
{
output->fraction = lower;
output->normal = normals[index];
return true;
}
return false;
}
b3Vec3 lowerBound; // lower vertex
b3Vec3 upperBound; // upper vertex
};
// Compute an AABB that encloses two AABBs.
inline b3AABB b3Combine(const b3AABB& a, const b3AABB& b)
{
b3AABB aabb;
aabb.lowerBound = b3Min(a.lowerBound, b.lowerBound);
aabb.upperBound = b3Max(a.upperBound, b.upperBound);
return aabb;
}
// Test if two AABBs are overlapping.
inline bool b3TestOverlap(const b3AABB& a, const b3AABB& b)
{
return (a.lowerBound.x <= b.upperBound.x) && (a.lowerBound.y <= b.upperBound.y) && (a.lowerBound.z <= b.upperBound.z) &&
(a.upperBound.x >= b.lowerBound.x) && (a.upperBound.y >= b.lowerBound.y) && (a.upperBound.z >= b.lowerBound.z);
}
// Transform a AABB by a given frame.
inline b3AABB b3TransformAABB(const b3AABB& local_aabb, const b3Transform& xf)
{
b3Vec3 local_center = local_aabb.GetCenter();
b3Vec3 local_radius = local_aabb.GetExtents();
b3Vec3 center = xf * local_center;
b3Mat33 rotation = b3Abs(b3QuatMat33(xf.rotation));
b3Vec3 radius;
radius.x = b3Dot(local_radius, rotation.x);
radius.y = b3Dot(local_radius, rotation.y);
radius.z = b3Dot(local_radius, rotation.z);
b3AABB aabb;
aabb.Set(center, radius);
return aabb;
}
// Transform a AABB given a local scale by a given frame.
inline b3AABB b3TransformAABB(const b3AABB& local_aabb, const b3Vec3& local_scale, const b3Transform& xf)
{
b3Vec3 local_center = local_aabb.GetCenter();
b3Vec3 local_radius = b3MulCW(b3Abs(local_scale), local_aabb.GetExtents());
b3Vec3 center = xf * local_center;
b3Mat33 rotation = b3Abs(b3QuatMat33(xf.rotation));
b3Vec3 radius;
radius.x = b3Dot(local_radius, rotation.x);
radius.y = b3Dot(local_radius, rotation.y);
radius.z = b3Dot(local_radius, rotation.z);
b3AABB aabb;
aabb.Set(center, radius);
return aabb;
}
// Scale an AABB by a scale.
// The scale can be non-uniform and negative.
inline b3AABB b3ScaleAABB(const b3AABB& aabb, const b3Vec3& scale)
{
b3AABB scaled_aabb;
scaled_aabb.lowerBound.x = scale.x > scalar(0) ? scale.x * aabb.lowerBound.x : scale.x * aabb.upperBound.x;
scaled_aabb.lowerBound.y = scale.y > scalar(0) ? scale.y * aabb.lowerBound.y : scale.y * aabb.upperBound.y;
scaled_aabb.lowerBound.z = scale.z > scalar(0) ? scale.z * aabb.lowerBound.z : scale.z * aabb.upperBound.z;
scaled_aabb.upperBound.x = scale.x > scalar(0) ? scale.x * aabb.upperBound.x : scale.x * aabb.lowerBound.x;
scaled_aabb.upperBound.y = scale.y > scalar(0) ? scale.y * aabb.upperBound.y : scale.y * aabb.lowerBound.y;
scaled_aabb.upperBound.z = scale.z > scalar(0) ? scale.z * aabb.upperBound.z : scale.z * aabb.lowerBound.z;
return scaled_aabb;
}
#endif

View File

@@ -1,253 +0,0 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_AABB_3_H
#define B3_AABB_3_H
#include <bounce/common/math/transform.h>
// A min-max representation of a three-dimensional AABB.
struct b3AABB3
{
b3Vec3 m_lower; // lower vertex
b3Vec3 m_upper; // upper vertex
// Get the support vertex in a given direction.
b3Vec3 GetSupportVertex(const b3Vec3& direction) const
{
b3Vec3 support;
support.x = direction.x < 0.0f ? m_lower.x : m_upper.x;
support.y = direction.y < 0.0f ? m_lower.y : m_upper.y;
support.z = direction.z < 0.0f ? m_lower.z : m_upper.z;
return support;
}
// Set this AABB from a list of points.
void Set(const b3Vec3* points, u32 count)
{
m_lower = m_upper = points[0];
for (u32 i = 1; i < count; ++i)
{
m_lower = b3Min(m_lower, points[i]);
m_upper = b3Max(m_upper, points[i]);
}
}
// Set this AABB from a list of points and a transform.
void Set(const b3Vec3* points, u32 count, const b3Transform& xf)
{
m_lower = m_upper = b3Mul(xf, points[0]);
for (u32 i = 1; i < count; ++i)
{
b3Vec3 v = b3Mul(xf, points[i]);
m_lower = b3Min(m_lower, v);
m_upper = b3Max(m_upper, v);
}
}
// Set this AABB from a triangle.
void Set(const b3Vec3& v1, const b3Vec3& v2, const b3Vec3& v3)
{
m_lower = b3Min(v1, b3Min(v2, v3));
m_upper = b3Max(v1, b3Max(v2, v3));
}
// Set this AABB from a center point and a radius vector.
void Set(const b3Vec3& center, const b3Vec3& r)
{
m_lower = center - r;
m_upper = center + r;
}
// Set this AABB from a center point and a radius value.
void Set(const b3Vec3& center, float32 radius)
{
b3Vec3 r(radius, radius, radius);
Set(center, r);
}
// Extend this AABB by a scalar.
void Extend(float32 s)
{
b3Vec3 r(s, s, s);
m_lower -= r;
m_upper += r;
}
// Extend this AABB by a radius vector.
void Extend(const b3Vec3& r)
{
m_lower -= r;
m_upper += r;
}
// Compute the centroid of this AABB.
b3Vec3 Centroid() const
{
return 0.5f * (m_lower + m_upper);
}
// Compute the width of this AABB.
float32 Width() const
{
return m_upper.x - m_lower.x;
}
// Compute the height of this AABB.
float32 Height() const
{
return m_upper.y - m_lower.y;
}
// Compute the depth of this AABB.
float32 Depth() const
{
return m_upper.z - m_lower.z;
}
// Compute the total of cubic units contained in this AABB.
float32 Volume() const
{
return Width() * Height() * Depth();
}
// Compute the surface area of this AABB.
float32 SurfaceArea() const
{
return 2.0f * (Width() * Depth() + Width() * Height() + Depth() * Height());
}
// Read the index of the longest axis of this AABB.
u32 GetLongestAxisIndex() const
{
b3Vec3 c = Centroid();
b3Vec3 r = m_upper - c;
float32 max = r[0];
u32 i = 0;
if (r[1] > max)
{
max = r[1];
i = 1;
}
if (r[2] > max)
{
max = r[2];
i = 2;
}
return i;
}
// Test if this AABB contains a point.
bool Contains(const b3Vec3& point) const
{
return m_lower.x <= point.x && point.x <= m_upper.x &&
m_lower.y <= point.y && point.y <= m_upper.y &&
m_lower.z <= point.z && point.z <= m_upper.z;
}
// Test if this AABB contains another AABB.
bool Contains(const b3AABB3& aabb) const
{
return Contains(aabb.m_lower) && Contains(aabb.m_upper);
}
// Test if a ray intersects this AABB.
bool TestRay(float32& minFraction, const b3Vec3& p1, const b3Vec3& p2, float32 maxFraction) const
{
b3Vec3 d = p2 - p1;
float32 lower = 0.0f;
float32 upper = maxFraction;
for (u32 i = 0; i < 3; ++i)
{
float32 numerators[2], denominators[2];
numerators[0] = p1[i] - m_lower[i];
numerators[1] = m_upper[i] - p1[i];
denominators[0] = -d[i];
denominators[1] = d[i];
for (u32 j = 0; j < 2; ++j)
{
float32 numerator = numerators[j];
float32 denominator = denominators[j];
if (denominator == 0.0f)
{
// s is parallel to this half-space.
if (numerator < 0.0f)
{
// s is outside of this half-space.
// dot(n, p1) and dot(n, p2) < 0.
return false;
}
}
else
{
if (denominator < 0.0f)
{
// s enters this half-space.
if (numerator < lower * denominator)
{
// Increase lower.
lower = numerator / denominator;
}
}
else
{
// s exits the half-space.
if (numerator < upper * denominator)
{
// Decrease upper.
upper = numerator / denominator;
}
}
// Exit if intersection becomes empty.
if (upper < lower)
{
return false;
}
}
}
}
B3_ASSERT(lower >= 0.0f && lower <= maxFraction);
minFraction = lower;
return true;
}
};
// Compute an AABB that encloses two AABBs.
inline b3AABB3 b3Combine(const b3AABB3& a, const b3AABB3& b)
{
b3AABB3 aabb;
aabb.m_lower = b3Min(a.m_lower, b.m_lower);
aabb.m_upper = b3Max(a.m_upper, b.m_upper);
return aabb;
}
// Test if two AABBs are overlapping.
inline bool b3TestOverlap(const b3AABB3& a, const b3AABB3& b)
{
return (a.m_lower.x <= b.m_upper.x) && (a.m_lower.y <= b.m_upper.y) && (a.m_lower.z <= b.m_upper.z) &&
(a.m_upper.x >= b.m_lower.x) && (a.m_upper.y >= b.m_lower.y) && (a.m_upper.z >= b.m_lower.z);
}
#endif

View File

@@ -32,140 +32,74 @@ struct b3BoxHull : public b3Hull
b3BoxHull() { }
// Construct this box from three extents and centered at the origin.
b3BoxHull(float32 ex, float32 ey, float32 ez)
b3BoxHull(scalar ex, scalar ey, scalar ez)
{
Set(ex, ey, ez);
SetExtents(ex, ey, ez);
}
// Set this box to the unit box centered at the origin.
void SetIdentity()
{
boxVertices[0] = b3Vec3(1.0f, 1.0f, -1.0f);
boxVertices[1] = b3Vec3(-1.0f, 1.0f, -1.0f);
boxVertices[2] = b3Vec3(-1.0f, -1.0f, -1.0f);
boxVertices[3] = b3Vec3(1.0f, -1.0f, -1.0f);
boxVertices[4] = b3Vec3(1.0f, 1.0f, 1.0f);
boxVertices[5] = b3Vec3(-1.0f, 1.0f, 1.0f);
boxVertices[6] = b3Vec3(-1.0f, -1.0f, 1.0f);
boxVertices[7] = b3Vec3(1.0f, -1.0f, 1.0f);
boxVertices[0] = b3Vec3(-1, -1, 1);
boxVertices[1] = b3Vec3(1, -1, -1);
boxVertices[2] = b3Vec3(1, 1, 1);
boxVertices[3] = b3Vec3(-1, 1, -1);
boxVertices[4] = b3Vec3(1, 1, -1);
boxVertices[5] = b3Vec3(-1, 1, 1);
boxVertices[6] = b3Vec3(1, -1, 1);
boxVertices[7] = b3Vec3(-1, -1, -1);
boxEdges[0] = b3MakeEdge(1, 1, 0, 2);
boxEdges[1] = b3MakeEdge(2, 0, 5, 21);
boxEdges[2] = b3MakeEdge(2, 3, 0, 4);
boxEdges[3] = b3MakeEdge(6, 2, 2, 18);
boxEdges[4] = b3MakeEdge(6, 5, 0, 6);
boxEdges[5] = b3MakeEdge(5, 4, 4, 17);
boxEdges[6] = b3MakeEdge(5, 7, 0, 0);
boxEdges[7] = b3MakeEdge(1, 6, 3, 22);
boxEdges[8] = b3MakeEdge(4, 9, 1, 10);
boxEdges[9] = b3MakeEdge(7, 8, 4, 23);
boxEdges[10] = b3MakeEdge(7, 11, 1, 12);
boxEdges[11] = b3MakeEdge(3, 10, 2, 16);
boxEdges[12] = b3MakeEdge(3, 13, 1, 14);
boxEdges[13] = b3MakeEdge(0, 12, 5, 19);
boxEdges[14] = b3MakeEdge(0, 15, 1, 8);
boxEdges[15] = b3MakeEdge(4, 14, 3, 20);
boxEdges[16] = b3MakeEdge(7, 17, 2, 3);
boxEdges[17] = b3MakeEdge(6, 16, 4, 9);
boxEdges[18] = b3MakeEdge(2, 19, 2, 11);
boxEdges[19] = b3MakeEdge(3, 18, 5, 1);
boxEdges[20] = b3MakeEdge(0, 21, 3, 7);
boxEdges[21] = b3MakeEdge(1, 20, 5, 13);
boxEdges[22] = b3MakeEdge(5, 23, 3, 15);
boxEdges[23] = b3MakeEdge(4, 22, 4, 5);
boxEdges[0] = b3MakeEdge(0, 1, 0, 6, 2);
boxEdges[1] = b3MakeEdge(5, 0, 1, 12, 8);
boxEdges[2] = b3MakeEdge(5, 3, 0, 0, 4);
boxEdges[3] = b3MakeEdge(3, 2, 5, 19, 13);
boxEdges[4] = b3MakeEdge(3, 5, 0, 2, 6);
boxEdges[5] = b3MakeEdge(7, 4, 3, 15, 18);
boxEdges[6] = b3MakeEdge(7, 7, 0, 4, 0);
boxEdges[7] = b3MakeEdge(0, 6, 2, 9, 14);
boxEdges[8] = b3MakeEdge(0, 9, 1, 1, 10);
boxEdges[9] = b3MakeEdge(6, 8, 2, 16, 7);
boxEdges[10] = b3MakeEdge(6, 11, 1, 8, 12);
boxEdges[11] = b3MakeEdge(2, 10, 4, 22, 17);
boxEdges[12] = b3MakeEdge(2, 13, 1, 10, 1);
boxEdges[13] = b3MakeEdge(5, 12, 5, 3, 23);
boxEdges[14] = b3MakeEdge(7, 15, 2, 7, 16);
boxEdges[15] = b3MakeEdge(1, 14, 3, 20, 5);
boxEdges[16] = b3MakeEdge(1, 17, 2, 14, 9);
boxEdges[17] = b3MakeEdge(6, 16, 4, 11, 21);
boxEdges[18] = b3MakeEdge(3, 19, 3, 5, 20);
boxEdges[19] = b3MakeEdge(4, 18, 5, 23, 3);
boxEdges[20] = b3MakeEdge(4, 21, 3, 18, 15);
boxEdges[21] = b3MakeEdge(1, 20, 4, 17, 22);
boxEdges[22] = b3MakeEdge(4, 23, 4, 21, 11);
boxEdges[23] = b3MakeEdge(2, 22, 5, 13, 19);
boxFaces[0].edge = 6;
boxFaces[1].edge = 14;
boxFaces[2].edge = 18;
boxFaces[0].edge = 0;
boxFaces[1].edge = 8;
boxFaces[2].edge = 7;
boxFaces[3].edge = 15;
boxFaces[4].edge = 9;
boxFaces[5].edge = 21;
boxFaces[4].edge = 21;
boxFaces[5].edge = 23;
boxPlanes[0] = b3Plane(b3Vec3(-1.0f, 0.0f, 0.0f), boxVertices[1]);
boxPlanes[1] = b3Plane(b3Vec3(1.0f, 0.0f, 0.0f), boxVertices[0]);
boxPlanes[2] = b3Plane(b3Vec3(0.0f, -1.0f, 0.0f), boxVertices[2]);
boxPlanes[3] = b3Plane(b3Vec3(0.0f, 1.0f, 0.0f), boxVertices[1]);
boxPlanes[4] = b3Plane(b3Vec3(0.0f, 0.0f, 1.0f), boxVertices[4]);
boxPlanes[5] = b3Plane(b3Vec3(0.0f, 0.0f, -1.0f), boxVertices[0]);
centroid = b3Vec3(0.0f, 0.0f, 0.0f);
vertices = boxVertices;
vertexCount = 8;
edges = boxEdges;
edgeCount = 24;
faces = boxFaces;
planes = boxPlanes;
faceCount = 6;
boxPlanes[0].normal = b3Vec3(-1, 0, 0);
boxPlanes[0].offset = 1;
Validate();
}
// Set this box from three extents and centered at the origin.
void Set(float32 ex, float32 ey, float32 ez)
{
b3Transform xf;
xf.position.SetZero();
xf.rotation = b3Diagonal(ex, ey, ez);
SetTransform(xf);
}
boxPlanes[1].normal = b3Vec3(0, 0, 1);
boxPlanes[1].offset = 1;
boxPlanes[2].normal = b3Vec3(0, -1, 0);
boxPlanes[2].offset = 1;
boxPlanes[3].normal = b3Vec3(0, 0, -1);
boxPlanes[3].offset = 1;
boxPlanes[4].normal = b3Vec3(1, 0, 0);
boxPlanes[4].offset = 1;
boxPlanes[5].normal = b3Vec3(0, 1, 0);
boxPlanes[5].offset = 1;
// Set this box to the unit box and transform it.
void SetTransform(const b3Transform& T)
{
boxVertices[0] = b3Vec3(1.0f, 1.0f, -1.0f);
boxVertices[1] = b3Vec3(-1.0f, 1.0f, -1.0f);
boxVertices[2] = b3Vec3(-1.0f, -1.0f, -1.0f);
boxVertices[3] = b3Vec3(1.0f, -1.0f, -1.0f);
boxVertices[4] = b3Vec3(1.0f, 1.0f, 1.0f);
boxVertices[5] = b3Vec3(-1.0f, 1.0f, 1.0f);
boxVertices[6] = b3Vec3(-1.0f, -1.0f, 1.0f);
boxVertices[7] = b3Vec3(1.0f, -1.0f, 1.0f);
for (u32 i = 0; i < 8; ++i)
{
boxVertices[i] = T * boxVertices[i];
}
boxEdges[0] = b3MakeEdge(1, 1, 0, 2);
boxEdges[1] = b3MakeEdge(2, 0, 5, 21);
boxEdges[2] = b3MakeEdge(2, 3, 0, 4);
boxEdges[3] = b3MakeEdge(6, 2, 2, 18);
boxEdges[4] = b3MakeEdge(6, 5, 0, 6);
boxEdges[5] = b3MakeEdge(5, 4, 4, 17);
boxEdges[6] = b3MakeEdge(5, 7, 0, 0);
boxEdges[7] = b3MakeEdge(1, 6, 3, 22);
boxEdges[8] = b3MakeEdge(4, 9, 1, 10);
boxEdges[9] = b3MakeEdge(7, 8, 4, 23);
boxEdges[10] = b3MakeEdge(7, 11, 1, 12);
boxEdges[11] = b3MakeEdge(3, 10, 2, 16);
boxEdges[12] = b3MakeEdge(3, 13, 1, 14);
boxEdges[13] = b3MakeEdge(0, 12, 5, 19);
boxEdges[14] = b3MakeEdge(0, 15, 1, 8);
boxEdges[15] = b3MakeEdge(4, 14, 3, 20);
boxEdges[16] = b3MakeEdge(7, 17, 2, 3);
boxEdges[17] = b3MakeEdge(6, 16, 4, 9);
boxEdges[18] = b3MakeEdge(2, 19, 2, 11);
boxEdges[19] = b3MakeEdge(3, 18, 5, 1);
boxEdges[20] = b3MakeEdge(0, 21, 3, 7);
boxEdges[21] = b3MakeEdge(1, 20, 5, 13);
boxEdges[22] = b3MakeEdge(5, 23, 3, 15);
boxEdges[23] = b3MakeEdge(4, 22, 4, 5);
boxFaces[0].edge = 6;
boxFaces[1].edge = 14;
boxFaces[2].edge = 18;
boxFaces[3].edge = 15;
boxFaces[4].edge = 9;
boxFaces[5].edge = 21;
boxPlanes[0] = b3Plane(b3Vec3(-1.0f, 0.0f, 0.0f), boxVertices[1]);
boxPlanes[1] = b3Plane(b3Vec3(1.0f, 0.0f, 0.0f), boxVertices[0]);
boxPlanes[2] = b3Plane(b3Vec3(0.0f, -1.0f, 0.0f), boxVertices[2]);
boxPlanes[3] = b3Plane(b3Vec3(0.0f, 1.0f, 0.0f), boxVertices[1]);
boxPlanes[4] = b3Plane(b3Vec3(0.0f, 0.0f, 1.0f), boxVertices[4]);
boxPlanes[5] = b3Plane(b3Vec3(0.0f, 0.0f, -1.0f), boxVertices[0]);
centroid = b3Vec3(0.0f, 0.0f, 0.0f);
centroid = b3Vec3(0, 0, 0);
vertices = boxVertices;
vertexCount = 8;
edges = boxEdges;
@@ -174,10 +108,17 @@ struct b3BoxHull : public b3Hull
planes = boxPlanes;
faceCount = 6;
centroid = T * centroid;
Validate();
}
// Set this box from three extents and centered and aligned at the origin.
void SetExtents(scalar ex, scalar ey, scalar ez)
{
SetIdentity();
b3Vec3 scale(ex, ey, ez);
Scale(scale);
}
};
extern const b3BoxHull b3BoxHull_identity;

View File

@@ -23,23 +23,18 @@
struct b3Capsule
{
//
b3Vec3 vertex1, vertex2;
scalar radius;
b3Capsule() { }
//
b3Capsule(const b3Vec3& v1, const b3Vec3& v2, float32 r)
b3Capsule(const b3Vec3& v1, const b3Vec3& v2, scalar r)
{
vertices[0] = v1;
vertices[1] = v2;
vertex1 = v1;
vertex2 = v2;
radius = r;
}
//
~b3Capsule() { }
b3Vec3 vertices[2];
float32 radius;
const b3Vec3& GetVertex(u32 index) const;
u32 GetSupportVertex(const b3Vec3& direction) const;
};
@@ -49,12 +44,12 @@ extern const b3Capsule b3Capsule_identity;
inline const b3Vec3& b3Capsule::GetVertex(u32 index) const
{
return vertices[index];
return (&vertex1)[index];
}
inline u32 b3Capsule::GetSupportVertex(const b3Vec3& d) const
{
if (b3Dot(d, vertices[0]) > b3Dot(d, vertices[1]))
if (b3Dot(d, vertex1) > b3Dot(d, vertex2))
{
return 0;
}

View File

@@ -0,0 +1,240 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_CONE_HULL_H
#define B3_CONE_HULL_H
#include <bounce/collision/shapes/hull.h>
// A cone with 20 segments.
struct b3ConeHull : public b3Hull
{
b3Vec3 coneVertices[21];
b3HalfEdge coneEdges[80];
b3Face coneFaces[21];
b3Plane conePlanes[21];
// Does nothing for performance.
b3ConeHull()
{
}
// Construct this cone from radius and y extent centered at the origin.
// The cone will have radius and extent set to 1;
b3ConeHull(scalar radius, scalar ey)
{
SetExtents(radius, ey);
}
// Set this cone to the unit cylinder centered at the origin.
void SetIdentity()
{
coneVertices[0] = b3Vec3(-0.95105665922164916992, -1.00000000000000000000, -0.30901667475700378418);
coneVertices[1] = b3Vec3(-0.95105648040771484375, -1.00000000000000000000, 0.30901741981506347656);
coneVertices[2] = b3Vec3(0.30901747941970825195, -1.00000000000000000000, 0.95105648040771484375);
coneVertices[3] = b3Vec3(0.95105648040771484375, -1.00000000000000000000, -0.30901703238487243652);
coneVertices[4] = b3Vec3(-0.58778500556945800781, -1.00000000000000000000, 0.80901730060577392578);
coneVertices[5] = b3Vec3(-0.30901724100112915039, -1.00000000000000000000, -0.95105648040771484375);
coneVertices[6] = b3Vec3(0.30901682376861572266, -1.00000000000000000000, -0.95105654001235961914);
coneVertices[7] = b3Vec3(0.80901741981506347656, -1.00000000000000000000, 0.58778494596481323242);
coneVertices[8] = b3Vec3(-0.80901724100112915039, -1.00000000000000000000, -0.58778500556945800781);
coneVertices[9] = b3Vec3(0.95105683803558349609, -1.00000000000000000000, 0.30901655554771423340);
coneVertices[10] = b3Vec3(-0.30901664495468139648, -1.00000000000000000000, 0.95105671882629394531);
coneVertices[11] = b3Vec3(0.80901694297790527344, -1.00000000000000000000, -0.58778530359268188477);
coneVertices[12] = b3Vec3(0.58778578042984008789, -1.00000000000000000000, 0.80901682376861572266);
coneVertices[13] = b3Vec3(0.58778512477874755859, -1.00000000000000000000, -0.80901706218719482422);
coneVertices[14] = b3Vec3(-0.80901682376861572266, -1.00000000000000000000, 0.58778566122055053711);
coneVertices[15] = b3Vec3(-0.58778554201126098633, -1.00000000000000000000, -0.80901688337326049805);
coneVertices[16] = b3Vec3(0.00000044982880353928, -1.00000000000000000000, 1.00000011920928955078);
coneVertices[17] = b3Vec3(-0.00000022072345018387, -1.00000000000000000000, -1.00000000000000000000);
coneVertices[18] = b3Vec3(-1.00000011920928955078, -1.00000000000000000000, 0.00000039115548133850);
coneVertices[19] = b3Vec3(0.00000000000000000000, 1.00000000000000000000, 0.00000000000000000000);
coneVertices[20] = b3Vec3(1.00000000000000000000, -1.00000000000000000000, 0.00000000000000000000);
coneEdges[0] = b3MakeEdge(0, 1, 0, 4, 2);
coneEdges[1] = b3MakeEdge(19, 0, 1, 8, 6);
coneEdges[2] = b3MakeEdge(19, 3, 0, 0, 4);
coneEdges[3] = b3MakeEdge(8, 2, 17, 11, 71);
coneEdges[4] = b3MakeEdge(8, 5, 0, 2, 0);
coneEdges[5] = b3MakeEdge(0, 4, 2, 7, 10);
coneEdges[6] = b3MakeEdge(0, 7, 1, 1, 8);
coneEdges[7] = b3MakeEdge(18, 6, 2, 44, 5);
coneEdges[8] = b3MakeEdge(18, 9, 1, 6, 1);
coneEdges[9] = b3MakeEdge(19, 8, 3, 46, 45);
coneEdges[10] = b3MakeEdge(8, 11, 2, 5, 12);
coneEdges[11] = b3MakeEdge(15, 10, 17, 71, 3);
coneEdges[12] = b3MakeEdge(15, 13, 2, 10, 14);
coneEdges[13] = b3MakeEdge(5, 12, 12, 67, 70);
coneEdges[14] = b3MakeEdge(5, 15, 2, 12, 16);
coneEdges[15] = b3MakeEdge(17, 14, 11, 68, 66);
coneEdges[16] = b3MakeEdge(17, 17, 2, 14, 18);
coneEdges[17] = b3MakeEdge(6, 16, 14, 73, 69);
coneEdges[18] = b3MakeEdge(6, 19, 2, 16, 20);
coneEdges[19] = b3MakeEdge(13, 18, 13, 74, 72);
coneEdges[20] = b3MakeEdge(13, 21, 2, 18, 22);
coneEdges[21] = b3MakeEdge(11, 20, 20, 61, 75);
coneEdges[22] = b3MakeEdge(11, 23, 2, 20, 24);
coneEdges[23] = b3MakeEdge(3, 22, 8, 57, 60);
coneEdges[24] = b3MakeEdge(3, 25, 2, 22, 26);
coneEdges[25] = b3MakeEdge(20, 24, 7, 58, 56);
coneEdges[26] = b3MakeEdge(20, 27, 2, 24, 28);
coneEdges[27] = b3MakeEdge(9, 26, 18, 79, 59);
coneEdges[28] = b3MakeEdge(9, 29, 2, 26, 30);
coneEdges[29] = b3MakeEdge(7, 28, 16, 77, 78);
coneEdges[30] = b3MakeEdge(7, 31, 2, 28, 32);
coneEdges[31] = b3MakeEdge(12, 30, 15, 55, 76);
coneEdges[32] = b3MakeEdge(12, 33, 2, 30, 34);
coneEdges[33] = b3MakeEdge(2, 32, 6, 51, 54);
coneEdges[34] = b3MakeEdge(2, 35, 2, 32, 36);
coneEdges[35] = b3MakeEdge(16, 34, 5, 52, 50);
coneEdges[36] = b3MakeEdge(16, 37, 2, 34, 38);
coneEdges[37] = b3MakeEdge(10, 36, 19, 65, 53);
coneEdges[38] = b3MakeEdge(10, 39, 2, 36, 40);
coneEdges[39] = b3MakeEdge(4, 38, 10, 63, 64);
coneEdges[40] = b3MakeEdge(4, 41, 2, 38, 42);
coneEdges[41] = b3MakeEdge(14, 40, 9, 49, 62);
coneEdges[42] = b3MakeEdge(14, 43, 2, 40, 44);
coneEdges[43] = b3MakeEdge(1, 42, 4, 47, 48);
coneEdges[44] = b3MakeEdge(1, 45, 2, 42, 7);
coneEdges[45] = b3MakeEdge(18, 44, 3, 9, 46);
coneEdges[46] = b3MakeEdge(1, 47, 3, 45, 9);
coneEdges[47] = b3MakeEdge(19, 46, 4, 48, 43);
coneEdges[48] = b3MakeEdge(14, 49, 4, 43, 47);
coneEdges[49] = b3MakeEdge(19, 48, 9, 62, 41);
coneEdges[50] = b3MakeEdge(2, 51, 5, 35, 52);
coneEdges[51] = b3MakeEdge(19, 50, 6, 54, 33);
coneEdges[52] = b3MakeEdge(19, 53, 5, 50, 35);
coneEdges[53] = b3MakeEdge(16, 52, 19, 37, 65);
coneEdges[54] = b3MakeEdge(12, 55, 6, 33, 51);
coneEdges[55] = b3MakeEdge(19, 54, 15, 76, 31);
coneEdges[56] = b3MakeEdge(3, 57, 7, 25, 58);
coneEdges[57] = b3MakeEdge(19, 56, 8, 60, 23);
coneEdges[58] = b3MakeEdge(19, 59, 7, 56, 25);
coneEdges[59] = b3MakeEdge(20, 58, 18, 27, 79);
coneEdges[60] = b3MakeEdge(11, 61, 8, 23, 57);
coneEdges[61] = b3MakeEdge(19, 60, 20, 75, 21);
coneEdges[62] = b3MakeEdge(4, 63, 9, 41, 49);
coneEdges[63] = b3MakeEdge(19, 62, 10, 64, 39);
coneEdges[64] = b3MakeEdge(10, 65, 10, 39, 63);
coneEdges[65] = b3MakeEdge(19, 64, 19, 53, 37);
coneEdges[66] = b3MakeEdge(5, 67, 11, 15, 68);
coneEdges[67] = b3MakeEdge(19, 66, 12, 70, 13);
coneEdges[68] = b3MakeEdge(19, 69, 11, 66, 15);
coneEdges[69] = b3MakeEdge(17, 68, 14, 17, 73);
coneEdges[70] = b3MakeEdge(15, 71, 12, 13, 67);
coneEdges[71] = b3MakeEdge(19, 70, 17, 3, 11);
coneEdges[72] = b3MakeEdge(6, 73, 13, 19, 74);
coneEdges[73] = b3MakeEdge(19, 72, 14, 69, 17);
coneEdges[74] = b3MakeEdge(19, 75, 13, 72, 19);
coneEdges[75] = b3MakeEdge(13, 74, 20, 21, 61);
coneEdges[76] = b3MakeEdge(7, 77, 15, 31, 55);
coneEdges[77] = b3MakeEdge(19, 76, 16, 78, 29);
coneEdges[78] = b3MakeEdge(9, 79, 16, 29, 77);
coneEdges[79] = b3MakeEdge(19, 78, 18, 59, 27);
coneFaces[0].edge = 0;
coneFaces[1].edge = 6;
coneFaces[2].edge = 5;
coneFaces[3].edge = 46;
coneFaces[4].edge = 43;
coneFaces[5].edge = 50;
coneFaces[6].edge = 33;
coneFaces[7].edge = 56;
coneFaces[8].edge = 23;
coneFaces[9].edge = 62;
coneFaces[10].edge = 39;
coneFaces[11].edge = 66;
coneFaces[12].edge = 13;
coneFaces[13].edge = 72;
coneFaces[14].edge = 17;
coneFaces[15].edge = 76;
coneFaces[16].edge = 29;
coneFaces[17].edge = 3;
coneFaces[18].edge = 27;
coneFaces[19].edge = 37;
coneFaces[20].edge = 21;
conePlanes[0].normal = b3Vec3(-0.79889804124832153320, 0.44279259443283081055, -0.40705847740173339844);
conePlanes[0].offset = 0.44279259443283081055;
conePlanes[1].normal = b3Vec3(-0.88558518886566162109, 0.44279265403747558594, -0.14026281237602233887);
conePlanes[1].offset = 0.44279262423515319824;
conePlanes[2].normal = b3Vec3(0.00000000000000000000, -1.00000000000000000000, 0.00000000000000000000);
conePlanes[2].offset = 1.00000000000000000000;
conePlanes[3].normal = b3Vec3(-0.88558501005172729492, 0.44279259443283081055, 0.14026330411434173584);
conePlanes[3].offset = 0.44279262423515319824;
conePlanes[4].normal = b3Vec3(-0.79889774322509765625, 0.44279259443283081055, 0.40705913305282592773);
conePlanes[4].offset = 0.44279265403747558594;
conePlanes[5].normal = b3Vec3(0.14026331901550292969, 0.44279259443283081055, 0.88558501005172729492);
conePlanes[5].offset = 0.44279265403747558594;
conePlanes[6].normal = b3Vec3(0.40705907344818115234, 0.44279259443283081055, 0.79889774322509765625);
conePlanes[6].offset = 0.44279265403747558594;
conePlanes[7].normal = b3Vec3(0.88558512926101684570, 0.44279256463050842285, -0.14026297628879547119);
conePlanes[7].offset = 0.44279259443283081055;
conePlanes[8].normal = b3Vec3(0.79889786243438720703, 0.44279253482818603516, -0.40705886483192443848);
conePlanes[8].offset = 0.44279256463050842285;
conePlanes[9].normal = b3Vec3(-0.63400870561599731445, 0.44279262423515319824, 0.63400918245315551758);
conePlanes[9].offset = 0.44279256463050842285;
conePlanes[10].normal = b3Vec3(-0.40705844759941101074, 0.44279259443283081055, 0.79889804124832153320);
conePlanes[10].offset = 0.44279265403747558594;
conePlanes[11].normal = b3Vec3(-0.14026300609111785889, 0.44279259443283081055, -0.88558506965637207031);
conePlanes[11].offset = 0.44279253482818603516;
conePlanes[12].normal = b3Vec3(-0.40705892443656921387, 0.44279259443283081055, -0.79889780282974243164);
conePlanes[12].offset = 0.44279259443283081055;
conePlanes[13].normal = b3Vec3(0.40705865621566772461, 0.44279253482818603516, -0.79889798164367675781);
conePlanes[13].offset = 0.44279259443283081055;
conePlanes[14].normal = b3Vec3(0.14026281237602233887, 0.44279256463050842285, -0.88558518886566162109);
conePlanes[14].offset = 0.44279259443283081055;
conePlanes[15].normal = b3Vec3(0.63400930166244506836, 0.44279262423515319824, 0.63400864601135253906);
conePlanes[15].offset = 0.44279265403747558594;
conePlanes[16].normal = b3Vec3(0.79889810085296630859, 0.44279265403747558594, 0.40705841779708862305);
conePlanes[16].offset = 0.44279265403747558594;
conePlanes[17].normal = b3Vec3(-0.63400924205780029297, 0.44279265403747558594, -0.63400876522064208984);
conePlanes[17].offset = 0.44279265403747558594;
conePlanes[18].normal = b3Vec3(0.88558530807495117188, 0.44279265403747558594, 0.14026220142841339111);
conePlanes[18].offset = 0.44279268383979797363;
conePlanes[19].normal = b3Vec3(-0.14026261866092681885, 0.44279259443283081055, 0.88558512926101684570);
conePlanes[19].offset = 0.44279259443283081055;
conePlanes[20].normal = b3Vec3(0.63400888442993164063, 0.44279256463050842285, -0.63400906324386596680);
conePlanes[20].offset = 0.44279259443283081055;
centroid = b3Vec3(-0.00000003081002830641, -0.50000011920928955078, 0.00000003992893837790);
vertices = coneVertices;
vertexCount = 21;
edges = coneEdges;
edgeCount = 80;
faces = coneFaces;
planes = conePlanes;
faceCount = 21;
Validate();
}
// Construct this cylinder from radius and y extent centered at the origin.
void SetExtents(scalar radius, scalar ey)
{
SetIdentity();
b3Vec3 scale(radius, ey, radius);
Scale(scale);
}
};
extern const b3ConeHull b3ConeHull_identity;
#endif

View File

@@ -0,0 +1,322 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_CYLINDER_HULL_H
#define B3_CYLINDER_HULL_H
#include <bounce/collision/shapes/hull.h>
// A cylinder with 20 segments.
struct b3CylinderHull : public b3Hull
{
b3Vec3 cylinderVertices[40];
b3HalfEdge cylinderEdges[120];
b3Face cylinderFaces[22];
b3Plane cylinderPlanes[22];
// Does nothing for performance.
b3CylinderHull()
{
}
// Construct this cylinder from radius and y extent centered at the origin.
b3CylinderHull(scalar radius, scalar ey)
{
SetExtents(radius, ey);
}
// Set this cylinder to the unit cylinder centered at the origin.
void SetIdentity()
{
cylinderVertices[0] = b3Vec3(0.80901741981506347656, 1, 0.58778494596481323242);
cylinderVertices[1] = b3Vec3(-0.80901724100112915039, -1, -0.58778500556945800781);
cylinderVertices[2] = b3Vec3(-0.30901724100112915039, 1, -0.95105648040771484375);
cylinderVertices[3] = b3Vec3(0.30901747941970825195, 1, 0.95105648040771484375);
cylinderVertices[4] = b3Vec3(0.95105648040771484375, 1, -0.30901703238487243652);
cylinderVertices[5] = b3Vec3(-0.95105648040771484375, -1, 0.30901741981506347656);
cylinderVertices[6] = b3Vec3(0.58778512477874755859, -1, -0.80901706218719482422);
cylinderVertices[7] = b3Vec3(0.95105683803558349609, -1, 0.30901655554771423340);
cylinderVertices[8] = b3Vec3(-0.58778500556945800781, 1, 0.80901730060577392578);
cylinderVertices[9] = b3Vec3(0.30901747941970825195, -1, 0.95105648040771484375);
cylinderVertices[10] = b3Vec3(-0.30901724100112915039, -1, -0.95105648040771484375);
cylinderVertices[11] = b3Vec3(-0.95105648040771484375, 1, 0.30901741981506347656);
cylinderVertices[12] = b3Vec3(0.95105648040771484375, -1, -0.30901703238487243652);
cylinderVertices[13] = b3Vec3(0.58778512477874755859, 1, -0.80901706218719482422);
cylinderVertices[14] = b3Vec3(-0.80901724100112915039, 1, -0.58778500556945800781);
cylinderVertices[15] = b3Vec3(-0.58778500556945800781, -1, 0.80901730060577392578);
cylinderVertices[16] = b3Vec3(-0.30901664495468139648, -1, 0.95105671882629394531);
cylinderVertices[17] = b3Vec3(0.95105683803558349609, 1, 0.30901655554771423340);
cylinderVertices[18] = b3Vec3(-0.95105665922164916992, 1, -0.30901667475700378418);
cylinderVertices[19] = b3Vec3(0.30901682376861572266, 1, -0.95105654001235961914);
cylinderVertices[20] = b3Vec3(-0.95105665922164916992, -1, -0.30901667475700378418);
cylinderVertices[21] = b3Vec3(0.30901682376861572266, -1, -0.95105654001235961914);
cylinderVertices[22] = b3Vec3(0.80901741981506347656, -1, 0.58778494596481323242);
cylinderVertices[23] = b3Vec3(-0.30901664495468139648, 1, 0.95105671882629394531);
cylinderVertices[24] = b3Vec3(-0.80901682376861572266, 1, 0.58778566122055053711);
cylinderVertices[25] = b3Vec3(0.80901694297790527344, -1, -0.58778530359268188477);
cylinderVertices[26] = b3Vec3(-0.58778554201126098633, -1, -0.80901688337326049805);
cylinderVertices[27] = b3Vec3(0.58778578042984008789, -1, 0.80901682376861572266);
cylinderVertices[28] = b3Vec3(0.58778578042984008789, 1, 0.80901682376861572266);
cylinderVertices[29] = b3Vec3(-0.80901682376861572266, -1, 0.58778566122055053711);
cylinderVertices[30] = b3Vec3(0.80901694297790527344, 1, -0.58778530359268188477);
cylinderVertices[31] = b3Vec3(-0.58778554201126098633, 1, -0.80901688337326049805);
cylinderVertices[32] = b3Vec3(1, 1, 0);
cylinderVertices[33] = b3Vec3(0.00000044982880353928, -1, 1.00000011920928955078);
cylinderVertices[34] = b3Vec3(-1.00000011920928955078, 1, 0.00000039115548133850);
cylinderVertices[35] = b3Vec3(-0.00000022072345018387, -1, -1);
cylinderVertices[36] = b3Vec3(0.00000044982880353928, 1, 1.00000011920928955078);
cylinderVertices[37] = b3Vec3(-0.00000022072345018387, 1, -1);
cylinderVertices[38] = b3Vec3(1, -1, 0);
cylinderVertices[39] = b3Vec3(-1.00000011920928955078, -1, 0.00000039115548133850);
cylinderEdges[0] = b3MakeEdge(0, 1, 0, 6, 2);
cylinderEdges[1] = b3MakeEdge(22, 0, 1, 12, 8);
cylinderEdges[2] = b3MakeEdge(22, 3, 0, 0, 4);
cylinderEdges[3] = b3MakeEdge(7, 2, 4, 72, 13);
cylinderEdges[4] = b3MakeEdge(7, 5, 0, 2, 6);
cylinderEdges[5] = b3MakeEdge(17, 4, 16, 15, 73);
cylinderEdges[6] = b3MakeEdge(17, 7, 0, 4, 0);
cylinderEdges[7] = b3MakeEdge(0, 6, 2, 9, 14);
cylinderEdges[8] = b3MakeEdge(0, 9, 1, 1, 10);
cylinderEdges[9] = b3MakeEdge(28, 8, 2, 48, 7);
cylinderEdges[10] = b3MakeEdge(28, 11, 1, 8, 12);
cylinderEdges[11] = b3MakeEdge(27, 10, 9, 75, 49);
cylinderEdges[12] = b3MakeEdge(27, 13, 1, 10, 1);
cylinderEdges[13] = b3MakeEdge(22, 12, 4, 3, 74);
cylinderEdges[14] = b3MakeEdge(17, 15, 2, 7, 16);
cylinderEdges[15] = b3MakeEdge(32, 14, 16, 101, 5);
cylinderEdges[16] = b3MakeEdge(32, 17, 2, 14, 18);
cylinderEdges[17] = b3MakeEdge(4, 16, 10, 102, 100);
cylinderEdges[18] = b3MakeEdge(4, 19, 2, 16, 20);
cylinderEdges[19] = b3MakeEdge(30, 18, 11, 104, 103);
cylinderEdges[20] = b3MakeEdge(30, 21, 2, 18, 22);
cylinderEdges[21] = b3MakeEdge(13, 20, 15, 115, 105);
cylinderEdges[22] = b3MakeEdge(13, 23, 2, 20, 24);
cylinderEdges[23] = b3MakeEdge(19, 22, 14, 112, 114);
cylinderEdges[24] = b3MakeEdge(19, 25, 2, 22, 26);
cylinderEdges[25] = b3MakeEdge(37, 24, 21, 93, 113);
cylinderEdges[26] = b3MakeEdge(37, 27, 2, 24, 28);
cylinderEdges[27] = b3MakeEdge(2, 26, 6, 94, 92);
cylinderEdges[28] = b3MakeEdge(2, 29, 2, 26, 30);
cylinderEdges[29] = b3MakeEdge(31, 28, 7, 91, 95);
cylinderEdges[30] = b3MakeEdge(31, 31, 2, 28, 32);
cylinderEdges[31] = b3MakeEdge(14, 30, 5, 55, 90);
cylinderEdges[32] = b3MakeEdge(14, 33, 2, 30, 34);
cylinderEdges[33] = b3MakeEdge(18, 32, 3, 52, 54);
cylinderEdges[34] = b3MakeEdge(18, 35, 2, 32, 36);
cylinderEdges[35] = b3MakeEdge(34, 34, 20, 111, 53);
cylinderEdges[36] = b3MakeEdge(34, 37, 2, 34, 38);
cylinderEdges[37] = b3MakeEdge(11, 36, 13, 109, 110);
cylinderEdges[38] = b3MakeEdge(11, 39, 2, 36, 40);
cylinderEdges[39] = b3MakeEdge(24, 38, 12, 106, 108);
cylinderEdges[40] = b3MakeEdge(24, 41, 2, 38, 42);
cylinderEdges[41] = b3MakeEdge(8, 40, 17, 116, 107);
cylinderEdges[42] = b3MakeEdge(8, 43, 2, 40, 44);
cylinderEdges[43] = b3MakeEdge(23, 42, 18, 118, 117);
cylinderEdges[44] = b3MakeEdge(23, 45, 2, 42, 46);
cylinderEdges[45] = b3MakeEdge(36, 44, 19, 97, 119);
cylinderEdges[46] = b3MakeEdge(36, 47, 2, 44, 48);
cylinderEdges[47] = b3MakeEdge(3, 46, 8, 98, 96);
cylinderEdges[48] = b3MakeEdge(3, 49, 2, 46, 9);
cylinderEdges[49] = b3MakeEdge(28, 48, 9, 11, 99);
cylinderEdges[50] = b3MakeEdge(1, 51, 3, 54, 52);
cylinderEdges[51] = b3MakeEdge(20, 50, 4, 88, 56);
cylinderEdges[52] = b3MakeEdge(20, 53, 3, 50, 33);
cylinderEdges[53] = b3MakeEdge(18, 52, 20, 35, 89);
cylinderEdges[54] = b3MakeEdge(14, 55, 3, 33, 50);
cylinderEdges[55] = b3MakeEdge(1, 54, 5, 57, 31);
cylinderEdges[56] = b3MakeEdge(1, 57, 4, 51, 58);
cylinderEdges[57] = b3MakeEdge(26, 56, 5, 90, 55);
cylinderEdges[58] = b3MakeEdge(26, 59, 4, 56, 60);
cylinderEdges[59] = b3MakeEdge(10, 58, 7, 95, 91);
cylinderEdges[60] = b3MakeEdge(10, 61, 4, 58, 62);
cylinderEdges[61] = b3MakeEdge(35, 60, 6, 92, 94);
cylinderEdges[62] = b3MakeEdge(35, 63, 4, 60, 64);
cylinderEdges[63] = b3MakeEdge(21, 62, 21, 113, 93);
cylinderEdges[64] = b3MakeEdge(21, 65, 4, 62, 66);
cylinderEdges[65] = b3MakeEdge(6, 64, 14, 114, 112);
cylinderEdges[66] = b3MakeEdge(6, 67, 4, 64, 68);
cylinderEdges[67] = b3MakeEdge(25, 66, 15, 105, 115);
cylinderEdges[68] = b3MakeEdge(25, 69, 4, 66, 70);
cylinderEdges[69] = b3MakeEdge(12, 68, 11, 103, 104);
cylinderEdges[70] = b3MakeEdge(12, 71, 4, 68, 72);
cylinderEdges[71] = b3MakeEdge(38, 70, 10, 100, 102);
cylinderEdges[72] = b3MakeEdge(38, 73, 4, 70, 3);
cylinderEdges[73] = b3MakeEdge(7, 72, 16, 5, 101);
cylinderEdges[74] = b3MakeEdge(27, 75, 4, 13, 76);
cylinderEdges[75] = b3MakeEdge(9, 74, 9, 99, 11);
cylinderEdges[76] = b3MakeEdge(9, 77, 4, 74, 78);
cylinderEdges[77] = b3MakeEdge(33, 76, 8, 96, 98);
cylinderEdges[78] = b3MakeEdge(33, 79, 4, 76, 80);
cylinderEdges[79] = b3MakeEdge(16, 78, 19, 119, 97);
cylinderEdges[80] = b3MakeEdge(16, 81, 4, 78, 82);
cylinderEdges[81] = b3MakeEdge(15, 80, 18, 117, 118);
cylinderEdges[82] = b3MakeEdge(15, 83, 4, 80, 84);
cylinderEdges[83] = b3MakeEdge(29, 82, 17, 107, 116);
cylinderEdges[84] = b3MakeEdge(29, 85, 4, 82, 86);
cylinderEdges[85] = b3MakeEdge(5, 84, 12, 108, 106);
cylinderEdges[86] = b3MakeEdge(5, 87, 4, 84, 88);
cylinderEdges[87] = b3MakeEdge(39, 86, 13, 110, 109);
cylinderEdges[88] = b3MakeEdge(39, 89, 4, 86, 51);
cylinderEdges[89] = b3MakeEdge(20, 88, 20, 53, 111);
cylinderEdges[90] = b3MakeEdge(31, 91, 5, 31, 57);
cylinderEdges[91] = b3MakeEdge(26, 90, 7, 59, 29);
cylinderEdges[92] = b3MakeEdge(37, 93, 6, 27, 61);
cylinderEdges[93] = b3MakeEdge(35, 92, 21, 63, 25);
cylinderEdges[94] = b3MakeEdge(10, 95, 6, 61, 27);
cylinderEdges[95] = b3MakeEdge(2, 94, 7, 29, 59);
cylinderEdges[96] = b3MakeEdge(36, 97, 8, 47, 77);
cylinderEdges[97] = b3MakeEdge(33, 96, 19, 79, 45);
cylinderEdges[98] = b3MakeEdge(9, 99, 8, 77, 47);
cylinderEdges[99] = b3MakeEdge(3, 98, 9, 49, 75);
cylinderEdges[100] = b3MakeEdge(32, 101, 10, 17, 71);
cylinderEdges[101] = b3MakeEdge(38, 100, 16, 73, 15);
cylinderEdges[102] = b3MakeEdge(12, 103, 10, 71, 17);
cylinderEdges[103] = b3MakeEdge(4, 102, 11, 19, 69);
cylinderEdges[104] = b3MakeEdge(25, 105, 11, 69, 19);
cylinderEdges[105] = b3MakeEdge(30, 104, 15, 21, 67);
cylinderEdges[106] = b3MakeEdge(29, 107, 12, 85, 39);
cylinderEdges[107] = b3MakeEdge(24, 106, 17, 41, 83);
cylinderEdges[108] = b3MakeEdge(11, 109, 12, 39, 85);
cylinderEdges[109] = b3MakeEdge(5, 108, 13, 87, 37);
cylinderEdges[110] = b3MakeEdge(34, 111, 13, 37, 87);
cylinderEdges[111] = b3MakeEdge(39, 110, 20, 89, 35);
cylinderEdges[112] = b3MakeEdge(21, 113, 14, 65, 23);
cylinderEdges[113] = b3MakeEdge(19, 112, 21, 25, 63);
cylinderEdges[114] = b3MakeEdge(13, 115, 14, 23, 65);
cylinderEdges[115] = b3MakeEdge(6, 114, 15, 67, 21);
cylinderEdges[116] = b3MakeEdge(15, 117, 17, 83, 41);
cylinderEdges[117] = b3MakeEdge(8, 116, 18, 43, 81);
cylinderEdges[118] = b3MakeEdge(16, 119, 18, 81, 43);
cylinderEdges[119] = b3MakeEdge(23, 118, 19, 45, 79);
cylinderFaces[0].edge = 0;
cylinderFaces[1].edge = 8;
cylinderFaces[2].edge = 7;
cylinderFaces[3].edge = 50;
cylinderFaces[4].edge = 56;
cylinderFaces[5].edge = 55;
cylinderFaces[6].edge = 27;
cylinderFaces[7].edge = 95;
cylinderFaces[8].edge = 47;
cylinderFaces[9].edge = 99;
cylinderFaces[10].edge = 17;
cylinderFaces[11].edge = 103;
cylinderFaces[12].edge = 85;
cylinderFaces[13].edge = 109;
cylinderFaces[14].edge = 65;
cylinderFaces[15].edge = 115;
cylinderFaces[16].edge = 73;
cylinderFaces[17].edge = 41;
cylinderFaces[18].edge = 117;
cylinderFaces[19].edge = 79;
cylinderFaces[20].edge = 53;
cylinderFaces[21].edge = 113;
cylinderPlanes[0].normal = b3Vec3(0.89100682735443115234, 0, 0.45399010181427001953);
cylinderPlanes[0].offset = 0.98768866062164306641;
cylinderPlanes[1].normal = b3Vec3(0.70710718631744384766, 0, 0.70710641145706176758);
cylinderPlanes[1].offset = 0.98768854141235351563;
cylinderPlanes[2].normal = b3Vec3(0, 1, 0);
cylinderPlanes[2].offset = 1;
cylinderPlanes[3].normal = b3Vec3(-0.89100670814514160156, 0, -0.45399013161659240723);
cylinderPlanes[3].offset = 0.98768842220306396484;
cylinderPlanes[4].normal = b3Vec3(0, -1, 0);
cylinderPlanes[4].offset = 1;
cylinderPlanes[5].normal = b3Vec3(-0.70710712671279907227, 0, -0.70710653066635131836);
cylinderPlanes[5].offset = 0.98768848180770874023;
cylinderPlanes[6].normal = b3Vec3(-0.15643458068370819092, 0, -0.98768836259841918945);
cylinderPlanes[6].offset = 0.98768842220306396484;
cylinderPlanes[7].normal = b3Vec3(-0.45399063825607299805, 0, -0.89100646972656250000);
cylinderPlanes[7].offset = 0.98768842220306396484;
cylinderPlanes[8].normal = b3Vec3(0.15643493831157684326, 0, 0.98768830299377441406);
cylinderPlanes[8].offset = 0.98768848180770874023;
cylinderPlanes[9].normal = b3Vec3(0.45399075746536254883, 0, 0.89100635051727294922);
cylinderPlanes[9].offset = 0.98768836259841918945;
cylinderPlanes[10].normal = b3Vec3(0.98768830299377441406, 0, -0.15643455088138580322);
cylinderPlanes[10].offset = 0.98768830299377441406;
cylinderPlanes[11].normal = b3Vec3(0.89100646972656250000, 0, -0.45399051904678344727);
cylinderPlanes[11].offset = 0.98768830299377441406;
cylinderPlanes[12].normal = b3Vec3(-0.89100635051727294922, 0, 0.45399084687232971191);
cylinderPlanes[12].offset = 0.98768842220306396484;
cylinderPlanes[13].normal = b3Vec3(-0.98768830299377441406, 0, 0.15643493831157684326);
cylinderPlanes[13].offset = 0.98768842220306396484;
cylinderPlanes[14].normal = b3Vec3(0.45399031043052673340, 0, -0.89100658893585205078);
cylinderPlanes[14].offset = 0.98768830299377441406;
cylinderPlanes[15].normal = b3Vec3(0.70710670948028564453, 0, -0.70710688829421997070);
cylinderPlanes[15].offset = 0.98768830299377441406;
cylinderPlanes[16].normal = b3Vec3(0.98768848180770874023, 0, 0.15643368661403656006);
cylinderPlanes[16].offset = 0.98768854141235351563;
cylinderPlanes[17].normal = b3Vec3(-0.70710653066635131836, 0, 0.70710712671279907227);
cylinderPlanes[17].offset = 0.98768854141235351563;
cylinderPlanes[18].normal = b3Vec3(-0.45399010181427001953, 0, 0.89100670814514160156);
cylinderPlanes[18].offset = 0.98768842220306396484;
cylinderPlanes[19].normal = b3Vec3(-0.15643416345119476318, 0, 0.98768842220306396484);
cylinderPlanes[19].offset = 0.98768848180770874023;
cylinderPlanes[20].normal = b3Vec3(-0.98768842220306396484, 0, -0.15643437206745147705);
cylinderPlanes[20].offset = 0.98768848180770874023;
cylinderPlanes[21].normal = b3Vec3(0.15643437206745147705, 0, -0.98768842220306396484);
cylinderPlanes[21].offset = 0.98768836259841918945;
centroid = b3Vec3(0, 0, 0);
vertices = cylinderVertices;
vertexCount = 40;
edges = cylinderEdges;
edgeCount = 120;
faces = cylinderFaces;
planes = cylinderPlanes;
faceCount = 22;
Validate();
}
// Construct this cylinder from radius and y extent centered at the origin.
void SetExtents(scalar radius, scalar ey)
{
SetIdentity();
b3Vec3 scale(radius, ey, radius);
Scale(scale);
}
};
extern const b3CylinderHull b3CylinderHull_identity;
#endif

View File

@@ -26,28 +26,30 @@
template<u32 H = 1, u32 W = 1>
struct b3GridMesh : public b3Mesh
{
b3Vec3 gridVertices[ (H + 1) * (W + 1) ];
b3Triangle gridTriangles[2 * H * W];
b3Vec3 gridVertices[(H + 1) * (W + 1)];
b3MeshTriangle gridTriangles[2 * H * W];
// Set this grid to a W (width) per H (height) dimensioned grid centered at the origin and aligned
// with the world x-z axes.
b3GridMesh()
{
vertexCount = 0;
for (u32 i = 0; i <= H; ++i)
for (u32 j = 0; j <= W; ++j)
{
for (u32 j = 0; j <= W; ++j)
for (u32 i = 0; i <= H; ++i)
{
gridVertices[vertexCount++].Set(float32(j), 0.0f, float32(i));
u32 vertex = GetVertex(i, j);
gridVertices[vertex].Set(scalar(j), 0, scalar(i));
++vertexCount;
}
}
B3_ASSERT(vertexCount == (H + 1) * (W + 1));
b3Vec3 translation;
translation.x = -0.5f * float32(W);
translation.y = 0.0f;
translation.z = -0.5f * float32(H);
translation.x = scalar(-0.5) * scalar(W);
translation.y = 0;
translation.z = scalar(-0.5) * scalar(H);
for (u32 i = 0; i < vertexCount; ++i)
{
@@ -59,20 +61,23 @@ struct b3GridMesh : public b3Mesh
{
for (u32 j = 0; j < W; ++j)
{
u32 v1 = i * (W + 1) + j;
u32 v2 = (i + 1) * (W + 1) + j;
u32 v3 = (i + 1) * (W + 1) + (j + 1);
u32 v4 = i * (W + 1) + (j + 1);
// 1*|----|*4
// |----|
// 2*|----|*3
u32 v1 = GetVertex(i, j);
u32 v2 = GetVertex(i + 1, j);
u32 v3 = GetVertex(i + 1, j + 1);
u32 v4 = GetVertex(i, j + 1);
b3Triangle* t1 = gridTriangles + triangleCount++;
t1->v1 = v3;
b3MeshTriangle* t1 = gridTriangles + triangleCount++;
t1->v1 = v1;
t1->v2 = v2;
t1->v3 = v1;
t1->v3 = v3;
b3Triangle* t2 = gridTriangles + triangleCount++;
t2->v1 = v1;
b3MeshTriangle* t2 = gridTriangles + triangleCount++;
t2->v1 = v3;
t2->v2 = v4;
t2->v3 = v3;
t2->v3 = v1;
}
}
@@ -81,6 +86,13 @@ struct b3GridMesh : public b3Mesh
vertices = gridVertices;
triangles = gridTriangles;
}
u32 GetVertex(u32 i, u32 j)
{
B3_ASSERT(i < H + 1);
B3_ASSERT(j < W + 1);
return i * (W + 1) + j;
}
};
#endif

View File

@@ -31,6 +31,7 @@ struct b3HalfEdge
u32 origin;
u32 twin;
u32 face;
u32 prev;
u32 next;
};
@@ -61,6 +62,15 @@ struct b3Hull
void Validate() const;
void Validate(const b3Face* face) const;
void Validate(const b3HalfEdge* edge) const;
void Dump() const;
void Scale(const b3Vec3& scale);
void Rotate(const b3Quat& rotation);
void Translate(const b3Vec3& translation);
// Scale -> Rotate -> Translate
void Transform(const b3Transform& xf, const b3Vec3& scale);
};
#include <bounce/collision/shapes/hull.inl>

View File

@@ -1,9 +1,10 @@
inline b3HalfEdge b3MakeEdge(u32 origin, u32 twin, u32 face, u32 next)
inline b3HalfEdge b3MakeEdge(u32 origin, u32 twin, u32 face, u32 prev, u32 next)
{
b3HalfEdge edge;
edge.origin = origin;
edge.twin = twin;
edge.face = face;
edge.prev = prev;
edge.next = next;
return edge;
}
@@ -31,10 +32,10 @@ inline const b3Plane& b3Hull::GetPlane(u32 index) const
inline u32 b3Hull::GetSupportVertex(const b3Vec3& direction) const
{
u32 maxIndex = 0;
float32 maxProjection = b3Dot(direction, vertices[maxIndex]);
scalar maxProjection = b3Dot(direction, vertices[maxIndex]);
for (u32 i = 1; i < vertexCount; ++i)
{
float32 projection = b3Dot(direction, vertices[i]);
scalar projection = b3Dot(direction, vertices[i]);
if (projection > maxProjection)
{
maxIndex = i;
@@ -47,10 +48,10 @@ inline u32 b3Hull::GetSupportVertex(const b3Vec3& direction) const
inline u32 b3Hull::GetSupportFace(const b3Vec3& direction) const
{
u32 maxIndex = 0;
float32 maxProjection = b3Dot(direction, planes[maxIndex].normal);
scalar maxProjection = b3Dot(direction, planes[maxIndex].normal);
for (u32 i = 1; i < faceCount; ++i)
{
float32 projection = b3Dot(direction, planes[i].normal);
scalar projection = b3Dot(direction, planes[i].normal);
if (projection > maxProjection)
{
maxIndex = i;

View File

@@ -19,40 +19,72 @@
#ifndef B3_MESH_H
#define B3_MESH_H
#include <bounce/common/geometry.h>
#include <bounce/collision/trees/static_tree.h>
struct b3Triangle
#define B3_NULL_VERTEX B3_MAX_U32
// Mesh triangle.
struct b3MeshTriangle
{
// Test if this triangle contains a given vertex.
bool TestVertex(u32 v) const
{
return v == v1 || v == v2 || v == v3;
}
// Write an indexed vertex to this triangle.
u32& GetVertex(u32 i) { return (&v1)[i]; }
// Test if this triangle contains two vertices.
bool TestEdge(u32 _v1, u32 _v2) const
{
return TestVertex(_v1) && TestVertex(_v2);
}
// Read an indexed vertex from this triangle.
u32 GetVertex(u32 i) const { return (&v1)[i]; }
// The triangle vertices in the mesh.
u32 v1, v2, v3;
};
// Mesh triangle adjacency.
// This is used for smooth edge collision.
struct b3MeshTriangleWings
{
// Write an indexed edge wing vertex to this triangle.
u32& GetVertex(u32 i) { return (&u1)[i]; }
// Read an indexed edge wing vertex from this triangle.
u32 GetVertex(u32 i) const { return (&u1)[i]; }
// The wing vertex of each edge in this triangle.
// An edge is a boundary if its wing vertex is set to B3_NULL_VERTEX.
u32 u1, u2, u3;
};
struct b3Mesh
{
u32 vertexCount;
b3Vec3* vertices;
u32 triangleCount;
b3Triangle* triangles;
b3MeshTriangle* triangles;
b3MeshTriangleWings* triangleWings;
b3StaticTree tree;
b3Mesh();
~b3Mesh();
// Build the static AABB tree.
void BuildTree();
// Build mesh adjacency.
// This won't work properly if there are non-manifold edges.
void BuildAdjacency();
const b3Vec3& GetVertex(u32 index) const;
const b3Triangle& GetTriangle(u32 index) const;
const b3MeshTriangle* GetTriangle(u32 index) const;
const b3MeshTriangleWings* GetTriangleWings(u32 index) const;
b3AABB GetTriangleAABB(u32 index) const;
u32 GetSize() const;
b3AABB3 GetTriangleAABB(u32 index) const;
void Scale(const b3Vec3& scale);
void Rotate(const b3Quat& rotation);
void Translate(const b3Vec3& translation);
void BuildTree();
// Scale -> Rotate -> Translate
void Transform(const b3Transform& xf, const b3Vec3& scale);
};
inline const b3Vec3& b3Mesh::GetVertex(u32 index) const
@@ -60,9 +92,24 @@ inline const b3Vec3& b3Mesh::GetVertex(u32 index) const
return vertices[index];
}
inline const b3Triangle& b3Mesh::GetTriangle(u32 index) const
inline const b3MeshTriangle* b3Mesh::GetTriangle(u32 index) const
{
return triangles[index];
return triangles + index;
}
inline const b3MeshTriangleWings* b3Mesh::GetTriangleWings(u32 index) const
{
return triangleWings + index;
}
inline b3AABB b3Mesh::GetTriangleAABB(u32 index) const
{
const b3MeshTriangle* triangle = triangles + index;
b3AABB aabb;
aabb.SetTriangle(vertices[triangle->v1], vertices[triangle->v2], vertices[triangle->v3]);
return aabb;
}
inline u32 b3Mesh::GetSize() const
@@ -70,32 +117,10 @@ inline u32 b3Mesh::GetSize() const
u32 size = 0;
size += sizeof(b3Mesh);
size += sizeof(b3Vec3) * vertexCount;
size += sizeof(b3Triangle) * triangleCount;
size += sizeof(b3MeshTriangle) * triangleCount;
size += sizeof(b3MeshTriangleWings) * triangleCount;
size += tree.GetSize();
return size;
}
inline b3AABB3 b3Mesh::GetTriangleAABB(u32 index) const
{
const b3Triangle* triangle = triangles + index;
b3AABB3 aabb;
aabb.Set(vertices[triangle->v1], vertices[triangle->v2], vertices[triangle->v3]);
return aabb;
}
inline void b3Mesh::BuildTree()
{
b3AABB3* aabbs = (b3AABB3*)b3Alloc(triangleCount * sizeof(b3AABB3));
for (u32 i = 0; i < triangleCount; ++i)
{
aabbs[i] = GetTriangleAABB(i);
}
tree.Build(aabbs, triangleCount);
b3Free(aabbs);
}
#endif
#endif

View File

@@ -52,15 +52,15 @@ struct b3QHull : public b3Hull
// Set this hull as a sphere located at the origin
// given the radius.
void SetAsSphere(float32 radius = 1.0f);
void SetAsSphere(scalar radius = 1, u32 subdivisions = 0);
// Set this hull as a cylinder located at the origin
// given the radius and extent along the y axis.
void SetAsCylinder(float32 radius = 1.0f, float32 ey = 1.0f);
// given the radius, extent along the y axis, and number of segments.
void SetAsCylinder(scalar radius = 1, scalar ey = 1, u32 segments = 20);
// Set this hull as a cone located at the origin
// given the radius and extent along the y axis.
void SetAsCone(float32 radius = 1.0f, float32 ey = 1.0f);
// given the radius, extent along the y axis, and number of segments.
void SetAsCone(scalar radius = 1, scalar ey = 1, u32 segments = 20);
};
#endif

View File

@@ -0,0 +1,168 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_SDF_H
#define B3_SDF_H
#include <bounce/collision/shapes/aabb.h>
struct b3MultiIndex
{
unsigned int& operator[](unsigned int i)
{
return v[i];
}
const unsigned int& operator[](unsigned int i) const
{
return v[i];
}
unsigned int v[3];
};
struct b3Cell32
{
unsigned int v[32];
};
// This class stores a discretized signed distance function (SDF)
// generated by Discregrid.
// Discregrid is available at https://github.com/InteractiveComputerGraphics/Discregrid
// Inside Discregrid, there is a tool called GenerateSDF that can
// generate an SDF of a triangle mesh stored in .obj file format.
// You may call this tool from a command line.
// For example, the following command will generate an SDF for a given .obj mesh.
// GenerateSDF -r "32 32 32" -d "-5 -5 -5 5 5 5" teapot.obj
// The parameters are:
// 1. r - resolution
// 2. d - domain (an AABB)
// 3. input filename
// You will need to set a reasonable large domain depending on the radius of
// the vertices that can collide against the SDF because the SDF
// can only return valid output values for points that are inside the domain.
// Therefore, its a good idea to set the domain to the AABB containing the
// associated object extended by twice the largest vertex radius that can collide against this SDF.
// Generally, the greater the SDF resolution the more accurate is the result of the signed distance function.
class b3SDF
{
public:
// Construct this SDF
b3SDF();
// Destruct this SDF
~b3SDF();
// Read this SDF from a .cdf (binary) file given the filename.
// Returns true if this SDF was loaded sucessfuly and false otherwise.
bool Load(const char* filename);
// Return the domain (AABB) of this SDF.
const b3AABB& GetDomain() const
{
return m_domain;
}
// Evaluate the signed distance function for a point if the point is inside the domain of this SDF.
// Optionally output the normal at the SDF boundary.
// Return true if the output values are valid and false otherwise.
bool Evaluate(const b3Vec3& point, double& distance, b3Vec3* normal = nullptr) const
{
return interpolate(0, distance, point, normal);
}
private:
bool interpolate(unsigned int field_id, double& dist, b3Vec3 const& x, b3Vec3* gradient = nullptr) const;
b3MultiIndex singleToMultiIndex(unsigned int i) const;
unsigned int multiToSingleIndex(b3MultiIndex const& ijk) const;
b3AABB subdomain(b3MultiIndex const& ijk) const;
b3AABB subdomain(unsigned int l) const;
b3AABB m_domain;
unsigned int m_resolution[3];
b3Vec3 m_cell_size;
b3Vec3 m_inv_cell_size;
std::size_t m_n_cells;
std::size_t m_n_fields;
struct b3SDFNodeArray
{
double& operator[](u32 i)
{
B3_ASSERT(i < count);
return values[i];
}
const double& operator[](u32 i) const
{
B3_ASSERT(i < count);
return values[i];
}
u32 count;
double* values;
};
struct b3SDFCellArray
{
b3Cell32& operator[](u32 i)
{
B3_ASSERT(i < count);
return values[i];
}
const b3Cell32& operator[](u32 i) const
{
B3_ASSERT(i < count);
return values[i];
}
u32 count;
b3Cell32* values;
};
struct b3SDFCellMapArray
{
unsigned int& operator[](u32 i)
{
B3_ASSERT(i < count);
return values[i];
}
const unsigned int& operator[](u32 i) const
{
B3_ASSERT(i < count);
return values[i];
}
u32 count;
unsigned int* values;
};
u32 m_nodeCount;
b3SDFNodeArray* m_nodes;
u32 m_cellCount;
b3SDFCellArray* m_cells;
u32 m_cellMapCount;
b3SDFCellMapArray* m_cell_map;
};
#endif

View File

@@ -27,7 +27,7 @@ struct b3Sphere
b3Sphere() { }
//
b3Sphere(const b3Vec3& v, float32 r)
b3Sphere(const b3Vec3& v, scalar r)
{
vertex = v;
radius = r;
@@ -37,7 +37,7 @@ struct b3Sphere
~b3Sphere() { }
b3Vec3 vertex;
float32 radius;
scalar radius;
const b3Vec3& GetVertex(u32 index) const;
u32 GetSupportVertex(const b3Vec3& direction) const;

View File

@@ -37,20 +37,20 @@ struct b3TriangleHull : public b3Hull
void Set(const b3Vec3& A, const b3Vec3& B, const b3Vec3& C)
{
centroid = (A + B + C) / 3.0f;
centroid = (A + B + C) / scalar(3);
triangleVertices[0] = A;
triangleVertices[1] = B;
triangleVertices[2] = C;
// Each edge must be followed by its twin.
triangleEdges[0] = b3MakeEdge(0, 1, 0, 2); // Face 0 - Edge 0
triangleEdges[2] = b3MakeEdge(1, 3, 0, 4); // Face 0 - Edge 1
triangleEdges[4] = b3MakeEdge(2, 5, 0, 0); // Face 0 - Edge 2
triangleEdges[0] = b3MakeEdge(0, 1, 0, 4, 2); // Face 0 - Edge 0
triangleEdges[2] = b3MakeEdge(1, 3, 0, 0, 4); // Face 0 - Edge 1
triangleEdges[4] = b3MakeEdge(2, 5, 0, 2, 0); // Face 0 - Edge 2
triangleEdges[1] = b3MakeEdge(1, 0, 1, 3); // Face 1 - Edge 0
triangleEdges[3] = b3MakeEdge(2, 2, 1, 5); // Face 1 - Edge 1
triangleEdges[5] = b3MakeEdge(0, 4, 1, 1); // Face 1 - Edge 2
triangleEdges[1] = b3MakeEdge(1, 0, 1, 3, 5); // Face 1 - Edge 0
triangleEdges[3] = b3MakeEdge(2, 2, 1, 5, 1); // Face 1 - Edge 1
triangleEdges[5] = b3MakeEdge(0, 4, 1, 1, 3); // Face 1 - Edge 2
triangleFaces[0].edge = 0;
triangleFaces[1].edge = 1;

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2016-2019 Irlan Robson https://irlanrobson.github.io
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B3_TIME_OF_IMPACT_H
#define B3_TIME_OF_IMPACT_H
#include <bounce/collision/gjk/gjk_proxy.h>
#include <bounce/collision/shapes/aabb.h>
#include <bounce/common/math/transform.h>
// Input parameters for b3TimeOfImpact
struct b3TOIInput
{
b3GJKProxy proxyA;
b3GJKProxy proxyB;
b3Sweep sweepA;
b3Sweep sweepB;
scalar tMax; // sweep interval in [0, 1]
};
// Output parameters of b3TimeOfImpact
struct b3TOIOutput
{
enum State
{
e_unknown,
e_failed,
e_overlapped,
e_touching,
e_separated
};
State state;
scalar t;
u32 iterations;
};
// Compute the time of impact between two shapes.
// This is represented as a fraction between [0, tMax].
// Use b3GJK to compute the contact point and normal at the time of impact.
b3TOIOutput b3TimeOfImpact(const b3TOIInput& input);
// Compute the time of impact between two shapes.
// This is represented as a fraction between [0, 1].
// You must supply the linear displacements of each shape.
// Use b3GJK to compute the contact point and normal at the time of impact.
b3TOIOutput b3TimeOfImpact(const b3Transform& xf1, const b3GJKProxy& proxy1, const b3Vec3& d1,
const b3Transform& xf2, const b3GJKProxy& proxy2, const b3Vec3& d2,
u32 maxIterations = 20);
// Compute the time of impact between two AABBs.
// This is represented as a fraction between [0, 1].
// You must supply the linear displacements of each AABB center.
b3TOIOutput b3TimeOfImpact(const b3AABB& aabb1, const b3Vec3& d1, const b3AABB& aabb2, const b3Vec3& d2);
#endif

View File

@@ -20,29 +20,29 @@
#define B3_DYNAMIC_TREE_H
#include <bounce/common/template/stack.h>
#include <bounce/collision/shapes/aabb3.h>
#include <bounce/collision/shapes/aabb.h>
#include <bounce/collision/collision.h>
#define B3_NULL_NODE_D (0xFFFFFFFF)
// AABB tree for dynamic AABBs.
class b3DynamicTree
class b3DynamicTree
{
public :
public:
b3DynamicTree();
~b3DynamicTree();
// Insert a node into the tree and return its ID.
u32 InsertNode(const b3AABB3& aabb, void* userData);
u32 InsertNode(const b3AABB& aabb, void* userData);
// Remove a node from the tree.
void RemoveNode(u32 proxyId);
// Update a node AABB.
void UpdateNode(u32 proxyId, const b3AABB3& aabb);
void UpdateNode(u32 proxyId, const b3AABB& aabb);
// Get the (fat) AABB of a given proxy.
const b3AABB3& GetAABB(u32 proxyId) const;
const b3AABB& GetAABB(u32 proxyId) const;
// Get the data associated with a given proxy.
void* GetUserData(u32 proxyId) const;
@@ -53,8 +53,8 @@ public :
// Keep reporting the client callback the AABBs that are overlapping with
// the given AABB. The client callback must return true if the query
// must be stopped or false to continue looking for more overlapping pairs.
template<class T>
void QueryAABB(T* callback, const b3AABB3& aabb) const;
template<class T>
void QueryAABB(T* callback, const b3AABB& aabb) const;
// Keep reporting the client callback all AABBs that are overlapping with
// the given ray. The client callback must return the new intersection fraction.
@@ -67,23 +67,23 @@ public :
// Draw this tree.
void Draw() const;
private :
struct b3Node
private:
struct b3Node
{
// Is this node a leaf?
bool IsLeaf() const
bool IsLeaf() const
{
//A node is a leaf if child 2 == B3_NULL_NODE_D or height == 0.
return child1 == B3_NULL_NODE_D;
}
// The fattened node AABB.
b3AABB3 aabb;
b3AABB aabb;
// The associated user data.
void* userData;
union
union
{
u32 parent;
u32 next;
@@ -96,18 +96,18 @@ private :
// leaf if 0, free node if -1
i32 height;
};
// Insert a node into the tree.
void InsertLeaf(u32 node);
// Remove a node from the tree.
void RemoveLeaf(u32 node);
// Rebuild the hierarchy starting from the given node.
void WalkBackNodeAndCombineVolumes(u32 node);
// Find the best node that can be merged with a given AABB.
u32 FindBest(const b3AABB3& aabb) const;
void Refit(u32 node);
// Pick the best node that can be merged with a given AABB.
u32 PickBest(const b3AABB& aabb) const;
// Peel a node from the free list and insert into the node array.
// Allocate a new node if necessary. The function returns the new node index.
@@ -129,7 +129,7 @@ private :
u32 m_freeList;
};
inline const b3AABB3& b3DynamicTree::GetAABB(u32 proxyId) const
inline const b3AABB& b3DynamicTree::GetAABB(u32 proxyId) const
{
B3_ASSERT(proxyId != B3_NULL_NODE_D && proxyId < m_nodeCapacity);
return m_nodes[proxyId].aabb;
@@ -149,12 +149,12 @@ inline bool b3DynamicTree::TestOverlap(u32 proxy1, u32 proxy2) const
}
template<class T>
inline void b3DynamicTree::QueryAABB(T* callback, const b3AABB3& aabb) const
inline void b3DynamicTree::QueryAABB(T* callback, const b3AABB& aabb) const
{
b3Stack<u32, 256> stack;
stack.Push(m_root);
while (stack.IsEmpty() == false)
while (stack.IsEmpty() == false)
{
u32 nodeIndex = stack.Top();
stack.Pop();
@@ -166,16 +166,16 @@ inline void b3DynamicTree::QueryAABB(T* callback, const b3AABB3& aabb) const
const b3Node* node = m_nodes + nodeIndex;
if (b3TestOverlap(node->aabb, aabb) == true)
if (b3TestOverlap(node->aabb, aabb) == true)
{
if (node->IsLeaf() == true)
if (node->IsLeaf() == true)
{
if (callback->Report(nodeIndex) == false)
if (callback->Report(nodeIndex) == false)
{
return;
}
}
else
else
{
stack.Push(node->child1);
stack.Push(node->child2);
@@ -185,55 +185,142 @@ inline void b3DynamicTree::QueryAABB(T* callback, const b3AABB3& aabb) const
}
template<class T>
inline void b3DynamicTree::RayCast(T* callback, const b3RayCastInput& input) const
inline void b3DynamicTree::RayCast(T* callback, const b3RayCastInput& input) const
{
b3Vec3 p1 = input.p1;
b3Vec3 p2 = input.p2;
b3Vec3 d = p2 - p1;
float32 maxFraction = input.maxFraction;
b3Vec3 r = p2 - p1;
B3_ASSERT(b3LengthSquared(r) > scalar(0));
r.Normalize();
scalar maxFraction = input.maxFraction;
// Build an AABB for the segment.
b3Vec3 q2;
b3AABB segmentAABB;
{
q2 = p1 + maxFraction * (p2 - p1);
segmentAABB.lowerBound = b3Min(p1, q2);
segmentAABB.upperBound = b3Max(p1, q2);
}
// Ensure non-degenerate segment.
B3_ASSERT(b3Dot(d, d) > B3_EPSILON * B3_EPSILON);
b3Vec3 e1 = b3Vec3_x;
b3Vec3 e2 = b3Vec3_y;
b3Vec3 e3 = b3Vec3_z;
b3Stack<u32, 256> stack;
stack.Push(m_root);
while (stack.IsEmpty() == false)
while (stack.IsEmpty() == false)
{
u32 nodeIndex = stack.Top();
stack.Pop();
if (nodeIndex == B3_NULL_NODE_D)
if (nodeIndex == B3_NULL_NODE_D)
{
continue;
}
const b3Node* node = m_nodes + nodeIndex;
float32 minFraction;
if (node->aabb.TestRay(minFraction, p1, p2, maxFraction) == true)
if (b3TestOverlap(segmentAABB, node->aabb) == false)
{
if (node->IsLeaf() == true)
{
b3RayCastInput subInput;
subInput.p1 = input.p1;
subInput.p2 = input.p2;
subInput.maxFraction = maxFraction;
continue;
}
// Separating axis for segment (Gino, p80).
b3Vec3 c = node->aabb.GetCenter();
b3Vec3 h = node->aabb.GetExtents();
float32 newFraction = callback->Report(subInput, nodeIndex);
b3Vec3 s = p1 - c;
b3Vec3 t = q2 - c;
if (newFraction == 0.0f)
{
// The client has stopped the query.
return;
}
}
else
// |sigma + tau| > |sigma - tau| + 2 * eta
scalar sigma_1 = s.x;
scalar tau_1 = t.x;
scalar eta_1 = h.x;
scalar s1 = b3Abs(sigma_1 + tau_1) - (b3Abs(sigma_1 - tau_1) + scalar(2) * eta_1);
if (s1 > scalar(0))
{
continue;
}
scalar sigma_2 = s.y;
scalar tau_2 = t.y;
scalar eta_2 = h.y;
scalar s2 = b3Abs(sigma_2 + tau_2) - (b3Abs(sigma_2 - tau_2) + scalar(2) * eta_2);
if (s2 > scalar(0))
{
continue;
}
scalar sigma_3 = s.z;
scalar tau_3 = t.z;
scalar eta_3 = h.z;
scalar s3 = b3Abs(sigma_3 + tau_3) - (b3Abs(sigma_3 - tau_3) + scalar(2) * eta_3);
if (s3 > scalar(0))
{
continue;
}
// v = cross(ei, r)
// |dot(v, s)| > dot(|v|, h)
b3Vec3 v1 = b3Cross(e1, r);
b3Vec3 abs_v1 = b3Abs(v1);
scalar s4 = b3Abs(b3Dot(v1, s)) - b3Dot(abs_v1, h);
if (s4 > scalar(0))
{
continue;
}
b3Vec3 v2 = b3Cross(e2, r);
b3Vec3 abs_v2 = b3Abs(v2);
scalar s5 = b3Abs(b3Dot(v2, s)) - b3Dot(abs_v2, h);
if (s5 > scalar(0))
{
continue;
}
b3Vec3 v3 = b3Cross(e3, r);
b3Vec3 abs_v3 = b3Abs(v3);
scalar s6 = b3Abs(b3Dot(v3, s)) - b3Dot(abs_v3, h);
if (s6 > scalar(0))
{
continue;
}
if (node->IsLeaf() == true)
{
b3RayCastInput subInput;
subInput.p1 = input.p1;
subInput.p2 = input.p2;
subInput.maxFraction = maxFraction;
scalar newMaxFraction = callback->Report(subInput, nodeIndex);
if (newMaxFraction == scalar(0))
{
stack.Push(node->child1);
stack.Push(node->child2);
// The client has stopped the query.
return;
}
if (newMaxFraction > scalar(0))
{
// Update the segment AABB.
maxFraction = newMaxFraction;
q2 = p1 + maxFraction * (p2 - p1);
segmentAABB.lowerBound = b3Min(p1, q2);
segmentAABB.upperBound = b3Max(p1, q2);
}
}
else
{
stack.Push(node->child1);
stack.Push(node->child2);
}
}
}

View File

@@ -20,7 +20,7 @@
#define B3_STATIC_TREE_H
#include <bounce/common/template/stack.h>
#include <bounce/collision/shapes/aabb3.h>
#include <bounce/collision/shapes/aabb.h>
#include <bounce/collision/collision.h>
#define B3_NULL_NODE_S (0xFFFFFFFF)
@@ -33,10 +33,10 @@ public:
~b3StaticTree();
// Build this tree from a list of AABBs.
void Build(const b3AABB3* aabbs, u32 count);
void Build(const b3AABB* aabbs, u32 count);
// Get the AABB of a given proxy.
const b3AABB3& GetAABB(u32 proxyId) const;
const b3AABB& GetAABB(u32 proxyId) const;
// Get the user data associated with a given proxy.
u32 GetUserData(u32 proxyId) const;
@@ -45,7 +45,7 @@ public:
// the given AABB. The client callback must return true if the query
// must be stopped or false to continue looking for more overlapping pairs.
template<class T>
void QueryAABB(T* callback, const b3AABB3& aabb) const;
void QueryAABB(T* callback, const b3AABB& aabb) const;
// Report the client callback all AABBs that are overlapping with
// the given ray. The client callback must return the new intersection fraction
@@ -56,12 +56,13 @@ public:
// Draw this tree.
void Draw() const;
// Get the size in bytes of this tree.
u32 GetSize() const;
private :
// A node in a static tree.
struct b3Node
{
b3AABB3 aabb;
b3AABB aabb;
u32 child1;
union
{
@@ -76,15 +77,18 @@ private :
}
};
//
void Build(const b3AABB3* set, b3Node* node, u32* indices, u32 count, u32 minObjectsPerLeaf, u32 nodeCapacity, u32& leafCount, u32& internalCount);
// Build this tree recursively.
void RecurseBuild(const b3AABB* set, b3Node* node, u32* indices, u32 count, u32 minObjectsPerLeaf, u32 nodeCapacity, u32& leafCount, u32& internalCount);
// The root of this tree.
u32 m_root;
// The nodes of this tree stored in an array.
u32 m_nodeCount;
b3Node* m_nodes;
};
inline const b3AABB3& b3StaticTree::GetAABB(u32 proxyId) const
inline const b3AABB& b3StaticTree::GetAABB(u32 proxyId) const
{
B3_ASSERT(proxyId < m_nodeCount);
return m_nodes[proxyId].aabb;
@@ -98,17 +102,15 @@ inline u32 b3StaticTree::GetUserData(u32 proxyId) const
}
template<class T>
inline void b3StaticTree::QueryAABB(T* callback, const b3AABB3& aabb) const
inline void b3StaticTree::QueryAABB(T* callback, const b3AABB& aabb) const
{
if (m_nodeCount == 0)
{
return;
}
u32 root = 0;
b3Stack<u32, 256> stack;
stack.Push(root);
stack.Push(m_root);
while (stack.IsEmpty() == false)
{
@@ -151,20 +153,32 @@ inline void b3StaticTree::RayCast(T* callback, const b3RayCastInput& input) cons
b3Vec3 p1 = input.p1;
b3Vec3 p2 = input.p2;
b3Vec3 d = p2 - p1;
float32 maxFraction = input.maxFraction;
b3Vec3 r = p2 - p1;
B3_ASSERT(b3LengthSquared(r) > scalar(0));
r.Normalize();
// Ensure non-degenerate segment.
B3_ASSERT(b3Dot(d, d) > B3_EPSILON * B3_EPSILON);
scalar maxFraction = input.maxFraction;
u32 root = 0;
// Build an AABB for the segment.
b3Vec3 q2;
b3AABB segmentAABB;
{
q2 = p1 + maxFraction * (p2 - p1);
segmentAABB.lowerBound = b3Min(p1, q2);
segmentAABB.upperBound = b3Max(p1, q2);
}
b3Vec3 e1 = b3Vec3_x;
b3Vec3 e2 = b3Vec3_y;
b3Vec3 e3 = b3Vec3_z;
b3Stack<u32, 256> stack;
stack.Push(root);
while (stack.IsEmpty() == false)
stack.Push(m_root);
while (stack.IsEmpty() == false)
{
u32 nodeIndex = stack.Top();
u32 nodeIndex = stack.Top();
stack.Pop();
if (nodeIndex == B3_NULL_NODE_S)
@@ -174,29 +188,103 @@ inline void b3StaticTree::RayCast(T* callback, const b3RayCastInput& input) cons
const b3Node* node = m_nodes + nodeIndex;
float32 minFraction;
if (node->aabb.TestRay(minFraction, p1, p2, maxFraction) == true)
if (b3TestOverlap(segmentAABB, node->aabb) == false)
{
if (node->IsLeaf() == true)
{
b3RayCastInput subInput;
subInput.p1 = input.p1;
subInput.p2 = input.p2;
subInput.maxFraction = maxFraction;
continue;
}
float32 newFraction = callback->Report(subInput, nodeIndex);
// Separating axis for segment (Gino, p80).
b3Vec3 c = node->aabb.GetCenter();
b3Vec3 h = node->aabb.GetExtents();
if (newFraction == 0.0f)
{
// The client has stopped the query.
return;
}
}
else
b3Vec3 s = p1 - c;
b3Vec3 t = q2 - c;
// |sigma + tau| > |sigma - tau| + 2 * eta
scalar sigma_1 = s.x;
scalar tau_1 = t.x;
scalar eta_1 = h.x;
scalar s1 = b3Abs(sigma_1 + tau_1) - (b3Abs(sigma_1 - tau_1) + scalar(2) * eta_1);
if (s1 > scalar(0))
{
continue;
}
scalar sigma_2 = s.y;
scalar tau_2 = t.y;
scalar eta_2 = h.y;
scalar s2 = b3Abs(sigma_2 + tau_2) - (b3Abs(sigma_2 - tau_2) + scalar(2) * eta_2);
if (s2 > scalar(0))
{
continue;
}
scalar sigma_3 = s.z;
scalar tau_3 = t.z;
scalar eta_3 = h.z;
scalar s3 = b3Abs(sigma_3 + tau_3) - (b3Abs(sigma_3 - tau_3) + scalar(2) * eta_3);
if (s3 > scalar(0))
{
continue;
}
// v = cross(ei, r)
// |dot(v, s)| > dot(|v|, h)
b3Vec3 v1 = b3Cross(e1, r);
b3Vec3 abs_v1 = b3Abs(v1);
scalar s4 = b3Abs(b3Dot(v1, s)) - b3Dot(abs_v1, h);
if (s4 > scalar(0))
{
continue;
}
b3Vec3 v2 = b3Cross(e2, r);
b3Vec3 abs_v2 = b3Abs(v2);
scalar s5 = b3Abs(b3Dot(v2, s)) - b3Dot(abs_v2, h);
if (s5 > scalar(0))
{
continue;
}
b3Vec3 v3 = b3Cross(e3, r);
b3Vec3 abs_v3 = b3Abs(v3);
scalar s6 = b3Abs(b3Dot(v3, s)) - b3Dot(abs_v3, h);
if (s6 > scalar(0))
{
continue;
}
if (node->IsLeaf() == true)
{
b3RayCastInput subInput;
subInput.p1 = input.p1;
subInput.p2 = input.p2;
subInput.maxFraction = maxFraction;
scalar newMaxFraction = callback->Report(subInput, nodeIndex);
if (newMaxFraction == scalar(0))
{
stack.Push(node->child1);
stack.Push(node->child2);
// The client has stopped the query.
return;
}
if (newMaxFraction > scalar(0))
{
// Update the segment AABB.
maxFraction = newMaxFraction;
q2 = p1 + maxFraction * (p2 - p1);
segmentAABB.lowerBound = b3Min(p1, q2);
segmentAABB.upperBound = b3Max(p1, q2);
}
}
else
{
stack.Push(node->child1);
stack.Push(node->child2);
}
}
}