The code I mentioned before for multiple convex cast results, in case someone wants it. And I realize now the reason I thought it wasn’t possible to draw the collision shapes directly was because my code created the convex bullet collision shapes directly rather than using Urho3D::CollisionShape
.
#include <BulletCollision/CollisionShapes/btSphereShape.h>
#include <Urho3D/Physics/PhysicsWorld.h>
#include <Urho3D/Physics/CollisionShape.h>
#include <Urho3D/ThirdParty/Bullet/BulletCollision/CollisionShapes/btCollisionShape.h>
#include <Urho3D/ThirdParty/Bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
#include <Urho3D/ThirdParty/Bullet/btBulletDynamicsCommon.h>
#include <Urho3D/ThirdParty/Bullet/btBulletCollisionCommon.h>
#include <Urho3D/ThirdParty/Bullet/btBulletDynamicsCommon.h>
#include <Urho3D/Physics/PhysicsUtils.h>
struct AllHitsConvexResultCallback : public btCollisionWorld::ConvexResultCallback
{
AllHitsConvexResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld)
: m_convexFromWorld(rayFromWorld),
m_convexToWorld(rayToWorld)
{
}
btAlignedObjectArray<const btCollisionObject*> m_collisionObjects;
btVector3 m_convexFromWorld; //used to calculate hitPointWorld from hitFraction
btVector3 m_convexToWorld;
btAlignedObjectArray<btVector3> m_hitNormalWorld;
btAlignedObjectArray<btVector3> m_hitPointWorld;
btAlignedObjectArray<btScalar> m_hitFractions;
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& rayResult, bool normalInWorldSpace)
{
m_collisionObjects.push_back(rayResult.m_hitCollisionObject);
btVector3 hitNormalWorld;
if (normalInWorldSpace)
{
hitNormalWorld = rayResult.m_hitNormalLocal;
}
else
{
///need to transform normal into worldspace
hitNormalWorld = rayResult.m_hitCollisionObject->getWorldTransform().getBasis() * rayResult.m_hitNormalLocal;
}
m_hitNormalWorld.push_back(hitNormalWorld);
btVector3 hitPointWorld;
// hitPointWorld.setInterpolate3(m_rayFromWorld, m_rayToWorld, rayResult.m_hitFraction);
// m_hitPointWorld.push_back(hitPointWorld);
m_hitPointWorld.push_back(rayResult.m_hitPointLocal);
m_hitFractions.push_back(rayResult.m_hitFraction);
return m_closestHitFraction; // i.e. 1.0
}
};
namespace Urho3D {
void SphereCastMultiple(PhysicsWorld* pw, Vector<PhysicsRaycastResult>& results, const Ray& ray, float radius, float maxDistance, unsigned collisionMask)
{
if (maxDistance >= M_INFINITY)
URHO3D_LOGWARNING("Infinite maxDistance in physics sphere cast is not supported");
btSphereShape shape(radius);
Vector3 endPos = ray.origin_ + maxDistance * ray.direction_;
AllHitsConvexResultCallback
convexCallback(ToBtVector3(ray.origin_), ToBtVector3(endPos));
convexCallback.m_collisionFilterGroup = (short)0xffff;
convexCallback.m_collisionFilterMask = (short)collisionMask;
pw->GetWorld()->convexSweepTest(&shape, btTransform(btQuaternion::getIdentity(), convexCallback.m_convexFromWorld),
btTransform(btQuaternion::getIdentity(), convexCallback.m_convexToWorld), convexCallback);
for (unsigned i = 0; (int)i < convexCallback.m_hitFractions.size(); ++i)
{
PhysicsRaycastResult result;
result.body_ = static_cast<RigidBody*>(convexCallback.m_collisionObjects[i]->getUserPointer());
result.position_ = ToVector3(convexCallback.m_hitPointWorld[i]);
result.normal_ = ToVector3(convexCallback.m_hitNormalWorld[i]);
result.distance_ = convexCallback.m_hitFractions[i] * (endPos - ray.origin_).Length();
result.hitFraction_ = convexCallback.m_hitFractions[i];
results.Push(result);
}
}
void ConvexCastMultiple(PhysicsWorld* pw, Vector<PhysicsRaycastResult>& results, const Ray& ray, CollisionShape* shape, float maxDistance, unsigned collisionMask)
{
if (!pw || !shape)
return;
const auto& btShape = shape->GetCollisionShape();
if (!btShape || !btShape->isConvex())
return;
const btConvexShape* btConvex = static_cast<const btConvexShape*>(btShape);
ConvexCastMultiple(pw,results,ray,btConvex,maxDistance,collisionMask);
}
void ConvexCastMultiple(PhysicsWorld* pw, Vector<PhysicsRaycastResult>& results, const Ray& ray, const btConvexShape* shape, float maxDistance, unsigned collisionMask)
{
if (!pw || !shape)
return;
if (maxDistance >= M_INFINITY)
URHO3D_LOGWARNING("Infinite maxDistance in physics convex cast is not supported");
Vector3 endPos = ray.origin_ + maxDistance * ray.direction_;
AllHitsConvexResultCallback
convexCallback(ToBtVector3(ray.origin_), ToBtVector3(endPos));
convexCallback.m_collisionFilterGroup = (short)0xffff;
convexCallback.m_collisionFilterMask = (short)collisionMask;
pw->GetWorld()->convexSweepTest(shape, btTransform(btQuaternion::getIdentity(), convexCallback.m_convexFromWorld),
btTransform(btQuaternion::getIdentity(), convexCallback.m_convexToWorld), convexCallback);
for (unsigned i = 0; (int)i < convexCallback.m_hitFractions.size(); ++i)
{
PhysicsRaycastResult result;
result.body_ = static_cast<RigidBody*>(convexCallback.m_collisionObjects[i]->getUserPointer());
result.position_ = ToVector3(convexCallback.m_hitPointWorld[i]);
result.normal_ = ToVector3(convexCallback.m_hitNormalWorld[i]);
result.distance_ = convexCallback.m_hitFractions[i] * (endPos - ray.origin_).Length();
result.hitFraction_ = convexCallback.m_hitFractions[i];
results.Push(result);
}
}
}