code out of Model into base and derived classes

PhysicalEntity (base class) gets some shape management stuff
SkeletonModel (derived class) gets some boundary shape and
joint-shape stuff
This commit is contained in:
Andrew Meadows 2014-06-17 16:22:18 -07:00
parent 118717d96a
commit ecbf5043d7
7 changed files with 371 additions and 377 deletions

View file

@ -230,7 +230,6 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
}
if (renderBounding && shouldRenderHead(cameraPosition, renderMode)) {
getHead()->getFaceModel().renderBoundingCollisionShapes(0.7f);
_skeletonModel.renderBoundingCollisionShapes(0.7f);
}

View file

@ -11,6 +11,9 @@
#include <glm/gtx/transform.hpp>
#include <CapsuleShape.h>
#include <SphereShape.h>
#include "Application.h"
#include "Avatar.h"
#include "Hand.h"
@ -20,7 +23,9 @@
SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
Model(parent),
Ragdoll(),
_owningAvatar(owningAvatar) {
_owningAvatar(owningAvatar),
_boundingShape(),
_boundingShapeLocalOffset(0.0f) {
}
void SkeletonModel::setJointStates(QVector<JointState> states) {
@ -524,3 +529,251 @@ void SkeletonModel::renderRagdoll() {
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
}
// virtual
void SkeletonModel::buildShapes() {
if (!_geometry || _rootIndex == -1) {
return;
}
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (geometry.joints.isEmpty()) {
return;
}
// We create the shapes with proper dimensions, but we set their transforms later.
float uniformScale = extractUniformScale(_scale);
for (int i = 0; i < _jointStates.size(); i++) {
const FBXJoint& joint = geometry.joints[i];
float radius = uniformScale * joint.boneRadius;
float halfHeight = 0.5f * uniformScale * joint.distanceToParent;
Shape::Type type = joint.shapeType;
if (type == Shape::CAPSULE_SHAPE && halfHeight < EPSILON) {
// this capsule is effectively a sphere
type = Shape::SPHERE_SHAPE;
}
if (type == Shape::CAPSULE_SHAPE) {
CapsuleShape* capsule = new CapsuleShape(radius, halfHeight);
capsule->setEntity(this);
_shapes.push_back(capsule);
} else if (type == Shape::SPHERE_SHAPE) {
SphereShape* sphere = new SphereShape(radius, glm::vec3(0.0f));
_shapes.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
_shapes.push_back(NULL);
}
}
// This method moves the shapes to their default positions in Model frame
// which is where we compute the bounding shape's parameters.
computeBoundingShape(geometry);
// finally sync shapes to joint positions
_shapesAreDirty = true;
updateShapePositions();
}
void SkeletonModel::updateShapePositionsLegacy() {
if (_shapesAreDirty && _shapes.size() == _jointStates.size()) {
glm::vec3 rootPosition(0.0f);
_boundingRadius = 0.0f;
float uniformScale = extractUniformScale(_scale);
for (int i = 0; i < _jointStates.size(); i++) {
const JointState& state = _jointStates[i];
const FBXJoint& joint = state.getFBXJoint();
// shape position and rotation need to be in world-frame
glm::quat stateRotation = state.getRotation();
glm::vec3 shapeOffset = uniformScale * (stateRotation * joint.shapePosition);
glm::vec3 worldPosition = _translation + _rotation * (state.getPosition() + shapeOffset);
Shape* shape = _shapes[i];
if (shape) {
shape->setCenter(worldPosition);
shape->setRotation(_rotation * stateRotation * joint.shapeRotation);
float distance = glm::distance(worldPosition, _translation) + shape->getBoundingRadius();
if (distance > _boundingRadius) {
_boundingRadius = distance;
}
}
if (joint.parentIndex == -1) {
rootPosition = worldPosition;
}
}
_shapesAreDirty = false;
_boundingShape.setCenter(rootPosition + _rotation * _boundingShapeLocalOffset);
_boundingShape.setRotation(_rotation);
}
}
void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) {
// compute default joint transforms and rotations
// (in local frame, ignoring Model translation and rotation)
int numJoints = geometry.joints.size();
QVector<glm::mat4> transforms;
transforms.fill(glm::mat4(), numJoints);
QVector<glm::quat> finalRotations;
finalRotations.fill(glm::quat(), numJoints);
QVector<bool> shapeIsSet;
shapeIsSet.fill(false, numJoints);
int numShapesSet = 0;
int lastNumShapesSet = -1;
while (numShapesSet < numJoints && numShapesSet != lastNumShapesSet) {
lastNumShapesSet = numShapesSet;
for (int i = 0; i < numJoints; i++) {
const FBXJoint& joint = geometry.joints.at(i);
int parentIndex = joint.parentIndex;
if (parentIndex == -1) {
glm::mat4 baseTransform = glm::scale(_scale) * glm::translate(_offset);
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
glm::mat4 rootTransform = baseTransform * geometry.offset * glm::translate(joint.translation)
* joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform;
// remove the tranlsation part before we save the root transform
transforms[i] = glm::translate(- extractTranslation(rootTransform)) * rootTransform;
finalRotations[i] = combinedRotation;
++numShapesSet;
shapeIsSet[i] = true;
} else if (shapeIsSet[parentIndex]) {
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
* joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform;
finalRotations[i] = finalRotations[parentIndex] * combinedRotation;
++numShapesSet;
shapeIsSet[i] = true;
}
}
}
// sync shapes to joints
_boundingRadius = 0.0f;
float uniformScale = extractUniformScale(_scale);
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (!shape) {
continue;
}
const FBXJoint& joint = geometry.joints[i];
glm::vec3 jointToShapeOffset = uniformScale * (finalRotations[i] * joint.shapePosition);
glm::vec3 localPosition = extractTranslation(transforms[i]) + jointToShapeOffset;
shape->setCenter(localPosition);
shape->setRotation(finalRotations[i] * joint.shapeRotation);
float distance = glm::length(localPosition) + shape->getBoundingRadius();
if (distance > _boundingRadius) {
_boundingRadius = distance;
}
}
// compute bounding box
Extents totalExtents;
totalExtents.reset();
totalExtents.addPoint(glm::vec3(0.0f));
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (!shape) {
continue;
}
Extents shapeExtents;
shapeExtents.reset();
glm::vec3 localPosition = shape->getCenter();
int type = shape->getType();
if (type == Shape::CAPSULE_SHAPE) {
// add the two furthest surface points of the capsule
CapsuleShape* capsule = static_cast<CapsuleShape*>(shape);
glm::vec3 axis;
capsule->computeNormalizedAxis(axis);
float radius = capsule->getRadius();
float halfHeight = capsule->getHalfHeight();
axis = halfHeight * axis + glm::vec3(radius);
shapeExtents.addPoint(localPosition + axis);
shapeExtents.addPoint(localPosition - axis);
totalExtents.addExtents(shapeExtents);
} else if (type == Shape::SPHERE_SHAPE) {
float radius = shape->getBoundingRadius();
glm::vec3 axis = glm::vec3(radius);
shapeExtents.addPoint(localPosition + axis);
shapeExtents.addPoint(localPosition - axis);
totalExtents.addExtents(shapeExtents);
}
}
// compute bounding shape parameters
// NOTE: we assume that the longest side of totalExtents is the yAxis...
glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum;
// ... and assume the radius is half the RMS of the X and Z sides:
float capsuleRadius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z));
_boundingShape.setRadius(capsuleRadius);
_boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius);
_boundingShapeLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum);
}
void SkeletonModel::resetShapePositions() {
// DEBUG method.
// Moves shapes to the joint default locations for debug visibility into
// how the bounding shape is computed.
if (!_geometry || _rootIndex == -1 || _shapes.isEmpty()) {
// geometry or joints have not yet been created
return;
}
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (geometry.joints.isEmpty() || _shapes.size() != geometry.joints.size()) {
return;
}
// The shapes are moved to their default positions in computeBoundingShape().
computeBoundingShape(geometry);
// Then we move them into world frame for rendering at the Model's location.
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (shape) {
shape->setCenter(_translation + _rotation * shape->getCenter());
shape->setRotation(_rotation * shape->getRotation());
}
}
_boundingShape.setCenter(_translation + _rotation * _boundingShapeLocalOffset);
_boundingShape.setRotation(_rotation);
}
void SkeletonModel::renderBoundingCollisionShapes(float alpha) {
const int BALL_SUBDIVISIONS = 10;
if (_shapes.isEmpty()) {
// the bounding shape has not been propery computed
// so no need to render it
return;
}
glPushMatrix();
Application::getInstance()->loadTranslatedViewMatrix(_translation);
// draw a blue sphere at the capsule endpoint
glm::vec3 endPoint;
_boundingShape.getEndPoint(endPoint);
endPoint = endPoint - _translation;
glTranslatef(endPoint.x, endPoint.y, endPoint.z);
glColor4f(0.6f, 0.6f, 0.8f, alpha);
glutSolidSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
// draw a yellow sphere at the capsule startpoint
glm::vec3 startPoint;
_boundingShape.getStartPoint(startPoint);
startPoint = startPoint - _translation;
glm::vec3 axis = endPoint - startPoint;
glTranslatef(-axis.x, -axis.y, -axis.z);
glColor4f(0.8f, 0.8f, 0.6f, alpha);
glutSolidSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
// draw a green cylinder between the two points
glm::vec3 origin(0.0f);
glColor4f(0.6f, 0.8f, 0.6f, alpha);
Avatar::renderJointConnectingCone( origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius());
glPopMatrix();
}

