diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index cee0e6a1fa..b716d5c0d1 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -121,6 +121,8 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { _dynamicsWorld->addAction(this); // restore gravity settings because adding an object to the world overwrites its gravity setting _rigidBody->setGravity(_currentGravity * _currentUp); + // set flag to enable custom contactAddedCallback + _rigidBody->setCollisionFlags(btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); btCollisionShape* shape = _rigidBody->getCollisionShape(); assert(shape && shape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE); _ghost.setCharacterShape(static_cast(shape)); @@ -294,14 +296,14 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // compute the angle we will resolve for this dt, but don't overshoot float angle = 2.0f * acosf(qDot); - if ( dt < _followTimeRemaining) { + if (dt < _followTimeRemaining) { angle *= dt / _followTimeRemaining; } - + // accumulate rotation deltaRot = btQuaternion(axis, angle); _followAngularDisplacement = (deltaRot * _followAngularDisplacement).normalize(); - + // in order to accumulate displacement of avatar position, we need to take _shapeLocalOffset into account. btVector3 shapeLocalOffset = glmToBullet(_shapeLocalOffset); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 66a4edb486..eca8324e9f 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "CharacterController.h" #include "ObjectMotionState.h" @@ -26,6 +27,25 @@ #include "ThreadSafeDynamicsWorld.h" #include "PhysicsLogging.h" + +static bool flipNormalsMyAvatarVsBackfacingTriangles( btManifoldPoint& cp, + const btCollisionObjectWrapper* colObj0Wrap, int partId0, int index0, + const btCollisionObjectWrapper* colObj1Wrap, int partId1, int index1) { + if (colObj1Wrap->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE) { + auto triShape = static_cast(colObj1Wrap->getCollisionShape()); + const btVector3* v = triShape->m_vertices1; + btVector3 faceNormal = colObj1Wrap->getWorldTransform().getBasis() * btCross(v[1] - v[0], v[2] - v[0]); + float nDotF = btDot(faceNormal, cp.m_normalWorldOnB); + if (nDotF <= 0.0f) { + faceNormal.normalize(); + // flip the contact normal to be aligned with the face normal + cp.m_normalWorldOnB += -2.0f * nDotF * faceNormal; + } + } + // return value is currently ignored but to be future-proof: return false when not modifying friction + return false; +} + PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : _originOffset(offset), _myAvatarController(nullptr) { @@ -68,6 +88,9 @@ void PhysicsEngine::init() { // in order for its broadphase collision queries to work correctly. Look at how we use // _activeStaticBodies to track and update the Aabb's of moved static objects. _dynamicsWorld->setForceUpdateAllAabbs(false); + + // register contact filter to help MyAvatar pass through backfacing triangles + gContactAddedCallback = flipNormalsMyAvatarVsBackfacingTriangles; } }