|
@@ -267,7 +267,7 @@ void CharacterVirtual::DetermineConstraints(TempContactList &inContacts, Constra
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-bool CharacterVirtual::HandleContact(Vec3Arg inVelocity, Constraint &ioConstraint, Vec3Arg inGravity, float inDeltaTime) const
|
|
|
|
|
|
+bool CharacterVirtual::HandleContact(Vec3Arg inVelocity, Constraint &ioConstraint, float inDeltaTime) const
|
|
{
|
|
{
|
|
Contact &contact = *ioConstraint.mContact;
|
|
Contact &contact = *ioConstraint.mContact;
|
|
|
|
|
|
@@ -322,17 +322,17 @@ bool CharacterVirtual::HandleContact(Vec3Arg inVelocity, Constraint &ioConstrain
|
|
// Calculate the world space impulse to apply
|
|
// Calculate the world space impulse to apply
|
|
Vec3 world_impulse = -impulse * contact.mContactNormal;
|
|
Vec3 world_impulse = -impulse * contact.mContactNormal;
|
|
|
|
|
|
- // Add the impulse due to gravity working on the player: P = F dt = M g dt
|
|
|
|
- float normal_dot_gravity = contact.mContactNormal.Dot(inGravity);
|
|
|
|
- if (normal_dot_gravity < 0.0f)
|
|
|
|
- world_impulse -= (mMass * normal_dot_gravity / inGravity.Length() * inDeltaTime) * inGravity;
|
|
|
|
|
|
+ // Cancel impulse in down direction (we apply gravity later)
|
|
|
|
+ float impulse_dot_up = world_impulse.Dot(mUp);
|
|
|
|
+ if (impulse_dot_up < 0.0f)
|
|
|
|
+ world_impulse -= impulse_dot_up * mUp;
|
|
|
|
|
|
// Now apply the impulse (body is already locked so we use the no-lock interface)
|
|
// Now apply the impulse (body is already locked so we use the no-lock interface)
|
|
mSystem->GetBodyInterfaceNoLock().AddImpulse(contact.mBodyB, world_impulse, contact.mPosition);
|
|
mSystem->GetBodyInterfaceNoLock().AddImpulse(contact.mBodyB, world_impulse, contact.mPosition);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-void CharacterVirtual::SolveConstraints(Vec3Arg inVelocity, Vec3Arg inGravity, float inDeltaTime, float inTimeRemaining, ConstraintList &ioConstraints, IgnoredContactList &ioIgnoredContacts, float &outTimeSimulated, Vec3 &outDisplacement, TempAllocator &inAllocator
|
|
|
|
|
|
+void CharacterVirtual::SolveConstraints(Vec3Arg inVelocity, float inDeltaTime, float inTimeRemaining, ConstraintList &ioConstraints, IgnoredContactList &ioIgnoredContacts, float &outTimeSimulated, Vec3 &outDisplacement, TempAllocator &inAllocator
|
|
#ifdef JPH_DEBUG_RENDERER
|
|
#ifdef JPH_DEBUG_RENDERER
|
|
, bool inDrawConstraints
|
|
, bool inDrawConstraints
|
|
#endif // JPH_DEBUG_RENDERER
|
|
#endif // JPH_DEBUG_RENDERER
|
|
@@ -433,7 +433,7 @@ void CharacterVirtual::SolveConstraints(Vec3Arg inVelocity, Vec3Arg inGravity, f
|
|
if (!c->mContact->mHadCollision)
|
|
if (!c->mContact->mHadCollision)
|
|
{
|
|
{
|
|
// Handle the contact
|
|
// Handle the contact
|
|
- if (!HandleContact(velocity, *c, inGravity, inDeltaTime))
|
|
|
|
|
|
+ if (!HandleContact(velocity, *c, inDeltaTime))
|
|
{
|
|
{
|
|
// Constraint should be ignored, remove it from the list
|
|
// Constraint should be ignored, remove it from the list
|
|
c->mContact->mWasDiscarded = true;
|
|
c->mContact->mWasDiscarded = true;
|
|
@@ -562,8 +562,9 @@ void CharacterVirtual::SolveConstraints(Vec3Arg inVelocity, Vec3Arg inGravity, f
|
|
previous_contacts[num_previous_contacts] = constraint;
|
|
previous_contacts[num_previous_contacts] = constraint;
|
|
num_previous_contacts++;
|
|
num_previous_contacts++;
|
|
|
|
|
|
- // If there's not enough velocity left, bail
|
|
|
|
- if (velocity.LengthSq() < 1.0e-8f)
|
|
|
|
|
|
+ // Check early out
|
|
|
|
+ if (constraint->mProjectedVelocity < 1.0e-8f // Constraint should not be pushing, otherwise there may be other constraints that are pushing us
|
|
|
|
+ && velocity.LengthSq() < 1.0e-8f) // There's not enough velocity left
|
|
return;
|
|
return;
|
|
|
|
|
|
// If the constraint has velocity we accept the new velocity, otherwise check that we didn't reverse velocity
|
|
// If the constraint has velocity we accept the new velocity, otherwise check that we didn't reverse velocity
|
|
@@ -717,7 +718,7 @@ void CharacterVirtual::UpdateSupportingContact(bool inSkipContactVelocityCheck,
|
|
float time_simulated;
|
|
float time_simulated;
|
|
IgnoredContactList ignored_contacts(inAllocator);
|
|
IgnoredContactList ignored_contacts(inAllocator);
|
|
ignored_contacts.reserve(contacts.size());
|
|
ignored_contacts.reserve(contacts.size());
|
|
- SolveConstraints(-mUp, mSystem->GetGravity(), 1.0f, 1.0f, constraints, ignored_contacts, time_simulated, displacement, inAllocator);
|
|
|
|
|
|
+ SolveConstraints(-mUp, 1.0f, 1.0f, constraints, ignored_contacts, time_simulated, displacement, inAllocator);
|
|
|
|
|
|
// If we're blocked then we're supported, otherwise we're sliding
|
|
// If we're blocked then we're supported, otherwise we're sliding
|
|
float min_required_displacement_sq = Square(0.6f * mLastDeltaTime);
|
|
float min_required_displacement_sq = Square(0.6f * mLastDeltaTime);
|
|
@@ -740,7 +741,7 @@ void CharacterVirtual::StoreActiveContacts(const TempContactList &inContacts, Te
|
|
UpdateSupportingContact(true, inAllocator);
|
|
UpdateSupportingContact(true, inAllocator);
|
|
}
|
|
}
|
|
|
|
|
|
-void CharacterVirtual::MoveShape(Vec3 &ioPosition, Vec3Arg inVelocity, Vec3Arg inGravity, float inDeltaTime, ContactList *outActiveContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, TempAllocator &inAllocator
|
|
|
|
|
|
+void CharacterVirtual::MoveShape(Vec3 &ioPosition, Vec3Arg inVelocity, float inDeltaTime, ContactList *outActiveContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, TempAllocator &inAllocator
|
|
#ifdef JPH_DEBUG_RENDERER
|
|
#ifdef JPH_DEBUG_RENDERER
|
|
, bool inDrawConstraints
|
|
, bool inDrawConstraints
|
|
#endif // JPH_DEBUG_RENDERER
|
|
#endif // JPH_DEBUG_RENDERER
|
|
@@ -789,7 +790,7 @@ void CharacterVirtual::MoveShape(Vec3 &ioPosition, Vec3Arg inVelocity, Vec3Arg i
|
|
// Solve the displacement using these constraints
|
|
// Solve the displacement using these constraints
|
|
Vec3 displacement;
|
|
Vec3 displacement;
|
|
float time_simulated;
|
|
float time_simulated;
|
|
- SolveConstraints(inVelocity, inGravity, inDeltaTime, time_remaining, constraints, ignored_contacts, time_simulated, displacement, inAllocator
|
|
|
|
|
|
+ SolveConstraints(inVelocity, inDeltaTime, time_remaining, constraints, ignored_contacts, time_simulated, displacement, inAllocator
|
|
#ifdef JPH_DEBUG_RENDERER
|
|
#ifdef JPH_DEBUG_RENDERER
|
|
, draw_constraints
|
|
, draw_constraints
|
|
#endif // JPH_DEBUG_RENDERER
|
|
#endif // JPH_DEBUG_RENDERER
|
|
@@ -827,7 +828,7 @@ void CharacterVirtual::Update(float inDeltaTime, Vec3Arg inGravity, const BroadP
|
|
mLastDeltaTime = inDeltaTime;
|
|
mLastDeltaTime = inDeltaTime;
|
|
|
|
|
|
// Slide the shape through the world
|
|
// Slide the shape through the world
|
|
- MoveShape(mPosition, mLinearVelocity, inGravity, inDeltaTime, &mActiveContacts, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inAllocator
|
|
|
|
|
|
+ MoveShape(mPosition, mLinearVelocity, inDeltaTime, &mActiveContacts, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inAllocator
|
|
#ifdef JPH_DEBUG_RENDERER
|
|
#ifdef JPH_DEBUG_RENDERER
|
|
, sDrawConstraints
|
|
, sDrawConstraints
|
|
#endif // JPH_DEBUG_RENDERER
|
|
#endif // JPH_DEBUG_RENDERER
|
|
@@ -835,6 +836,18 @@ void CharacterVirtual::Update(float inDeltaTime, Vec3Arg inGravity, const BroadP
|
|
|
|
|
|
// Determine the object that we're standing on
|
|
// Determine the object that we're standing on
|
|
UpdateSupportingContact(false, inAllocator);
|
|
UpdateSupportingContact(false, inAllocator);
|
|
|
|
+
|
|
|
|
+ // If we're on the ground
|
|
|
|
+ if (!mGroundBodyID.IsInvalid() && mMass > 0.0f)
|
|
|
|
+ {
|
|
|
|
+ // Add the impulse to the ground due to gravity: P = F dt = M g dt
|
|
|
|
+ float normal_dot_gravity = mGroundNormal.Dot(inGravity);
|
|
|
|
+ if (normal_dot_gravity < 0.0f)
|
|
|
|
+ {
|
|
|
|
+ Vec3 world_impulse = -(mMass * normal_dot_gravity / inGravity.Length() * inDeltaTime) * inGravity;
|
|
|
|
+ mSystem->GetBodyInterface().AddImpulse(mGroundBodyID, world_impulse, mGroundPosition);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
void CharacterVirtual::RefreshContacts(const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, TempAllocator &inAllocator)
|
|
void CharacterVirtual::RefreshContacts(const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, TempAllocator &inAllocator)
|
|
@@ -922,7 +935,7 @@ bool CharacterVirtual::CanWalkStairs(Vec3Arg inLinearVelocity) const
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
-bool CharacterVirtual::WalkStairs(float inDeltaTime, Vec3Arg inGravity, Vec3Arg inStepUp, Vec3Arg inStepForward, Vec3Arg inStepForwardTest, Vec3Arg inStepDownExtra, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, TempAllocator &inAllocator)
|
|
|
|
|
|
+bool CharacterVirtual::WalkStairs(float inDeltaTime, Vec3Arg inStepUp, Vec3Arg inStepForward, Vec3Arg inStepForwardTest, Vec3Arg inStepDownExtra, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, TempAllocator &inAllocator)
|
|
{
|
|
{
|
|
// Move up
|
|
// Move up
|
|
Vec3 up = inStepUp;
|
|
Vec3 up = inStepUp;
|
|
@@ -946,7 +959,7 @@ bool CharacterVirtual::WalkStairs(float inDeltaTime, Vec3Arg inGravity, Vec3Arg
|
|
|
|
|
|
// Horizontal movement
|
|
// Horizontal movement
|
|
Vec3 new_position = up_position;
|
|
Vec3 new_position = up_position;
|
|
- MoveShape(new_position, inStepForward / inDeltaTime, inGravity, inDeltaTime, nullptr, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inAllocator);
|
|
|
|
|
|
+ MoveShape(new_position, inStepForward / inDeltaTime, inDeltaTime, nullptr, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inAllocator);
|
|
if (new_position.IsClose(up_position, 1.0e-8f))
|
|
if (new_position.IsClose(up_position, 1.0e-8f))
|
|
return false; // No movement, cancel
|
|
return false; // No movement, cancel
|
|
|
|
|