mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 16:41:02 +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
|
// 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 rightHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/RightHandAnim.fbx";
|
||||||
var leftHandAnimation = "";
|
var leftHandAnimation = "https://s3-us-west-1.amazonaws.com/highfidelity-public/animations/LeftHandAnim.fbx";
|
||||||
|
|
||||||
var LEFT = 0;
|
var LEFT = 0;
|
||||||
var RIGHT = 1;
|
var RIGHT = 1;
|
||||||
|
@ -18,17 +18,20 @@ var RIGHT = 1;
|
||||||
var lastLeftFrame = 0;
|
var lastLeftFrame = 0;
|
||||||
var lastRightFrame = 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) {
|
Script.update.connect(function(deltaTime) {
|
||||||
var leftTriggerValue = Controller.getTriggerValue(LEFT);
|
var leftTriggerValue = Math.sqrt(Controller.getTriggerValue(LEFT));
|
||||||
var rightTriggerValue = Controller.getTriggerValue(RIGHT);
|
var rightTriggerValue = Math.sqrt(Controller.getTriggerValue(RIGHT));
|
||||||
|
|
||||||
var leftFrame, rightFrame;
|
var leftFrame, rightFrame;
|
||||||
|
|
||||||
// Average last two trigger frames together for a bit of smoothing
|
// Average last few trigger frames together for a bit of smoothing
|
||||||
leftFrame = (leftTriggerValue * LAST_FRAME) * 0.5 + lastLeftFrame * 0.5;
|
leftFrame = (leftTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastLeftFrame * SMOOTH_FACTOR;
|
||||||
rightFrame = (rightTriggerValue * LAST_FRAME) * 0.5 + lastRightFrame * 0.5;
|
rightFrame = (rightTriggerValue * LAST_FRAME) * (1.0 - SMOOTH_FACTOR) + lastRightFrame * SMOOTH_FACTOR;
|
||||||
|
|
||||||
|
|
||||||
if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){
|
if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){
|
||||||
MyAvatar.stopAnimation(leftHandAnimation);
|
MyAvatar.stopAnimation(leftHandAnimation);
|
||||||
|
|
|
@ -21,6 +21,11 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) :
|
||||||
_owningAvatar(owningAvatar) {
|
_owningAvatar(owningAvatar) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonModel::setJointStates(QVector<JointState> states) {
|
||||||
|
Model::setJointStates(states);
|
||||||
|
_ragDoll.init(_jointStates);
|
||||||
|
}
|
||||||
|
|
||||||
const float PALM_PRIORITY = 3.0f;
|
const float PALM_PRIORITY = 3.0f;
|
||||||
|
|
||||||
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
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.leftHandJointIndex, hand->getPalms()[leftPalmIndex]);
|
||||||
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
|
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 {
|
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() {
|
void SkeletonModel::renderIKConstraints() {
|
||||||
renderJointConstraints(getRightHandJointIndex());
|
renderJointConstraints(getRightHandJointIndex());
|
||||||
renderJointConstraints(getLeftHandJointIndex());
|
renderJointConstraints(getLeftHandJointIndex());
|
||||||
|
renderRagDoll();
|
||||||
}
|
}
|
||||||
|
|
||||||
class IndexValue {
|
class IndexValue {
|
||||||
|
@ -452,3 +473,30 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco
|
||||||
return false;
|
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
|
#define hifi_SkeletonModel_h
|
||||||
|
|
||||||
#include "renderer/Model.h"
|
#include "renderer/Model.h"
|
||||||
|
#include "renderer/RagDoll.h"
|
||||||
|
|
||||||
class Avatar;
|
class Avatar;
|
||||||
|
|
||||||
|
@ -23,8 +24,11 @@ class SkeletonModel : public Model {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SkeletonModel(Avatar* owningAvatar);
|
SkeletonModel(Avatar* owningAvatar);
|
||||||
|
|
||||||
|
void setJointStates(QVector<JointState> states);
|
||||||
|
|
||||||
void simulate(float deltaTime, bool fullUpdate = true);
|
void simulate(float deltaTime, bool fullUpdate = true);
|
||||||
|
void simulateRagDoll(float deltaTime);
|
||||||
|
|
||||||
/// \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
|
||||||
|
@ -89,6 +93,7 @@ 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 renderRagDoll();
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/// \param jointIndex index of joint in model
|
/// \param jointIndex index of joint in model
|
||||||
|
@ -114,6 +119,7 @@ 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;
|
||||||
|
RagDoll _ragDoll;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_SkeletonModel_h
|
#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::vec3 position;
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
|
|
||||||
SkeletonModel* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel();
|
SkeletonModel* skeletonModel = &Application::getInstance()->getAvatar()->getSkeletonModel();
|
||||||
int jointIndex;
|
int jointIndex;
|
||||||
glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation());
|
glm::quat inverseRotation = glm::inverse(Application::getInstance()->getAvatar()->getOrientation());
|
||||||
if (index == LEFT_HAND_INDEX) {
|
if (index == LEFT_HAND_INDEX) {
|
||||||
jointIndex = skeletonModel->getLeftHandJointIndex();
|
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));
|
rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
jointIndex = skeletonModel->getRightHandJointIndex();
|
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));
|
rotation = inverseRotation * rotation * glm::quat(glm::vec3(0.0f, -PI_OVER_TWO, 0.0f));
|
||||||
}
|
}
|
||||||
skeletonModel->getJointPositionInWorldFrame(jointIndex, position);
|
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();
|
deleteGeometry();
|
||||||
_dilatedTextures.clear();
|
_dilatedTextures.clear();
|
||||||
_geometry = geometry;
|
_geometry = geometry;
|
||||||
_jointStates = newJointStates;
|
setJointStates(newJointStates);
|
||||||
needToRebuild = true;
|
needToRebuild = true;
|
||||||
} else if (_jointStates.isEmpty()) {
|
} else if (_jointStates.isEmpty()) {
|
||||||
const FBXGeometry& fbxGeometry = geometry->getFBXGeometry();
|
const FBXGeometry& fbxGeometry = geometry->getFBXGeometry();
|
||||||
if (fbxGeometry.joints.size() > 0) {
|
if (fbxGeometry.joints.size() > 0) {
|
||||||
_jointStates = createJointStates(fbxGeometry);
|
setJointStates(createJointStates(fbxGeometry));
|
||||||
needToRebuild = true;
|
needToRebuild = true;
|
||||||
}
|
}
|
||||||
} else if (!geometry->isLoaded()) {
|
} else if (!geometry->isLoaded()) {
|
||||||
|
@ -557,6 +557,11 @@ bool Model::updateGeometry() {
|
||||||
return needFullUpdate;
|
return needFullUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// virtual
|
||||||
|
void Model::setJointStates(QVector<JointState> states) {
|
||||||
|
_jointStates = states;
|
||||||
|
}
|
||||||
|
|
||||||
bool Model::render(float alpha, RenderMode mode, bool receiveShadows) {
|
bool Model::render(float alpha, RenderMode mode, bool receiveShadows) {
|
||||||
// render the attachments
|
// render the attachments
|
||||||
foreach (Model* attachment, _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 "GeometryCache.h"
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
|
#include "JointState.h"
|
||||||
#include "ProgramObject.h"
|
#include "ProgramObject.h"
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
|
|
||||||
|
@ -30,51 +31,6 @@ class Shape;
|
||||||
|
|
||||||
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
|
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
|
||||||
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
|
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.
|
/// A generic 3D model displaying geometry loaded from a URL.
|
||||||
class Model : public QObject {
|
class Model : public QObject {
|
||||||
|
@ -250,6 +206,8 @@ protected:
|
||||||
|
|
||||||
// returns 'true' if needs fullUpdate after geometry change
|
// returns 'true' if needs fullUpdate after geometry change
|
||||||
bool updateGeometry();
|
bool updateGeometry();
|
||||||
|
|
||||||
|
virtual void setJointStates(QVector<JointState> states);
|
||||||
|
|
||||||
void setScaleInternal(const glm::vec3& scale);
|
void setScaleInternal(const glm::vec3& scale);
|
||||||
void scaleToFit();
|
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
|
// register the streamers for all enumerators
|
||||||
for (int i = 0; i < metaObject->enumeratorCount(); i++) {
|
// temporarily disabled: crashes on Windows
|
||||||
QMetaEnum metaEnum = metaObject->enumerator(i);
|
//for (int i = 0; i < metaObject->enumeratorCount(); i++) {
|
||||||
const TypeStreamer*& streamer = getEnumStreamers()[QPair<QByteArray, QByteArray>(metaEnum.scope(), metaEnum.name())];
|
// QMetaEnum metaEnum = metaObject->enumerator(i);
|
||||||
if (!streamer) {
|
// const TypeStreamer*& streamer = getEnumStreamers()[QPair<QByteArray, QByteArray>(metaEnum.scope(), metaEnum.name())];
|
||||||
getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum));
|
// if (!streamer) {
|
||||||
}
|
// getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum));
|
||||||
}
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue