unit tests for VerletShapes

This commit is contained in:
Andrew Meadows 2014-06-18 14:06:00 -07:00
parent 9e839f0980
commit 96eebec0fc
10 changed files with 92 additions and 36 deletions

View file

@ -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();
}

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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<VerletCapsuleShape*>(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<VerletCapsuleShape*>(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

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -9,8 +9,10 @@
//
#include "ShapeColliderTests.h"
#include "VerletShapeTests.h"
int main(int argc, char** argv) {
ShapeColliderTests::runAllTests();
VerletShapeTests::runAllTests();
return 0;
}