Physics3D/PhysWorld3D: Add generic RaycastQuery
This commit is contained in:
parent
4d42c0cf9c
commit
63d75e8904
|
|
@ -14,6 +14,7 @@
|
||||||
#include <Nazara/Math/Vector3.hpp>
|
#include <Nazara/Math/Vector3.hpp>
|
||||||
#include <NazaraUtils/FunctionRef.hpp>
|
#include <NazaraUtils/FunctionRef.hpp>
|
||||||
#include <NazaraUtils/MovablePtr.hpp>
|
#include <NazaraUtils/MovablePtr.hpp>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
class btDynamicsWorld;
|
class btDynamicsWorld;
|
||||||
class btRigidBody;
|
class btRigidBody;
|
||||||
|
|
@ -39,6 +40,7 @@ namespace Nz
|
||||||
std::size_t GetMaxStepCount() const;
|
std::size_t GetMaxStepCount() const;
|
||||||
Time GetStepSize() const;
|
Time GetStepSize() const;
|
||||||
|
|
||||||
|
bool RaycastQuery(const Vector3f& from, const Vector3f& to, const FunctionRef<std::optional<float>(const RaycastHit& hitInfo)>& callback);
|
||||||
bool RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo = nullptr);
|
bool RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo = nullptr);
|
||||||
|
|
||||||
void SetGravity(const Vector3f& gravity);
|
void SetGravity(const Vector3f& gravity);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ namespace Nz
|
||||||
inline BulletPhysWorld3D& GetPhysWorld();
|
inline BulletPhysWorld3D& GetPhysWorld();
|
||||||
inline const BulletPhysWorld3D& GetPhysWorld() const;
|
inline const BulletPhysWorld3D& GetPhysWorld() const;
|
||||||
|
|
||||||
|
bool RaycastQuery(const Vector3f& from, const Vector3f& to, const FunctionRef<std::optional<float>(const RaycastHit& hitInfo)>& callback);
|
||||||
bool RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo = nullptr);
|
bool RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo = nullptr);
|
||||||
|
|
||||||
void Update(Time elapsedTime);
|
void Update(Time elapsedTime);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,38 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
class CallbackHitResult : public btCollisionWorld::RayResultCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CallbackHitResult(const Vector3f& from, const Vector3f& to, const FunctionRef<std::optional<float>(const BulletPhysWorld3D::RaycastHit& hitInfo)>& callback) :
|
||||||
|
m_callback(callback),
|
||||||
|
m_from(from),
|
||||||
|
m_to(to)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) override
|
||||||
|
{
|
||||||
|
m_collisionObject = rayResult.m_collisionObject;
|
||||||
|
|
||||||
|
BulletPhysWorld3D::RaycastHit hitInfo;
|
||||||
|
hitInfo.fraction = rayResult.m_hitFraction;
|
||||||
|
hitInfo.hitPosition = Lerp(m_from, m_to, rayResult.m_hitFraction);
|
||||||
|
hitInfo.hitNormal = FromBullet((normalInWorldSpace) ? rayResult.m_hitNormalLocal : m_collisionObject->getWorldTransform().getBasis() * rayResult.m_hitNormalLocal);
|
||||||
|
|
||||||
|
if (const btRigidBody* body = btRigidBody::upcast(m_collisionObject))
|
||||||
|
hitInfo.hitBody = static_cast<BulletRigidBody3D*>(body->getUserPointer());
|
||||||
|
|
||||||
|
m_closestHitFraction = std::max(m_callback(hitInfo).value_or(m_closestHitFraction), 0.f);
|
||||||
|
return m_closestHitFraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const FunctionRef<std::optional<float>(const BulletPhysWorld3D::RaycastHit& hitInfo)>& m_callback;
|
||||||
|
Vector3f m_from;
|
||||||
|
Vector3f m_to;
|
||||||
|
};
|
||||||
|
|
||||||
struct BulletPhysWorld3D::BulletWorld
|
struct BulletPhysWorld3D::BulletWorld
|
||||||
{
|
{
|
||||||
btDefaultCollisionConfiguration collisionConfiguration;
|
btDefaultCollisionConfiguration collisionConfiguration;
|
||||||
|
|
@ -70,21 +102,29 @@ namespace Nz
|
||||||
return m_stepSize;
|
return m_stepSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BulletPhysWorld3D::RaycastQuery(const Vector3f& from, const Vector3f& to, const FunctionRef<std::optional<float>(const RaycastHit& hitInfo)>& callback)
|
||||||
|
{
|
||||||
|
CallbackHitResult resultHandler(from, to, callback);
|
||||||
|
m_world->dynamicWorld.rayTest(ToBullet(from), ToBullet(to), resultHandler);
|
||||||
|
|
||||||
|
return resultHandler.hasHit();
|
||||||
|
}
|
||||||
|
|
||||||
bool BulletPhysWorld3D::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo)
|
bool BulletPhysWorld3D::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo)
|
||||||
{
|
{
|
||||||
btCollisionWorld::ClosestRayResultCallback callback(ToBullet(from), ToBullet(to));
|
btCollisionWorld::ClosestRayResultCallback resultHandler(ToBullet(from), ToBullet(to));
|
||||||
m_world->dynamicWorld.rayTest(ToBullet(from), ToBullet(to), callback);
|
m_world->dynamicWorld.rayTest(ToBullet(from), ToBullet(to), resultHandler);
|
||||||
|
|
||||||
if (!callback.hasHit())
|
if (!resultHandler.hasHit())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (hitInfo)
|
if (hitInfo)
|
||||||
{
|
{
|
||||||
hitInfo->fraction = callback.m_closestHitFraction;
|
hitInfo->fraction = resultHandler.m_closestHitFraction;
|
||||||
hitInfo->hitNormal = FromBullet(callback.m_hitNormalWorld);
|
hitInfo->hitNormal = FromBullet(resultHandler.m_hitNormalWorld);
|
||||||
hitInfo->hitPosition = FromBullet(callback.m_hitPointWorld);
|
hitInfo->hitPosition = FromBullet(resultHandler.m_hitPointWorld);
|
||||||
|
|
||||||
if (const btRigidBody* body = btRigidBody::upcast(callback.m_collisionObject))
|
if (const btRigidBody* body = btRigidBody::upcast(resultHandler.m_collisionObject))
|
||||||
hitInfo->hitBody = static_cast<BulletRigidBody3D*>(body->getUserPointer());
|
hitInfo->hitBody = static_cast<BulletRigidBody3D*>(body->getUserPointer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,24 @@ namespace Nz
|
||||||
m_updateTime = Time::Zero();
|
m_updateTime = Time::Zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BulletPhysics3DSystem::RaycastQuery(const Vector3f& from, const Vector3f& to, const FunctionRef<std::optional<float>(const RaycastHit& hitInfo)>& callback)
|
||||||
|
{
|
||||||
|
return m_physWorld.RaycastQuery(from, to, [&](const BulletPhysWorld3D::RaycastHit& hitInfo)
|
||||||
|
{
|
||||||
|
RaycastHit hitWithEntity;
|
||||||
|
static_cast<BulletPhysWorld3D::RaycastHit&>(hitWithEntity) = hitInfo;
|
||||||
|
|
||||||
|
if (hitWithEntity.hitBody)
|
||||||
|
{
|
||||||
|
std::size_t uniqueIndex = hitWithEntity.hitBody->GetUniqueIndex();
|
||||||
|
if (uniqueIndex < m_physicsEntities.size())
|
||||||
|
hitWithEntity.hitEntity = entt::handle(m_registry, m_physicsEntities[uniqueIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(hitWithEntity);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool BulletPhysics3DSystem::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo)
|
bool BulletPhysics3DSystem::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo)
|
||||||
{
|
{
|
||||||
if (!m_physWorld.RaycastQueryFirst(from, to, hitInfo))
|
if (!m_physWorld.RaycastQueryFirst(from, to, hitInfo))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue