diff --git a/libraries/shared/src/CapsuleShape.cpp b/libraries/shared/src/CapsuleShape.cpp index ab8cbdae3d..12ab6ba479 100644 --- a/libraries/shared/src/CapsuleShape.cpp +++ b/libraries/shared/src/CapsuleShape.cpp @@ -18,9 +18,6 @@ #include "SharedUtil.h" -// default axis of CapsuleShape is Y-axis -const glm::vec3 localAxis(0.0f, 1.0f, 0.0f); - CapsuleShape::CapsuleShape() : Shape(Shape::CAPSULE_SHAPE), _radius(0.0f), _halfHeight(0.0f) {} CapsuleShape::CapsuleShape(float radius, float halfHeight) : Shape(Shape::CAPSULE_SHAPE), @@ -50,7 +47,7 @@ void CapsuleShape::getEndPoint(glm::vec3& endPoint) const { void CapsuleShape::computeNormalizedAxis(glm::vec3& axis) const { // default axis of a capsule is along the yAxis - axis = _rotation * glm::vec3(0.0f, 1.0f, 0.0f); + axis = _rotation * DEFAULT_CAPSULE_AXIS; } void CapsuleShape::setRadius(float radius) { @@ -76,12 +73,7 @@ void CapsuleShape::setEndPoints(const glm::vec3& startPoint, const glm::vec3& en if (height > EPSILON) { _halfHeight = 0.5f * height; axis /= height; - glm::vec3 yAxis(0.0f, 1.0f, 0.0f); - float angle = glm::angle(axis, yAxis); - if (angle > EPSILON) { - axis = glm::normalize(glm::cross(yAxis, axis)); - _rotation = glm::angleAxis(angle, axis); - } + computeNewRotation(axis); } updateBoundingRadius(); } @@ -94,3 +86,13 @@ bool CapsuleShape::findRayIntersection(const glm::vec3& rayStart, const glm::vec // TODO: implement the raycast to return inside surface intersection for the internal rayStart. return findRayCapsuleIntersection(rayStart, rayDirection, capsuleStart, capsuleEnd, _radius, distance); } + +// static +glm::quat CapsuleShape::computeNewRotation(const glm::vec3& newAxis) { + float angle = glm::angle(newAxis, DEFAULT_CAPSULE_AXIS); + if (angle > EPSILON) { + glm::vec3 rotationAxis = glm::normalize(glm::cross(DEFAULT_CAPSULE_AXIS, newAxis)); + return glm::angleAxis(angle, rotationAxis); + } + return glm::quat(); +} diff --git a/libraries/shared/src/CapsuleShape.h b/libraries/shared/src/CapsuleShape.h index 41474e3e38..e97a6a4917 100644 --- a/libraries/shared/src/CapsuleShape.h +++ b/libraries/shared/src/CapsuleShape.h @@ -15,6 +15,8 @@ #include "Shape.h" // default axis of CapsuleShape is Y-axis +const glm::vec3 DEFAULT_CAPSULE_AXIS(0.0f, 1.0f, 0.0f); + class CapsuleShape : public Shape { public: @@ -26,7 +28,7 @@ public: virtual ~CapsuleShape() {} float getRadius() const { return _radius; } - float getHalfHeight() const { return _halfHeight; } + virtual float getHalfHeight() const { return _halfHeight; } /// \param[out] startPoint is the center of start cap virtual void getStartPoint(glm::vec3& startPoint) const; @@ -47,6 +49,7 @@ public: protected: virtual void updateBoundingRadius() { _boundingRadius = _radius + getHalfHeight(); } + static glm::quat computeNewRotation(const glm::vec3& newAxis); float _radius; float _halfHeight; diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index dae1114992..0a03ae18e3 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -31,18 +31,17 @@ public: virtual ~Shape() {} int getType() const { return _type; } - float getBoundingRadius() const { return _boundingRadius; } -// const glm::vec3& getPosition() const { return _position; } - const glm::quat& getRotation() const { return _rotation; } - -// virtual void setPosition(const glm::vec3& position) { _translation = position; } - virtual void setRotation(const glm::quat& rotation) { _rotation = rotation; } void setEntity(PhysicalEntity* entity) { _owningEntity = entity; } PhysicalEntity* getEntity() const { return _owningEntity; } - virtual void setTranslation(const glm::vec3& center) { _translation = center; } - virtual glm::vec3 getTranslation() const { return _translation; } + float getBoundingRadius() const { return _boundingRadius; } + + virtual const glm::quat& getRotation() const { return _rotation; } + virtual void setRotation(const glm::quat& rotation) { _rotation = rotation; } + + virtual void setTranslation(const glm::vec3& translation) { _translation = translation; } + virtual const glm::vec3& getTranslation() const { return _translation; } virtual bool findRayIntersection(const glm::vec3& rayStart, const glm::vec3& rayDirection, float& distance) const = 0; diff --git a/libraries/shared/src/ShapeCollider.cpp b/libraries/shared/src/ShapeCollider.cpp index 2b672f764d..ffb51660e2 100644 --- a/libraries/shared/src/ShapeCollider.cpp +++ b/libraries/shared/src/ShapeCollider.cpp @@ -24,7 +24,6 @@ namespace ShapeCollider { bool collideShapes(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions) { - // ATM we only have two shape types so we just check every case. // TODO: make a fast lookup for correct method int typeA = shapeA->getType(); int typeB = shapeB->getType(); diff --git a/libraries/shared/src/VerletCapsuleShape.cpp b/libraries/shared/src/VerletCapsuleShape.cpp index 9cae13ba2d..b4117e40f7 100644 --- a/libraries/shared/src/VerletCapsuleShape.cpp +++ b/libraries/shared/src/VerletCapsuleShape.cpp @@ -28,6 +28,45 @@ VerletCapsuleShape::VerletCapsuleShape(float radius, glm::vec3* startPoint, glm: updateBoundingRadius(); } +const glm::quat& VerletCapsuleShape::getRotation() const { + // NOTE: The "rotation" of this shape must be computed on the fly, + // which makes this method MUCH more more expensive than you might expect. + glm::vec3 axis; + computeNormalizedAxis(axis); + VerletCapsuleShape* thisCapsule = const_cast(this); + thisCapsule->_rotation = computeNewRotation(axis); + return _rotation; +} + +void VerletCapsuleShape::setRotation(const glm::quat& rotation) { + // NOTE: this method will update the verlet points, which is probably not + // what you want to do. Only call this method if you know what you're doing. + + // update points such that they have the same center but a different axis + glm::vec3 center = getTranslation(); + float halfHeight = getHalfHeight(); + glm::vec3 axis = rotation * DEFAULT_CAPSULE_AXIS; + *_startPoint = center - halfHeight * axis; + *_endPoint = center + halfHeight * axis; +} + +void VerletCapsuleShape::setTranslation(const glm::vec3& position) { + // NOTE: this method will update the verlet points, which is probably not + // what you want to do. Only call this method if you know what you're doing. + + // update the points such that their center is at position + glm::vec3 movement = position - getTranslation(); + *_startPoint += movement; + *_endPoint += movement; +} + +const glm::vec3& VerletCapsuleShape::getTranslation() const { + // the "translation" of this shape must be computed on the fly + VerletCapsuleShape* thisCapsule = const_cast(this); + thisCapsule->_translation = 0.5f * ((*_startPoint) + (*_endPoint)); + return _translation; +} + // virtual float VerletCapsuleShape::getHalfHeight() const { return 0.5f * glm::distance(*_startPoint, *_endPoint); @@ -57,15 +96,20 @@ void VerletCapsuleShape::computeNormalizedAxis(glm::vec3& axis) const { } // virtual -void VerletCapsuleShape::setHalfHeight(float height) { - // don't call this method because this is a verlet shape - assert(false); +void VerletCapsuleShape::setHalfHeight(float halfHeight) { + // push points along axis so they are 2*halfHeight apart + glm::vec3 center = getTranslation(); + glm::vec3 axis; + computeNormalizedAxis(axis); + *_startPoint = center - halfHeight * axis; + *_endPoint = center + halfHeight * axis; + _boundingRadius = _radius + halfHeight; } // virtual -void VerletCapsuleShape::setRadiusAndHalfHeight(float radius, float height) { - // don't call this method because this is a verlet shape - assert(false); +void VerletCapsuleShape::setRadiusAndHalfHeight(float radius, float halfHeight) { + _radius = radius; + setHalfHeight(halfHeight); } // virtual diff --git a/libraries/shared/src/VerletCapsuleShape.h b/libraries/shared/src/VerletCapsuleShape.h index c06b9c7758..b2a7f8be30 100644 --- a/libraries/shared/src/VerletCapsuleShape.h +++ b/libraries/shared/src/VerletCapsuleShape.h @@ -24,8 +24,12 @@ class VerletCapsuleShape : public CapsuleShape { public: VerletCapsuleShape(glm::vec3* startPoint, glm::vec3* endPoint); VerletCapsuleShape(float radius, glm::vec3* startPoint, glm::vec3* endPoint); - //VerletCapsuleShape(float radius, float halfHeight, const glm::vec3& position, const glm::quat& rotation); - //VerletCapsuleShape(float radius, const glm::vec3& startPoint, const glm::vec3& endPoint); + + // virtual overrides from Shape + const glm::quat& getRotation() const; + void setRotation(const glm::quat& rotation); + void setTranslation(const glm::vec3& position); + const glm::vec3& getTranslation() const; //float getRadius() const { return _radius; } virtual float getHalfHeight() const; @@ -40,14 +44,14 @@ public: void computeNormalizedAxis(glm::vec3& axis) const; //void setRadius(float radius); - void setHalfHeight(float height); - void setRadiusAndHalfHeight(float radius, float height); + void setHalfHeight(float halfHeight); + void setRadiusAndHalfHeight(float radius, float halfHeight); void setEndPoints(const glm::vec3& startPoint, const glm::vec3& endPoint); //void assignEndPoints(glm::vec3* startPoint, glm::vec3* endPoint); protected: - // NOTE: VerletCapsuleShape does NOT own its points. + // NOTE: VerletCapsuleShape does NOT own the data in its points. glm::vec3* _startPoint; glm::vec3* _endPoint; }; diff --git a/libraries/shared/src/VerletSphereShape.cpp b/libraries/shared/src/VerletSphereShape.cpp index f17184f434..2c659b8159 100644 --- a/libraries/shared/src/VerletSphereShape.cpp +++ b/libraries/shared/src/VerletSphereShape.cpp @@ -27,6 +27,6 @@ void VerletSphereShape::setTranslation(const glm::vec3& position) { } // virtual from Shape class -glm::vec3 VerletSphereShape::getTranslation() { +const glm::vec3& VerletSphereShape::getTranslation() const { return *_point; } diff --git a/libraries/shared/src/VerletSphereShape.h b/libraries/shared/src/VerletSphereShape.h index e6a70e948e..747d02ff7c 100644 --- a/libraries/shared/src/VerletSphereShape.h +++ b/libraries/shared/src/VerletSphereShape.h @@ -15,16 +15,19 @@ #include "SphereShape.h" // The VerletSphereShape is similar to a regular SphereShape, except it keeps a pointer -// to its center which is owned by some other data structure. This allows it to -// participate in a verlet integration engine. +// to its center which is owned by some other data structure (a verlet simulation system). +// This makes it easier for the points to be moved around by constraints in the system +// as well as collisions with the shape. +// class VerletSphereShape : public SphereShape { public: VerletSphereShape(glm::vec3* centerPoint); VerletSphereShape(float radius, glm::vec3* centerPoint); + // virtual overrides from Shape void setTranslation(const glm::vec3& position); - glm::vec3 getTranslation(); + const glm::vec3& getTranslation() const; protected: // NOTE: VerletSphereShape does NOT own its _point diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index 4ec823f738..4d3c90b905 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -441,7 +441,7 @@ void ShapeColliderTests::capsuleMissesCapsule() { float totalHalfLength = totalRadius + halfHeightA + halfHeightB; CapsuleShape capsuleA(radiusA, halfHeightA); - CapsuleShape capsuleB(radiusA, halfHeightA); + CapsuleShape capsuleB(radiusB, halfHeightB); CollisionList collisions(16); diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index ca98f4d546..086bff4dcd 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -9,8 +9,10 @@ // #include "ShapeColliderTests.h" +#include "VerletShapeTests.h" int main(int argc, char** argv) { ShapeColliderTests::runAllTests(); + VerletShapeTests::runAllTests(); return 0; }