mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 08:23:40 +02:00
improved shape prevents avatar walking up walls
This commit is contained in:
parent
6125357104
commit
72ad974b3e
6 changed files with 54 additions and 36 deletions
|
@ -37,12 +37,32 @@ void MyCharacterController::updateShapeIfNecessary() {
|
|||
if (_radius > 0.0f) {
|
||||
// create RigidBody if it doesn't exist
|
||||
if (!_rigidBody) {
|
||||
// HACK: the avatar collides using convex hull with a collision margin equal to
|
||||
// the old capsule radius. Two points define a capsule and additional points are
|
||||
// spread out at chest level to produce a slight taper toward the feet. This
|
||||
// makes the avatar more likely to collide with vertical walls at a higher point
|
||||
// and thus less likely to produce a single-point collision manifold below the
|
||||
// _maxStepHeight when walking into against vertical surfaces --> fixes a bug
|
||||
// where the "walk up steps" feature would allow the avatar to walk up vertical
|
||||
// walls.
|
||||
const int32_t NUM_POINTS = 6;
|
||||
btVector3 points[NUM_POINTS];
|
||||
btVector3 xAxis = btVector3(1.0f, 0.0f, 0.0f);
|
||||
btVector3 yAxis = btVector3(0.0f, 1.0f, 0.0f);
|
||||
btVector3 zAxis = btVector3(0.0f, 0.0f, 1.0f);
|
||||
points[0] = _halfHeight * yAxis;
|
||||
points[1] = -_halfHeight * yAxis;
|
||||
points[2] = (0.75f * _halfHeight) * yAxis - (0.1f * _radius) * zAxis;
|
||||
points[3] = (0.75f * _halfHeight) * yAxis + (0.1f * _radius) * zAxis;
|
||||
points[4] = (0.75f * _halfHeight) * yAxis - (0.1f * _radius) * xAxis;
|
||||
points[5] = (0.75f * _halfHeight) * yAxis + (0.1f * _radius) * xAxis;
|
||||
btCollisionShape* shape = new btConvexHullShape(reinterpret_cast<btScalar*>(points), NUM_POINTS);
|
||||
shape->setMargin(_radius);
|
||||
|
||||
// HACK: use some simple mass property defaults for now
|
||||
const float DEFAULT_AVATAR_MASS = 100.0f;
|
||||
const btVector3 DEFAULT_AVATAR_INERTIA_TENSOR(30.0f, 8.0f, 30.0f);
|
||||
|
||||
btCollisionShape* shape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
||||
_rigidBody = new btRigidBody(DEFAULT_AVATAR_MASS, nullptr, shape, DEFAULT_AVATAR_INERTIA_TENSOR);
|
||||
} else {
|
||||
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
||||
|
|
|
@ -116,8 +116,8 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
|||
// restore gravity settings because adding an object to the world overwrites its gravity setting
|
||||
_rigidBody->setGravity(_gravity * _currentUp);
|
||||
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
||||
assert(shape && shape->getShapeType() == CAPSULE_SHAPE_PROXYTYPE);
|
||||
_ghost.setCharacterCapsule(static_cast<btCapsuleShape*>(shape)); // KINEMATIC_CONTROLLER_HACK
|
||||
assert(shape && shape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE);
|
||||
_ghost.setCharacterShape(static_cast<btConvexHullShape*>(shape));
|
||||
}
|
||||
// KINEMATIC_CONTROLLER_HACK
|
||||
_ghost.setCollisionGroupAndMask(_collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR & (~ _collisionGroup));
|
||||
|
@ -171,7 +171,6 @@ bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld, btSc
|
|||
btVector3 normal = characterIsFirst ? contact.m_normalWorldOnB : -contact.m_normalWorldOnB; // points toward character
|
||||
btScalar hitHeight = _halfHeight + _radius + pointOnCharacter.dot(_currentUp);
|
||||
if (hitHeight < _maxStepHeight && normal.dot(_currentUp) > COS_PI_OVER_THREE) {
|
||||
//std::cout << "adebug manifoldIndex = " << i << " contactIndex = " << j << " hitOnCharacter*up = " << pointOnCharacter.dot(_currentUp) << std::endl; // adebug
|
||||
hasFloor = true;
|
||||
if (!pushing) {
|
||||
// we're not pushing against anything so we can early exit
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
#include <PhysicsHelpers.h>
|
||||
|
||||
#include "CharacterGhostShape.h"
|
||||
#include "CharacterRayResult.h"
|
||||
#include "CharacterGhostShape.h"
|
||||
|
||||
|
||||
CharacterGhostObject::~CharacterGhostObject() {
|
||||
|
@ -62,13 +62,14 @@ void CharacterGhostObject::setMotorVelocity(const btVector3& velocity) {
|
|||
}
|
||||
|
||||
// override of btCollisionObject::setCollisionShape()
|
||||
void CharacterGhostObject::setCharacterCapsule(btCapsuleShape* capsule) {
|
||||
assert(capsule);
|
||||
// we create our own CharacterGhostShape which has a larger Aabb for more reliable sweep tests
|
||||
void CharacterGhostObject::setCharacterShape(btConvexHullShape* shape) {
|
||||
assert(shape);
|
||||
// we create our own shape with an expanded Aabb for more reliable sweep tests
|
||||
if (_ghostShape) {
|
||||
delete _ghostShape;
|
||||
}
|
||||
_ghostShape = new CharacterGhostShape(capsule->getRadius(), 2.0f * capsule->getHalfHeight());
|
||||
|
||||
_ghostShape = new CharacterGhostShape(static_cast<const btConvexHullShape*>(shape));
|
||||
setCollisionShape(_ghostShape);
|
||||
}
|
||||
|
||||
|
@ -127,14 +128,10 @@ void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravit
|
|||
return;
|
||||
}
|
||||
|
||||
const btCollisionShape* shape = getCollisionShape();
|
||||
assert(shape->isConvex());
|
||||
const btConvexShape* convexShape= static_cast<const btConvexShape*>(shape);
|
||||
|
||||
// augment forwardSweep to help slow moving sweeps get over steppable ledges
|
||||
btScalar margin = shape->getMargin();
|
||||
if (overshoot < margin) {
|
||||
overshoot = margin;
|
||||
const btScalar MIN_OVERSHOOT = 0.04f; // default margin
|
||||
if (overshoot < MIN_OVERSHOOT) {
|
||||
overshoot = MIN_OVERSHOOT;
|
||||
}
|
||||
btScalar longSweepDistance = stepDistance + overshoot;
|
||||
forwardSweep *= longSweepDistance / stepDistance;
|
||||
|
@ -143,7 +140,7 @@ void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravit
|
|||
CharacterSweepResult result(this);
|
||||
btTransform nextTransform = startTransform;
|
||||
nextTransform.setOrigin(startPosition + forwardSweep);
|
||||
sweepTest(convexShape, startTransform, nextTransform, result); // forward
|
||||
sweepTest(_characterShape, startTransform, nextTransform, result); // forward
|
||||
|
||||
if (!result.hasHit()) {
|
||||
nextTransform.setOrigin(startPosition + (stepDistance / longSweepDistance) * forwardSweep);
|
||||
|
@ -151,7 +148,7 @@ void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravit
|
|||
updateTraction(nextTransform.getOrigin());
|
||||
return;
|
||||
}
|
||||
bool verticalOnly = btFabs(btFabs(_linearVelocity.dot(_upDirection)) - speed) < margin;
|
||||
bool verticalOnly = btFabs(btFabs(_linearVelocity.dot(_upDirection)) - speed) < MIN_OVERSHOOT;
|
||||
if (verticalOnly) {
|
||||
// no need to step
|
||||
nextTransform.setOrigin(startPosition + (result.m_closestHitFraction * stepDistance / longSweepDistance) * forwardSweep);
|
||||
|
@ -172,7 +169,7 @@ void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravit
|
|||
btVector3 hitFromBase = result.m_hitPointWorld - (startPosition - ((_radius + _halfHeight) * _upDirection));
|
||||
btScalar hitHeight = hitFromBase.dot(_upDirection);
|
||||
if (hitHeight > _maxStepHeight) {
|
||||
// capsule can't step over the obstacle so move forward as much as possible before we bail
|
||||
// shape can't step over the obstacle so move forward as much as possible before we bail
|
||||
btVector3 forwardTranslation = result.m_closestHitFraction * forwardSweep;
|
||||
btScalar forwardDistance = forwardTranslation.length();
|
||||
if (forwardDistance > stepDistance) {
|
||||
|
@ -195,7 +192,7 @@ void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravit
|
|||
result.resetHitHistory();
|
||||
startTransform.setOrigin(startPosition + availableStepHeight * _upDirection);
|
||||
nextTransform.setOrigin(startTransform.getOrigin() + forwardSweep);
|
||||
sweepTest(convexShape, startTransform, nextTransform, result);
|
||||
sweepTest(_characterShape, startTransform, nextTransform, result);
|
||||
if (result.hasHit()) {
|
||||
startTransform.setOrigin(startTransform.getOrigin() + result.m_closestHitFraction * forwardSweep);
|
||||
} else {
|
||||
|
@ -206,7 +203,7 @@ void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravit
|
|||
result.resetHitHistory();
|
||||
btVector3 downSweep = (- availableStepHeight) * _upDirection;
|
||||
nextTransform.setOrigin(startTransform.getOrigin() + downSweep);
|
||||
sweepTest(convexShape, startTransform, nextTransform, result);
|
||||
sweepTest(_characterShape, startTransform, nextTransform, result);
|
||||
if (result.hasHit() && result.m_hitNormalWorld.dot(_upDirection) > _maxWallNormalUpComponent) {
|
||||
// can stand on future landing spot, so we interpolate toward it
|
||||
_floorNormal = result.m_hitNormalWorld;
|
||||
|
@ -395,7 +392,7 @@ void CharacterGhostObject::updateTraction(const btVector3& position) {
|
|||
if (_hovering || _motorOnly) {
|
||||
_linearVelocity = _motorVelocity;
|
||||
} else if (_onFloor) {
|
||||
// compute a velocity that swings the capsule around the _floorContact
|
||||
// compute a velocity that swings the shape around the _floorContact
|
||||
btVector3 leverArm = _floorContact - position;
|
||||
btVector3 pathDirection = leverArm.cross(_motorVelocity.cross(leverArm));
|
||||
btScalar pathLength = pathDirection.length();
|
||||
|
@ -408,15 +405,11 @@ void CharacterGhostObject::updateTraction(const btVector3& position) {
|
|||
}
|
||||
|
||||
btScalar CharacterGhostObject::measureAvailableStepHeight() const {
|
||||
const btCollisionShape* shape = getCollisionShape();
|
||||
assert(shape->isConvex());
|
||||
const btConvexShape* convexShape= static_cast<const btConvexShape*>(shape);
|
||||
|
||||
CharacterSweepResult result(this);
|
||||
btTransform transform = getWorldTransform();
|
||||
btTransform nextTransform = transform;
|
||||
nextTransform.setOrigin(transform.getOrigin() + _maxStepHeight * _upDirection);
|
||||
sweepTest(convexShape, transform, nextTransform, result);
|
||||
sweepTest(_characterShape, transform, nextTransform, result);
|
||||
return result.m_closestHitFraction * _maxStepHeight;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
void setLinearVelocity(const btVector3& velocity) { _linearVelocity = velocity; }
|
||||
const btVector3& getLinearVelocity() const { return _linearVelocity; }
|
||||
|
||||
void setCharacterCapsule(btCapsuleShape* capsule);
|
||||
void setCharacterShape(btConvexHullShape* shape);
|
||||
|
||||
void setCollisionWorld(btCollisionWorld* world);
|
||||
|
||||
|
@ -88,8 +88,8 @@ protected:
|
|||
btScalar _radius { 0.0f };
|
||||
btScalar _maxWallNormalUpComponent { 0.0f }; // input: max vertical component of wall normal
|
||||
btScalar _maxStepHeight { 0.0f }; // input, max step height the character can climb
|
||||
btCapsuleShape* _characterShape { nullptr }; // input, shape of character
|
||||
CharacterGhostShape* _ghostShape{ nullptr }; // internal, shape whose Aabb is used for overlap cache
|
||||
btConvexHullShape* _characterShape { nullptr }; // input, shape of character
|
||||
CharacterGhostShape* _ghostShape { nullptr }; // internal, shape whose Aabb is used for overlap cache
|
||||
int16_t _collisionFilterGroup { 0 };
|
||||
int16_t _collisionFilterMask { 0 };
|
||||
bool _inWorld { false }; // internal, was added to world
|
||||
|
|
|
@ -10,9 +10,16 @@
|
|||
//
|
||||
|
||||
#include "CharacterGhostShape.h"
|
||||
CharacterGhostShape::CharacterGhostShape(const btConvexHullShape* shape) :
|
||||
btConvexHullShape(reinterpret_cast<const btScalar*>(shape->getUnscaledPoints()), shape->getNumPoints(), sizeof(btVector3)) {
|
||||
assert(shape);
|
||||
assert(shape->getUnscaledPoints());
|
||||
assert(shape->getNumPoints() > 0);
|
||||
setMargin(shape->getMargin());
|
||||
}
|
||||
|
||||
void CharacterGhostShape::getAabb (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const {
|
||||
btCapsuleShape::getAabb(t, aabbMin, aabbMax);
|
||||
btConvexHullShape::getAabb(t, aabbMin, aabbMax);
|
||||
// double the size of the Aabb by expanding both corners by half the extent
|
||||
btVector3 expansion = 0.5f * (aabbMax - aabbMin);
|
||||
aabbMin -= expansion;
|
||||
|
|
|
@ -12,13 +12,12 @@
|
|||
#ifndef hifi_CharacterGhostShape_h
|
||||
#define hifi_CharacterGhostShape_h
|
||||
|
||||
#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
|
||||
#include <BulletCollision/CollisionShapes/btConvexHullShape.h>
|
||||
|
||||
class CharacterGhostShape : public btCapsuleShape {
|
||||
// Same as btCapsuleShape but reports an expanded Aabb for larger ghost overlap cache
|
||||
class CharacterGhostShape : public btConvexHullShape {
|
||||
// Same as btConvexHullShape but reports an expanded Aabb for larger ghost overlap cache
|
||||
public:
|
||||
CharacterGhostShape(btScalar radius, btScalar height) : btCapsuleShape(radius, height) {
|
||||
}
|
||||
CharacterGhostShape(const btConvexHullShape* shape);
|
||||
|
||||
virtual void getAabb (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const override;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue