mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
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:
parent
118717d96a
commit
ecbf5043d7
7 changed files with 371 additions and 377 deletions
|
@ -230,7 +230,6 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
||||||
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
|
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
|
||||||
}
|
}
|
||||||
if (renderBounding && shouldRenderHead(cameraPosition, renderMode)) {
|
if (renderBounding && shouldRenderHead(cameraPosition, renderMode)) {
|
||||||
getHead()->getFaceModel().renderBoundingCollisionShapes(0.7f);
|
|
||||||
_skeletonModel.renderBoundingCollisionShapes(0.7f);
|
_skeletonModel.renderBoundingCollisionShapes(0.7f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
#include <glm/gtx/transform.hpp>
|
#include <glm/gtx/transform.hpp>
|
||||||
|
|
||||||
|
#include <CapsuleShape.h>
|
||||||
|
#include <SphereShape.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
#include "Hand.h"
|
#include "Hand.h"
|
||||||
|
@ -20,7 +23,9 @@
|
||||||
SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
||||||
Model(parent),
|
Model(parent),
|
||||||
Ragdoll(),
|
Ragdoll(),
|
||||||
_owningAvatar(owningAvatar) {
|
_owningAvatar(owningAvatar),
|
||||||
|
_boundingShape(),
|
||||||
|
_boundingShapeLocalOffset(0.0f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonModel::setJointStates(QVector<JointState> states) {
|
void SkeletonModel::setJointStates(QVector<JointState> states) {
|
||||||
|
@ -524,3 +529,251 @@ void SkeletonModel::renderRagdoll() {
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glEnable(GL_LIGHTING);
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "renderer/Model.h"
|
#include "renderer/Model.h"
|
||||||
|
|
||||||
|
#include <CapsuleShape.h>
|
||||||
#include <Ragdoll.h>
|
#include <Ragdoll.h>
|
||||||
|
|
||||||
class Avatar;
|
class Avatar;
|
||||||
|
@ -30,7 +31,6 @@ public:
|
||||||
|
|
||||||
void simulate(float deltaTime, bool fullUpdate = true);
|
void simulate(float deltaTime, bool fullUpdate = true);
|
||||||
void simulateRagdoll(float deltaTime);
|
void simulateRagdoll(float deltaTime);
|
||||||
void updateShapePositions();
|
|
||||||
|
|
||||||
/// \param jointIndex index of hand joint
|
/// \param jointIndex index of hand joint
|
||||||
/// \param shapes[out] list in which is stored pointers to hand shapes
|
/// \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
|
/// \return whether or not both eye meshes were found
|
||||||
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
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();
|
void renderRagdoll();
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -121,6 +132,9 @@ private:
|
||||||
void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation);
|
void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation);
|
||||||
|
|
||||||
Avatar* _owningAvatar;
|
Avatar* _owningAvatar;
|
||||||
|
|
||||||
|
CapsuleShape _boundingShape;
|
||||||
|
glm::vec3 _boundingShapeLocalOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_SkeletonModel_h
|
#endif // hifi_SkeletonModel_h
|
||||||
|
|
|
@ -33,7 +33,6 @@ static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
||||||
|
|
||||||
Model::Model(QObject* parent) :
|
Model::Model(QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
PhysicalEntity(PhysicalEntity::ENTITY_MODEL),
|
|
||||||
_scale(1.0f, 1.0f, 1.0f),
|
_scale(1.0f, 1.0f, 1.0f),
|
||||||
_scaleToFit(false),
|
_scaleToFit(false),
|
||||||
_scaleToFitLargestDimension(0.0f),
|
_scaleToFitLargestDimension(0.0f),
|
||||||
|
@ -42,8 +41,6 @@ Model::Model(QObject* parent) :
|
||||||
_snappedToCenter(false),
|
_snappedToCenter(false),
|
||||||
_rootIndex(-1),
|
_rootIndex(-1),
|
||||||
//_enableCollisionShapes(false),
|
//_enableCollisionShapes(false),
|
||||||
_boundingShape(),
|
|
||||||
_boundingShapeLocalOffset(0.0f),
|
|
||||||
_lodDistance(0.0f),
|
_lodDistance(0.0f),
|
||||||
_pupilDilation(0.0f),
|
_pupilDilation(0.0f),
|
||||||
_url("http://invalid.com") {
|
_url("http://invalid.com") {
|
||||||
|
@ -793,308 +790,11 @@ AnimationHandlePointer Model::createAnimationHandle() {
|
||||||
|
|
||||||
// virtual override from PhysicalEntity
|
// virtual override from PhysicalEntity
|
||||||
void Model::buildShapes() {
|
void Model::buildShapes() {
|
||||||
if (!_geometry || _rootIndex == -1) {
|
// TODO: figure out how to load/build collision shapes for general models
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::updateShapePositions() {
|
void Model::updateShapePositions() {
|
||||||
if (_shapesAreDirty && _shapes.size() == _jointStates.size()) {
|
// TODO: implement this when we know how to build shapes for regular Models
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Blender : public QRunnable {
|
class Blender : public QRunnable {
|
||||||
|
@ -1441,41 +1141,6 @@ void Model::renderJointCollisionShapes(float alpha) {
|
||||||
glPopMatrix();
|
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) {
|
void Model::setBlendedVertices(const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
||||||
if (_blendedVertexBuffers.isEmpty()) {
|
if (_blendedVertexBuffers.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include <CapsuleShape.h>
|
|
||||||
#include <PhysicalEntity.h>
|
#include <PhysicalEntity.h>
|
||||||
|
|
||||||
#include <AnimationCache.h>
|
#include <AnimationCache.h>
|
||||||
|
@ -132,34 +131,15 @@ public:
|
||||||
|
|
||||||
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
|
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
|
||||||
|
|
||||||
// virtual override from PhysicalEntity
|
// virtual overrides from PhysicalEntity
|
||||||
virtual void buildShapes();
|
virtual void buildShapes();
|
||||||
|
|
||||||
void resetShapePositions(); // DEBUG method
|
|
||||||
virtual void updateShapePositions();
|
virtual void updateShapePositions();
|
||||||
|
|
||||||
void renderJointCollisionShapes(float alpha);
|
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.
|
/// Sets blended vertices computed in a separate thread.
|
||||||
void setBlendedVertices(const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
void setBlendedVertices(const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
||||||
|
|
||||||
const CapsuleShape& getBoundingShape() const { return _boundingShape; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSharedPointer<NetworkGeometry> _geometry;
|
QSharedPointer<NetworkGeometry> _geometry;
|
||||||
|
|
||||||
|
@ -176,9 +156,6 @@ protected:
|
||||||
|
|
||||||
QVector<JointState> _jointStates;
|
QVector<JointState> _jointStates;
|
||||||
|
|
||||||
CapsuleShape _boundingShape;
|
|
||||||
glm::vec3 _boundingShapeLocalOffset;
|
|
||||||
|
|
||||||
class MeshState {
|
class MeshState {
|
||||||
public:
|
public:
|
||||||
QVector<glm::mat4> clusterMatrices;
|
QVector<glm::mat4> clusterMatrices;
|
||||||
|
@ -222,8 +199,6 @@ protected:
|
||||||
/// first free ancestor.
|
/// first free ancestor.
|
||||||
float getLimbLength(int jointIndex) const;
|
float getLimbLength(int jointIndex) const;
|
||||||
|
|
||||||
void computeBoundingShape(const FBXGeometry& geometry);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class AnimationHandle;
|
friend class AnimationHandle;
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
|
|
||||||
#include "PhysicalEntity.h"
|
#include "PhysicalEntity.h"
|
||||||
#include "Shape.h"
|
#include "Shape.h"
|
||||||
|
#include "ShapeCollider.h"
|
||||||
|
|
||||||
PhysicalEntity::PhysicalEntity(EntityType type) :
|
PhysicalEntity::PhysicalEntity() :
|
||||||
_entityType(type),
|
|
||||||
_translation(0.0f),
|
_translation(0.0f),
|
||||||
_rotation(),
|
_rotation(),
|
||||||
_boundingRadius(0.0f),
|
_boundingRadius(0.0f),
|
||||||
|
@ -61,4 +61,93 @@ void PhysicalEntity::clearShapes() {
|
||||||
_shapes.clear();
|
_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;
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
|
||||||
|
#include "CollisionInfo.h"
|
||||||
|
|
||||||
class Shape;
|
class Shape;
|
||||||
|
|
||||||
// PhysicalEntity is the base class for anything that owns one or more Shapes that collide in a
|
// 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 {
|
class PhysicalEntity {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum EntityType {
|
PhysicalEntity();
|
||||||
ENTITY_UNKNOWN,
|
|
||||||
ENTITY_MODEL,
|
|
||||||
};
|
|
||||||
|
|
||||||
PhysicalEntity(EntityType type = ENTITY_UNKNOWN);
|
|
||||||
virtual ~PhysicalEntity() {}
|
virtual ~PhysicalEntity() {}
|
||||||
|
|
||||||
void setTranslation(const glm::vec3& translation);
|
void setTranslation(const glm::vec3& translation);
|
||||||
|
@ -41,8 +38,6 @@ public:
|
||||||
const glm::quat& getRotation() const { return _rotation; }
|
const glm::quat& getRotation() const { return _rotation; }
|
||||||
float getBoundingRadius() const { return _boundingRadius; }
|
float getBoundingRadius() const { return _boundingRadius; }
|
||||||
|
|
||||||
EntityType getEntityType() const { return _entityType; }
|
|
||||||
|
|
||||||
void setShapeBackPointers();
|
void setShapeBackPointers();
|
||||||
|
|
||||||
void setEnableShapes(bool enable);
|
void setEnableShapes(bool enable);
|
||||||
|
@ -50,8 +45,12 @@ public:
|
||||||
virtual void buildShapes() = 0;
|
virtual void buildShapes() = 0;
|
||||||
virtual void clearShapes();
|
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:
|
protected:
|
||||||
EntityType _entityType;
|
|
||||||
glm::vec3 _translation;
|
glm::vec3 _translation;
|
||||||
glm::quat _rotation;
|
glm::quat _rotation;
|
||||||
float _boundingRadius;
|
float _boundingRadius;
|
||||||
|
|
Loading…
Reference in a new issue