View file

@ -14,6 +14,7 @@
#include "renderer/Model.h"
#include <CapsuleShape.h>
#include <Ragdoll.h>
class Avatar;
@ -30,7 +31,6 @@ public:
void simulate(float deltaTime, bool fullUpdate = true);
void simulateRagdoll(float deltaTime);
void updateShapePositions();
/// \param jointIndex index of hand joint
/// \param shapes[out] list in which is stored pointers to hand shapes
@ -95,6 +95,17 @@ public:
/// \return whether or not both eye meshes were found
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
void buildShapes();
void updateShapePositions();
void updateShapePositionsLegacy();
void computeBoundingShape(const FBXGeometry& geometry);
void renderBoundingCollisionShapes(float alpha);
float getBoundingShapeRadius() const { return _boundingShape.getRadius(); }
const CapsuleShape& getBoundingShape() const { return _boundingShape; }
void resetShapePositions(); // DEBUG method
void renderRagdoll();
protected:
@ -121,6 +132,9 @@ private:
void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation);
Avatar* _owningAvatar;
CapsuleShape _boundingShape;
glm::vec3 _boundingShapeLocalOffset;
};
#endif // hifi_SkeletonModel_h

View file

@ -33,7 +33,6 @@ 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),
@ -42,8 +41,6 @@ Model::Model(QObject* parent) :
_snappedToCenter(false),
_rootIndex(-1),
//_enableCollisionShapes(false),
_boundingShape(),
_boundingShapeLocalOffset(0.0f),
_lodDistance(0.0f),
_pupilDilation(0.0f),
_url("http://invalid.com") {
@ -793,308 +790,11 @@ AnimationHandlePointer Model::createAnimationHandle() {
// virtual override from PhysicalEntity
void Model::buildShapes() {
if (!_geometry || _rootIndex == -1) {
return;
}
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (geometry.joints.isEmpty()) {
return;
}
// We create the shapes with proper dimensions, but we set their transforms later.
float uniformScale = extractUniformScale(_scale);
for (int i = 0; i < _jointStates.size(); i++) {
const FBXJoint& joint = geometry.joints[i];
float radius = uniformScale * joint.boneRadius;
float halfHeight = 0.5f * uniformScale * joint.distanceToParent;
Shape::Type type = joint.shapeType;
if (type == Shape::CAPSULE_SHAPE && halfHeight < EPSILON) {
// this capsule is effectively a sphere
type = Shape::SPHERE_SHAPE;
}
if (type == Shape::CAPSULE_SHAPE) {
CapsuleShape* capsule = new CapsuleShape(radius, halfHeight);
capsule->setEntity(this);
_shapes.push_back(capsule);
} else if (type == Shape::SPHERE_SHAPE) {
SphereShape* sphere = new SphereShape(radius, glm::vec3(0.0f));
_shapes.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
_shapes.push_back(NULL);
}
}
// This method moves the shapes to their default positions in Model frame
// which is where we compute the bounding shape's parameters.
computeBoundingShape(geometry);
// finally sync shapes to joint positions
_shapesAreDirty = true;
updateShapePositions();
}
void Model::computeBoundingShape(const FBXGeometry& geometry) {
// compute default joint transforms and rotations
// (in local frame, ignoring Model translation and rotation)
int numJoints = geometry.joints.size();
QVector<glm::mat4> transforms;
transforms.fill(glm::mat4(), numJoints);
QVector<glm::quat> finalRotations;
finalRotations.fill(glm::quat(), numJoints);
QVector<bool> shapeIsSet;
shapeIsSet.fill(false, numJoints);
int numShapesSet = 0;
int lastNumShapesSet = -1;
while (numShapesSet < numJoints && numShapesSet != lastNumShapesSet) {
lastNumShapesSet = numShapesSet;
for (int i = 0; i < numJoints; i++) {
const FBXJoint& joint = geometry.joints.at(i);
int parentIndex = joint.parentIndex;
if (parentIndex == -1) {
glm::mat4 baseTransform = glm::scale(_scale) * glm::translate(_offset);
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
glm::mat4 rootTransform = baseTransform * geometry.offset * glm::translate(joint.translation)
* joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform;
// remove the tranlsation part before we save the root transform
transforms[i] = glm::translate(- extractTranslation(rootTransform)) * rootTransform;
finalRotations[i] = combinedRotation;
++numShapesSet;
shapeIsSet[i] = true;
} else if (shapeIsSet[parentIndex]) {
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
transforms[i] = transforms[parentIndex] * glm::translate(joint.translation)
* joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform;
finalRotations[i] = finalRotations[parentIndex] * combinedRotation;
++numShapesSet;
shapeIsSet[i] = true;
}
}
}
// sync shapes to joints
_boundingRadius = 0.0f;
float uniformScale = extractUniformScale(_scale);
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (!shape) {
continue;
}
const FBXJoint& joint = geometry.joints[i];
glm::vec3 jointToShapeOffset = uniformScale * (finalRotations[i] * joint.shapePosition);
glm::vec3 localPosition = extractTranslation(transforms[i]) + jointToShapeOffset;
shape->setCenter(localPosition);
shape->setRotation(finalRotations[i] * joint.shapeRotation);
float distance = glm::length(localPosition) + shape->getBoundingRadius();
if (distance > _boundingRadius) {
_boundingRadius = distance;
}
}
// compute bounding box
Extents totalExtents;
totalExtents.reset();
totalExtents.addPoint(glm::vec3(0.0f));
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (!shape) {
continue;
}
Extents shapeExtents;
shapeExtents.reset();
glm::vec3 localPosition = shape->getCenter();
int type = shape->getType();
if (type == Shape::CAPSULE_SHAPE) {
// add the two furthest surface points of the capsule
CapsuleShape* capsule = static_cast<CapsuleShape*>(shape);
glm::vec3 axis;
capsule->computeNormalizedAxis(axis);
float radius = capsule->getRadius();
float halfHeight = capsule->getHalfHeight();
axis = halfHeight * axis + glm::vec3(radius);
shapeExtents.addPoint(localPosition + axis);
shapeExtents.addPoint(localPosition - axis);
totalExtents.addExtents(shapeExtents);
} else if (type == Shape::SPHERE_SHAPE) {
float radius = shape->getBoundingRadius();
glm::vec3 axis = glm::vec3(radius);
shapeExtents.addPoint(localPosition + axis);
shapeExtents.addPoint(localPosition - axis);
totalExtents.addExtents(shapeExtents);
}
}
// compute bounding shape parameters
// NOTE: we assume that the longest side of totalExtents is the yAxis...
glm::vec3 diagonal = totalExtents.maximum - totalExtents.minimum;
// ... and assume the radius is half the RMS of the X and Z sides:
float capsuleRadius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z));
_boundingShape.setRadius(capsuleRadius);
_boundingShape.setHalfHeight(0.5f * diagonal.y - capsuleRadius);
_boundingShapeLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum);
}
void Model::resetShapePositions() {
// DEBUG method.
// Moves shapes to the joint default locations for debug visibility into
// how the bounding shape is computed.
if (!_geometry || _rootIndex == -1 || _shapes.isEmpty()) {
// geometry or joints have not yet been created
return;
}
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (geometry.joints.isEmpty() || _shapes.size() != geometry.joints.size()) {
return;
}
// The shapes are moved to their default positions in computeBoundingShape().
computeBoundingShape(geometry);
// Then we move them into world frame for rendering at the Model's location.
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (shape) {
shape->setCenter(_translation + _rotation * shape->getCenter());
shape->setRotation(_rotation * shape->getRotation());
}
}
_boundingShape.setCenter(_translation + _rotation * _boundingShapeLocalOffset);
_boundingShape.setRotation(_rotation);
// TODO: figure out how to load/build collision shapes for general models
}
void Model::updateShapePositions() {
if (_shapesAreDirty && _shapes.size() == _jointStates.size()) {
glm::vec3 rootPosition(0.0f);
_boundingRadius = 0.0f;
float uniformScale = extractUniformScale(_scale);
for (int i = 0; i < _jointStates.size(); i++) {
const JointState& state = _jointStates[i];
const FBXJoint& joint = state.getFBXJoint();
// shape position and rotation need to be in world-frame
glm::quat stateRotation = state.getRotation();
glm::vec3 shapeOffset = uniformScale * (stateRotation * joint.shapePosition);
glm::vec3 worldPosition = _translation + _rotation * (state.getPosition() + shapeOffset);
Shape* shape = _shapes[i];
if (shape) {
shape->setCenter(worldPosition);
shape->setRotation(_rotation * stateRotation * joint.shapeRotation);
float distance = glm::distance(worldPosition, _translation) + shape->getBoundingRadius();
if (distance > _boundingRadius) {
_boundingRadius = distance;
}
}
if (joint.parentIndex == -1) {
rootPosition = worldPosition;
}
}
_shapesAreDirty = false;
_boundingShape.setCenter(rootPosition + _rotation * _boundingShapeLocalOffset);
_boundingShape.setRotation(_rotation);
}
}
bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
const glm::vec3 relativeOrigin = origin - _translation;
const FBXGeometry& geometry = _geometry->getFBXGeometry();
float minDistance = FLT_MAX;
float radiusScale = extractUniformScale(_scale);
for (int i = 0; i < _jointStates.size(); i++) {
const FBXJoint& joint = geometry.joints[i];
glm::vec3 end = _translation + _rotation * _jointStates[i].getPosition();
float endRadius = joint.boneRadius * radiusScale;
glm::vec3 start = end;
float startRadius = joint.boneRadius * radiusScale;
if (joint.parentIndex != -1) {
start = _translation + _rotation * _jointStates[joint.parentIndex].getPosition();
startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale;
}
// for now, use average of start and end radii
float capsuleDistance;
if (findRayCapsuleIntersection(relativeOrigin, direction, start, end,
(startRadius + endRadius) / 2.0f, capsuleDistance)) {
minDistance = qMin(minDistance, capsuleDistance);
}
}
if (minDistance < FLT_MAX) {
distance = minDistance;
return true;
}
return false;
}
bool Model::findCollisions(const QVector<const Shape*> shapes, CollisionList& collisions) {
bool collided = false;
for (int i = 0; i < shapes.size(); ++i) {
const Shape* theirShape = shapes[i];
if (!theirShape) {
continue;
}
for (int j = 0; j < _shapes.size(); ++j) {
const Shape* ourShape = _shapes[j];
if (ourShape && ShapeCollider::collideShapes(theirShape, ourShape, collisions)) {
collided = true;
}
}
}
return collided;
}
bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadius,
CollisionList& collisions, int skipIndex) {
bool collided = false;
SphereShape sphere(sphereRadius, sphereCenter);
const FBXGeometry& geometry = _geometry->getFBXGeometry();
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (!shape) {
continue;
}
const FBXJoint& joint = geometry.joints[i];
if (joint.parentIndex != -1) {
if (skipIndex != -1) {
int ancestorIndex = joint.parentIndex;
do {
if (ancestorIndex == skipIndex) {
goto outerContinue;
}
ancestorIndex = geometry.joints[ancestorIndex].parentIndex;
} while (ancestorIndex != -1);
}
}
if (ShapeCollider::collideShapes(&sphere, shape, collisions)) {
CollisionInfo* collision = collisions.getLastCollision();
collision->_data = (void*)(this);
collision->_intData = i;
collided = true;
}
outerContinue: ;
}
return collided;
}
bool Model::findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions) {
bool collided = false;
PlaneShape planeShape(plane);
for (int i = 0; i < _shapes.size(); i++) {
if (_shapes[i] && ShapeCollider::collideShapes(&planeShape, _shapes[i], collisions)) {
CollisionInfo* collision = collisions.getLastCollision();
collision->_data = (void*)(this);
collision->_intData = i;
collided = true;
}
}
return collided;
// TODO: implement this when we know how to build shapes for regular Models
}
class Blender : public QRunnable {
@ -1441,41 +1141,6 @@ void Model::renderJointCollisionShapes(float alpha) {
glPopMatrix();
}
void Model::renderBoundingCollisionShapes(float alpha) {
if (_shapes.isEmpty()) {
// the bounding shape has not been propery computed
// so no need to render it
return;
}
glPushMatrix();
Application::getInstance()->loadTranslatedViewMatrix(_translation);
// draw a blue sphere at the capsule endpoint
glm::vec3 endPoint;
_boundingShape.getEndPoint(endPoint);
endPoint = endPoint - _translation;
glTranslatef(endPoint.x, endPoint.y, endPoint.z);
glColor4f(0.6f, 0.6f, 0.8f, alpha);
glutSolidSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
// draw a yellow sphere at the capsule startpoint
glm::vec3 startPoint;
_boundingShape.getStartPoint(startPoint);
startPoint = startPoint - _translation;
glm::vec3 axis = endPoint - startPoint;
glTranslatef(-axis.x, -axis.y, -axis.z);
glColor4f(0.8f, 0.8f, 0.6f, alpha);
glutSolidSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
// draw a green cylinder between the two points
glm::vec3 origin(0.0f);
glColor4f(0.6f, 0.8f, 0.6f, alpha);
Avatar::renderJointConnectingCone( origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius());
glPopMatrix();
}
void Model::setBlendedVertices(const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
if (_blendedVertexBuffers.isEmpty()) {
return;

View file

@ -16,7 +16,6 @@
#include <QObject>
#include <QUrl>
#include <CapsuleShape.h>
#include <PhysicalEntity.h>
#include <AnimationCache.h>
@ -132,34 +131,15 @@ public:
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
// virtual override from PhysicalEntity
// virtual overrides from PhysicalEntity
virtual void buildShapes();
void resetShapePositions(); // DEBUG method
virtual void updateShapePositions();
void renderJointCollisionShapes(float alpha);
void renderBoundingCollisionShapes(float alpha);
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
/// \param shapes list of pointers shapes to test against Model
/// \param collisions list to store collision results
/// \return true if at least one shape collided agains Model
bool findCollisions(const QVector<const Shape*> shapes, CollisionList& collisions);
bool findSphereCollisions(const glm::vec3& penetratorCenter, float penetratorRadius,
CollisionList& collisions, int skipIndex = -1);
bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions);
float getBoundingShapeRadius() const { return _boundingShape.getRadius(); }
/// Sets blended vertices computed in a separate thread.
void setBlendedVertices(const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
const CapsuleShape& getBoundingShape() const { return _boundingShape; }
protected:
QSharedPointer<NetworkGeometry> _geometry;
@ -176,9 +156,6 @@ protected:
QVector<JointState> _jointStates;
CapsuleShape _boundingShape;
glm::vec3 _boundingShapeLocalOffset;
class MeshState {
public:
QVector<glm::mat4> clusterMatrices;
@ -222,8 +199,6 @@ protected:
/// first free ancestor.
float getLimbLength(int jointIndex) const;
void computeBoundingShape(const FBXGeometry& geometry);
private:
friend class AnimationHandle;

View file

@ -11,9 +11,9 @@
#include "PhysicalEntity.h"
#include "Shape.h"
#include "ShapeCollider.h"
PhysicalEntity::PhysicalEntity(EntityType type) :
_entityType(type),
PhysicalEntity::PhysicalEntity() :
_translation(0.0f),
_rotation(),
_boundingRadius(0.0f),
@ -61,4 +61,93 @@ void PhysicalEntity::clearShapes() {
_shapes.clear();
}
bool PhysicalEntity::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
/* TODO: Andrew to make this work
int numShapes = _shapes.size();
float minDistance = FLT_MAX;
for (int j = 0; j < numShapes; ++j) {
const Shape* shape = _shapes[j];
float thisDistance = FLT_MAX;
if (shape && ShapeCollider::findRayIntersection(ourShape, origin, direction, thisDistance)) {
if (thisDistance < minDistance) {
minDistance = thisDistance;
}
}
}
if (minDistance < FLT_MAX) {
distance = minDistance;
return true;
}
*/
return false;
}
bool PhysicalEntity::findCollisions(const QVector<const Shape*> shapes, CollisionList& collisions) {
bool collided = false;
int numTheirShapes = shapes.size();
for (int i = 0; i < numTheirShapes; ++i) {
const Shape* theirShape = shapes[i];
if (!theirShape) {
continue;
}
int numOurShapes = _shapes.size();
for (int j = 0; j < numOurShapes; ++j) {
const Shape* ourShape = _shapes[j];
if (ourShape && ShapeCollider::collideShapes(theirShape, ourShape, collisions)) {
collided = true;
}
}
}
return collided;
}
bool PhysicalEntity::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadius,
CollisionList& collisions, int skipIndex) {
bool collided = false;
// TODO: Andrew to implement this or make it unecessary
/*
SphereShape sphere(sphereRadius, sphereCenter);
const FBXGeometry& geometry = _geometry->getFBXGeometry();
for (int i = 0; i < _shapes.size(); i++) {
Shape* shape = _shapes[i];
if (!shape) {
continue;
}
const FBXJoint& joint = geometry.joints[i];
if (joint.parentIndex != -1) {
if (skipIndex != -1) {
int ancestorIndex = joint.parentIndex;
do {
if (ancestorIndex == skipIndex) {
goto outerContinue;
}
ancestorIndex = geometry.joints[ancestorIndex].parentIndex;
} while (ancestorIndex != -1);
}
}
if (ShapeCollider::collideShapes(&sphere, shape, collisions)) {
CollisionInfo* collision = collisions.getLastCollision();
collision->_data = (void*)(this);
collision->_intData = i;
collided = true;
}
outerContinue: ;
}
*/
return collided;
}
bool PhysicalEntity::findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions) {
bool collided = false;
PlaneShape planeShape(plane);
for (int i = 0; i < _shapes.size(); i++) {
if (_shapes[i] && ShapeCollider::collideShapes(&planeShape, _shapes[i], collisions)) {
CollisionInfo* collision = collisions.getLastCollision();
collision->_data = (void*)(this);
collision->_intData = i;
collided = true;
}
}
return collided;
}

View file

@ -17,6 +17,8 @@
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "CollisionInfo.h"
class Shape;
// PhysicalEntity is the base class for anything that owns one or more Shapes that collide in a
@ -26,12 +28,7 @@ class Shape;
class PhysicalEntity {
public:
enum EntityType {
ENTITY_UNKNOWN,
ENTITY_MODEL,
};
PhysicalEntity(EntityType type = ENTITY_UNKNOWN);
PhysicalEntity();
virtual ~PhysicalEntity() {}
void setTranslation(const glm::vec3& translation);
@ -41,8 +38,6 @@ public:
const glm::quat& getRotation() const { return _rotation; }
float getBoundingRadius() const { return _boundingRadius; }
EntityType getEntityType() const { return _entityType; }
void setShapeBackPointers();
void setEnableShapes(bool enable);
@ -50,8 +45,12 @@ public:
virtual void buildShapes() = 0;
virtual void clearShapes();
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
bool findCollisions(const QVector<const Shape*> shapes, CollisionList& collisions);
bool findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadius, CollisionList& collisions, int skipIndex);
bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions);
protected:
EntityType _entityType;
glm::vec3 _translation;
glm::quat _rotation;
float _boundingRadius;