add PhysicalEntity class

Model and RagDoll derive from PhysicalEntity
Shape gets back pointer to its Entity (shape sharing not possible)
CollisionInfo gets backpointers the shapes involved
This commit is contained in:
Andrew Meadows 2014-06-12 13:13:00 -07:00
parent e0ebc61b25
commit 5be470bcbc
10 changed files with 145 additions and 52 deletions

View file

@ -16,15 +16,15 @@
#include <glm/gtx/transform.hpp>
#include <glm/gtx/norm.hpp>
#include <CapsuleShape.h>
#include <GeometryUtil.h>
#include <PhysicalEntity.h>
#include <ShapeCollider.h>
#include <SphereShape.h>
#include "Application.h"
#include "Model.h"
#include <SphereShape.h>
#include <CapsuleShape.h>
#include <ShapeCollider.h>
using namespace std;
static int modelPointerTypeId = qRegisterMetaType<QPointer<Model> >();
@ -33,6 +33,7 @@ static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
Model::Model(QObject* parent) :
QObject(parent),
PhysicalEntity(PhysicalEntity::ENTITY_MODEL),
_scale(1.0f, 1.0f, 1.0f),
_scaleToFit(false),
_scaleToFitLargestDimension(0.0f),
@ -775,34 +776,6 @@ AnimationHandlePointer Model::createAnimationHandle() {
return handle;
}
quint8 BITS_FOR_SHAPE_INDEX = 15;
int MAX_SIMULATION_ID = 1 << (31 - BITS_FOR_SHAPE_INDEX);
void Model::setSimulationIndex(int index) {
_simulationIndex = index;
if (_simulationIndex < 0 || _simulationIndex > MAX_SIMULATION_ID) {
// clear simulation ID's of all the shapes
for (int i = 0; i < _jointShapes.size(); i++) {
Shape* shape = _jointShapes[i];
if (shape) {
shape->setSimulationID(-1);
}
}
} else {
// update the simulation ID's of the shapes
// upper bits store this Model's index...
int shiftedIndex = _simulationIndex << BITS_FOR_SHAPE_INDEX;
for (int i = 0; i < _jointShapes.size(); i++) {
Shape* shape = _jointShapes[i];
if (shape) {
// ... lower bits are for the shape's index
shape->setSimulationID(shiftedIndex + i);
}
}
}
}
void Model::clearShapes() {
for (int i = 0; i < _jointShapes.size(); ++i) {
delete _jointShapes[i];
@ -836,10 +809,12 @@ void Model::rebuildShapes() {
}
if (type == Shape::CAPSULE_SHAPE) {
CapsuleShape* capsule = new CapsuleShape(radius, halfHeight);
capsule->setEntity(this);
_jointShapes.push_back(capsule);
} else if (type == Shape::SPHERE_SHAPE) {
SphereShape* sphere = new SphereShape(radius, glm::vec3(0.0f));
_jointShapes.push_back(sphere);
sphere->setEntity(this);
} else {
// this shape type is not handled and the joint shouldn't collide,
// however we must have a Shape* for each joint, so we push NULL
@ -1815,6 +1790,10 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
}
}
void Model::setShapeBackPointers() {
PhysicalEntity::setShapeBackPointers(_jointShapes, this);
}
void AnimationHandle::setURL(const QUrl& url) {
if (_url != url) {
_animation = Application::getInstance()->getAnimationCache()->getAnimation(_url = url);

View file

@ -17,6 +17,7 @@
#include <QUrl>
#include <CapsuleShape.h>
#include <PhysicalEntity.h>
#include <AnimationCache.h>
@ -33,7 +34,7 @@ typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
/// A generic 3D model displaying geometry loaded from a URL.
class Model : public QObject {
class Model : public QObject, public PhysicalEntity {
Q_OBJECT
public:
@ -137,7 +138,6 @@ public:
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
void setSimulationIndex(int index);
void clearShapes();
void rebuildShapes();
void resetShapePositions(); // DEBUG method
@ -167,6 +167,7 @@ public:
const CapsuleShape& getBoundingShape() const { return _boundingShape; }
protected:
virtual void setShapeBackPointers();
QSharedPointer<NetworkGeometry> _geometry;

View file

@ -47,8 +47,8 @@ void CollisionList::clear() {
//collision._intData = 0;
//collision._floatDAta = 0.0f;
//collision._vecData = glm::vec3(0.0f);
//collision._shapeA = -1;
//collision._shapeB = -1;
//collision._shapeA = NULL;
//collision._shapeB = NULL;
//collision._damping;
//collision._elasticity;
//collision._contactPoint;

View file

@ -17,6 +17,8 @@
#include <QVector>
class Shape;
const quint32 COLLISION_GROUP_ENVIRONMENT = 1U << 0;
const quint32 COLLISION_GROUP_AVATARS = 1U << 1;
const quint32 COLLISION_GROUP_VOXELS = 1U << 2;
@ -33,8 +35,8 @@ public:
CollisionInfo()
: _data(NULL),
_intData(0),
_shapeA(-1),
_shapeB(-1),
_shapeA(NULL),
_shapeB(NULL),
_damping(0.f),
_elasticity(1.f),
_contactPoint(0.f),
@ -45,8 +47,8 @@ public:
CollisionInfo(qint32 type)
: _data(NULL),
_intData(0),
_shapeA(-1),
_shapeB(-1),
_shapeA(NULL),
_shapeB(NULL),
_damping(0.f),
_elasticity(1.f),
_contactPoint(0.f),
@ -62,8 +64,11 @@ public:
float _floatData;
glm::vec3 _vecData;
int _shapeA; // ID of shapeA in its SimulationEngine
int _shapeB; // ID of shapeB in its SimulationEngine
Shape* getShapeA() const { return const_cast<Shape*>(_shapeA); }
Shape* getShapeB() const { return const_cast<Shape*>(_shapeB); }
const Shape* _shapeA; // pointer to shapeA in this collision
const Shape* _shapeB; // pointer to shapeB in this collision
float _damping; // range [0,1] of friction coeficient
float _elasticity; // range [0,1] of energy conservation

View file

@ -0,0 +1,24 @@
//
// PhysicalEntity.cpp
// libraries/shared/src
//
// Created by Andrew Meadows 2014.06.11
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "PhysicalEntity.h"
#include "Shape.h"
// static
void PhysicalEntity::setShapeBackPointers(const QVector<Shape*>& shapes, PhysicalEntity* entity) {
for (int i = 0; i < shapes.size(); i++) {
Shape* shape = shapes[i];
if (shape) {
shape->setEntity(entity);
}
}
}

View file

@ -0,0 +1,43 @@
//
// PhysicalEntity.h
// libraries/shared/src
//
// Created by Andrew Meadows 2014.05.30
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_PhysicalEntity_h
#define hifi_PhysicalEntity_h
#include <QVector>
class Shape;
// PhysicalEntity is the base class for anything that owns one or more Shapes that collide in a
// SimulationEngine. Each CollisionInfo generated by a SimulationEngine has back pointers to the
// two Shapes involved, and those Shapes may (optionally) have valid back pointers to their PhysicalEntity.
class PhysicalEntity {
public:
enum EntityType {
ENTITY_UNKNOWN,
ENTITY_MODEL,
ENTITY_RAGDOLL,
};
static void setShapeBackPointers(const QVector<Shape*>& shapes, PhysicalEntity* entity);
PhysicalEntity(EntityType type = ENTITY_UNKNOWN) : _entityType(type) {}
virtual ~PhysicalEntity() {}
EntityType getEntityType() const { return _entityType; }
protected:
EntityType _entityType;
};
#endif // hifi_PhysicalEntity_h

View file

@ -94,7 +94,7 @@ void DistanceConstraint::updateProxyShape(Shape* shape, const glm::quat& rotatio
// RagDoll
// ----------------------------------------------------------------------------
RagDoll::RagDoll() : _shapes(NULL) {
RagDoll::RagDoll() : PhysicalEntity(PhysicalEntity::ENTITY_RAGDOLL), _shapes(NULL) {
}
RagDoll::~RagDoll() {
@ -121,6 +121,9 @@ void RagDoll::init(QVector<Shape*>* shapes, const QVector<int>& parentIndices, c
_constraints.push_back(stick);
}
}
if (_shapes) {
PhysicalEntity::setShapeBackPointers(*_shapes, this);
}
}
/// Delete all data.
@ -131,6 +134,10 @@ void RagDoll::clear() {
}
_constraints.clear();
_points.clear();
if (_shapes) {
PhysicalEntity::setShapeBackPointers(*_shapes, NULL);
}
_shapes = NULL;
}
float RagDoll::enforceConstraints() {

View file

@ -17,7 +17,7 @@
#include <QVector>
class Shape;
#include "PhysicalEntity.h"
class Constraint {
public:
@ -61,7 +61,7 @@ private:
glm::vec3* _points[2];
};
class RagDoll {
class RagDoll : public PhysicalEntity {
public:
RagDoll();

View file

@ -15,6 +15,7 @@
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
class PhysicalEntity;
class Shape {
public:
@ -26,7 +27,7 @@ public:
LIST_SHAPE
};
Shape() : _type(UNKNOWN_SHAPE), _simulationID(-1), _boundingRadius(0.f), _position(0.f), _rotation() { }
Shape() : _type(UNKNOWN_SHAPE), _owningEntity(NULL), _boundingRadius(0.f), _position(0.f), _rotation() { }
virtual ~Shape() {}
int getType() const { return _type; }
@ -37,23 +38,23 @@ public:
virtual void setPosition(const glm::vec3& position) { _position = position; }
virtual void setRotation(const glm::quat& rotation) { _rotation = rotation; }
void setSimulationID(int id) { _simulationID = id; }
int getSimulationID() const { return _simulationID; }
void setEntity(PhysicalEntity* entity) { _owningEntity = entity; }
PhysicalEntity* getEntity() const { return _owningEntity; }
protected:
// these ctors are protected (used by derived classes only)
Shape(Type type) : _type(type), _boundingRadius(0.f), _position(0.f), _rotation() {}
Shape(Type type) : _type(type), _owningEntity(NULL), _boundingRadius(0.f), _position(0.f), _rotation() {}
Shape(Type type, const glm::vec3& position)
: _type(type), _boundingRadius(0.f), _position(position), _rotation() {}
: _type(type), _owningEntity(NULL), _boundingRadius(0.f), _position(position), _rotation() {}
Shape(Type type, const glm::vec3& position, const glm::quat& rotation)
: _type(type), _boundingRadius(0.f), _position(position), _rotation(rotation) {}
: _type(type), _owningEntity(NULL), _boundingRadius(0.f), _position(position), _rotation(rotation) {}
void setBoundingRadius(float radius) { _boundingRadius = radius; }
int _type;
int _simulationID; // shape's simulation ID in SimulationEngine
PhysicalEntity* _owningEntity;
float _boundingRadius;
glm::vec3 _position;
glm::quat _rotation;

View file

@ -87,6 +87,9 @@ bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<con
}
collision._penetration = totalPenetration;
collision._contactPoint = averageContactPoint / (float)(tempCollisions.size());
// there are no valid shape pointers for this collision so we set them NULL
collision._shapeA = NULL;
collision._shapeB = NULL;
return true;
}
return false;
@ -135,6 +138,8 @@ bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, Collis
collision->_penetration = BA * (totalRadius - distance);
// contactPoint is on surface of A
collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * BA;
collision->_shapeA = sphereA;
collision->_shapeB = sphereB;
return true;
}
}
@ -179,6 +184,8 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
collision->_penetration = (totalRadius - radialDistance) * radialAxis; // points from A into B
// contactPoint is on surface of sphereA
collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * radialAxis;
collision->_shapeA = sphereA;
collision->_shapeB = capsuleB;
} else {
// A is on B's axis, so the penetration is undefined...
if (absAxialDistance > capsuleB->getHalfHeight()) {
@ -200,6 +207,8 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
collision->_penetration = (sign * (totalRadius + capsuleB->getHalfHeight() - absAxialDistance)) * capsuleAxis;
// contactPoint is on surface of sphereA
collision->_contactPoint = sphereA->getPosition() + (sign * sphereA->getRadius()) * capsuleAxis;
collision->_shapeA = sphereA;
collision->_shapeB = capsuleB;
}
return true;
}
@ -215,6 +224,8 @@ bool spherePlane(const SphereShape* sphereA, const PlaneShape* planeB, Collision
}
collision->_penetration = penetration;
collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * glm::normalize(penetration);
collision->_shapeA = sphereA;
collision->_shapeB = planeB;
return true;
}
return false;
@ -264,6 +275,8 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col
collision->_penetration = (radialDistance - totalRadius) * radialAxis; // points from A into B
// contactPoint is on surface of capsuleA
collision->_contactPoint = closestApproach - capsuleA->getRadius() * radialAxis;
collision->_shapeA = capsuleA;
collision->_shapeB = sphereB;
} else {
// A is on B's axis, so the penetration is undefined...
if (absAxialDistance > capsuleA->getHalfHeight()) {
@ -284,6 +297,8 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col
collision->_penetration = (sign * (totalRadius + capsuleA->getHalfHeight() - absAxialDistance)) * capsuleAxis;
// contactPoint is on surface of sphereA
collision->_contactPoint = closestApproach + (sign * capsuleA->getRadius()) * capsuleAxis;
collision->_shapeA = capsuleA;
collision->_shapeB = sphereB;
}
}
return true;
@ -355,6 +370,8 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
collision->_penetration = BA * (totalRadius - distance);
// contactPoint is on surface of A
collision->_contactPoint = centerA + distanceA * axisA + capsuleA->getRadius() * BA;
collision->_shapeA = capsuleA;
collision->_shapeB = capsuleB;
return true;
}
} else {
@ -420,6 +437,8 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
// average the internal pair, and then do the math from centerB
collision->_contactPoint = centerB + (0.5f * (points[1] + points[2])) * axisB
+ (capsuleA->getRadius() - distance) * BA;
collision->_shapeA = capsuleA;
collision->_shapeB = capsuleB;
return true;
}
}
@ -439,6 +458,8 @@ bool capsulePlane(const CapsuleShape* capsuleA, const PlaneShape* planeB, Collis
collision->_penetration = penetration;
glm::vec3 deepestEnd = (glm::dot(start, glm::vec3(plane)) < glm::dot(end, glm::vec3(plane))) ? start : end;
collision->_contactPoint = deepestEnd + capsuleA->getRadius() * glm::normalize(penetration);
collision->_shapeA = capsuleA;
collision->_shapeB = planeB;
return true;
}
return false;
@ -454,6 +475,8 @@ bool planeSphere(const PlaneShape* planeA, const SphereShape* sphereB, Collision
collision->_penetration = -penetration;
collision->_contactPoint = sphereB->getPosition() +
(sphereB->getRadius() / glm::length(penetration) - 1.0f) * penetration;
collision->_shapeA = planeA;
collision->_shapeB = sphereB;
return true;
}
return false;
@ -472,6 +495,8 @@ bool planeCapsule(const PlaneShape* planeA, const CapsuleShape* capsuleB, Collis
collision->_penetration = -penetration;
glm::vec3 deepestEnd = (glm::dot(start, glm::vec3(plane)) < glm::dot(end, glm::vec3(plane))) ? start : end;
collision->_contactPoint = deepestEnd + (capsuleB->getRadius() / glm::length(penetration) - 1.0f) * penetration;
collision->_shapeA = planeA;
collision->_shapeB = capsuleB;
return true;
}
return false;
@ -664,6 +689,8 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm::
}
collision->_floatData = cubeSide;
collision->_vecData = cubeCenter;
collision->_shapeA = NULL;
collision->_shapeB = NULL;
return true;
} else if (sphereRadius + halfCubeSide > distance) {
// NOTE: for cocentric approximation we collide sphere and cube as two spheres which means
@ -677,6 +704,8 @@ bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm::
collision->_floatData = cubeSide;
collision->_vecData = cubeCenter;
collision->_shapeA = NULL;
collision->_shapeB = NULL;
return true;
}
}
@ -712,6 +741,8 @@ bool sphereAACube_StarkAngles(const glm::vec3& sphereCenter, float sphereRadius,
collision->_penetration = glm::dot(surfaceAB, direction) * direction;
// contactPoint is on surface of A
collision->_contactPoint = sphereCenter + sphereRadius * direction;
collision->_shapeA = NULL;
collision->_shapeB = NULL;
return true;
}
}
@ -724,6 +755,8 @@ bool sphereAACube_StarkAngles(const glm::vec3& sphereCenter, float sphereRadius,
collision->_penetration = (sphereRadius + 0.5f * cubeSide) * glm::vec3(0.0f, -1.0f, 0.0f);
// contactPoint is on surface of A
collision->_contactPoint = sphereCenter + collision->_penetration;
collision->_shapeA = NULL;
collision->_shapeB = NULL;
return true;
}
}