mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-09 15:33:02 +02:00
unit tests for VerletShapes
This commit is contained in:
parent
9e839f0980
commit
96eebec0fc
10 changed files with 92 additions and 36 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
//
|
||||
|
||||
#include "ShapeColliderTests.h"
|
||||
#include "VerletShapeTests.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ShapeColliderTests::runAllTests();
|
||||
VerletShapeTests::runAllTests();
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue