mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 18:23:22 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into metavoxels
This commit is contained in:
commit
072bbb308c
11 changed files with 464 additions and 152 deletions
|
@ -9,8 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/HandAnim.fbx";
|
||||
var leftHandAnimation = "";
|
||||
var rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/RightHandAnim.fbx";
|
||||
var leftHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/LeftHandAnim.fbx";
|
||||
|
||||
var LEFT = 0;
|
||||
var RIGHT = 1;
|
||||
|
@ -18,17 +18,20 @@ var RIGHT = 1;
|
|||
var lastLeftFrame = 0;
|
||||
var lastRightFrame = 0;
|
||||
|
||||
var LAST_FRAME = 15.0; // What is the number of the last frame we want to use in the animation?
|
||||
var LAST_FRAME = 11.0; // What is the number of the last frame we want to use in the animation?
|
||||
var SMOOTH_FACTOR = 0.80;
|
||||
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
var leftTriggerValue = Controller.getTriggerValue(LEFT);
|
||||
var rightTriggerValue = Controller.getTriggerValue(RIGHT);
|
||||
var leftTriggerValue = Math.sqrt(Controller.getTriggerValue(LEFT));
|
||||
var rightTriggerValue = Math.sqrt(Controller.getTriggerValue(RIGHT));
|
||||
|
||||
var leftFrame, rightFrame;
|
||||
|
||||
// Average last two trigger frames together for a bit of smoothing
|
||||
leftFrame = (leftTriggerValue * LAST_FRAME) * 0.5 + lastLeftFrame * 0.5;
|
||||
rightFrame = (rightTriggerValue * LAST_FRAME) * 0.5 + lastRightFrame * 0.5;
|
||||
// Average last few trigger frames together for a bit of smoothing
|
||||
leftFrame = (leftTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastLeftFrame * SMOOTH_FACTOR;
|
||||
rightFrame = (rightTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastRightFrame * SMOOTH_FACTOR;
|
||||
|
||||
|
||||
if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){
|
||||
MyAvatar.stopAnimation(leftHandAnimation);
|
||||
|
|
|
@ -21,6 +21,11 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) :
|
|||
_owningAvatar(owningAvatar) {
|
||||
}
|
||||
|
||||
void SkeletonModel::setJointStates(QVector<JointState> states) {
|
||||
Model::setJointStates(states);
|
||||
_ragDoll.init(_jointStates);
|
||||
}
|
||||
|
||||
const float PALM_PRIORITY = 3.0f;
|
||||
|
||||
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
||||
|
@ -78,6 +83,21 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]);
|
||||
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
|
||||
}
|
||||
|
||||
simulateRagDoll(deltaTime);
|
||||
}
|
||||
|
||||
void SkeletonModel::simulateRagDoll(float deltaTime) {
|
||||
_ragDoll.slaveToSkeleton(_jointStates, 0.5f);
|
||||
|
||||
float MIN_CONSTRAINT_ERROR = 0.005f; // 5mm
|
||||
int MAX_ITERATIONS = 4;
|
||||
int iterations = 0;
|
||||
float delta = 0.0f;
|
||||
do {
|
||||
delta = _ragDoll.enforceConstraints();
|
||||
++iterations;
|
||||
} while (delta > MIN_CONSTRAINT_ERROR && iterations < MAX_ITERATIONS);
|
||||
}
|
||||
|
||||
void SkeletonModel::getHandShapes(int jointIndex, QVector<const Shape*>& shapes) const {
|
||||
|
@ -121,6 +141,7 @@ void SkeletonModel::getBodyShapes(QVector<const Shape*>& shapes) const {
|
|||
void SkeletonModel::renderIKConstraints() {
|
||||
renderJointConstraints(getRightHandJointIndex());
|
||||
renderJointConstraints(getLeftHandJointIndex());
|
||||
renderRagDoll();
|
||||
}
|
||||
|
||||
class IndexValue {
|
||||
|
@ -452,3 +473,30 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco
|
|||
return false;
|
||||
}
|
||||
|
||||
void SkeletonModel::renderRagDoll() {
|
||||
const int BALL_SUBDIVISIONS = 6;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glPushMatrix();
|
||||
|
||||
Application::getInstance()->loadTranslatedViewMatrix(_translation);
|
||||
QVector<glm::vec3> points = _ragDoll.getPoints();
|
||||
int numPoints = points.size();
|
||||
float alpha = 0.3f;
|
||||
float radius1 = 0.008f;
|
||||
float radius2 = 0.01f;
|
||||
for (int i = 0; i < numPoints; ++i) {
|
||||
glPushMatrix();
|
||||
// draw each point as a yellow hexagon with black border
|
||||
glm::vec3 position = _rotation * points[i];
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glColor4f(0.0f, 0.0f, 0.0f, alpha);
|
||||
glutSolidSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
glColor4f(1.0f, 1.0f, 0.0f, alpha);
|
||||
glutSolidSphere(radius1, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS);
|
||||
glPopMatrix();
|
||||
}
|
||||
glPopMatrix();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_SkeletonModel_h
|
||||
|
||||
#include "renderer/Model.h"
|
||||
#include "renderer/RagDoll.h"
|
||||
|
||||
class Avatar;
|
||||
|
||||
|
@ -23,8 +24,11 @@ class SkeletonModel : public Model {
|
|||
public:
|
||||
|
||||
SkeletonModel(Avatar* owningAvatar);
|
||||
|
||||
|
||||
void setJointStates(QVector<JointState> states);
|
||||
|
||||
void simulate(float deltaTime, bool fullUpdate = true);
|
||||
void simulateRagDoll(float deltaTime);
|
||||
|
||||
/// \param jointIndex index of hand joint
|
||||
/// \param shapes[out] list in which is stored pointers to hand shapes
|
||||
|
@ -89,6 +93,7 @@ public:
|
|||
/// \return whether or not both eye meshes were found
|
||||
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
||||
|
||||
void renderRagDoll();
|
||||
protected:
|
||||
|
||||
/// \param jointIndex index of joint in model
|
||||
|
@ -114,6 +119,7 @@ private:
|
|||
void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation);
|
||||
|
||||
Avatar* _owningAvatar;
|
||||
RagDoll _ragDoll;
|
||||
};
|
||||
|
||||
#endif // hifi_SkeletonModel_h
|
||||
|
|
|
@ -76,20 +76,21 @@ static void setPalm(float deltaTime, int index) {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: this math is done in the worl-frame with unecessary complexity.
|
||||
// TODO: transfom this to stay in the model-frame.
|
||||
glm::vec3 position;
|
||||
glm::quat rotation;
|
||||
|
||||
SkeletonModel* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel();
|
||||
int jointIndex;
|
||||
glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation());
|
||||
if (index == LEFT_HAND_INDEX) {
|
||||
jointIndex = skeletonModel->getLeftHandJointIndex();
|
||||
skeletonModel->getJointRotation(jointIndex, rotation, true);
|
||||
skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation);
|
||||
rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f));
|
||||
|
||||
} else {
|
||||
jointIndex = skeletonModel->getRightHandJointIndex();
|
||||
skeletonModel->getJointRotation(jointIndex, rotation, true);
|
||||
skeletonModel->getJointRotationInWorldFrame(jointIndex, rotation);
|
||||
rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, -PI_OVER_TWO, 0.0f));
|
||||
}
|
||||
skeletonModel->getJointPositionInWorldFrame(jointIndex, position);
|
||||
|
|
101
interface/src/renderer/JointState.cpp
Normal file
101
interface/src/renderer/JointState.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// JointState.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/18/13.
|
||||
// Copyright 2013 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 <glm/gtx/norm.hpp>
|
||||
|
||||
//#include <GeometryUtil.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "JointState.h"
|
||||
|
||||
JointState::JointState() :
|
||||
_animationPriority(0.0f),
|
||||
_fbxJoint(NULL) {
|
||||
}
|
||||
|
||||
void JointState::setFBXJoint(const FBXJoint* joint) {
|
||||
assert(joint != NULL);
|
||||
_rotationInParentFrame = joint->rotation;
|
||||
// NOTE: JointState does not own the FBXJoint to which it points.
|
||||
_fbxJoint = joint;
|
||||
}
|
||||
|
||||
void JointState::copyState(const JointState& state) {
|
||||
_rotationInParentFrame = state._rotationInParentFrame;
|
||||
_transform = state._transform;
|
||||
_rotation = extractRotation(_transform);
|
||||
_animationPriority = state._animationPriority;
|
||||
// DO NOT copy _fbxJoint
|
||||
}
|
||||
|
||||
void JointState::computeTransform(const glm::mat4& parentTransform) {
|
||||
glm::quat modifiedRotation = _fbxJoint->preRotation * _rotationInParentFrame * _fbxJoint->postRotation;
|
||||
glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform;
|
||||
_transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform;
|
||||
_rotation = extractRotation(_transform);
|
||||
}
|
||||
|
||||
glm::quat JointState::getRotationFromBindToModelFrame() const {
|
||||
return _rotation * _fbxJoint->inverseBindRotation;
|
||||
}
|
||||
|
||||
void JointState::restoreRotation(float fraction, float priority) {
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority == _animationPriority || _animationPriority == 0.0f) {
|
||||
_rotationInParentFrame = safeMix(_rotationInParentFrame, _fbxJoint->rotation, fraction);
|
||||
_animationPriority = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) {
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority >= _animationPriority) {
|
||||
// rotation is from bind- to model-frame
|
||||
_rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation);
|
||||
_animationPriority = priority;
|
||||
}
|
||||
}
|
||||
|
||||
void JointState::clearTransformTranslation() {
|
||||
_transform[3][0] = 0.0f;
|
||||
_transform[3][1] = 0.0f;
|
||||
_transform[3][2] = 0.0f;
|
||||
}
|
||||
|
||||
void JointState::setRotation(const glm::quat& rotation, bool constrain, float priority) {
|
||||
applyRotationDelta(rotation * glm::inverse(_rotation), true, priority);
|
||||
}
|
||||
|
||||
void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) {
|
||||
// NOTE: delta is in jointParent-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority < _animationPriority) {
|
||||
return;
|
||||
}
|
||||
_animationPriority = priority;
|
||||
if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) &&
|
||||
_fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) {
|
||||
// no constraints
|
||||
_rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation;
|
||||
_rotation = delta * _rotation;
|
||||
return;
|
||||
}
|
||||
glm::quat targetRotation = delta * _rotation;
|
||||
glm::vec3 eulers = safeEulerAngles(_rotationInParentFrame * glm::inverse(_rotation) * targetRotation);
|
||||
glm::quat newRotation = glm::quat(glm::clamp(eulers, _fbxJoint->rotationMin, _fbxJoint->rotationMax));
|
||||
_rotation = _rotation * glm::inverse(_rotationInParentFrame) * newRotation;
|
||||
_rotationInParentFrame = newRotation;
|
||||
}
|
||||
|
||||
const glm::vec3& JointState::getDefaultTranslationInParentFrame() const {
|
||||
assert(_fbxJoint != NULL);
|
||||
return _fbxJoint->translation;
|
||||
}
|
66
interface/src/renderer/JointState.h
Normal file
66
interface/src/renderer/JointState.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// JointState.h
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Andrzej Kapolka on 10/18/13.
|
||||
// Copyright 2013 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_JointState_h
|
||||
#define hifi_JointState_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <FBXReader.h>
|
||||
|
||||
class JointState {
|
||||
public:
|
||||
JointState();
|
||||
|
||||
void setFBXJoint(const FBXJoint* joint);
|
||||
const FBXJoint& getFBXJoint() const { return *_fbxJoint; }
|
||||
|
||||
void copyState(const JointState& state);
|
||||
|
||||
void computeTransform(const glm::mat4& parentTransform);
|
||||
const glm::mat4& getTransform() const { return _transform; }
|
||||
|
||||
glm::quat getRotation() const { return _rotation; }
|
||||
glm::vec3 getPosition() const { return extractTranslation(_transform); }
|
||||
|
||||
/// \return rotation from bind to model frame
|
||||
glm::quat getRotationFromBindToModelFrame() const;
|
||||
|
||||
/// \param rotation rotation of joint in model-frame
|
||||
void setRotation(const glm::quat& rotation, bool constrain, float priority);
|
||||
|
||||
/// \param delta is in the jointParent-frame
|
||||
void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f);
|
||||
|
||||
const glm::vec3& getDefaultTranslationInParentFrame() const;
|
||||
|
||||
void restoreRotation(float fraction, float priority);
|
||||
|
||||
/// \param rotation is from bind- to model-frame
|
||||
/// computes and sets new _rotationInParentFrame
|
||||
/// NOTE: the JointState's model-frame transform/rotation are NOT updated!
|
||||
void setRotationFromBindFrame(const glm::quat& rotation, float priority);
|
||||
|
||||
void clearTransformTranslation();
|
||||
|
||||
glm::quat _rotationInParentFrame; // joint- to parentJoint-frame
|
||||
float _animationPriority; // the priority of the animation affecting this joint
|
||||
|
||||
private:
|
||||
glm::mat4 _transform; // joint- to model-frame
|
||||
glm::quat _rotation; // joint- to model-frame
|
||||
|
||||
const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint
|
||||
};
|
||||
|
||||
#endif // hifi_JointState_h
|
|
@ -510,12 +510,12 @@ bool Model::updateGeometry() {
|
|||
deleteGeometry();
|
||||
_dilatedTextures.clear();
|
||||
_geometry = geometry;
|
||||
_jointStates = newJointStates;
|
||||
setJointStates(newJointStates);
|
||||
needToRebuild = true;
|
||||
} else if (_jointStates.isEmpty()) {
|
||||
const FBXGeometry& fbxGeometry = geometry->getFBXGeometry();
|
||||
if (fbxGeometry.joints.size() > 0) {
|
||||
_jointStates = createJointStates(fbxGeometry);
|
||||
setJointStates(createJointStates(fbxGeometry));
|
||||
needToRebuild = true;
|
||||
}
|
||||
} else if (!geometry->isLoaded()) {
|
||||
|
@ -557,6 +557,11 @@ bool Model::updateGeometry() {
|
|||
return needFullUpdate;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void Model::setJointStates(QVector<JointState> states) {
|
||||
_jointStates = states;
|
||||
}
|
||||
|
||||
bool Model::render(float alpha, RenderMode mode, bool receiveShadows) {
|
||||
// render the attachments
|
||||
foreach (Model* attachment, _attachments) {
|
||||
|
@ -1974,89 +1979,3 @@ void AnimationHandle::replaceMatchingPriorities(float newPriority) {
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// JointState TODO: move this class to its own files
|
||||
// ----------------------------------------------------------------------------
|
||||
JointState::JointState() :
|
||||
_animationPriority(0.0f),
|
||||
_fbxJoint(NULL) {
|
||||
}
|
||||
|
||||
void JointState::setFBXJoint(const FBXJoint* joint) {
|
||||
assert(joint != NULL);
|
||||
_rotationInParentFrame = joint->rotation;
|
||||
// NOTE: JointState does not own the FBXJoint to which it points.
|
||||
_fbxJoint = joint;
|
||||
}
|
||||
|
||||
void JointState::copyState(const JointState& state) {
|
||||
_rotationInParentFrame = state._rotationInParentFrame;
|
||||
_transform = state._transform;
|
||||
_rotation = extractRotation(_transform);
|
||||
_animationPriority = state._animationPriority;
|
||||
// DO NOT copy _fbxJoint
|
||||
}
|
||||
|
||||
void JointState::computeTransform(const glm::mat4& parentTransform) {
|
||||
glm::quat modifiedRotation = _fbxJoint->preRotation * _rotationInParentFrame * _fbxJoint->postRotation;
|
||||
glm::mat4 modifiedTransform = _fbxJoint->preTransform * glm::mat4_cast(modifiedRotation) * _fbxJoint->postTransform;
|
||||
_transform = parentTransform * glm::translate(_fbxJoint->translation) * modifiedTransform;
|
||||
_rotation = extractRotation(_transform);
|
||||
}
|
||||
|
||||
glm::quat JointState::getRotationFromBindToModelFrame() const {
|
||||
return _rotation * _fbxJoint->inverseBindRotation;
|
||||
}
|
||||
|
||||
void JointState::restoreRotation(float fraction, float priority) {
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority == _animationPriority || _animationPriority == 0.0f) {
|
||||
_rotationInParentFrame = safeMix(_rotationInParentFrame, _fbxJoint->rotation, fraction);
|
||||
_animationPriority = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void JointState::setRotationFromBindFrame(const glm::quat& rotation, float priority) {
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority >= _animationPriority) {
|
||||
// rotation is from bind- to model-frame
|
||||
_rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * rotation * glm::inverse(_fbxJoint->inverseBindRotation);
|
||||
_animationPriority = priority;
|
||||
}
|
||||
}
|
||||
|
||||
void JointState::clearTransformTranslation() {
|
||||
_transform[3][0] = 0.0f;
|
||||
_transform[3][1] = 0.0f;
|
||||
_transform[3][2] = 0.0f;
|
||||
}
|
||||
|
||||
void JointState::setRotation(const glm::quat& rotation, bool constrain, float priority) {
|
||||
applyRotationDelta(rotation * glm::inverse(_rotation), true, priority);
|
||||
}
|
||||
|
||||
void JointState::applyRotationDelta(const glm::quat& delta, bool constrain, float priority) {
|
||||
// NOTE: delta is in jointParent-frame
|
||||
assert(_fbxJoint != NULL);
|
||||
if (priority < _animationPriority) {
|
||||
return;
|
||||
}
|
||||
_animationPriority = priority;
|
||||
if (!constrain || (_fbxJoint->rotationMin == glm::vec3(-PI, -PI, -PI) &&
|
||||
_fbxJoint->rotationMax == glm::vec3(PI, PI, PI))) {
|
||||
// no constraints
|
||||
_rotationInParentFrame = _rotationInParentFrame * glm::inverse(_rotation) * delta * _rotation;
|
||||
_rotation = delta * _rotation;
|
||||
return;
|
||||
}
|
||||
glm::quat targetRotation = delta * _rotation;
|
||||
glm::vec3 eulers = safeEulerAngles(_rotationInParentFrame * glm::inverse(_rotation) * targetRotation);
|
||||
glm::quat newRotation = glm::quat(glm::clamp(eulers, _fbxJoint->rotationMin, _fbxJoint->rotationMax));
|
||||
_rotation = _rotation * glm::inverse(_rotationInParentFrame) * newRotation;
|
||||
_rotationInParentFrame = newRotation;
|
||||
}
|
||||
|
||||
const glm::vec3& JointState::getDefaultTranslationInParentFrame() const {
|
||||
assert(_fbxJoint != NULL);
|
||||
return _fbxJoint->translation;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "GeometryCache.h"
|
||||
#include "InterfaceConfig.h"
|
||||
#include "JointState.h"
|
||||
#include "ProgramObject.h"
|
||||
#include "TextureCache.h"
|
||||
|
||||
|
@ -30,51 +31,6 @@ class Shape;
|
|||
|
||||
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
|
||||
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
|
||||
|
||||
class JointState {
|
||||
public:
|
||||
JointState();
|
||||
|
||||
void setFBXJoint(const FBXJoint* joint);
|
||||
const FBXJoint& getFBXJoint() const { return *_fbxJoint; }
|
||||
|
||||
void copyState(const JointState& state);
|
||||
|
||||
void computeTransform(const glm::mat4& parentTransform);
|
||||
const glm::mat4& getTransform() const { return _transform; }
|
||||
|
||||
glm::quat getRotation() const { return _rotation; }
|
||||
glm::vec3 getPosition() const { return extractTranslation(_transform); }
|
||||
|
||||
/// \return rotation from bind to model frame
|
||||
glm::quat getRotationFromBindToModelFrame() const;
|
||||
|
||||
/// \param rotation rotation of joint in model-frame
|
||||
void setRotation(const glm::quat& rotation, bool constrain, float priority);
|
||||
|
||||
/// \param delta is in the jointParent-frame
|
||||
void applyRotationDelta(const glm::quat& delta, bool constrain = true, float priority = 1.0f);
|
||||
|
||||
const glm::vec3& getDefaultTranslationInParentFrame() const;
|
||||
|
||||
void restoreRotation(float fraction, float priority);
|
||||
|
||||
/// \param rotation is from bind- to model-frame
|
||||
/// computes and sets new _rotationInParentFrame
|
||||
/// NOTE: the JointState's model-frame transform/rotation are NOT updated!
|
||||
void setRotationFromBindFrame(const glm::quat& rotation, float priority);
|
||||
|
||||
void clearTransformTranslation();
|
||||
|
||||
glm::quat _rotationInParentFrame; // joint- to parentJoint-frame
|
||||
float _animationPriority; // the priority of the animation affecting this joint
|
||||
|
||||
private:
|
||||
glm::mat4 _transform; // joint- to model-frame
|
||||
glm::quat _rotation; // joint- to model-frame
|
||||
|
||||
const FBXJoint* _fbxJoint; // JointState does NOT own its FBXJoint
|
||||
};
|
||||
|
||||
/// A generic 3D model displaying geometry loaded from a URL.
|
||||
class Model : public QObject {
|
||||
|
@ -250,6 +206,8 @@ protected:
|
|||
|
||||
// returns 'true' if needs fullUpdate after geometry change
|
||||
bool updateGeometry();
|
||||
|
||||
virtual void setJointStates(QVector<JointState> states);
|
||||
|
||||
void setScaleInternal(const glm::vec3& scale);
|
||||
void scaleToFit();
|
||||
|
|
131
interface/src/renderer/RagDoll.cpp
Normal file
131
interface/src/renderer/RagDoll.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
//
|
||||
// RagDoll.cpp
|
||||
// interface/src/avatar
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <CollisionInfo.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "RagDoll.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// FixedConstraint
|
||||
// ----------------------------------------------------------------------------
|
||||
FixedConstraint::FixedConstraint() : _point(NULL), _anchor(0.0f, 0.0f, 0.0f) {
|
||||
}
|
||||
|
||||
float FixedConstraint::enforce() {
|
||||
assert(_point != NULL);
|
||||
float distance = glm::distance(_anchor, *_point);
|
||||
*_point = _anchor;
|
||||
return distance;
|
||||
}
|
||||
|
||||
void FixedConstraint::setPoint(glm::vec3* point) {
|
||||
_point = point;
|
||||
}
|
||||
|
||||
void FixedConstraint::setAnchor(const glm::vec3& anchor) {
|
||||
_anchor = anchor;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DistanceConstraint
|
||||
// ----------------------------------------------------------------------------
|
||||
DistanceConstraint::DistanceConstraint(glm::vec3* pointA, glm::vec3* pointB) : _distance(-1.0f) {
|
||||
_points[0] = pointA;
|
||||
_points[1] = pointB;
|
||||
_distance = glm::distance(*(_points[0]), *(_points[1]));
|
||||
}
|
||||
|
||||
DistanceConstraint::DistanceConstraint(const DistanceConstraint& other) {
|
||||
_distance = other._distance;
|
||||
_points[0] = other._points[0];
|
||||
_points[1] = other._points[1];
|
||||
}
|
||||
|
||||
void DistanceConstraint::setDistance(float distance) {
|
||||
_distance = fabsf(distance);
|
||||
}
|
||||
|
||||
float DistanceConstraint::enforce() {
|
||||
float newDistance = glm::distance(*(_points[0]), *(_points[1]));
|
||||
glm::vec3 direction(0.0f, 1.0f, 0.0f);
|
||||
if (newDistance > EPSILON) {
|
||||
direction = (*(_points[0]) - *(_points[1])) / newDistance;
|
||||
}
|
||||
glm::vec3 center = 0.5f * (*(_points[0]) + *(_points[1]));
|
||||
*(_points[0]) = center + (0.5f * _distance) * direction;
|
||||
*(_points[1]) = center - (0.5f * _distance) * direction;
|
||||
return glm::abs(newDistance - _distance);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// RagDoll
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
RagDoll::RagDoll() {
|
||||
}
|
||||
|
||||
RagDoll::~RagDoll() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void RagDoll::init(const QVector<JointState>& states) {
|
||||
clear();
|
||||
const int numStates = states.size();
|
||||
_points.reserve(numStates);
|
||||
for (int i = 0; i < numStates; ++i) {
|
||||
const JointState& state = states[i];
|
||||
_points.push_back(state.getPosition());
|
||||
int parentIndex = state.getFBXJoint().parentIndex;
|
||||
assert(parentIndex < i);
|
||||
if (parentIndex != -1) {
|
||||
DistanceConstraint* stick = new DistanceConstraint(&(_points[i]), &(_points[parentIndex]));
|
||||
_constraints.push_back(stick);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Delete all data.
|
||||
void RagDoll::clear() {
|
||||
int numConstraints = _constraints.size();
|
||||
for (int i = 0; i < numConstraints; ++i) {
|
||||
delete _constraints[i];
|
||||
}
|
||||
_constraints.clear();
|
||||
_points.clear();
|
||||
}
|
||||
|
||||
float RagDoll::slaveToSkeleton(const QVector<JointState>& states, float fraction) {
|
||||
const int numStates = states.size();
|
||||
assert(numStates == _points.size());
|
||||
fraction = glm::clamp(fraction, 0.0f, 1.0f);
|
||||
float maxDistance = 0.0f;
|
||||
for (int i = 0; i < numStates; ++i) {
|
||||
glm::vec3 oldPoint = _points[i];
|
||||
_points[i] = (1.0f - fraction) * _points[i] + fraction * states[i].getPosition();
|
||||
maxDistance = glm::max(maxDistance, glm::distance(oldPoint, _points[i]));
|
||||
}
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
float RagDoll::enforceConstraints() {
|
||||
float maxDistance = 0.0f;
|
||||
const int numConstraints = _constraints.size();
|
||||
for (int i = 0; i < numConstraints; ++i) {
|
||||
DistanceConstraint* c = static_cast<DistanceConstraint*>(_constraints[i]);
|
||||
//maxDistance = glm::max(maxDistance, _constraints[i]->enforce());
|
||||
maxDistance = glm::max(maxDistance, c->enforce());
|
||||
}
|
||||
return maxDistance;
|
||||
}
|
78
interface/src/renderer/RagDoll.h
Normal file
78
interface/src/renderer/RagDoll.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// RagDoll.h
|
||||
// interface/src/avatar
|
||||
//
|
||||
// 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_RagDoll_h
|
||||
#define hifi_RagDoll_h
|
||||
|
||||
#include "renderer/Model.h"
|
||||
|
||||
class Constraint {
|
||||
public:
|
||||
Constraint() {}
|
||||
virtual ~Constraint() {}
|
||||
|
||||
/// Enforce contraint by moving relevant points.
|
||||
/// \return max distance of point movement
|
||||
virtual float enforce() = 0;
|
||||
};
|
||||
|
||||
class FixedConstraint : public Constraint {
|
||||
public:
|
||||
FixedConstraint();
|
||||
float enforce();
|
||||
void setPoint(glm::vec3* point);
|
||||
void setAnchor(const glm::vec3& anchor);
|
||||
private:
|
||||
glm::vec3* _point;
|
||||
glm::vec3 _anchor;
|
||||
};
|
||||
|
||||
class DistanceConstraint : public Constraint {
|
||||
public:
|
||||
DistanceConstraint(glm::vec3* pointA, glm::vec3* pointB);
|
||||
DistanceConstraint(const DistanceConstraint& other);
|
||||
float enforce();
|
||||
void setDistance(float distance);
|
||||
private:
|
||||
float _distance;
|
||||
glm::vec3* _points[2];
|
||||
};
|
||||
|
||||
class RagDoll {
|
||||
public:
|
||||
|
||||
RagDoll();
|
||||
virtual ~RagDoll();
|
||||
|
||||
/// Create points and constraints based on topology of collection of joints
|
||||
/// \param joints list of connected joint states
|
||||
void init(const QVector<JointState>& states);
|
||||
|
||||
/// Delete all data.
|
||||
void clear();
|
||||
|
||||
/// \param states list of joint states
|
||||
/// \param fraction range from 0.0 (no movement) to 1.0 (use joint locations)
|
||||
/// \return max distance of point movement
|
||||
float slaveToSkeleton(const QVector<JointState>& states, float fraction);
|
||||
|
||||
/// Enforce contraints.
|
||||
/// \return max distance of point movement
|
||||
float enforceConstraints();
|
||||
|
||||
const QVector<glm::vec3>& getPoints() const { return _points; }
|
||||
|
||||
private:
|
||||
QVector<Constraint*> _constraints;
|
||||
QVector<glm::vec3> _points;
|
||||
};
|
||||
|
||||
#endif // hifi_RagDoll_h
|
|
@ -92,13 +92,14 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta
|
|||
}
|
||||
|
||||
// register the streamers for all enumerators
|
||||
for (int i = 0; i < metaObject->enumeratorCount(); i++) {
|
||||
QMetaEnum metaEnum = metaObject->enumerator(i);
|
||||
const TypeStreamer*& streamer = getEnumStreamers()[QPair<QByteArray, QByteArray>(metaEnum.scope(), metaEnum.name())];
|
||||
if (!streamer) {
|
||||
getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum));
|
||||
}
|
||||
}
|
||||
// temporarily disabled: crashes on Windows
|
||||
//for (int i = 0; i < metaObject->enumeratorCount(); i++) {
|
||||
// QMetaEnum metaEnum = metaObject->enumerator(i);
|
||||
// const TypeStreamer*& streamer = getEnumStreamers()[QPair<QByteArray, QByteArray>(metaEnum.scope(), metaEnum.name())];
|
||||
// if (!streamer) {
|
||||
// getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum));
|
||||
// }
|
||||
//}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue