JoltPhysics3D: Add RaycastQuery and RaycastQueryFirst

This commit is contained in:
SirLynix 2023-03-25 13:53:44 +01:00 committed by Jérôme Leclercq
parent 707a486e74
commit b3595178a1
6 changed files with 134 additions and 34 deletions

View File

@ -299,16 +299,21 @@ int main()
Nz::Vector3f from = cameraComponent.Unproject({ float(event.x), float(event.y), 0.f });
Nz::Vector3f to = cameraComponent.Unproject({ float(event.x), float(event.y), 1.f });
/*/Nz::Physics3DSystem::RaycastHit lastHitInfo;
auto callback = [&](const Nz::Physics3DSystem::RaycastHit& hitInfo) -> std::optional<float>
Nz::JoltPhysics3DSystem::RaycastHit lastHitInfo;
auto callback = [&](const Nz::JoltPhysics3DSystem::RaycastHit& hitInfo) -> std::optional<float>
{
if (hitInfo.hitEntity == boxEntity)
{
Nz::Vector3f dirToCenter = Nz::Vector3f::Zero() - hitInfo.hitPosition;
dirToCenter.Normalize();
#ifdef USE_JOLT
if (Nz::Vector3f::DotProduct(dirToCenter, (hitInfo.hitPosition - from).Normalize()) < 0.f)
return std::nullopt;
#else
if (Nz::Vector3f::DotProduct(dirToCenter, hitInfo.hitNormal) < 0.f)
return std::nullopt;
#endif
}
lastHitInfo = hitInfo;
@ -320,8 +325,8 @@ int main()
{
if (lastHitInfo.hitBody && lastHitInfo.hitEntity != boxEntity)
{
grabConstraint.emplace(*lastHitInfo.hitBody, lastHitInfo.hitPosition);
grabConstraint->SetImpulseClamp(30.f);
//grabConstraint.emplace(*lastHitInfo.hitBody, lastHitInfo.hitPosition);
//grabConstraint->SetImpulseClamp(30.f);
grabbedObjectMove.Connect(eventHandler.OnMouseMoved, [&, body = lastHitInfo.hitBody, distance = Nz::Vector3f::Distance(from, lastHitInfo.hitPosition)](const Nz::WindowEventHandler*, const Nz::WindowEvent::MouseMoveEvent& event)
{
@ -329,14 +334,14 @@ int main()
Nz::Vector3f to = cameraComponent.Unproject({ float(event.x), float(event.y), 1.f });
Nz::Vector3f newPosition = from + (to - from).Normalize() * distance;
grabConstraint->SetSecondAnchor(newPosition);
//grabConstraint->SetSecondAnchor(newPosition);
});
}
else
cameraMove.Connect(eventHandler.OnMouseMoved, mouseMoveCallback);
}
else
cameraMove.Connect(eventHandler.OnMouseMoved, mouseMoveCallback);*/
cameraMove.Connect(eventHandler.OnMouseMoved, mouseMoveCallback);
}
});

View File

@ -47,7 +47,8 @@ namespace Nz
inline bool IsBodyActive(UInt32 bodyIndex) const;
bool RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo = nullptr);
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, const FunctionRef<void(const RaycastHit& hitInfo)>& callback);
void SetGravity(const Vector3f& gravity);
void SetMaxStepCount(std::size_t maxStepCount);
@ -63,7 +64,6 @@ namespace Nz
float fraction;
JoltRigidBody3D* hitBody = nullptr;
Vector3f hitPosition;
Vector3f hitNormal;
};
private:

View File

@ -38,7 +38,8 @@ namespace Nz
inline JoltPhysWorld3D& GetPhysWorld();
inline const JoltPhysWorld3D& GetPhysWorld() const;
bool RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo = nullptr);
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, const FunctionRef<void(const RaycastHit& hitInfo)>& callback);
void Update(Time elapsedTime);

View File

@ -11,6 +11,9 @@
#include <NazaraUtils/StackVector.hpp>
#include <Jolt/Jolt.h>
#include <Jolt/Core/TempAllocator.h>
#include <Jolt/Physics/Collision/CastResult.h>
#include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
#include <Jolt/Physics/Collision/RayCast.h>
#include <Jolt/Physics/Collision/ObjectLayer.h>
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
#include <Jolt/Physics/PhysicsSettings.h>
@ -157,6 +160,59 @@ namespace DitchMeAsap
namespace Nz
{
namespace NAZARA_ANONYMOUS_NAMESPACE
{
class CallbackHitResult : public JPH::RayCastBodyCollector
{
public:
CallbackHitResult(const JPH::BodyLockInterface& bodyLockInterface, const Vector3f& from, const Vector3f& to, const FunctionRef<std::optional<float>(const JoltPhysWorld3D::RaycastHit& hitInfo)>& callback) :
m_bodyLockInterface(bodyLockInterface),
m_callback(callback),
m_from(from),
m_to(to),
m_didHit(false)
{
}
void AddHit(const JPH::BroadPhaseCastResult& result) override
{
JoltPhysWorld3D::RaycastHit hitInfo;
hitInfo.fraction = result.mFraction;
hitInfo.hitPosition = Lerp(m_from, m_to, result.mFraction);
JPH::BodyLockWrite lock(m_bodyLockInterface, result.mBodyID);
if (!lock.Succeeded())
return; //< body was destroyed
hitInfo.hitBody = reinterpret_cast<JoltRigidBody3D*>(static_cast<std::uintptr_t>(lock.GetBody().GetUserData()));
if (auto fractionOpt = m_callback(hitInfo))
{
float fraction = fractionOpt.value();
if (fraction > 0.f)
{
m_didHit = true;
UpdateEarlyOutFraction(fraction);
}
else
ForceEarlyOut();
}
}
bool DidHit() const
{
return m_didHit;
}
private:
const JPH::BodyLockInterface& m_bodyLockInterface;
const FunctionRef<std::optional<float>(const JoltPhysWorld3D::RaycastHit& hitInfo)>& m_callback;
Vector3f m_from;
Vector3f m_to;
bool m_didHit;
};
}
class JoltPhysWorld3D::BodyActivationListener : public JPH::BodyActivationListener
{
public:
@ -256,27 +312,40 @@ namespace Nz
return m_stepSize;
}
bool JoltPhysWorld3D::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo)
bool JoltPhysWorld3D::RaycastQuery(const Vector3f& from, const Vector3f& to, const FunctionRef<std::optional<float>(const RaycastHit& hitInfo)>& callback)
{
return false;
/*
btCollisionWorld::ClosestRayResultCallback callback(ToBullet(from), ToBullet(to));
m_world->dynamicWorld.rayTest(ToBullet(from), ToBullet(to), callback);
JPH::RayCast rayCast;
rayCast.mDirection = ToJolt(to - from);
rayCast.mOrigin = ToJolt(from);
if (!callback.hasHit())
CallbackHitResult collector(m_world->physicsSystem.GetBodyLockInterface(), from, to, callback);
m_world->physicsSystem.GetBroadPhaseQuery().CastRay(rayCast, collector);
return collector.DidHit();
}
bool JoltPhysWorld3D::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, const FunctionRef<void(const RaycastHit& hitInfo)>& callback)
{
JPH::RayCast rayCast;
rayCast.mDirection = ToJolt(to - from);
rayCast.mOrigin = ToJolt(from);
JPH::ClosestHitCollisionCollector<JPH::RayCastBodyCollector> collector;
m_world->physicsSystem.GetBroadPhaseQuery().CastRay(rayCast, collector);
if (!collector.HadHit())
return false;
if (hitInfo)
{
hitInfo->fraction = callback.m_closestHitFraction;
hitInfo->hitNormal = FromBullet(callback.m_hitNormalWorld);
hitInfo->hitPosition = FromBullet(callback.m_hitPointWorld);
JPH::BodyLockWrite lock(m_world->physicsSystem.GetBodyLockInterface(), collector.mHit.mBodyID);
if (!lock.Succeeded())
return false; //< body was destroyed before lock
if (const btRigidBody* body = btRigidBody::upcast(callback.m_collisionObject))
hitInfo->hitBody = static_cast<BulletRigidBody3D*>(body->getUserPointer());
}
RaycastHit hitInfo;
hitInfo.fraction = collector.mHit.GetEarlyOutFraction();
hitInfo.hitPosition = Lerp(from, to, hitInfo.fraction);
hitInfo.hitBody = reinterpret_cast<JoltRigidBody3D*>(static_cast<std::uintptr_t>(lock.GetBody().GetUserData()));
return true;*/
return true;
}
void JoltPhysWorld3D::SetGravity(const Vector3f& gravity)

View File

@ -53,6 +53,8 @@ namespace Nz
m_bodyIndex(object.m_bodyIndex),
m_world(object.m_world)
{
m_body->SetUserData(SafeCast<UInt64>(reinterpret_cast<std::uintptr_t>(this)));
object.m_body = nullptr;
object.m_bodyIndex = std::numeric_limits<UInt32>::max();
}
@ -333,6 +335,8 @@ namespace Nz
m_geom = std::move(object.m_geom);
m_world = object.m_world;
m_body->SetUserData(SafeCast<UInt64>(reinterpret_cast<std::uintptr_t>(this)));
object.m_body = nullptr;
object.m_bodyIndex = std::numeric_limits<UInt32>::max();

View File

@ -46,19 +46,40 @@ namespace Nz
m_updateTime = Time::Zero();
}
bool JoltPhysics3DSystem::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo)
bool JoltPhysics3DSystem::RaycastQuery(const Vector3f& from, const Vector3f& to, const FunctionRef<std::optional<float>(const RaycastHit& hitInfo)>& callback)
{
if (!m_physWorld.RaycastQueryFirst(from, to, hitInfo))
return false;
/*if (hitInfo->hitBody)
return m_physWorld.RaycastQuery(from, to, [&](const JoltPhysWorld3D::RaycastHit& hitInfo)
{
std::size_t uniqueIndex = hitInfo->hitBody->GetUniqueIndex();
if (uniqueIndex < m_physicsEntities.size())
hitInfo->hitEntity = entt::handle(m_registry, m_physicsEntities[uniqueIndex]);
}*/
RaycastHit extendedHitInfo;
static_cast<JoltPhysWorld3D::RaycastHit&>(extendedHitInfo) = hitInfo;
return true;
if (extendedHitInfo.hitBody)
{
std::size_t bodyIndex = extendedHitInfo.hitBody->GetBodyIndex();
if (bodyIndex < m_physicsEntities.size())
extendedHitInfo.hitEntity = entt::handle(m_registry, m_physicsEntities[bodyIndex]);
}
return callback(extendedHitInfo);
});
}
bool JoltPhysics3DSystem::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, const FunctionRef<void(const RaycastHit& hitInfo)>& callback)
{
return m_physWorld.RaycastQueryFirst(from, to, [&](const JoltPhysWorld3D::RaycastHit& hitInfo)
{
RaycastHit extendedHitInfo;
static_cast<JoltPhysWorld3D::RaycastHit&>(extendedHitInfo) = hitInfo;
if (extendedHitInfo.hitBody)
{
std::size_t bodyIndex = extendedHitInfo.hitBody->GetBodyIndex();
if (bodyIndex < m_physicsEntities.size())
extendedHitInfo.hitEntity = entt::handle(m_registry, m_physicsEntities[bodyIndex]);
}
callback(extendedHitInfo);
});
}
void JoltPhysics3DSystem::Update(Time elapsedTime)