Fixed physics and added ghost body to virtual characters

This commit is contained in:
Antoine Pilote
2024-03-23 15:08:43 -04:00
parent 69205ec4fa
commit 48f2c69c38
2 changed files with 86 additions and 17 deletions

View File

@@ -72,7 +72,9 @@ namespace Nuake
static constexpr uint8_t NON_MOVING = 0;
static constexpr uint8_t MOVING = 1;
static constexpr uint8_t KINEMATIC = 2;
static constexpr uint8_t NUM_LAYERS = 3;
static constexpr uint8_t CHARACTER_GHOST = 3;
static constexpr uint8_t CHARACTER = 4;
static constexpr uint8_t NUM_LAYERS = 5;
};
// Function that determines if two object layers can collide
@@ -81,11 +83,13 @@ namespace Nuake
switch (inObject1)
{
case Layers::NON_MOVING:
return inObject2 == Layers::MOVING || inObject2 == Layers::KINEMATIC; // Non moving only collides with moving
return inObject2 == Layers::MOVING || inObject2 == Layers::KINEMATIC || inObject2 == Layers::CHARACTER; // Non moving only collides with moving
case Layers::MOVING:
return true; // Moving collides with everything
case Layers::KINEMATIC:
return inObject2 == Layers::NON_MOVING || inObject2 == Layers::MOVING; // Only collides with non moving
return inObject2 == Layers::NON_MOVING || inObject2 == Layers::MOVING || inObject2 == Layers::CHARACTER; // Only collides with non moving
case Layers::CHARACTER:
return true;
default:
//JPH_ASSERT(false);
return false;
@@ -114,6 +118,8 @@ namespace Nuake
// Create a mapping table from object to broad phase layer
mObjectToBroadPhase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING;
mObjectToBroadPhase[Layers::MOVING] = BroadPhaseLayers::MOVING;
mObjectToBroadPhase[Layers::CHARACTER] = BroadPhaseLayers::MOVING;
mObjectToBroadPhase[Layers::CHARACTER_GHOST] = BroadPhaseLayers::MOVING;
}
virtual JPH::uint GetNumBroadPhaseLayers() const override
@@ -239,9 +245,13 @@ namespace Nuake
switch (inObject1)
{
case Layers::NON_MOVING:
return inObject2 == Layers::MOVING; // Non moving only collides with moving
return inObject2 == Layers::MOVING || Layers::CHARACTER_GHOST; // Non moving only collides with moving
case Layers::MOVING:
return true; // Moving collides with everything
case Layers::CHARACTER_GHOST:
return true;// inObject2 != Layers::CHARACTER;
case Layers::CHARACTER:
return inObject2 != Layers::CHARACTER_GHOST;
default:
return false;
@@ -258,7 +268,7 @@ namespace Nuake
{
DynamicWorld::DynamicWorld() : _stepCount(0)
{
_registeredCharacters = std::map<uint32_t, Ref<JPH::CharacterVirtual>>();
_registeredCharacters = std::map<uint32_t, CharacterGhostPair>();
// Initialize Jolt Physics
const uint32_t MaxBodies = 4096;
@@ -364,7 +374,8 @@ namespace Nuake
bodySettings.mUserData = entityId;
// Create the actual rigid body
JPH::BodyID body = _JoltBodyInterface->CreateAndAddBody(bodySettings, JPH::EActivation::Activate); // Note that if we run out of bodies this can return nullptr
uint32_t bodyIndex = (uint32_t)body.GetIndex();
uint32_t bodyIndex = (uint32_t)body.GetIndexAndSequenceNumber();
auto userData = _JoltBodyInterface->GetUserData(body);
_registeredBodies.push_back(bodyIndex);
}
@@ -386,10 +397,34 @@ namespace Nuake
const Quat& bodyRotation = cc->Rotation;
const auto& joltRotation = JPH::Quat(bodyRotation.x, bodyRotation.y, bodyRotation.z, bodyRotation.w);
auto character = CreateRef<JPH::CharacterVirtual>(settings, std::move(joltPosition), std::move(joltRotation), _JoltPhysicsSystem.get());
auto character = CreateRef<JPH::CharacterVirtual>(settings, std::move(joltPosition), joltRotation, _JoltPhysicsSystem.get());
// add ghost kinematic body to respond to hit test as the virtual char are not present in the world.
JPH::BodyInterface& bodyInterface = _JoltPhysicsSystem->GetBodyInterface();
const float mass = 0.1f;
JPH::EMotionType motionType = JPH::EMotionType::Kinematic;
JPH::ObjectLayer layer = Layers::CHARACTER_GHOST;
const auto& startPos = joltPosition;
auto joltShape = GetJoltShape(cc->Shape);
JPH::BodyCreationSettings bodySettings(joltShape, startPos, joltRotation, motionType, layer);
int entityId = cc->GetEntity().GetID();
if (entityId == 0)
{
Logger::Log("ERROR");
}
//bodySettings.mUserData = entityId;
// Create the actual rigid body
JPH::BodyID body = _JoltBodyInterface->CreateAndAddBody(bodySettings, JPH::EActivation::Activate); // Note that if we run out of bodies this can return nullptr
uint32_t bodyIndex = body.GetIndexAndSequenceNumber();
_registeredBodies.push_back(bodyIndex);
// To get the jolt character control from a scene entity.
_registeredCharacters[cc->Owner.GetHandle()] = character;
_registeredCharacters[cc->Owner.GetHandle()] = CharacterGhostPair{ character, bodyIndex };
}
bool DynamicWorld::IsCharacterGrounded(const Entity& entity)
@@ -397,7 +432,7 @@ namespace Nuake
const uint32_t entityHandle = entity.GetHandle();
if (_registeredCharacters.find(entityHandle) != _registeredCharacters.end())
{
auto& characterController = _registeredCharacters[entityHandle];
auto& characterController = _registeredCharacters[entityHandle].Character;
const auto groundState = characterController->GetGroundState();
return groundState == JPH::CharacterBase::EGroundState::OnGround;
@@ -493,7 +528,7 @@ namespace Nuake
{
Entity entity { (entt::entity)e.first, Engine::GetCurrentScene().get()};
Ref<JPH::CharacterVirtual> characterController = e.second;
Ref<JPH::CharacterVirtual> characterController = e.second.Character;
JPH::Mat44 joltTransform = characterController->GetWorldTransform();
const auto bodyRotation = characterController->GetRotation();
@@ -571,7 +606,7 @@ namespace Nuake
auto characterController = characterControllerComponent.GetCharacterController();
const auto& broadPhaseLayerFilter = _JoltPhysicsSystem->GetDefaultBroadPhaseLayerFilter(Layers::NON_MOVING);
const auto& LayerFilter = _JoltPhysicsSystem->GetDefaultLayerFilter(Layers::MOVING);
const auto& LayerFilter = _JoltPhysicsSystem->GetDefaultLayerFilter(Layers::CHARACTER);
const auto& joltGravity = _JoltPhysicsSystem->GetGravity();
auto& tempAllocatorPtr = *(joltTempAllocator);
if (characterController->AutoStepping)
@@ -583,11 +618,11 @@ namespace Nuake
joltUpdateSettings.mWalkStairsStepForwardTest = characterController->StepDistance;
joltUpdateSettings.mWalkStairsMinStepForward = characterController->StepMinDistance;
c.second->ExtendedUpdate(ts, joltGravity, joltUpdateSettings, broadPhaseLayerFilter, LayerFilter, { }, { }, tempAllocatorPtr);
c.second.Character->ExtendedUpdate(ts, joltGravity, joltUpdateSettings, broadPhaseLayerFilter, LayerFilter, { }, { }, tempAllocatorPtr);
}
else
{
c.second->Update(ts, joltGravity, broadPhaseLayerFilter, LayerFilter, {}, {}, tempAllocatorPtr);
c.second.Character->Update(ts, joltGravity, broadPhaseLayerFilter, LayerFilter, {}, {}, tempAllocatorPtr);
}
}
}
@@ -599,6 +634,30 @@ namespace Nuake
Logger::Log("Failed to run simulation update", "physics", CRITICAL);
}
for (auto& c : _registeredCharacters)
{
uint32_t ghostId = c.second.Ghost;
JPH::Mat44 joltTransform = c.second.Character->GetWorldTransform();
const auto bodyRotation = c.second.Character->GetRotation();
Matrix4 transform = glm::mat4(
joltTransform(0, 0), joltTransform(1, 0), joltTransform(2, 0), joltTransform(3, 0),
joltTransform(0, 1), joltTransform(1, 1), joltTransform(2, 1), joltTransform(3, 1),
joltTransform(0, 2), joltTransform(1, 2), joltTransform(2, 2), joltTransform(3, 2),
joltTransform(0, 3), joltTransform(1, 3), joltTransform(2, 3), joltTransform(3, 3)
);
Vector3 scale = Vector3();
Quat rotation = Quat();
Vector3 pos = Vector3();
Vector3 skew = Vector3();
Vector4 pesp = Vector4();
glm::decompose(transform, scale, rotation, pos, skew, pesp);
//auto& bodyInterface = _JoltPhysicsSystem->GetBodyInterfaceNoLock();
_JoltBodyInterface->MoveKinematic(static_cast<JPH::BodyID>(ghostId), JPH::Vec3{ pos.x, pos.y, pos.z }, { rotation.x, rotation.y, rotation.z, rotation.w }, 1.0);
}
SyncEntitiesTranforms();
SyncCharactersTransforms();
}
@@ -629,8 +688,12 @@ namespace Nuake
const uint32_t entityHandle = entity.GetHandle();
if (_registeredCharacters.find(entityHandle) != _registeredCharacters.end())
{
auto& characterController = _registeredCharacters[entityHandle];
characterController->SetLinearVelocity(JPH::Vec3(velocity.x, velocity.y, velocity.z));
auto& characterController = _registeredCharacters[entityHandle].Character;
const auto& joltVelocity = JPH::Vec3(velocity.x, velocity.y, velocity.z);
characterController->SetLinearVelocity(joltVelocity);
auto& ghost = _registeredCharacters[entityHandle].Ghost;
//_JoltBodyInterface->SetLinearVelocity(static_cast<JPH::BodyID>(ghost), joltVelocity);
}
}
@@ -640,7 +703,7 @@ namespace Nuake
for (const auto& body : _registeredBodies)
{
auto bodyId = static_cast<JPH::BodyID>(body);
auto entityId = static_cast<uint32_t>(bodyInterface.GetUserData(bodyId));
auto entityId = bodyInterface.GetUserData(bodyId);
if (entityId == entity.GetID())
{
bodyInterface.AddForce(bodyId, JPH::Vec3(force.x, force.y, force.z));

View File

@@ -35,6 +35,12 @@ namespace Nuake
namespace Physics
{
struct CharacterGhostPair
{
Ref<JPH::CharacterVirtual> Character;
uint32_t Ghost;
};
class DynamicWorld
{
private:
@@ -48,7 +54,7 @@ namespace Nuake
BPLayerInterfaceImpl* _JoltBroadphaseLayerInterface;
std::vector<uint32_t> _registeredBodies;
std::map<uint32_t, Ref<JPH::CharacterVirtual>> _registeredCharacters;
std::map<uint32_t, CharacterGhostPair> _registeredCharacters;
public:
DynamicWorld();