Skip to content

Commit

Permalink
Clean up collision masks.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hans-Kristian Arntzen committed Mar 24, 2019
1 parent 645db8d commit 6f526eb
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 53 deletions.
130 changes: 86 additions & 44 deletions physics/physics_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct PhysicsHandle
btCollisionObject *bt_object = nullptr;
btCollisionShape *bt_shape = nullptr;
Entity *entity = nullptr;
PhysicsSystem::InteractionType type = PhysicsSystem::InteractionType::Ghost;
bool copy_transform_from_node = false;

~PhysicsHandle()
Expand Down Expand Up @@ -103,29 +104,29 @@ void PhysicsSystem::tick_callback(float)
new_collision_buffer.clear();
}

struct ClosestRayCallback : btCollisionWorld::ClosestRayResultCallback
RaycastResult PhysicsSystem::query_closest_hit_ray(const vec3 &from, const vec3 &dir, float t,
InteractionTypeFlags flags)
{
using btCollisionWorld::ClosestRayResultCallback::ClosestRayResultCallback;
vec3 to = from + dir * t;
btVector3 ray_from_world(from.x, from.y, from.z);
btVector3 ray_to_world(to.x, to.y, to.z);
btCollisionWorld::ClosestRayResultCallback cb(ray_from_world, ray_to_world);

btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace) override
cb.m_collisionFilterMask = 0;
if (flags == INTERACTION_TYPE_ALL_BITS)
cb.m_collisionFilterMask = btBroadphaseProxy::AllFilter;
else
{
auto *obj = rayResult.m_collisionObject;

// Ignore ray casts against characters.
auto mask = obj->getBroadphaseHandle()->m_collisionFilterGroup & ~btBroadphaseProxy::CharacterFilter;
if (mask != 0)
return btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
else
return 1.0f;
if (flags & INTERACTION_TYPE_STATIC_BIT)
cb.m_collisionFilterMask |= btBroadphaseProxy::StaticFilter;
if (flags & INTERACTION_TYPE_DYNAMIC_BIT)
cb.m_collisionFilterMask |= btBroadphaseProxy::DefaultFilter;
if (flags & INTERACTION_TYPE_INVISIBLE_BIT)
cb.m_collisionFilterMask |= btBroadphaseProxy::SensorTrigger;
if (flags & INTERACTION_TYPE_KINEMATIC_BIT)
cb.m_collisionFilterMask |= btBroadphaseProxy::CharacterFilter;
}
};

RaycastResult PhysicsSystem::query_closest_hit_ray(const vec3 &from, const vec3 &dir, float t)
{
vec3 to = from + dir * t;
btVector3 ray_from_world(from.x, from.y, from.z);
btVector3 ray_to_world(to.x, to.y, to.z);
ClosestRayCallback cb(ray_from_world, ray_to_world);
world->rayTest(ray_from_world, ray_to_world, cb);

RaycastResult result = {};
Expand Down Expand Up @@ -301,7 +302,7 @@ void PhysicsSystem::iterate(double frame_time)
continue;

auto *obj = handle->bt_object;
auto *ghost = btGhostObject::upcast(obj);
auto *ghost = btPairCachingGhostObject::upcast(obj);
auto *body = btRigidBody::upcast(obj);

if (ghost)
Expand Down Expand Up @@ -343,7 +344,7 @@ void PhysicsSystem::iterate(double frame_time)
continue;

auto *obj = handle->bt_object;
auto *ghost = btGhostObject::upcast(obj);
auto *ghost = btPairCachingGhostObject::upcast(obj);
if (ghost)
continue;

Expand Down Expand Up @@ -453,38 +454,44 @@ PhysicsHandle *PhysicsSystem::add_shape(Scene::Node *node, const MaterialInfo &i

shape->setMargin(info.margin);
btVector3 local_inertia(0, 0, 0);
if (info.mass != 0.0f && info.type != ObjectType::Static)
if (info.mass != 0.0f && info.type != InteractionType::Static)
shape->calculateLocalInertia(info.mass, local_inertia);

PhysicsHandle *handle = nullptr;

if (info.type == ObjectType::Ghost)
if (info.type == InteractionType::Ghost || info.type == InteractionType::Area)
{
auto *body = new btGhostObject();
auto *body = new btPairCachingGhostObject();
body->setCollisionShape(shape);
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
body->setWorldTransform(t);

// Don't collide against other static objects and sensors.
world->addCollisionObject(body,
btBroadphaseProxy::SensorTrigger,
btBroadphaseProxy::AllFilter &
~(btBroadphaseProxy::SensorTrigger | btBroadphaseProxy::StaticFilter));

world->addCollisionObject(body);
handle = handle_pool.allocate();
body->setUserPointer(handle);
handle->node = node;
handle->bt_object = body;
handle->bt_shape = shape;
handle->copy_transform_from_node = true;
handle->copy_transform_from_node = info.type == InteractionType::Ghost;
handles.push_back(handle);
}
else if (info.type == ObjectType::Kinematic)
else if (info.type == InteractionType::Kinematic)
{
auto *motion = new btDefaultMotionState(t);
btRigidBody::btRigidBodyConstructionInfo rb_info(info.type == ObjectType::Static ? 0.0f : info.mass,
btRigidBody::btRigidBodyConstructionInfo rb_info(info.type == InteractionType::Static ? 0.0f : info.mass,
motion, shape, local_inertia);

auto *body = new btRigidBody(rb_info);
body->setCollisionShape(shape);
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
body->setActivationState(DISABLE_DEACTIVATION);

world->addRigidBody(body);
world->addRigidBody(body, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::AllFilter);
handle = handle_pool.allocate();
body->setUserPointer(handle);
handle->node = node;
Expand All @@ -496,9 +503,9 @@ PhysicsHandle *PhysicsSystem::add_shape(Scene::Node *node, const MaterialInfo &i
else
{
auto *motion = new btDefaultMotionState(t);
btRigidBody::btRigidBodyConstructionInfo rb_info(info.type != ObjectType::Dynamic ? 0.0f : info.mass,
btRigidBody::btRigidBodyConstructionInfo rb_info(info.type != InteractionType::Dynamic ? 0.0f : info.mass,
motion, shape, local_inertia);
if (info.mass != 0.0f && info.type == ObjectType::Dynamic)
if (info.mass != 0.0f && info.type == InteractionType::Dynamic)
{
rb_info.m_restitution = info.restitution;
rb_info.m_linearDamping = info.linear_damping;
Expand All @@ -511,10 +518,12 @@ PhysicsHandle *PhysicsSystem::add_shape(Scene::Node *node, const MaterialInfo &i
rb_info.m_rollingFriction = info.rolling_friction;

auto *body = new btRigidBody(rb_info);
if (info.type != ObjectType::Dynamic)
if (info.type != InteractionType::Dynamic)
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);

world->addRigidBody(body);
world->addRigidBody(body, info.type == InteractionType::Dynamic ?
btBroadphaseProxy::DefaultFilter : btBroadphaseProxy::StaticFilter,
btBroadphaseProxy::AllFilter);

handle = handle_pool.allocate();
body->setUserPointer(handle);
Expand All @@ -524,9 +533,15 @@ PhysicsHandle *PhysicsSystem::add_shape(Scene::Node *node, const MaterialInfo &i
handles.push_back(handle);
}

handle->type = info.type;
return handle;
}

PhysicsSystem::InteractionType PhysicsSystem::get_interaction_type(PhysicsHandle *handle)
{
return handle->type;
}

btCollisionShape *PhysicsSystem::create_shape(const ConvexMeshPart &part)
{
btCollisionShape *shape = nullptr;
Expand Down Expand Up @@ -638,7 +653,7 @@ PhysicsHandle *PhysicsSystem::add_mesh(Scene::Node *node, unsigned index, const

// Mesh objects cannot be dynamic.
MaterialInfo tmp = info;
tmp.type = ObjectType::Static;
tmp.type = InteractionType::Static;
tmp.mass = 0.0f;
tmp.restitution = 1.0f;

Expand Down Expand Up @@ -747,7 +762,7 @@ PhysicsHandle *PhysicsSystem::add_infinite_plane(const vec4 &plane, const Materi
auto *shape = new btStaticPlaneShape(btVector3(plane.x, plane.y, plane.z), plane.w);

MaterialInfo tmp = info;
tmp.type = ObjectType::Static;
tmp.type = InteractionType::Static;
tmp.mass = 0.0f;
tmp.restitution = 1.0f;

Expand Down Expand Up @@ -806,30 +821,57 @@ struct TriggerContactResultCallback : btCollisionWorld::ContactResultCallback
{
bool hit = false;

btScalar addSingleResult(btManifoldPoint &,
btScalar addSingleResult(btManifoldPoint &point,
const btCollisionObjectWrapper *, int, int,
const btCollisionObjectWrapper *, int, int) override
{
hit = true;
return 1.0f;
if (point.getDistance() <= 0.0f)
{
hit = true;
return btScalar(0);
}
else
return btScalar(1);
}
};

bool PhysicsSystem::get_overlapping_objects(PhysicsHandle *handle, vector<PhysicsHandle *> &other)
bool PhysicsSystem::get_overlapping_objects(PhysicsHandle *handle, vector<PhysicsHandle *> &other,
OverlapMethod method)
{
other.clear();
auto *ghost = btGhostObject::upcast(handle->bt_object);
auto *ghost = btPairCachingGhostObject::upcast(handle->bt_object);
if (!ghost)
return false;

int count = ghost->getNumOverlappingObjects();
auto &pairs = ghost->getOverlappingPairs();

int count = pairs.size();
other.reserve(count);
for (int i = 0; i < count; i++)
{
TriggerContactResultCallback cb;
world->contactPairTest(ghost, ghost->getOverlappingObject(i), cb);
if (cb.hit)
other.push_back(static_cast<PhysicsHandle *>(ghost->getOverlappingObject(i)->getUserPointer()));
auto *object = pairs[i];

bool response = (ghost->getBroadphaseHandle()->m_collisionFilterGroup &
object->getBroadphaseHandle()->m_collisionFilterMask) != 0;

response = response &&
(object->getBroadphaseHandle()->m_collisionFilterGroup &
ghost->getBroadphaseHandle()->m_collisionFilterMask) != 0;

if (!response)
continue;

if (method == OverlapMethod::Broadphase)
{
other.push_back(static_cast<PhysicsHandle *>(object->getUserPointer()));
}
else if (method == OverlapMethod::Nearphase)
{
TriggerContactResultCallback cb;
world->contactPairTest(ghost, object, cb);
if (cb.hit)
other.push_back(static_cast<PhysicsHandle *>(object->getUserPointer()));
}
}

return true;
Expand Down
28 changes: 24 additions & 4 deletions physics/physics_system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,18 @@ class PhysicsSystem
PhysicsSystem();
~PhysicsSystem();

enum class ObjectType
enum class InteractionType
{
Ghost,
Area,
Static,
Dynamic,
Kinematic
};

struct MaterialInfo
{
ObjectType type = ObjectType::Dynamic;
InteractionType type = InteractionType::Dynamic;
float mass = 1.0f;
float restitution = 0.5f;
float linear_damping = 0.1f;
Expand Down Expand Up @@ -224,19 +225,38 @@ class PhysicsSystem
static void set_handle_parent(PhysicsHandle *handle, Entity *entity);
static Entity *get_handle_parent(PhysicsHandle *handle);
static Scene::Node *get_scene_node(PhysicsHandle *handle);
static InteractionType get_interaction_type(PhysicsHandle *handle);

void apply_impulse(PhysicsHandle *handle, const vec3 &impulse, const vec3 &world_position);
void iterate(double frame_time);
void tick_callback(float tick_time);

RaycastResult query_closest_hit_ray(const vec3 &from, const vec3 &dir, float length);
enum InteractionTypeFlagBits
{
INTERACTION_TYPE_STATIC_BIT = 1 << 0,
INTERACTION_TYPE_DYNAMIC_BIT = 1 << 1,
INTERACTION_TYPE_INVISIBLE_BIT = 1 << 2,
INTERACTION_TYPE_KINEMATIC_BIT = 1 << 3,
INTERACTION_TYPE_ALL_BITS = 0x7fffffff
};
using InteractionTypeFlags = uint32_t;

RaycastResult query_closest_hit_ray(const vec3 &from, const vec3 &dir, float length,
InteractionTypeFlags mask = INTERACTION_TYPE_ALL_BITS);

void add_point_constraint(PhysicsHandle *handle, const vec3 &local_pivot);
void add_point_constraint(PhysicsHandle *handle0, PhysicsHandle *handle1,
const vec3 &local_pivot0, const vec3 &local_pivot1,
bool skip_collision = false);

bool get_overlapping_objects(PhysicsHandle *handle, std::vector<PhysicsHandle *> &other);
enum class OverlapMethod
{
Broadphase,
Nearphase
};

bool get_overlapping_objects(PhysicsHandle *handle, std::vector<PhysicsHandle *> &other,
OverlapMethod method = OverlapMethod::Nearphase);

private:
std::unique_ptr<btDefaultCollisionConfiguration> collision_config;
Expand Down
13 changes: 8 additions & 5 deletions viewer/physics_sandbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ struct PhysicsSandboxApplication : Application, EventHandler
if (e.get_pressed() && e.get_button() == MouseButton::Left)
{
auto result = Global::physics()->query_closest_hit_ray(
camera.get_position(), camera.get_front(), 100.0f);
camera.get_position(), camera.get_front(), 100.0f,
PhysicsSystem::INTERACTION_TYPE_DYNAMIC_BIT);

if (result.entity)
{
Expand Down Expand Up @@ -209,7 +210,7 @@ struct PhysicsSandboxApplication : Application, EventHandler
auto *renderable = scene.create_renderable(cube, static_node.get());

PhysicsSystem::MaterialInfo info;
info.type = PhysicsSystem::ObjectType::Kinematic;
info.type = PhysicsSystem::InteractionType::Area;
info.mass = 0.0f;
animated_cube = Global::physics()->add_cube(static_node.get(), info);
PhysicsSystem::set_handle_parent(animated_cube, renderable);
Expand Down Expand Up @@ -404,11 +405,13 @@ struct PhysicsSandboxApplication : Application, EventHandler
}
}

#if 0
{
auto *node = PhysicsSystem::get_scene_node(animated_cube);
node->transform.translation.x = float(3.0 * sin(0.2 * elapsed_time));
node->invalidate_cached_transform();
std::vector<PhysicsHandle *> overlapping;
Global::physics()->get_overlapping_objects(animated_cube, overlapping);
LOGI("Overlapping: %zu\n", overlapping.size());
}
#endif

Global::physics()->iterate(frame_time);
scene.update_cached_transforms();
Expand Down

0 comments on commit 6f526eb

Please sign in to comment.