reactphysics3d icon indicating copy to clipboard operation
reactphysics3d copied to clipboard

Overlaps without CollisionBody

Open jorisshh opened this issue 4 years ago • 3 comments

Problem: The current implementation of testOverlap and testCollision require a CollisionBody* argument. This means that currently, in order to get all collision objects in some area we're required to make a new collision body and get callbacks through this.

Example (current): Here's an example of one of our utilities.

static void entitiesInShape(base::PhysicsWorld* world, vec3 pos, rp3d::CollisionShape* shape, std::function<void(entt::entity)> func) {
		rp3d::Transform shapePose(convert(pos), rp3d::Quaternion::identity());

		rp3d::CollisionBody* body = world->getWorld()->createCollisionBody(shapePose);
		body->addCollider(shape, rp3d::Transform::identity());

		MyOverlapCallbackAll callback;
		callback.callback = std::move(func);

		world->getWorld()->testOverlap(body, callback);

		// Cleanup
		world->getWorld()->destroyCollisionBody(body);
	}

Overlaps are a very commonly used mechanic in games and performance is quite important on them.

I've dug through the code a bit to see if it'd be easy to provide some functions that only take a shape or specialized functions like testOverlapSphere(position, callback) or testOverlapSphere(position, List<Entity>&), but it seems most of the internal structure is really geared towards batch processing and CollisionBodies.

Suggestion usage

world->getWorld()->testOverlap(position, shape, callback);

// OR
world->getWorld()->testOverlapSphere(position, callback);

// OR (preferred)
rp3d::List<rp3d::Entity> overlapping(world->getMemoryManager().getSingleFrameAllocator(), 32);
world->getWorld()->testOverlapSphere(position, overlapping);

// Process overlapping here...

The benefit of using a reference to a list in which overlaps are written is that there are some easy C++ optimizations we can make use of. Instead of having to pass around a std::function (which can allocate), we can just inline the function at the call site through templates.

template <typename Func>
static void entitiesInSphere(rp3d::PhysicsWorld* world, const Vector3& pos, float radius, Func func) {
    rp3d::List<rp3d::Entity> overlapping(world->getMemoryManager().getSingleFrameAllocator(), 32);
    world->getWorld()->testOverlapSphere(pos, radius, overlapping);

    for(rp3d::Entity e : overlapping) {
        func(e); // Gets inlined
    }
}

Thoughts? I may have the time to implement this in the near future; some suggestions would be appreciated.

jorisshh avatar Feb 04 '21 10:02 jorisshh

Thanks a lot for your feedback. Yes, it would be a good idea to have a testOverlap() method where you can simply pass a collision shape and not a whole body.

I will need to check if I can add the following method:

PhysicsWorld::testOverlap(collisionShape, transform, callback)

Note that we need to use a transform here (position and rotation).

I don't really know if I will have the time to add this in the next release (v0.9.0). I will let you know here when this is implemented.

DanielChappuis avatar Feb 14 '21 08:02 DanielChappuis

@DanielChappuis any updates yet? Maybe somewhere in preview version?

caxapexac avatar Apr 23 '22 12:04 caxapexac

Hello. Sorry but this is not implemented yet.

DanielChappuis avatar Apr 23 '22 14:04 DanielChappuis