diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 5ff56b46dd..a68d727db0 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1620,18 +1620,18 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } // now that all joints have been scanned, compute a collision shape for each joint - glm::vec3 yAxis(0.f, 1.f, 0.f); + glm::vec3 defaultCapsuleAxis(0.f, 1.f, 0.f); for (int i = 0; i < geometry.joints.size(); ++i) { FBXJoint& joint = geometry.joints[i]; JointShapeInfo& jointShapeInfo = jointShapeInfos[i]; - // we use a capsule if the joint ANY mesh vertices that successfully projected onto the bone + // we use a capsule if the joint ANY mesh vertices successfully projected onto the bone // AND its boneRadius is not too close to zero bool collideLikeCapsule = jointShapeInfo.numProjectedVertices > 0 && glm::length(jointShapeInfo.boneBegin) > EPSILON; if (collideLikeCapsule) { - joint.shapeRotation = rotationBetween(yAxis, jointShapeInfo.boneBegin); + joint.shapeRotation = rotationBetween(defaultCapsuleAxis, jointShapeInfo.boneBegin); joint.shapePosition = 0.5f * jointShapeInfo.boneBegin; //joint.shapePosition = glm::vec3(0.f); joint.shapeType = Shape::CAPSULE_SHAPE; diff --git a/interface/src/renderer/FBXReader.h b/interface/src/renderer/FBXReader.h index 48c300358e..b96df3a03b 100644 --- a/interface/src/renderer/FBXReader.h +++ b/interface/src/renderer/FBXReader.h @@ -26,10 +26,17 @@ extern const char* FACESHIFT_BLENDSHAPES[]; class Extents { public: - //Extents() : minimum(FLT_MAX), maximum(-FLT_MAX) {} + /// set minimum and maximum to FLT_MAX and -FLT_MAX respectively void reset(); + + /// \param point new point to compare against existing limits + /// compare point to current limits and expand them if necessary to contain point void addPoint(const glm::vec3& point); + + /// \param point + /// \return true if point is within current limits bool containsPoint(const glm::vec3& point) const; + glm::vec3 minimum; glm::vec3 maximum; }; @@ -73,11 +80,9 @@ public: glm::quat inverseDefaultRotation; glm::quat inverseBindRotation; glm::mat4 bindTransform; - // TODO: add some comments to these data members - // Trying to provide enough info so that the proper shape can be generated in Model - QString name; - glm::vec3 shapePosition; // in joint frame (where boneEnd = origin) - glm::quat shapeRotation; + QString name; // temp field for debugging + glm::vec3 shapePosition; // in joint frame + glm::quat shapeRotation; // in joint frame int shapeType; }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index aac4b000bb..64200fd992 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -142,8 +142,15 @@ void Model::createCollisionShapes() { glm::vec3 position = _rotation * (extractTranslation(_jointStates[i].transform) + uniformScale * meshCenter) + _translation; float radius = uniformScale * joint.boneRadius; - SphereShape* shape = new SphereShape(radius, position); - _shapes.push_back(shape); + if (joint.shapeType == Shape::CAPSULE_SHAPE) { + float halfHeight = 0.5f * uniformScale * joint.distanceToParent; + CapsuleShape* shape = new CapsuleShape(radius, halfHeight); + shape->setPosition(position); + _shapes.push_back(shape); + } else { + SphereShape* shape = new SphereShape(radius, position); + _shapes.push_back(shape); + } } } @@ -153,10 +160,14 @@ void Model::updateShapePositions() { if (_shapesAreDirty && _shapes.size() == _jointStates.size()) { for (int i = 0; i < _jointStates.size(); i++) { const FBXJoint& joint = geometry.joints[i]; - // shape positions are stored in world-frame - glm::vec3 meshCenter = _jointStates[i].combinedRotation * joint.shapePosition; - _shapes[i]->setPosition(_rotation * (extractTranslation(_jointStates[i].transform) + uniformScale * meshCenter) + _translation); - _shapes[i]->setRotation(_jointStates[i].combinedRotation); + + // shape position and rotation are stored in world-frame + glm::vec3 localPosition = uniformScale * (_jointStates[i].combinedRotation * joint.shapePosition); + glm::vec3 worldPosition = _rotation * (extractTranslation(_jointStates[i].transform) + localPosition) + _translation; + _shapes[i]->setPosition(worldPosition); + glm::quat localRotation = _jointStates[i].combinedRotation * joint.shapeRotation; + glm::quat worldRotation = _rotation * localRotation; + _shapes[i]->setRotation(worldRotation); } _shapesAreDirty = false; } @@ -743,24 +754,56 @@ void Model::renderCollisionProxies(float alpha) { Application::getInstance()->loadTranslatedViewMatrix(_translation); updateShapePositions(); float uniformScale = extractUniformScale(_scale); + const int BALL_SUBDIVISIONS = 10; glm::quat inverseRotation = glm::inverse(_rotation); for (int i = 0; i < _shapes.size(); i++) { glPushMatrix(); Shape* shape = _shapes[i]; - // shapes are stored in world-frame, so we have to transform into local frame - glm::vec3 position = inverseRotation * (shape->getPosition() - _translation); - glTranslatef(position.x, position.y, position.z); - - const glm::quat& rotation = shape->getRotation(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); - - glColor4f(0.75f, 0.75f, 0.75f, alpha); - const int BALL_SUBDIVISIONS = 10; - glutSolidSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); - + if (shape->getType() == Shape::SPHERE_SHAPE) { + // shapes are stored in world-frame, so we have to transform into model frame + glm::vec3 position = inverseRotation * (shape->getPosition() - _translation); + glTranslatef(position.x, position.y, position.z); + const glm::quat& rotation = inverseRotation; + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + + // draw a grey sphere at shape position + glColor4f(0.75f, 0.75f, 0.75f, alpha); + glutSolidSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + } else if (shape->getType() == Shape::CAPSULE_SHAPE) { + CapsuleShape* capsule = static_cast(shape); + + // translate to capsule center + glm::vec3 point = inverseRotation * (capsule->getPosition() - _translation); + + // draw a blue sphere at the capsule endpoint + glm::vec3 endPoint; + capsule->getEndPoint(endPoint); + endPoint = inverseRotation * (endPoint - _translation); + glTranslatef(endPoint.x, endPoint.y, endPoint.z); + glColor4f(0.65f, 0.65f, 0.95f, alpha); + glutSolidSphere(0.95f * capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + + // draw a red sphere at the capsule startpoint + glm::vec3 startPoint; + capsule->getStartPoint(startPoint); + startPoint = inverseRotation * (startPoint - _translation); + glm::vec3 axis = endPoint - startPoint; + glTranslatef(-axis.x, -axis.y, -axis.z); + glColor4f(0.95f, 0.65f, 0.65f, alpha); + glutSolidSphere(0.95f * capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS); + + // draw a green cylinder between the two points + glm::vec3 origin(0.f); + glColor4f(0.05f, 0.95f, 0.65f, alpha); + Avatar::renderJointConnectingCone( + origin, + axis, + 1.05f * capsule->getRadius(), + 1.05f * capsule->getRadius()); + } glPopMatrix(); } glPopMatrix();