From d34b667e82ea1b9f93e36670e356ffeee02c3fc3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 30 Mar 2017 18:18:01 -0700 Subject: [PATCH] remove kinematic character controller implemention --- .../src/avatar/MyCharacterController.cpp | 152 --------- interface/src/avatar/MyCharacterController.h | 2 - libraries/physics/src/CharacterController.cpp | 4 - .../physics/src/CharacterGhostObject.cpp | 316 ------------------ libraries/physics/src/CharacterGhostObject.h | 41 --- 5 files changed, 515 deletions(-) diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index e90022b2c5..0cdbc77626 100755 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -201,158 +201,6 @@ bool MyCharacterController::testRayShotgun(const glm::vec3& position, const glm: return result.hitFraction < 1.0f; } -glm::vec3 MyCharacterController::computeHMDStep(const glm::vec3& position, const glm::vec3& step) { - btVector3 stepDirection = glmToBullet(step); - btScalar stepLength = stepDirection.length(); - if (stepLength < FLT_EPSILON) { - return glm::vec3(0.0f); - } - stepDirection /= stepLength; - - // get _ghost ready for ray traces - btTransform transform = _rigidBody->getWorldTransform(); - btVector3 newPosition = glmToBullet(position); - transform.setOrigin(newPosition); - btMatrix3x3 rotation = transform.getBasis(); - _ghost.setWorldTransform(transform); - _ghost.refreshOverlappingPairCache(); - - // compute rotation that will orient local ray start points to face stepDirection - btVector3 forward = rotation * btVector3(0.0f, 0.0f, -1.0f); - btVector3 horizontalDirection = stepDirection - stepDirection.dot(_currentUp) * _currentUp; - btVector3 axis = forward.cross(horizontalDirection); - btScalar lengthAxis = axis.length(); - if (lengthAxis > FLT_EPSILON) { - // non-zero sideways component - btScalar angle = asinf(lengthAxis / horizontalDirection.length()); - if (stepDirection.dot(forward) < 0.0f) { - angle = PI - angle; - } - axis /= lengthAxis; - rotation = btMatrix3x3(btQuaternion(axis, angle)) * rotation; - } else if (stepDirection.dot(forward) < 0.0f) { - // backwards - rotation = btMatrix3x3(btQuaternion(_currentUp, PI)) * rotation; - } - - CharacterRayResult rayResult(&_ghost); - btVector3 rayStart; - btVector3 rayEnd; - btVector3 penetration = btVector3(0.0f, 0.0f, 0.0f); - int32_t numPenetrations = 0; - - { // first we scan straight out from capsule center to see if we're stuck on anything - btScalar forwardRatio = 0.5f; - btScalar backRatio = 0.25f; - - btVector3 radial; - bool stuck = false; - for (int32_t i = 0; i < _topPoints.size(); ++i) { - rayStart = rotation * _topPoints[i]; - radial = rayStart - rayStart.dot(_currentUp) * _currentUp; - rayEnd = newPosition + rayStart + forwardRatio * radial; - rayStart += newPosition - backRatio * radial; - - // reset rayResult for next test - rayResult.m_closestHitFraction = 1.0f; - rayResult.m_collisionObject = nullptr; - - if (_ghost.rayTest(rayStart, rayEnd, rayResult)) { - btScalar totalRatio = backRatio + forwardRatio; - btScalar adjustedHitFraction = (rayResult.m_closestHitFraction * totalRatio - backRatio) / forwardRatio; - if (adjustedHitFraction < 0.0f) { - penetration += adjustedHitFraction * radial; - ++numPenetrations; - } else { - stuck = true; - } - } - } - if (numPenetrations > 0) { - if (numPenetrations > 1) { - penetration /= (btScalar)numPenetrations; - } - return bulletToGLM(penetration); - } else if (stuck) { - return glm::vec3(0.0f); - } - } - - // if we get here then we're not stuck pushing into any surface - // so now we scan to see if the way before us is "walkable" - - // scan the top - // NOTE: if we scan an extra distance forward we can detect flat surfaces that are too steep to walk on. - // The approximate extra distance can be derived with trigonometry. - // - // minimumForward = [ (maxStepHeight + radius / cosTheta - radius) * (cosTheta / sinTheta) - radius ] - // - // where: theta = max angle between floor normal and vertical - // - // if stepLength is not long enough we can add the difference. - // - btScalar cosTheta = _minFloorNormalDotUp; - btScalar sinTheta = sqrtf(1.0f - cosTheta * cosTheta); - const btScalar MIN_FORWARD_SLOP = 0.10f; // HACK: not sure why this is necessary to detect steepest walkable slope - btScalar forwardSlop = (_maxStepHeight + _radius / cosTheta - _radius) * (cosTheta / sinTheta) - (_radius + stepLength) + MIN_FORWARD_SLOP; - if (forwardSlop < 0.0f) { - // BIG step, no slop necessary - forwardSlop = 0.0f; - } - - // we push the step forward by stepMargin to help reduce accidental penetration - const btScalar MIN_STEP_MARGIN = 0.04f; - btScalar stepMargin = glm::max(_radius, MIN_STEP_MARGIN); - btScalar expandedStepLength = stepLength + forwardSlop + stepMargin; - - // loop over topPoints - bool walkable = true; - for (int32_t i = 0; i < _topPoints.size(); ++i) { - rayStart = newPosition + rotation * _topPoints[i]; - rayEnd = rayStart + expandedStepLength * stepDirection; - - // reset rayResult for next test - rayResult.m_closestHitFraction = 1.0f; - rayResult.m_collisionObject = nullptr; - - if (_ghost.rayTest(rayStart, rayEnd, rayResult)) { - if (rayResult.m_hitNormalWorld.dot(_currentUp) < _minFloorNormalDotUp) { - walkable = false; - break; - } - } - } - - // scan the bottom - // TODO: implement sliding along sloped floors - bool steppingUp = false; - expandedStepLength = stepLength + MIN_FORWARD_SLOP + MIN_STEP_MARGIN; - for (int32_t i = _bottomPoints.size() - 1; i > -1; --i) { - rayStart = newPosition + rotation * _bottomPoints[i] - MIN_STEP_MARGIN * stepDirection; - rayEnd = rayStart + expandedStepLength * stepDirection; - - // reset rayResult for next test - rayResult.m_closestHitFraction = 1.0f; - rayResult.m_collisionObject = nullptr; - - if (_ghost.rayTest(rayStart, rayEnd, rayResult)) { - btScalar adjustedHitFraction = (rayResult.m_closestHitFraction * expandedStepLength - MIN_STEP_MARGIN) / (stepLength + MIN_FORWARD_SLOP); - if (adjustedHitFraction < 1.0f) { - steppingUp = true; - break; - } - } - } - - if (!walkable && steppingUp ) { - return glm::vec3(0.0f); - } - // else it might not be walkable, but we aren't steppingUp yet which means we can still move forward - - // TODO: slide up ramps and fall off edges (then we can remove the vertical follow of Avatar's RigidBody) - return step; -} - btConvexHullShape* MyCharacterController::computeShape() const { // 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 diff --git a/interface/src/avatar/MyCharacterController.h b/interface/src/avatar/MyCharacterController.h index df9d31d3c5..6b38736352 100644 --- a/interface/src/avatar/MyCharacterController.h +++ b/interface/src/avatar/MyCharacterController.h @@ -40,8 +40,6 @@ public: /// return true if RayShotgun hits anything bool testRayShotgun(const glm::vec3& position, const glm::vec3& step, RayShotgunResult& result); - glm::vec3 computeHMDStep(const glm::vec3& position, const glm::vec3& step); - protected: void initRayShotgun(const btCollisionWorld* world); diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 95fcb27684..8150f8b45d 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -126,10 +126,6 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { _ghost.setCollisionGroupAndMask(_collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR & (~ _collisionGroup)); _ghost.setCollisionWorld(_dynamicsWorld); _ghost.setRadiusAndHalfHeight(_radius, _halfHeight); - _ghost.setMaxStepHeight(0.75f * (_radius + _halfHeight)); - _ghost.setMinWallAngle(PI / 4.0f); - _ghost.setUpDirection(_currentUp); - _ghost.setMotorOnly(true); _ghost.setWorldTransform(_rigidBody->getWorldTransform()); } if (_dynamicsWorld) { diff --git a/libraries/physics/src/CharacterGhostObject.cpp b/libraries/physics/src/CharacterGhostObject.cpp index 563605cd16..331485dd01 100755 --- a/libraries/physics/src/CharacterGhostObject.cpp +++ b/libraries/physics/src/CharacterGhostObject.cpp @@ -45,22 +45,6 @@ void CharacterGhostObject::setRadiusAndHalfHeight(btScalar radius, btScalar half _halfHeight = halfHeight; } -void CharacterGhostObject::setUpDirection(const btVector3& up) { - btScalar length = up.length(); - if (length > FLT_EPSILON) { - _upDirection /= length; - } else { - _upDirection = btVector3(0.0f, 1.0f, 0.0f); - } -} - -void CharacterGhostObject::setMotorVelocity(const btVector3& velocity) { - _motorVelocity = velocity; - if (_motorOnly) { - _linearVelocity = _motorVelocity; - } -} - // override of btCollisionObject::setCollisionShape() void CharacterGhostObject::setCharacterShape(btConvexHullShape* shape) { assert(shape); @@ -81,164 +65,6 @@ void CharacterGhostObject::setCollisionWorld(btCollisionWorld* world) { } } -void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravity) { - bool oldOnFloor = _onFloor; - _onFloor = false; - _steppingUp = false; - assert(_world && _inWorld); - updateVelocity(dt, gravity); - - // resolve any penetrations before sweeping - int32_t MAX_LOOPS = 4; - int32_t numExtractions = 0; - btVector3 totalPosition(0.0f, 0.0f, 0.0f); - while (numExtractions < MAX_LOOPS) { - if (resolvePenetration(numExtractions)) { - numExtractions = 0; - break; - } - totalPosition += getWorldTransform().getOrigin(); - ++numExtractions; - } - if (numExtractions > 1) { - // penetration resolution was probably oscillating between opposing objects - // so we use the average of the solutions - totalPosition /= btScalar(numExtractions); - btTransform transform = getWorldTransform(); - transform.setOrigin(totalPosition); - setWorldTransform(transform); - - // TODO: figure out how to untrap character - } - btTransform startTransform = getWorldTransform(); - btVector3 startPosition = startTransform.getOrigin(); - if (_onFloor) { - // resolvePenetration() pushed the avatar out of a floor so - // we must updateTraction() before using _linearVelocity - updateTraction(startPosition); - } - - btScalar speed = _linearVelocity.length(); - btVector3 forwardSweep = dt * _linearVelocity; - btScalar stepDistance = dt * speed; - btScalar MIN_SWEEP_DISTANCE = 0.0001f; - if (stepDistance < MIN_SWEEP_DISTANCE) { - // not moving, no need to sweep - updateTraction(startPosition); - return; - } - - // augment forwardSweep to help slow moving sweeps get over steppable ledges - const btScalar MIN_OVERSHOOT = 0.04f; // default margin - if (overshoot < MIN_OVERSHOOT) { - overshoot = MIN_OVERSHOOT; - } - btScalar longSweepDistance = stepDistance + overshoot; - forwardSweep *= longSweepDistance / stepDistance; - - // step forward - CharacterSweepResult result(this); - btTransform nextTransform = startTransform; - nextTransform.setOrigin(startPosition + forwardSweep); - sweepTest(_characterShape, startTransform, nextTransform, result); // forward - - if (!result.hasHit()) { - nextTransform.setOrigin(startPosition + (stepDistance / longSweepDistance) * forwardSweep); - setWorldTransform(nextTransform); - updateTraction(nextTransform.getOrigin()); - return; - } - 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); - setWorldTransform(nextTransform); - - if (result.m_hitNormalWorld.dot(_upDirection) > _maxWallNormalUpComponent) { - _floorNormal = result.m_hitNormalWorld; - _floorContact = result.m_hitPointWorld; - _steppingUp = false; - _onFloor = true; - _hovering = false; - } - updateTraction(nextTransform.getOrigin()); - return; - } - - // check if this hit is obviously unsteppable - btVector3 hitFromBase = result.m_hitPointWorld - (startPosition - ((_radius + _halfHeight) * _upDirection)); - btScalar hitHeight = hitFromBase.dot(_upDirection); - if (hitHeight > _maxStepHeight) { - // 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) { - forwardTranslation *= stepDistance / forwardDistance; - } - nextTransform.setOrigin(startPosition + forwardTranslation); - setWorldTransform(nextTransform); - _onFloor = _onFloor || oldOnFloor; - return; - } - // if we get here then we hit something that might be steppable - - // remember the forward sweep hit fraction for later - btScalar forwardSweepHitFraction = result.m_closestHitFraction; - - // figure out how high we can step up - btScalar availableStepHeight = measureAvailableStepHeight(); - - // raise by availableStepHeight before sweeping forward - result.resetHitHistory(); - startTransform.setOrigin(startPosition + availableStepHeight * _upDirection); - nextTransform.setOrigin(startTransform.getOrigin() + forwardSweep); - sweepTest(_characterShape, startTransform, nextTransform, result); - if (result.hasHit()) { - startTransform.setOrigin(startTransform.getOrigin() + result.m_closestHitFraction * forwardSweep); - } else { - startTransform = nextTransform; - } - - // sweep down in search of future landing spot - result.resetHitHistory(); - btVector3 downSweep = (- availableStepHeight) * _upDirection; - nextTransform.setOrigin(startTransform.getOrigin() + downSweep); - 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; - _floorContact = result.m_hitPointWorld; - _steppingUp = true; - _onFloor = true; - _hovering = false; - nextTransform.setOrigin(startTransform.getOrigin() + result.m_closestHitFraction * downSweep); - btVector3 totalStep = nextTransform.getOrigin() - startPosition; - nextTransform.setOrigin(startPosition + (stepDistance / totalStep.length()) * totalStep); - updateTraction(nextTransform.getOrigin()); - } else { - // either there is no future landing spot, or there is but we can't stand on it - // in any case: we go forward as much as possible - nextTransform.setOrigin(startPosition + forwardSweepHitFraction * (stepDistance / longSweepDistance) * forwardSweep); - _onFloor = _onFloor || oldOnFloor; - updateTraction(nextTransform.getOrigin()); - } - setWorldTransform(nextTransform); -} - -bool CharacterGhostObject::sweepTest( - const btConvexShape* shape, - const btTransform& start, - const btTransform& end, - CharacterSweepResult& result) const { - if (_world && _inWorld) { - assert(shape); - btScalar allowedPenetration = _world->getDispatchInfo().m_allowedCcdPenetration; - convexSweepTest(shape, start, end, result, allowedPenetration); - return result.hasHit(); - } - return false; -} - bool CharacterGhostObject::rayTest(const btVector3& start, const btVector3& end, CharacterRayResult& result) const { @@ -248,82 +74,6 @@ bool CharacterGhostObject::rayTest(const btVector3& start, return result.hasHit(); } -void CharacterGhostObject::measurePenetration(btVector3& minBoxOut, btVector3& maxBoxOut) { - // minBoxOut and maxBoxOut will be updated with penetration envelope. - // If one of the corner points is <0,0,0> then the penetration is resolvable in a single step, - // but if the space spanned by the two corners extends in both directions along at least one - // component then we the object is sandwiched between two opposing objects. - - // We assume this object has just been moved to its current location, or else objects have been - // moved around it since the last step so we must update the overlapping pairs. - refreshOverlappingPairCache(); - - // compute collision details - btHashedOverlappingPairCache* pairCache = getOverlappingPairCache(); - _world->getDispatcher()->dispatchAllCollisionPairs(pairCache, _world->getDispatchInfo(), _world->getDispatcher()); - - // loop over contact manifolds to compute the penetration box - minBoxOut = btVector3(0.0f, 0.0f, 0.0f); - maxBoxOut = btVector3(0.0f, 0.0f, 0.0f); - btManifoldArray manifoldArray; - - int numPairs = pairCache->getNumOverlappingPairs(); - for (int i = 0; i < numPairs; i++) { - manifoldArray.resize(0); - btBroadphasePair* collisionPair = &(pairCache->getOverlappingPairArray()[i]); - - btCollisionObject* obj0 = static_cast(collisionPair->m_pProxy0->m_clientObject); - btCollisionObject* obj1 = static_cast(collisionPair->m_pProxy1->m_clientObject); - - if ((obj0 && !obj0->hasContactResponse()) && (obj1 && !obj1->hasContactResponse())) { - // we know this probe has no contact response - // but neither does the other object so skip this manifold - continue; - } - - if (!collisionPair->m_algorithm) { - // null m_algorithm means the two shape types don't know how to collide! - // shouldn't fall in here but just in case - continue; - } - - btScalar mostFloorPenetration = 0.0f; - collisionPair->m_algorithm->getAllContactManifolds(manifoldArray); - for (int j = 0; j < manifoldArray.size(); j++) { - btPersistentManifold* manifold = manifoldArray[j]; - btScalar directionSign = (manifold->getBody0() == this) ? btScalar(1.0) : btScalar(-1.0); - for (int p = 0; p < manifold->getNumContacts(); p++) { - const btManifoldPoint& pt = manifold->getContactPoint(p); - if (pt.getDistance() > 0.0f) { - continue; - } - - // normal always points from object to character - btVector3 normal = directionSign * pt.m_normalWorldOnB; - - btScalar penetrationDepth = pt.getDistance(); - if (penetrationDepth < mostFloorPenetration) { // remember penetrationDepth is negative - btScalar normalDotUp = normal.dot(_upDirection); - if (normalDotUp > _maxWallNormalUpComponent) { - mostFloorPenetration = penetrationDepth; - _floorNormal = normal; - if (directionSign > 0.0f) { - _floorContact = pt.m_positionWorldOnA; - } else { - _floorContact = pt.m_positionWorldOnB; - } - _onFloor = true; - } - } - - btVector3 penetration = (-penetrationDepth) * normal; - minBoxOut.setMin(penetration); - maxBoxOut.setMax(penetration); - } - } - } -} - void CharacterGhostObject::refreshOverlappingPairCache() { assert(_world && _inWorld); btVector3 minAabb, maxAabb; @@ -347,69 +97,3 @@ void CharacterGhostObject::addToWorld() { _inWorld = true; } } - -bool CharacterGhostObject::resolvePenetration(int numTries) { - btVector3 minBox, maxBox; - measurePenetration(minBox, maxBox); - btVector3 restore = maxBox + minBox; - if (restore.length2() > 0.0f) { - btTransform transform = getWorldTransform(); - transform.setOrigin(transform.getOrigin() + restore); - setWorldTransform(transform); - return false; - } - return true; -} - -void CharacterGhostObject::updateVelocity(btScalar dt, btScalar gravity) { - if (!_motorOnly) { - if (_hovering) { - _linearVelocity *= 0.999f; // HACK damping - } else { - _linearVelocity += (dt * gravity) * _upDirection; - } - } -} - -void CharacterGhostObject::updateHoverState(const btVector3& position) { - if (_onFloor) { - _hovering = false; - } else { - // cast a ray down looking for floor support - CharacterRayResult rayResult(this); - btScalar distanceToFeet = _radius + _halfHeight; - btScalar slop = 2.0f * getCollisionShape()->getMargin(); // slop to help ray start OUTSIDE the floor object - btVector3 startPos = position - ((distanceToFeet - slop) * _upDirection); - btVector3 endPos = startPos - (2.0f * distanceToFeet) * _upDirection; - rayTest(startPos, endPos, rayResult); - // we're hovering if the ray didn't hit anything or hit unstandable slope - _hovering = !rayResult.hasHit() || rayResult.m_hitNormalWorld.dot(_upDirection) < _maxWallNormalUpComponent; - } -} - -void CharacterGhostObject::updateTraction(const btVector3& position) { - updateHoverState(position); - if (_hovering || _motorOnly) { - _linearVelocity = _motorVelocity; - } else if (_onFloor) { - // 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(); - if (pathLength > FLT_EPSILON) { - _linearVelocity = (_motorVelocity.length() / pathLength) * pathDirection; - } else { - _linearVelocity = btVector3(0.0f, 0.0f, 0.0f); - } - } -} - -btScalar CharacterGhostObject::measureAvailableStepHeight() const { - CharacterSweepResult result(this); - btTransform transform = getWorldTransform(); - btTransform nextTransform = transform; - nextTransform.setOrigin(transform.getOrigin() + _maxStepHeight * _upDirection); - sweepTest(_characterShape, transform, nextTransform, result); - return result.m_closestHitFraction * _maxStepHeight; -} - diff --git a/libraries/physics/src/CharacterGhostObject.h b/libraries/physics/src/CharacterGhostObject.h index feb132a53e..1e4625c6f6 100755 --- a/libraries/physics/src/CharacterGhostObject.h +++ b/libraries/physics/src/CharacterGhostObject.h @@ -33,71 +33,30 @@ public: void setRadiusAndHalfHeight(btScalar radius, btScalar halfHeight); void setUpDirection(const btVector3& up); - void setMotorVelocity(const btVector3& velocity); - void setMinWallAngle(btScalar angle) { _maxWallNormalUpComponent = cosf(angle); } - void setMaxStepHeight(btScalar height) { _maxStepHeight = height; } - - void setLinearVelocity(const btVector3& velocity) { _linearVelocity = velocity; } - const btVector3& getLinearVelocity() const { return _linearVelocity; } void setCharacterShape(btConvexHullShape* shape); void setCollisionWorld(btCollisionWorld* world); - void move(btScalar dt, btScalar overshoot, btScalar gravity); - - bool sweepTest(const btConvexShape* shape, - const btTransform& start, - const btTransform& end, - CharacterSweepResult& result) const; - bool rayTest(const btVector3& start, const btVector3& end, CharacterRayResult& result) const; - bool isHovering() const { return _hovering; } - void setHovering(bool hovering) { _hovering = hovering; } - void setMotorOnly(bool motorOnly) { _motorOnly = motorOnly; } - - bool hasSupport() const { return _onFloor; } - bool isSteppingUp() const { return _steppingUp; } - const btVector3& getFloorNormal() const { return _floorNormal; } - - void measurePenetration(btVector3& minBoxOut, btVector3& maxBoxOut); void refreshOverlappingPairCache(); protected: void removeFromWorld(); void addToWorld(); - bool resolvePenetration(int numTries); - void updateVelocity(btScalar dt, btScalar gravity); - void updateTraction(const btVector3& position); - btScalar measureAvailableStepHeight() const; - void updateHoverState(const btVector3& position); - protected: - btVector3 _upDirection { 0.0f, 1.0f, 0.0f }; // input, up in world-frame - btVector3 _motorVelocity { 0.0f, 0.0f, 0.0f }; // input, velocity character is trying to achieve - btVector3 _linearVelocity { 0.0f, 0.0f, 0.0f }; // internal, actual character velocity - btVector3 _floorNormal { 0.0f, 0.0f, 0.0f }; // internal, probable floor normal - btVector3 _floorContact { 0.0f, 0.0f, 0.0f }; // internal, last floor contact point btCollisionWorld* _world { nullptr }; // input, pointer to world - //btScalar _distanceToFeet { 0.0f }; // input, distance from object center to lowest point on shape btScalar _halfHeight { 0.0f }; 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 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 - bool _hovering { false }; // internal, - bool _onFloor { false }; // output, is actually standing on floor - bool _steppingUp { false }; // output, future sweep hit a steppable ledge - bool _hasFloor { false }; // output, has floor underneath to fall on - bool _motorOnly { false }; // input, _linearVelocity slaves to _motorVelocity }; #endif // hifi_CharacterGhostObject_h