mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-28 21:07:59 +03:00
Better slope handling, worse sudden elevation change handling.
This commit is contained in:
parent
e8e9fdafa2
commit
a2d77ae164
3 changed files with 41 additions and 41 deletions
|
@ -1,4 +1,4 @@
|
|||
#include "actor.hpp"
|
||||
#include "actor.hpp"
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btCylinderShape.h>
|
||||
|
||||
|
@ -36,6 +36,7 @@ namespace MWPhysics
|
|||
, mExternalCollisionMode(true)
|
||||
, mActive(false)
|
||||
, mTaskScheduler(scheduler)
|
||||
, mCurrentDeltaZ(0.0f)
|
||||
{
|
||||
// We can not create actor without collisions - he will fall through the ground.
|
||||
// In this case we should autogenerate collision box based on mesh shape
|
||||
|
|
|
@ -146,6 +146,8 @@ namespace MWPhysics
|
|||
|
||||
void setActive(bool value) { mActive = value; }
|
||||
|
||||
float mCurrentDeltaZ;
|
||||
|
||||
DetourNavigator::CollisionShapeType getCollisionShapeType() const { return mCollisionShapeType; }
|
||||
|
||||
private:
|
||||
|
|
|
@ -775,82 +775,72 @@ namespace MWPhysics
|
|||
osg::ref_ptr<osg::MatrixTransform> leftFootBone;
|
||||
osg::ref_ptr<osg::MatrixTransform> rightFootBone;
|
||||
|
||||
// Cast rays from actor feet and pull the actor down to the ground
|
||||
float desiredDeltaZ = 0.0f;
|
||||
|
||||
if (physicActor.get()->getOnGround())
|
||||
{
|
||||
// Finding left leg bones
|
||||
// Finding leg bones
|
||||
std::vector<std::string> leftLegBoneChainNames = { "Bip01 L Thigh", "Bip01 L Calf", "Bip01 L Foot" };
|
||||
std::vector<std::string> rightLegBoneChainNames = { "Bip01 R Thigh", "Bip01 R Calf", "Bip01 R Foot" };
|
||||
gatherMatchingBones(
|
||||
actptr.getRefData().getBaseNode()->asGroup(), leftLegBoneChainNames, leftLegBoneChain);
|
||||
|
||||
// Finding right leg bones
|
||||
std::vector<std::string> rightLegBoneChainNames = { "Bip01 R Thigh", "Bip01 R Calf", "Bip01 R Foot" };
|
||||
gatherMatchingBones(
|
||||
actptr.getRefData().getBaseNode()->asGroup(), rightLegBoneChainNames, rightLegBoneChain);
|
||||
|
||||
// Left foot stuff and ray cast
|
||||
osg::Matrix leftFootWorldMatrix;
|
||||
// Compute world transformation for foot bones
|
||||
osg::Matrix leftFootWorldMatrix, rightFootWorldMatrix;
|
||||
if (leftLegBoneChain.size() == leftLegBoneChainNames.size())
|
||||
leftFootBone = leftLegBoneChain.back();
|
||||
if (leftFootBone)
|
||||
leftFootWorldMatrix = osg::computeLocalToWorld(leftFootBone->getParentalNodePaths()[0]);
|
||||
osg::Vec3f leftFootPos
|
||||
= leftFootBone ? static_cast<osg::Vec3f>(leftFootWorldMatrix.getTrans()) : colliderPos;
|
||||
leftRayCast = castRay(leftFootPos, leftFootPos - osg::Vec3f(0.0f, 0.0f, 50.0f),
|
||||
CollisionType_HeightMap + CollisionType_World);
|
||||
|
||||
// Right foot stuff and ray cast
|
||||
osg::Matrix rightFootWorldMatrix;
|
||||
if (rightLegBoneChain.size() == rightLegBoneChainNames.size())
|
||||
rightFootBone = rightLegBoneChain.back();
|
||||
if (rightFootBone)
|
||||
rightFootWorldMatrix = osg::computeLocalToWorld(rightFootBone->getParentalNodePaths()[0]);
|
||||
osg::Vec3f rightFootPos
|
||||
= rightFootBone ? static_cast<osg::Vec3f>(rightFootWorldMatrix.getTrans()) : colliderPos;
|
||||
|
||||
// Perform raycasts
|
||||
leftRayCast = castRay(leftFootPos, leftFootPos - osg::Vec3f(0.0f, 0.0f, 50.0f),
|
||||
CollisionType_HeightMap + CollisionType_World);
|
||||
rightRayCast = castRay(rightFootPos, rightFootPos - osg::Vec3f(0.0f, 0.0f, 50.0f),
|
||||
CollisionType_HeightMap + CollisionType_World);
|
||||
|
||||
// Determine the largest raycast distance and adjust the position accordingly
|
||||
// Determine the desired delta Z
|
||||
if (leftRayCast.mHit && rightRayCast.mHit)
|
||||
{
|
||||
if (leftRayCast.mHitPos.z() < rightRayCast.mHitPos.z())
|
||||
{
|
||||
desiredPos.z() = leftRayCast.mHitPos.z();
|
||||
}
|
||||
else
|
||||
{
|
||||
desiredPos.z() = rightRayCast.mHitPos.z();
|
||||
}
|
||||
desiredDeltaZ = std::min(leftRayCast.mHitPos.z(), rightRayCast.mHitPos.z()) - colliderPos.z();
|
||||
}
|
||||
else if (leftRayCast.mHit)
|
||||
{
|
||||
desiredPos.z() = leftRayCast.mHitPos.z();
|
||||
desiredDeltaZ = leftRayCast.mHitPos.z() - colliderPos.z();
|
||||
}
|
||||
else if (rightRayCast.mHit)
|
||||
{
|
||||
desiredPos.z() = rightRayCast.mHitPos.z();
|
||||
desiredDeltaZ = rightRayCast.mHitPos.z() - colliderPos.z();
|
||||
}
|
||||
}
|
||||
|
||||
// Lerp actor Z position to smooth out sudden elevation transitions
|
||||
// Note: current solution is bad, this smoothing results in actors lagging behind on downslopes,
|
||||
// ideally only actual sudden jarring changes should be detected and smoothed out, but not slopes.
|
||||
osg::Vec3 lerpedPos = desiredPos;
|
||||
lerpedPos.z() = std::lerp(visualPos.z(), desiredPos.z(), mPhysicsDt * armatureZLerpSpeed);
|
||||
// Lerp the current delta Z towards the desired delta Z
|
||||
physicActor->mCurrentDeltaZ
|
||||
= std::lerp(physicActor->mCurrentDeltaZ, desiredDeltaZ, mPhysicsDt * armatureZLerpSpeed);
|
||||
|
||||
// For some reason player and actors supposed to be kept separately, so we do that here
|
||||
// Calculate the new armature position using the lerped delta Z
|
||||
osg::Vec3 armaturePos = colliderPos;
|
||||
armaturePos.z() += physicActor->mCurrentDeltaZ;
|
||||
|
||||
// For some reason player and actors supposed to be kept separately
|
||||
if (physicActor.get() != player)
|
||||
mActorsPositions.emplace_back(physicActor->getPtr(), physicActor->getSimulationPosition());
|
||||
|
||||
// Finally adjust position based on lerped data, this will adjust both player and actors
|
||||
world->moveObject(actptr, lerpedPos, false, false);
|
||||
// Finally adjust position based on the new armature position
|
||||
world->moveObject(actptr, armaturePos, false, false);
|
||||
|
||||
// At this point actor is moved down (if necessary) under its collider to touch the ground level, one of its
|
||||
// feet is most likely clipping through the ground, we raycast to detect that and use ik to bend the leg up
|
||||
|
||||
// Detecting righ leg clipping
|
||||
MWPhysics::RayCastingResult rightRayUpCast;
|
||||
MWPhysics::RayCastingResult leftRayUpCast;
|
||||
// Casting up from feet to detect clipping
|
||||
MWPhysics::RayCastingResult rightRayUpCast, leftRayUpCast;
|
||||
if (rightFootBone)
|
||||
{
|
||||
auto rightFootWorldMatrix = osg::computeLocalToWorld(rightFootBone->getParentalNodePaths()[0]);
|
||||
|
@ -859,13 +849,12 @@ namespace MWPhysics
|
|||
CollisionType_HeightMap + CollisionType_World);
|
||||
}
|
||||
|
||||
// IK-fixing the right leg
|
||||
if (rightRayUpCast.mHit)
|
||||
{
|
||||
|
||||
auto& debugRender = world->getRenderingManager()->getDebugDrawer();
|
||||
/*debugRender.drawCube(rightRayCast.mHitPos, osg::Vec3(10.0, 10.0, 10.0), Debug::colorBlue);*/
|
||||
|
||||
// Perform IK for right leg
|
||||
if (rightLegBoneChain.size() > 0)
|
||||
{
|
||||
// Note that its possible to provide a pole direction to specify in which direction a knee should
|
||||
|
@ -881,7 +870,6 @@ namespace MWPhysics
|
|||
}
|
||||
}
|
||||
|
||||
// Detecting left leg clipping
|
||||
if (leftFootBone)
|
||||
{
|
||||
auto leftFootWorldMatrix = osg::computeLocalToWorld(leftFootBone->getParentalNodePaths()[0]);
|
||||
|
@ -890,12 +878,12 @@ namespace MWPhysics
|
|||
CollisionType_HeightMap + CollisionType_World);
|
||||
}
|
||||
|
||||
// IK-fixing the left leg
|
||||
if (leftRayUpCast.mHit)
|
||||
{
|
||||
auto& debugRender = world->getRenderingManager()->getDebugDrawer();
|
||||
/*debugRender.drawCube(leftRayCast.mHitPos, osg::Vec3(10.0, 10.0, 10.0), Debug::colorBlue);*/
|
||||
|
||||
// Perform IK for left leg
|
||||
if (leftLegBoneChain.size() > 0)
|
||||
{
|
||||
EasyIK leftLegIK(leftLegBoneChain, leftRayUpCast.mHitPos + osg::Vec3f(0.0f, 0.0f, leftFootHeight),
|
||||
|
@ -907,6 +895,15 @@ namespace MWPhysics
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*for (const auto& [ptr, pos] : mActorsPositions)
|
||||
{
|
||||
|
||||
world->moveObject(ptr, desiredPos, false, false);
|
||||
}
|
||||
|
||||
if (player != nullptr)
|
||||
world->moveObject(player->getPtr(), player->getSimulationPosition(), false, false);*/
|
||||
}
|
||||
|
||||
void PhysicsSystem::updateAnimatedCollisionShape(const MWWorld::Ptr& object)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue