mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-24 21:27:40 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into bug/delete-avatar-entity
This commit is contained in:
commit
282b364fad
18 changed files with 544 additions and 367 deletions
|
@ -438,6 +438,7 @@ Var DesktopServerCheckbox
|
||||||
Var ServerStartupCheckbox
|
Var ServerStartupCheckbox
|
||||||
Var LaunchServerNowCheckbox
|
Var LaunchServerNowCheckbox
|
||||||
Var LaunchClientNowCheckbox
|
Var LaunchClientNowCheckbox
|
||||||
|
Var CleanInstallCheckbox
|
||||||
Var CurrentOffset
|
Var CurrentOffset
|
||||||
Var OffsetUnits
|
Var OffsetUnits
|
||||||
Var CopyFromProductionCheckbox
|
Var CopyFromProductionCheckbox
|
||||||
|
@ -483,19 +484,10 @@ Function PostInstallOptionsPage
|
||||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
|
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@"
|
||||||
Pop $DesktopServerCheckbox
|
Pop $DesktopServerCheckbox
|
||||||
|
IntOp $CurrentOffset $CurrentOffset + 15
|
||||||
|
|
||||||
; set the checkbox state depending on what is present in the registry
|
; set the checkbox state depending on what is present in the registry
|
||||||
!insertmacro SetPostInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
|
!insertmacro SetPostInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED}
|
||||||
|
|
||||||
IntOp $CurrentOffset $CurrentOffset + 15
|
|
||||||
|
|
||||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
|
|
||||||
Pop $ServerStartupCheckbox
|
|
||||||
|
|
||||||
; set the checkbox state depending on what is present in the registry
|
|
||||||
!insertmacro SetPostInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED}
|
|
||||||
|
|
||||||
IntOp $CurrentOffset $CurrentOffset + 15
|
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||||
|
@ -513,15 +505,31 @@ Function PostInstallOptionsPage
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||||
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
|
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install"
|
||||||
Pop $LaunchClientNowCheckbox
|
Pop $LaunchClientNowCheckbox
|
||||||
|
IntOp $CurrentOffset $CurrentOffset + 30
|
||||||
|
|
||||||
; set the checkbox state depending on what is present in the registry
|
; set the checkbox state depending on what is present in the registry
|
||||||
!insertmacro SetPostInstallOption $LaunchClientNowCheckbox @CLIENT_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED}
|
!insertmacro SetPostInstallOption $LaunchClientNowCheckbox @CLIENT_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED}
|
||||||
${StrContains} $substringResult "/forceNoLaunchClient" $CMDLINE
|
${StrContains} $substringResult "/forceNoLaunchClient" $CMDLINE
|
||||||
${IfNot} $substringResult == ""
|
${IfNot} $substringResult == ""
|
||||||
${NSD_SetState} $LaunchClientNowCheckbox ${BST_UNCHECKED}
|
${NSD_SetState} $LaunchClientNowCheckbox ${BST_UNCHECKED}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||||
|
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup"
|
||||||
|
Pop $ServerStartupCheckbox
|
||||||
|
IntOp $CurrentOffset $CurrentOffset + 15
|
||||||
|
|
||||||
|
; set the checkbox state depending on what is present in the registry
|
||||||
|
!insertmacro SetPostInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED}
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||||
|
${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)"
|
||||||
|
Pop $CleanInstallCheckbox
|
||||||
|
IntOp $CurrentOffset $CurrentOffset + 15
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
${If} @PR_BUILD@ == 1
|
${If} @PR_BUILD@ == 1
|
||||||
|
@ -558,6 +566,7 @@ Var ServerStartupState
|
||||||
Var LaunchServerNowState
|
Var LaunchServerNowState
|
||||||
Var LaunchClientNowState
|
Var LaunchClientNowState
|
||||||
Var CopyFromProductionState
|
Var CopyFromProductionState
|
||||||
|
Var CleanInstallState
|
||||||
|
|
||||||
Function ReadPostInstallOptions
|
Function ReadPostInstallOptions
|
||||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||||
|
@ -579,13 +588,18 @@ Function ReadPostInstallOptions
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
${If} ${SectionIsSelected} ${@SERVER_COMPONENT_NAME@}
|
||||||
; check if we need to launch the server post-install
|
; check if we need to launch the server post-install
|
||||||
${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState
|
${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||||
; check if we need to launch the client post-install
|
; check if we need to launch the client post-install
|
||||||
${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState
|
${NSD_GetState} $LaunchClientNowCheckbox $LaunchClientNowState
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||||
|
; check if the user asked for a clean install
|
||||||
|
${NSD_GetState} $CleanInstallCheckbox $CleanInstallState
|
||||||
${EndIf}
|
${EndIf}
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
@ -629,6 +643,15 @@ Function HandlePostInstallOptions
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
|
${If} ${SectionIsSelected} ${@CLIENT_COMPONENT_NAME@}
|
||||||
|
; check if the user asked for a clean install
|
||||||
|
${If} $CleanInstallState == ${BST_CHECKED}
|
||||||
|
SetShellVarContext current
|
||||||
|
RMDir /r "$APPDATA\@BUILD_ORGANIZATION@"
|
||||||
|
RMDir /r "$LOCALAPPDATA\@BUILD_ORGANIZATION@"
|
||||||
|
${EndIf}
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
${If} @PR_BUILD@ == 1
|
${If} @PR_BUILD@ == 1
|
||||||
|
|
||||||
; check if we need to copy settings/content from production for this PR build
|
; check if we need to copy settings/content from production for this PR build
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
#include <EntityScriptClient.h>
|
#include <EntityScriptClient.h>
|
||||||
#include <EntityScriptServerLogClient.h>
|
#include <EntityScriptServerLogClient.h>
|
||||||
#include <EntityScriptingInterface.h>
|
#include <EntityScriptingInterface.h>
|
||||||
|
#include <HoverOverlayInterface.h>
|
||||||
#include <ErrorDialog.h>
|
#include <ErrorDialog.h>
|
||||||
#include <FileScriptingInterface.h>
|
#include <FileScriptingInterface.h>
|
||||||
#include <Finally.h>
|
#include <Finally.h>
|
||||||
|
@ -588,6 +589,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
DependencyManager::set<Snapshot>();
|
DependencyManager::set<Snapshot>();
|
||||||
DependencyManager::set<CloseEventSender>();
|
DependencyManager::set<CloseEventSender>();
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
|
DependencyManager::set<HoverOverlayInterface>();
|
||||||
|
|
||||||
return previousSessionCrashed;
|
return previousSessionCrashed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,20 +23,23 @@
|
||||||
#include "CubicHermiteSpline.h"
|
#include "CubicHermiteSpline.h"
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
static void lookupJointChainInfo(AnimInverseKinematics::JointChainInfo* jointChainInfos, size_t numJointChainInfos,
|
static const float JOINT_CHAIN_INTERP_TIME = 0.25f;
|
||||||
|
|
||||||
|
static void lookupJointInfo(const AnimInverseKinematics::JointChainInfo& jointChainInfo,
|
||||||
int indexA, int indexB,
|
int indexA, int indexB,
|
||||||
AnimInverseKinematics::JointChainInfo** jointChainInfoA,
|
const AnimInverseKinematics::JointInfo** jointInfoA,
|
||||||
AnimInverseKinematics::JointChainInfo** jointChainInfoB) {
|
const AnimInverseKinematics::JointInfo** jointInfoB) {
|
||||||
*jointChainInfoA = nullptr;
|
*jointInfoA = nullptr;
|
||||||
*jointChainInfoB = nullptr;
|
*jointInfoB = nullptr;
|
||||||
for (size_t i = 0; i < numJointChainInfos; i++) {
|
for (size_t i = 0; i < jointChainInfo.jointInfoVec.size(); i++) {
|
||||||
if (jointChainInfos[i].jointIndex == indexA) {
|
const AnimInverseKinematics::JointInfo* jointInfo = &jointChainInfo.jointInfoVec[i];
|
||||||
*jointChainInfoA = jointChainInfos + i;
|
if (jointInfo->jointIndex == indexA) {
|
||||||
|
*jointInfoA = jointInfo;
|
||||||
}
|
}
|
||||||
if (jointChainInfos[i].jointIndex == indexB) {
|
if (jointInfo->jointIndex == indexB) {
|
||||||
*jointChainInfoB = jointChainInfos + i;
|
*jointInfoB = jointInfo;
|
||||||
}
|
}
|
||||||
if (*jointChainInfoA && *jointChainInfoB) {
|
if (*jointInfoA && *jointInfoB) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,25 +152,28 @@ void AnimInverseKinematics::setTargetVars(const QString& jointName, const QStrin
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses) {
|
void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses) {
|
||||||
// build a list of valid targets from _targetVarVec and animVars
|
|
||||||
_maxTargetIndex = -1;
|
|
||||||
_hipsTargetIndex = -1;
|
_hipsTargetIndex = -1;
|
||||||
bool removeUnfoundJoints = false;
|
|
||||||
|
targets.reserve(_targetVarVec.size());
|
||||||
|
|
||||||
for (auto& targetVar : _targetVarVec) {
|
for (auto& targetVar : _targetVarVec) {
|
||||||
|
|
||||||
|
// update targetVar jointIndex cache
|
||||||
if (targetVar.jointIndex == -1) {
|
if (targetVar.jointIndex == -1) {
|
||||||
// this targetVar hasn't been validated yet...
|
|
||||||
int jointIndex = _skeleton->nameToJointIndex(targetVar.jointName);
|
int jointIndex = _skeleton->nameToJointIndex(targetVar.jointName);
|
||||||
if (jointIndex >= 0) {
|
if (jointIndex >= 0) {
|
||||||
// this targetVar has a valid joint --> cache the indices
|
// this targetVar has a valid joint --> cache the indices
|
||||||
targetVar.jointIndex = jointIndex;
|
targetVar.jointIndex = jointIndex;
|
||||||
} else {
|
} else {
|
||||||
qCWarning(animation) << "AnimInverseKinematics could not find jointName" << targetVar.jointName << "in skeleton";
|
qCWarning(animation) << "AnimInverseKinematics could not find jointName" << targetVar.jointName << "in skeleton";
|
||||||
removeUnfoundJoints = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
IKTarget target;
|
|
||||||
|
IKTarget target;
|
||||||
|
if (targetVar.jointIndex != -1) {
|
||||||
target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition));
|
target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition));
|
||||||
|
target.setIndex(targetVar.jointIndex);
|
||||||
if (target.getType() != IKTarget::Type::Unknown) {
|
if (target.getType() != IKTarget::Type::Unknown) {
|
||||||
AnimPose absPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
AnimPose absPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
|
||||||
glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, absPose.rot());
|
glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, absPose.rot());
|
||||||
|
@ -175,7 +181,6 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
|
||||||
float weight = animVars.lookup(targetVar.weightVar, targetVar.weight);
|
float weight = animVars.lookup(targetVar.weightVar, targetVar.weight);
|
||||||
|
|
||||||
target.setPose(rotation, translation);
|
target.setPose(rotation, translation);
|
||||||
target.setIndex(targetVar.jointIndex);
|
|
||||||
target.setWeight(weight);
|
target.setWeight(weight);
|
||||||
target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients);
|
target.setFlexCoefficients(targetVar.numFlexCoefficients, targetVar.flexCoefficients);
|
||||||
|
|
||||||
|
@ -188,39 +193,20 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
|
||||||
glm::vec3 poleReferenceVector = animVars.lookupRigToGeometryVector(targetVar.poleReferenceVectorVar, Vectors::UNIT_Z);
|
glm::vec3 poleReferenceVector = animVars.lookupRigToGeometryVector(targetVar.poleReferenceVectorVar, Vectors::UNIT_Z);
|
||||||
target.setPoleReferenceVector(glm::normalize(poleReferenceVector));
|
target.setPoleReferenceVector(glm::normalize(poleReferenceVector));
|
||||||
|
|
||||||
targets.push_back(target);
|
|
||||||
|
|
||||||
if (targetVar.jointIndex > _maxTargetIndex) {
|
|
||||||
_maxTargetIndex = targetVar.jointIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// record the index of the hips ik target.
|
// record the index of the hips ik target.
|
||||||
if (target.getIndex() == _hipsIndex) {
|
if (target.getIndex() == _hipsIndex) {
|
||||||
_hipsTargetIndex = (int)targets.size() - 1;
|
_hipsTargetIndex = (int)targets.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
target.setType((int)IKTarget::Type::Unknown);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (removeUnfoundJoints) {
|
targets.push_back(target);
|
||||||
int numVars = (int)_targetVarVec.size();
|
|
||||||
int i = 0;
|
|
||||||
while (i < numVars) {
|
|
||||||
if (_targetVarVec[i].jointIndex == -1) {
|
|
||||||
if (numVars > 1) {
|
|
||||||
// swap i for last element
|
|
||||||
_targetVarVec[i] = _targetVarVec[numVars - 1];
|
|
||||||
}
|
|
||||||
_targetVarVec.pop_back();
|
|
||||||
--numVars;
|
|
||||||
} else {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<IKTarget>& targets) {
|
void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<IKTarget>& targets, float dt, JointChainInfoVec& jointChainInfoVec) {
|
||||||
// compute absolute poses that correspond to relative target poses
|
// compute absolute poses that correspond to relative target poses
|
||||||
AnimPoseVec absolutePoses;
|
AnimPoseVec absolutePoses;
|
||||||
absolutePoses.resize(_relativePoses.size());
|
absolutePoses.resize(_relativePoses.size());
|
||||||
|
@ -234,26 +220,75 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
|
||||||
accumulator.clearAndClean();
|
accumulator.clearAndClean();
|
||||||
}
|
}
|
||||||
|
|
||||||
float maxError = FLT_MAX;
|
float maxError = 0.0f;
|
||||||
int numLoops = 0;
|
int numLoops = 0;
|
||||||
const int MAX_IK_LOOPS = 16;
|
const int MAX_IK_LOOPS = 16;
|
||||||
const float MAX_ERROR_TOLERANCE = 0.1f; // cm
|
while (numLoops < MAX_IK_LOOPS) {
|
||||||
while (maxError > MAX_ERROR_TOLERANCE && numLoops < MAX_IK_LOOPS) {
|
|
||||||
++numLoops;
|
++numLoops;
|
||||||
|
|
||||||
bool debug = context.getEnableDebugDrawIKChains() && numLoops == MAX_IK_LOOPS;
|
bool debug = context.getEnableDebugDrawIKChains() && numLoops == MAX_IK_LOOPS;
|
||||||
|
|
||||||
// solve all targets
|
// solve all targets
|
||||||
for (auto& target: targets) {
|
for (size_t i = 0; i < targets.size(); i++) {
|
||||||
if (target.getType() == IKTarget::Type::Spline) {
|
switch (targets[i].getType()) {
|
||||||
solveTargetWithSpline(context, target, absolutePoses, debug);
|
case IKTarget::Type::Unknown:
|
||||||
} else {
|
break;
|
||||||
solveTargetWithCCD(context, target, absolutePoses, debug);
|
case IKTarget::Type::Spline:
|
||||||
|
solveTargetWithSpline(context, targets[i], absolutePoses, debug, jointChainInfoVec[i]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
solveTargetWithCCD(context, targets[i], absolutePoses, debug, jointChainInfoVec[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// on last iteration, interpolate jointChains, if necessary
|
||||||
|
if (numLoops == MAX_IK_LOOPS) {
|
||||||
|
for (size_t i = 0; i < _prevJointChainInfoVec.size(); i++) {
|
||||||
|
if (_prevJointChainInfoVec[i].timer > 0.0f) {
|
||||||
|
float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[i].timer) / JOINT_CHAIN_INTERP_TIME;
|
||||||
|
size_t chainSize = std::min(_prevJointChainInfoVec[i].jointInfoVec.size(), jointChainInfoVec[i].jointInfoVec.size());
|
||||||
|
for (size_t j = 0; j < chainSize; j++) {
|
||||||
|
jointChainInfoVec[i].jointInfoVec[j].rot = safeMix(_prevJointChainInfoVec[i].jointInfoVec[j].rot, jointChainInfoVec[i].jointInfoVec[j].rot, alpha);
|
||||||
|
jointChainInfoVec[i].jointInfoVec[j].trans = lerp(_prevJointChainInfoVec[i].jointInfoVec[j].trans, jointChainInfoVec[i].jointInfoVec[j].trans, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if joint chain was just disabled, ramp the weight toward zero.
|
||||||
|
if (_prevJointChainInfoVec[i].target.getType() != IKTarget::Type::Unknown &&
|
||||||
|
jointChainInfoVec[i].target.getType() == IKTarget::Type::Unknown) {
|
||||||
|
IKTarget newTarget = _prevJointChainInfoVec[i].target;
|
||||||
|
newTarget.setWeight((1.0f - alpha) * _prevJointChainInfoVec[i].target.getWeight());
|
||||||
|
jointChainInfoVec[i].target = newTarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy jointChainInfoVecs into accumulators
|
||||||
|
for (size_t i = 0; i < targets.size(); i++) {
|
||||||
|
const std::vector<JointInfo>& jointInfoVec = jointChainInfoVec[i].jointInfoVec;
|
||||||
|
|
||||||
|
// don't accumulate disabled or rotation only ik targets.
|
||||||
|
IKTarget::Type type = jointChainInfoVec[i].target.getType();
|
||||||
|
if (type != IKTarget::Type::Unknown && type != IKTarget::Type::RotationOnly) {
|
||||||
|
float weight = jointChainInfoVec[i].target.getWeight();
|
||||||
|
if (weight > 0.0f) {
|
||||||
|
for (size_t j = 0; j < jointInfoVec.size(); j++) {
|
||||||
|
const JointInfo& info = jointInfoVec[j];
|
||||||
|
if (info.jointIndex >= 0) {
|
||||||
|
_rotationAccumulators[info.jointIndex].add(info.rot, weight);
|
||||||
|
_translationAccumulators[info.jointIndex].add(info.trans, weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// harvest accumulated rotations and apply the average
|
// harvest accumulated rotations and apply the average
|
||||||
for (int i = 0; i < (int)_relativePoses.size(); ++i) {
|
for (int i = 0; i < (int)_relativePoses.size(); ++i) {
|
||||||
|
if (i == _hipsIndex) {
|
||||||
|
continue; // don't apply accumulators to hips
|
||||||
|
}
|
||||||
if (_rotationAccumulators[i].size() > 0) {
|
if (_rotationAccumulators[i].size() > 0) {
|
||||||
_relativePoses[i].rot() = _rotationAccumulators[i].getAverage();
|
_relativePoses[i].rot() = _rotationAccumulators[i].getAverage();
|
||||||
_rotationAccumulators[i].clear();
|
_rotationAccumulators[i].clear();
|
||||||
|
@ -289,7 +324,7 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
|
||||||
// finally set the relative rotation of each tip to agree with absolute target rotation
|
// finally set the relative rotation of each tip to agree with absolute target rotation
|
||||||
for (auto& target: targets) {
|
for (auto& target: targets) {
|
||||||
int tipIndex = target.getIndex();
|
int tipIndex = target.getIndex();
|
||||||
int parentIndex = _skeleton->getParentIndex(tipIndex);
|
int parentIndex = (tipIndex >= 0) ? _skeleton->getParentIndex(tipIndex) : -1;
|
||||||
|
|
||||||
// update rotationOnly targets that don't lie on the ik chain of other ik targets.
|
// update rotationOnly targets that don't lie on the ik chain of other ik targets.
|
||||||
if (parentIndex != -1 && !_rotationAccumulators[tipIndex].isDirty() && target.getType() == IKTarget::Type::RotationOnly) {
|
if (parentIndex != -1 && !_rotationAccumulators[tipIndex].isDirty() && target.getType() == IKTarget::Type::RotationOnly) {
|
||||||
|
@ -308,9 +343,34 @@ void AnimInverseKinematics::solve(const AnimContext& context, const std::vector<
|
||||||
absolutePoses[tipIndex].rot() = targetRotation;
|
absolutePoses[tipIndex].rot() = targetRotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy jointChainInfoVec into _prevJointChainInfoVec, and update timers
|
||||||
|
for (size_t i = 0; i < jointChainInfoVec.size(); i++) {
|
||||||
|
_prevJointChainInfoVec[i].timer = _prevJointChainInfoVec[i].timer - dt;
|
||||||
|
if (_prevJointChainInfoVec[i].timer <= 0.0f) {
|
||||||
|
_prevJointChainInfoVec[i] = jointChainInfoVec[i];
|
||||||
|
_prevJointChainInfoVec[i].target = targets[i];
|
||||||
|
// store relative poses into unknown/rotation only joint chains.
|
||||||
|
// so we have something to interpolate from if this chain is activated.
|
||||||
|
IKTarget::Type type = _prevJointChainInfoVec[i].target.getType();
|
||||||
|
if (type == IKTarget::Type::Unknown || type == IKTarget::Type::RotationOnly) {
|
||||||
|
for (size_t j = 0; j < _prevJointChainInfoVec[i].jointInfoVec.size(); j++) {
|
||||||
|
auto& info = _prevJointChainInfoVec[i].jointInfoVec[j];
|
||||||
|
if (info.jointIndex >= 0) {
|
||||||
|
info.rot = _relativePoses[info.jointIndex].rot();
|
||||||
|
info.trans = _relativePoses[info.jointIndex].trans();
|
||||||
|
} else {
|
||||||
|
info.rot = Quaternions::IDENTITY;
|
||||||
|
info.trans = glm::vec3(0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug) {
|
void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
|
||||||
|
bool debug, JointChainInfo& jointChainInfoOut) const {
|
||||||
size_t chainDepth = 0;
|
size_t chainDepth = 0;
|
||||||
|
|
||||||
IKTarget::Type targetType = target.getType();
|
IKTarget::Type targetType = target.getType();
|
||||||
|
@ -338,9 +398,6 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
||||||
// the tip's parent-relative as we proceed up the chain
|
// the tip's parent-relative as we proceed up the chain
|
||||||
glm::quat tipParentOrientation = absolutePoses[pivotIndex].rot();
|
glm::quat tipParentOrientation = absolutePoses[pivotIndex].rot();
|
||||||
|
|
||||||
const size_t MAX_CHAIN_DEPTH = 30;
|
|
||||||
JointChainInfo jointChainInfos[MAX_CHAIN_DEPTH];
|
|
||||||
|
|
||||||
// NOTE: if this code is removed, the head will remain rigid, causing the spine/hips to thrust forward backward
|
// NOTE: if this code is removed, the head will remain rigid, causing the spine/hips to thrust forward backward
|
||||||
// as the head is nodded.
|
// as the head is nodded.
|
||||||
if (targetType == IKTarget::Type::HmdHead ||
|
if (targetType == IKTarget::Type::HmdHead ||
|
||||||
|
@ -368,7 +425,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 tipRelativeTranslation = _relativePoses[target.getIndex()].trans();
|
glm::vec3 tipRelativeTranslation = _relativePoses[target.getIndex()].trans();
|
||||||
jointChainInfos[chainDepth] = { tipRelativeRotation, tipRelativeTranslation, target.getWeight(), tipIndex, constrained };
|
jointChainInfoOut.jointInfoVec[chainDepth] = { tipRelativeRotation, tipRelativeTranslation, tipIndex, constrained };
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache tip absolute position
|
// cache tip absolute position
|
||||||
|
@ -379,7 +436,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
||||||
// descend toward root, pivoting each joint to get tip closer to target position
|
// descend toward root, pivoting each joint to get tip closer to target position
|
||||||
while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) {
|
while (pivotIndex != _hipsIndex && pivotsParentIndex != -1) {
|
||||||
|
|
||||||
assert(chainDepth < MAX_CHAIN_DEPTH);
|
assert(chainDepth < jointChainInfoOut.jointInfoVec.size());
|
||||||
|
|
||||||
// compute the two lines that should be aligned
|
// compute the two lines that should be aligned
|
||||||
glm::vec3 jointPosition = absolutePoses[pivotIndex].trans();
|
glm::vec3 jointPosition = absolutePoses[pivotIndex].trans();
|
||||||
|
@ -444,9 +501,8 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
||||||
glm::quat twistPart;
|
glm::quat twistPart;
|
||||||
glm::vec3 axis = glm::normalize(deltaRotation * leverArm);
|
glm::vec3 axis = glm::normalize(deltaRotation * leverArm);
|
||||||
swingTwistDecomposition(missingRotation, axis, swingPart, twistPart);
|
swingTwistDecomposition(missingRotation, axis, swingPart, twistPart);
|
||||||
float dotSign = copysignf(1.0f, twistPart.w);
|
|
||||||
const float LIMIT_LEAK_FRACTION = 0.1f;
|
const float LIMIT_LEAK_FRACTION = 0.1f;
|
||||||
deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * twistPart, LIMIT_LEAK_FRACTION)) * deltaRotation;
|
deltaRotation = safeLerp(glm::quat(), twistPart, LIMIT_LEAK_FRACTION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,9 +511,8 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
||||||
// An HmdHead target slaves the orientation of the end-effector by distributing rotation
|
// An HmdHead target slaves the orientation of the end-effector by distributing rotation
|
||||||
// deltas up the hierarchy. Its target position is enforced later (by shifting the hips).
|
// deltas up the hierarchy. Its target position is enforced later (by shifting the hips).
|
||||||
deltaRotation = target.getRotation() * glm::inverse(tipOrientation);
|
deltaRotation = target.getRotation() * glm::inverse(tipOrientation);
|
||||||
float dotSign = copysignf(1.0f, deltaRotation.w);
|
|
||||||
const float ANGLE_DISTRIBUTION_FACTOR = 0.45f;
|
const float ANGLE_DISTRIBUTION_FACTOR = 0.45f;
|
||||||
deltaRotation = glm::normalize(glm::lerp(glm::quat(), dotSign * deltaRotation, ANGLE_DISTRIBUTION_FACTOR));
|
deltaRotation = safeLerp(glm::quat(), deltaRotation, ANGLE_DISTRIBUTION_FACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute joint's new parent-relative rotation after swing
|
// compute joint's new parent-relative rotation after swing
|
||||||
|
@ -480,7 +535,7 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 newTrans = _relativePoses[pivotIndex].trans();
|
glm::vec3 newTrans = _relativePoses[pivotIndex].trans();
|
||||||
jointChainInfos[chainDepth] = { newRot, newTrans, target.getWeight(), pivotIndex, constrained };
|
jointChainInfoOut.jointInfoVec[chainDepth] = { newRot, newTrans, pivotIndex, constrained };
|
||||||
|
|
||||||
// keep track of tip's new transform as we descend towards root
|
// keep track of tip's new transform as we descend towards root
|
||||||
tipPosition = jointPosition + deltaRotation * (tipPosition - jointPosition);
|
tipPosition = jointPosition + deltaRotation * (tipPosition - jointPosition);
|
||||||
|
@ -502,24 +557,25 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
||||||
int baseParentJointIndex = _skeleton->getParentIndex(baseJointIndex);
|
int baseParentJointIndex = _skeleton->getParentIndex(baseJointIndex);
|
||||||
AnimPose topPose, midPose, basePose;
|
AnimPose topPose, midPose, basePose;
|
||||||
int topChainIndex = -1, baseChainIndex = -1;
|
int topChainIndex = -1, baseChainIndex = -1;
|
||||||
|
const size_t MAX_CHAIN_DEPTH = 30;
|
||||||
AnimPose postAbsPoses[MAX_CHAIN_DEPTH];
|
AnimPose postAbsPoses[MAX_CHAIN_DEPTH];
|
||||||
AnimPose accum = absolutePoses[_hipsIndex];
|
AnimPose accum = absolutePoses[_hipsIndex];
|
||||||
AnimPose baseParentPose = absolutePoses[_hipsIndex];
|
AnimPose baseParentPose = absolutePoses[_hipsIndex];
|
||||||
for (int i = (int)chainDepth - 1; i >= 0; i--) {
|
for (int i = (int)chainDepth - 1; i >= 0; i--) {
|
||||||
accum = accum * AnimPose(glm::vec3(1.0f), jointChainInfos[i].relRot, jointChainInfos[i].relTrans);
|
accum = accum * AnimPose(glm::vec3(1.0f), jointChainInfoOut.jointInfoVec[i].rot, jointChainInfoOut.jointInfoVec[i].trans);
|
||||||
postAbsPoses[i] = accum;
|
postAbsPoses[i] = accum;
|
||||||
if (jointChainInfos[i].jointIndex == topJointIndex) {
|
if (jointChainInfoOut.jointInfoVec[i].jointIndex == topJointIndex) {
|
||||||
topChainIndex = i;
|
topChainIndex = i;
|
||||||
topPose = accum;
|
topPose = accum;
|
||||||
}
|
}
|
||||||
if (jointChainInfos[i].jointIndex == midJointIndex) {
|
if (jointChainInfoOut.jointInfoVec[i].jointIndex == midJointIndex) {
|
||||||
midPose = accum;
|
midPose = accum;
|
||||||
}
|
}
|
||||||
if (jointChainInfos[i].jointIndex == baseJointIndex) {
|
if (jointChainInfoOut.jointInfoVec[i].jointIndex == baseJointIndex) {
|
||||||
baseChainIndex = i;
|
baseChainIndex = i;
|
||||||
basePose = accum;
|
basePose = accum;
|
||||||
}
|
}
|
||||||
if (jointChainInfos[i].jointIndex == baseParentJointIndex) {
|
if (jointChainInfoOut.jointInfoVec[i].jointIndex == baseParentJointIndex) {
|
||||||
baseParentPose = accum;
|
baseParentPose = accum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -599,21 +655,16 @@ void AnimInverseKinematics::solveTargetWithCCD(const AnimContext& context, const
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat newBaseRelRot = glm::inverse(baseParentPose.rot()) * poleRot * basePose.rot();
|
glm::quat newBaseRelRot = glm::inverse(baseParentPose.rot()) * poleRot * basePose.rot();
|
||||||
jointChainInfos[baseChainIndex].relRot = newBaseRelRot;
|
jointChainInfoOut.jointInfoVec[baseChainIndex].rot = newBaseRelRot;
|
||||||
|
|
||||||
glm::quat newTopRelRot = glm::inverse(midPose.rot()) * glm::inverse(poleRot) * topPose.rot();
|
glm::quat newTopRelRot = glm::inverse(midPose.rot()) * glm::inverse(poleRot) * topPose.rot();
|
||||||
jointChainInfos[topChainIndex].relRot = newTopRelRot;
|
jointChainInfoOut.jointInfoVec[topChainIndex].rot = newTopRelRot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < chainDepth; i++) {
|
|
||||||
_rotationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relRot, jointChainInfos[i].weight);
|
|
||||||
_translationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relTrans, jointChainInfos[i].weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
debugDrawIKChain(jointChainInfos, chainDepth, context);
|
debugDrawIKChain(jointChainInfoOut, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,7 +679,7 @@ static CubicHermiteSplineFunctorWithArcLength computeSplineFromTipAndBase(const
|
||||||
}
|
}
|
||||||
|
|
||||||
// pre-compute information about each joint influeced by this spline IK target.
|
// pre-compute information about each joint influeced by this spline IK target.
|
||||||
void AnimInverseKinematics::computeSplineJointInfosForIKTarget(const AnimContext& context, const IKTarget& target) {
|
void AnimInverseKinematics::computeAndCacheSplineJointInfosForIKTarget(const AnimContext& context, const IKTarget& target) const {
|
||||||
std::vector<SplineJointInfo> splineJointInfoVec;
|
std::vector<SplineJointInfo> splineJointInfoVec;
|
||||||
|
|
||||||
// build spline between the default poses.
|
// build spline between the default poses.
|
||||||
|
@ -681,13 +732,13 @@ void AnimInverseKinematics::computeSplineJointInfosForIKTarget(const AnimContext
|
||||||
_splineJointInfoMap[target.getIndex()] = splineJointInfoVec;
|
_splineJointInfoMap[target.getIndex()] = splineJointInfoVec;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<AnimInverseKinematics::SplineJointInfo>* AnimInverseKinematics::findOrCreateSplineJointInfo(const AnimContext& context, const IKTarget& target) {
|
const std::vector<AnimInverseKinematics::SplineJointInfo>* AnimInverseKinematics::findOrCreateSplineJointInfo(const AnimContext& context, const IKTarget& target) const {
|
||||||
// find or create splineJointInfo for this target
|
// find or create splineJointInfo for this target
|
||||||
auto iter = _splineJointInfoMap.find(target.getIndex());
|
auto iter = _splineJointInfoMap.find(target.getIndex());
|
||||||
if (iter != _splineJointInfoMap.end()) {
|
if (iter != _splineJointInfoMap.end()) {
|
||||||
return &(iter->second);
|
return &(iter->second);
|
||||||
} else {
|
} else {
|
||||||
computeSplineJointInfosForIKTarget(context, target);
|
computeAndCacheSplineJointInfosForIKTarget(context, target);
|
||||||
auto iter = _splineJointInfoMap.find(target.getIndex());
|
auto iter = _splineJointInfoMap.find(target.getIndex());
|
||||||
if (iter != _splineJointInfoMap.end()) {
|
if (iter != _splineJointInfoMap.end()) {
|
||||||
return &(iter->second);
|
return &(iter->second);
|
||||||
|
@ -697,10 +748,8 @@ const std::vector<AnimInverseKinematics::SplineJointInfo>* AnimInverseKinematics
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug) {
|
void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
|
||||||
|
bool debug, JointChainInfo& jointChainInfoOut) const {
|
||||||
const size_t MAX_CHAIN_DEPTH = 30;
|
|
||||||
JointChainInfo jointChainInfos[MAX_CHAIN_DEPTH];
|
|
||||||
|
|
||||||
const int baseIndex = _hipsIndex;
|
const int baseIndex = _hipsIndex;
|
||||||
|
|
||||||
|
@ -720,7 +769,7 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
|
||||||
|
|
||||||
// This prevents the rotation interpolation from rotating the wrong physical way (but correct mathematical way)
|
// This prevents the rotation interpolation from rotating the wrong physical way (but correct mathematical way)
|
||||||
// when the head is arched backwards very far.
|
// when the head is arched backwards very far.
|
||||||
glm::quat halfRot = glm::normalize(glm::lerp(basePose.rot(), tipPose.rot(), 0.5f));
|
glm::quat halfRot = safeLerp(basePose.rot(), tipPose.rot(), 0.5f);
|
||||||
if (glm::dot(halfRot * Vectors::UNIT_Z, basePose.rot() * Vectors::UNIT_Z) < 0.0f) {
|
if (glm::dot(halfRot * Vectors::UNIT_Z, basePose.rot() * Vectors::UNIT_Z) < 0.0f) {
|
||||||
tipPose.rot() = -tipPose.rot();
|
tipPose.rot() = -tipPose.rot();
|
||||||
}
|
}
|
||||||
|
@ -743,7 +792,7 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
|
||||||
if (target.getIndex() == _headIndex) {
|
if (target.getIndex() == _headIndex) {
|
||||||
rotT = t * t;
|
rotT = t * t;
|
||||||
}
|
}
|
||||||
glm::quat twistRot = glm::normalize(glm::lerp(basePose.rot(), tipPose.rot(), rotT));
|
glm::quat twistRot = safeLerp(basePose.rot(), tipPose.rot(), rotT);
|
||||||
|
|
||||||
// compute the rotation by using the derivative of the spline as the y-axis, and the twistRot x-axis
|
// compute the rotation by using the derivative of the spline as the y-axis, and the twistRot x-axis
|
||||||
glm::vec3 y = glm::normalize(spline.d(t));
|
glm::vec3 y = glm::normalize(spline.d(t));
|
||||||
|
@ -783,19 +832,14 @@ void AnimInverseKinematics::solveTargetWithSpline(const AnimContext& context, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jointChainInfos[i] = { relPose.rot(), relPose.trans(), target.getWeight(), splineJointInfo.jointIndex, constrained };
|
jointChainInfoOut.jointInfoVec[i] = { relPose.rot(), relPose.trans(), splineJointInfo.jointIndex, constrained };
|
||||||
|
|
||||||
parentAbsPose = flexedAbsPose;
|
parentAbsPose = flexedAbsPose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < splineJointInfoVec->size(); i++) {
|
|
||||||
_rotationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relRot, jointChainInfos[i].weight);
|
|
||||||
_translationAccumulators[jointChainInfos[i].jointIndex].add(jointChainInfos[i].relTrans, jointChainInfos[i].weight);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
debugDrawIKChain(jointChainInfos, splineJointInfoVec->size(), context);
|
debugDrawIKChain(jointChainInfoOut, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,6 +850,24 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
|
||||||
return _relativePoses;
|
return _relativePoses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimPose AnimInverseKinematics::applyHipsOffset() const {
|
||||||
|
glm::vec3 hipsOffset = _hipsOffset;
|
||||||
|
AnimPose relHipsPose = _relativePoses[_hipsIndex];
|
||||||
|
float offsetLength = glm::length(hipsOffset);
|
||||||
|
const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
|
||||||
|
if (offsetLength > MIN_HIPS_OFFSET_LENGTH) {
|
||||||
|
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
||||||
|
glm::vec3 scaledHipsOffset = scaleFactor * hipsOffset;
|
||||||
|
if (_hipsParentIndex == -1) {
|
||||||
|
relHipsPose.trans() = _relativePoses[_hipsIndex].trans() + scaledHipsOffset;
|
||||||
|
} else {
|
||||||
|
AnimPose absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, _relativePoses);
|
||||||
|
absHipsPose.trans() += scaledHipsOffset;
|
||||||
|
relHipsPose = _skeleton->getAbsolutePose(_hipsParentIndex, _relativePoses).inverse() * absHipsPose;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return relHipsPose;
|
||||||
|
}
|
||||||
|
|
||||||
//virtual
|
//virtual
|
||||||
const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) {
|
const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) {
|
||||||
|
@ -850,33 +912,88 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
_relativePoses = underPoses;
|
_relativePoses = underPoses;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
JointChainInfoVec jointChainInfoVec(targets.size());
|
||||||
|
{
|
||||||
|
PROFILE_RANGE_EX(simulation_animation, "ik/jointChainInfo", 0xffff00ff, 0);
|
||||||
|
|
||||||
|
// initialize a new jointChainInfoVec, this will hold the results for solving each ik chain.
|
||||||
|
JointInfo defaultJointInfo = { glm::quat(), glm::vec3(), -1, false };
|
||||||
|
for (size_t i = 0; i < targets.size(); i++) {
|
||||||
|
size_t chainDepth = (size_t)_skeleton->getChainDepth(targets[i].getIndex());
|
||||||
|
jointChainInfoVec[i].jointInfoVec.reserve(chainDepth);
|
||||||
|
jointChainInfoVec[i].target = targets[i];
|
||||||
|
int index = targets[i].getIndex();
|
||||||
|
for (size_t j = 0; j < chainDepth; j++) {
|
||||||
|
jointChainInfoVec[i].jointInfoVec.push_back(defaultJointInfo);
|
||||||
|
jointChainInfoVec[i].jointInfoVec[j].jointIndex = index;
|
||||||
|
index = _skeleton->getParentIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// identify joint chains that have changed types this frame.
|
||||||
|
_prevJointChainInfoVec.resize(jointChainInfoVec.size());
|
||||||
|
for (size_t i = 0; i < _prevJointChainInfoVec.size(); i++) {
|
||||||
|
if (_prevJointChainInfoVec[i].timer <= 0.0f &&
|
||||||
|
(jointChainInfoVec[i].target.getType() != _prevJointChainInfoVec[i].target.getType() ||
|
||||||
|
jointChainInfoVec[i].target.getPoleVectorEnabled() != _prevJointChainInfoVec[i].target.getPoleVectorEnabled())) {
|
||||||
|
_prevJointChainInfoVec[i].timer = JOINT_CHAIN_INTERP_TIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
|
PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
|
||||||
|
|
||||||
if (_hipsTargetIndex >= 0 && _hipsTargetIndex < (int)targets.size()) {
|
if (_hipsTargetIndex >= 0) {
|
||||||
|
assert(_hipsTargetIndex < (int)targets.size());
|
||||||
|
|
||||||
// slam the hips to match the _hipsTarget
|
// slam the hips to match the _hipsTarget
|
||||||
|
|
||||||
AnimPose absPose = targets[_hipsTargetIndex].getPose();
|
AnimPose absPose = targets[_hipsTargetIndex].getPose();
|
||||||
|
|
||||||
int parentIndex = _skeleton->getParentIndex(targets[_hipsTargetIndex].getIndex());
|
int parentIndex = _skeleton->getParentIndex(targets[_hipsTargetIndex].getIndex());
|
||||||
if (parentIndex != -1) {
|
AnimPose parentAbsPose = _skeleton->getAbsolutePose(parentIndex, _relativePoses);
|
||||||
_relativePoses[_hipsIndex] = _skeleton->getAbsolutePose(parentIndex, _relativePoses).inverse() * absPose;
|
|
||||||
} else {
|
// do smooth interpolation of hips, if necessary.
|
||||||
_relativePoses[_hipsIndex] = absPose;
|
if (_prevJointChainInfoVec[_hipsTargetIndex].timer > 0.0f && _prevJointChainInfoVec[_hipsTargetIndex].jointInfoVec.size() > 0) {
|
||||||
|
float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[_hipsTargetIndex].timer) / JOINT_CHAIN_INTERP_TIME;
|
||||||
|
|
||||||
|
auto& info = _prevJointChainInfoVec[_hipsTargetIndex].jointInfoVec[0];
|
||||||
|
AnimPose prevHipsRelPose(info.rot, info.trans);
|
||||||
|
AnimPose prevHipsAbsPose = parentAbsPose * prevHipsRelPose;
|
||||||
|
::blend(1, &prevHipsAbsPose, &absPose, alpha, &absPose);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
_relativePoses[_hipsIndex] = parentAbsPose.inverse() * absPose;
|
||||||
|
_relativePoses[_hipsIndex].scale() = glm::vec3(1.0f);
|
||||||
|
_hipsOffset = Vectors::ZERO;
|
||||||
|
|
||||||
|
} else if (_hipsIndex >= 0) {
|
||||||
|
|
||||||
// if there is no hips target, shift hips according to the _hipsOffset from the previous frame
|
// if there is no hips target, shift hips according to the _hipsOffset from the previous frame
|
||||||
float offsetLength = glm::length(_hipsOffset);
|
AnimPose relHipsPose = applyHipsOffset();
|
||||||
const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
|
|
||||||
if (offsetLength > MIN_HIPS_OFFSET_LENGTH && _hipsIndex >= 0) {
|
// determine if we should begin interpolating the hips.
|
||||||
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
for (size_t i = 0; i < targets.size(); i++) {
|
||||||
glm::vec3 hipsOffset = scaleFactor * _hipsOffset;
|
if (_prevJointChainInfoVec[i].target.getIndex() == _hipsIndex) {
|
||||||
if (_hipsParentIndex == -1) {
|
if (_prevJointChainInfoVec[i].timer > 0.0f) {
|
||||||
_relativePoses[_hipsIndex].trans() = _relativePoses[_hipsIndex].trans() + hipsOffset;
|
// smoothly lerp in hipsOffset
|
||||||
} else {
|
float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[i].timer) / JOINT_CHAIN_INTERP_TIME;
|
||||||
auto absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, _relativePoses);
|
AnimPose prevRelHipsPose(_prevJointChainInfoVec[i].jointInfoVec[0].rot, _prevJointChainInfoVec[i].jointInfoVec[0].trans);
|
||||||
absHipsPose.trans() += hipsOffset;
|
::blend(1, &prevRelHipsPose, &relHipsPose, alpha, &relHipsPose);
|
||||||
_relativePoses[_hipsIndex] = _skeleton->getAbsolutePose(_hipsParentIndex, _relativePoses).inverse() * absHipsPose;
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_relativePoses[_hipsIndex] = relHipsPose;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is an active jointChainInfo for the hips store the post shifted hips into it.
|
||||||
|
// This is so we have a valid pose to interplate from when the hips target is disabled.
|
||||||
|
if (_hipsTargetIndex >= 0) {
|
||||||
|
jointChainInfoVec[_hipsTargetIndex].jointInfoVec[0].rot = _relativePoses[_hipsIndex].rot();
|
||||||
|
jointChainInfoVec[_hipsTargetIndex].jointInfoVec[0].trans = _relativePoses[_hipsIndex].trans();
|
||||||
}
|
}
|
||||||
|
|
||||||
// update all HipsRelative targets to account for the hips shift/ik target.
|
// update all HipsRelative targets to account for the hips shift/ik target.
|
||||||
|
@ -920,15 +1037,14 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
|
PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
|
||||||
|
|
||||||
preconditionRelativePosesToAvoidLimbLock(context, targets);
|
preconditionRelativePosesToAvoidLimbLock(context, targets);
|
||||||
solve(context, targets);
|
solve(context, targets, dt, jointChainInfoVec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_hipsTargetIndex < 0) {
|
if (_hipsTargetIndex < 0) {
|
||||||
PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0);
|
PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0);
|
||||||
computeHipsOffset(targets, underPoses, dt);
|
_hipsOffset = computeHipsOffset(targets, underPoses, dt, _hipsOffset);
|
||||||
} else {
|
|
||||||
_hipsOffset = Vectors::ZERO;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -937,23 +1053,15 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_leftHandIndex > -1) {
|
|
||||||
_uncontrolledLeftHandPose = _skeleton->getAbsolutePose(_leftHandIndex, underPoses);
|
|
||||||
}
|
|
||||||
if (_rightHandIndex > -1) {
|
|
||||||
_uncontrolledRightHandPose = _skeleton->getAbsolutePose(_rightHandIndex, underPoses);
|
|
||||||
}
|
|
||||||
if (_hipsIndex > -1) {
|
|
||||||
_uncontrolledHipsPose = _skeleton->getAbsolutePose(_hipsIndex, underPoses);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _relativePoses;
|
return _relativePoses;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt) {
|
glm::vec3 AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const {
|
||||||
|
|
||||||
// measure new _hipsOffset for next frame
|
// measure new _hipsOffset for next frame
|
||||||
// by looking for discrepancies between where a targeted endEffector is
|
// by looking for discrepancies between where a targeted endEffector is
|
||||||
// and where it wants to be (after IK solutions are done)
|
// and where it wants to be (after IK solutions are done)
|
||||||
|
glm::vec3 hipsOffset = prevHipsOffset;
|
||||||
glm::vec3 newHipsOffset = Vectors::ZERO;
|
glm::vec3 newHipsOffset = Vectors::ZERO;
|
||||||
for (auto& target: targets) {
|
for (auto& target: targets) {
|
||||||
int targetIndex = target.getIndex();
|
int targetIndex = target.getIndex();
|
||||||
|
@ -969,9 +1077,9 @@ void AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targe
|
||||||
} else if (target.getType() == IKTarget::Type::HmdHead) {
|
} else if (target.getType() == IKTarget::Type::HmdHead) {
|
||||||
// we want to shift the hips to bring the head to its designated position
|
// we want to shift the hips to bring the head to its designated position
|
||||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
|
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
|
||||||
_hipsOffset += target.getTranslation() - actual;
|
hipsOffset += target.getTranslation() - actual;
|
||||||
// and ignore all other targets
|
// and ignore all other targets
|
||||||
newHipsOffset = _hipsOffset;
|
newHipsOffset = hipsOffset;
|
||||||
break;
|
break;
|
||||||
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
||||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
|
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
|
||||||
|
@ -991,16 +1099,18 @@ void AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// smooth transitions by relaxing _hipsOffset toward the new value
|
// smooth transitions by relaxing hipsOffset toward the new value
|
||||||
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f;
|
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f;
|
||||||
float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f;
|
float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f;
|
||||||
_hipsOffset += (newHipsOffset - _hipsOffset) * tau;
|
hipsOffset += (newHipsOffset - hipsOffset) * tau;
|
||||||
|
|
||||||
// clamp the hips offset
|
// clamp the hips offset
|
||||||
float hipsOffsetLength = glm::length(_hipsOffset);
|
float hipsOffsetLength = glm::length(hipsOffset);
|
||||||
if (hipsOffsetLength > _maxHipsOffsetLength) {
|
if (hipsOffsetLength > _maxHipsOffsetLength) {
|
||||||
_hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength;
|
hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return hipsOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::setMaxHipsOffsetLength(float maxLength) {
|
void AnimInverseKinematics::setMaxHipsOffsetLength(float maxLength) {
|
||||||
|
@ -1414,8 +1524,6 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
|
||||||
targetVar.jointIndex = -1;
|
targetVar.jointIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_maxTargetIndex = -1;
|
|
||||||
|
|
||||||
for (auto& accumulator: _rotationAccumulators) {
|
for (auto& accumulator: _rotationAccumulators) {
|
||||||
accumulator.clearAndClean();
|
accumulator.clearAndClean();
|
||||||
}
|
}
|
||||||
|
@ -1446,10 +1554,6 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele
|
||||||
_leftHandIndex = -1;
|
_leftHandIndex = -1;
|
||||||
_rightHandIndex = -1;
|
_rightHandIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_uncontrolledLeftHandPose = AnimPose();
|
|
||||||
_uncontrolledRightHandPose = AnimPose();
|
|
||||||
_uncontrolledHipsPose = AnimPose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static glm::vec3 sphericalToCartesian(float phi, float theta) {
|
static glm::vec3 sphericalToCartesian(float phi, float theta) {
|
||||||
|
@ -1495,14 +1599,14 @@ void AnimInverseKinematics::debugDrawRelativePoses(const AnimContext& context) c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimInverseKinematics::debugDrawIKChain(JointChainInfo* jointChainInfos, size_t numJointChainInfos, const AnimContext& context) const {
|
void AnimInverseKinematics::debugDrawIKChain(const JointChainInfo& jointChainInfo, const AnimContext& context) const {
|
||||||
AnimPoseVec poses = _relativePoses;
|
AnimPoseVec poses = _relativePoses;
|
||||||
|
|
||||||
// copy debug joint rotations into the relative poses
|
// copy debug joint rotations into the relative poses
|
||||||
for (size_t i = 0; i < numJointChainInfos; i++) {
|
for (size_t i = 0; i < jointChainInfo.jointInfoVec.size(); i++) {
|
||||||
const JointChainInfo& info = jointChainInfos[i];
|
const JointInfo& info = jointChainInfo.jointInfoVec[i];
|
||||||
poses[info.jointIndex].rot() = info.relRot;
|
poses[info.jointIndex].rot() = info.rot;
|
||||||
poses[info.jointIndex].trans() = info.relTrans;
|
poses[info.jointIndex].trans() = info.trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert relative poses to absolute
|
// convert relative poses to absolute
|
||||||
|
@ -1519,9 +1623,9 @@ void AnimInverseKinematics::debugDrawIKChain(JointChainInfo* jointChainInfos, si
|
||||||
// draw each pose
|
// draw each pose
|
||||||
for (int i = 0; i < (int)poses.size(); i++) {
|
for (int i = 0; i < (int)poses.size(); i++) {
|
||||||
int parentIndex = _skeleton->getParentIndex(i);
|
int parentIndex = _skeleton->getParentIndex(i);
|
||||||
JointChainInfo* jointInfo = nullptr;
|
const JointInfo* jointInfo = nullptr;
|
||||||
JointChainInfo* parentJointInfo = nullptr;
|
const JointInfo* parentJointInfo = nullptr;
|
||||||
lookupJointChainInfo(jointChainInfos, numJointChainInfos, i, parentIndex, &jointInfo, &parentJointInfo);
|
lookupJointInfo(jointChainInfo, i, parentIndex, &jointInfo, &parentJointInfo);
|
||||||
if (jointInfo && parentJointInfo) {
|
if (jointInfo && parentJointInfo) {
|
||||||
|
|
||||||
// transform local axes into world space.
|
// transform local axes into world space.
|
||||||
|
@ -1608,7 +1712,7 @@ void AnimInverseKinematics::debugDrawConstraints(const AnimContext& context) con
|
||||||
|
|
||||||
const int NUM_SWING_STEPS = 10;
|
const int NUM_SWING_STEPS = 10;
|
||||||
for (int i = 0; i < NUM_SWING_STEPS + 1; i++) {
|
for (int i = 0; i < NUM_SWING_STEPS + 1; i++) {
|
||||||
glm::quat rot = glm::normalize(glm::lerp(minRot, maxRot, i * (1.0f / NUM_SWING_STEPS)));
|
glm::quat rot = safeLerp(minRot, maxRot, i * (1.0f / NUM_SWING_STEPS));
|
||||||
glm::vec3 axis = transformVectorFast(geomToWorldMatrix, parentAbsRot * rot * refRot * Vectors::UNIT_Y);
|
glm::vec3 axis = transformVectorFast(geomToWorldMatrix, parentAbsRot * rot * refRot * Vectors::UNIT_Y);
|
||||||
DebugDraw::getInstance().drawRay(pos, pos + TWIST_LENGTH * axis, CYAN);
|
DebugDraw::getInstance().drawRay(pos, pos + TWIST_LENGTH * axis, CYAN);
|
||||||
}
|
}
|
||||||
|
@ -1626,7 +1730,7 @@ void AnimInverseKinematics::debugDrawConstraints(const AnimContext& context) con
|
||||||
|
|
||||||
const int NUM_SWING_STEPS = 10;
|
const int NUM_SWING_STEPS = 10;
|
||||||
for (int i = 0; i < NUM_SWING_STEPS + 1; i++) {
|
for (int i = 0; i < NUM_SWING_STEPS + 1; i++) {
|
||||||
glm::quat rot = glm::normalize(glm::lerp(minRot, maxRot, i * (1.0f / NUM_SWING_STEPS)));
|
glm::quat rot = safeLerp(minRot, maxRot, i * (1.0f / NUM_SWING_STEPS));
|
||||||
glm::vec3 axis = transformVectorFast(geomToWorldMatrix, parentAbsRot * rot * refRot * Vectors::UNIT_X);
|
glm::vec3 axis = transformVectorFast(geomToWorldMatrix, parentAbsRot * rot * refRot * Vectors::UNIT_X);
|
||||||
DebugDraw::getInstance().drawRay(pos, pos + TWIST_LENGTH * axis, CYAN);
|
DebugDraw::getInstance().drawRay(pos, pos + TWIST_LENGTH * axis, CYAN);
|
||||||
}
|
}
|
||||||
|
@ -1666,10 +1770,9 @@ void AnimInverseKinematics::blendToPoses(const AnimPoseVec& targetPoses, const A
|
||||||
// relax toward poses
|
// relax toward poses
|
||||||
int numJoints = (int)_relativePoses.size();
|
int numJoints = (int)_relativePoses.size();
|
||||||
for (int i = 0; i < numJoints; ++i) {
|
for (int i = 0; i < numJoints; ++i) {
|
||||||
float dotSign = copysignf(1.0f, glm::dot(_relativePoses[i].rot(), targetPoses[i].rot()));
|
|
||||||
if (_rotationAccumulators[i].isDirty()) {
|
if (_rotationAccumulators[i].isDirty()) {
|
||||||
// this joint is affected by IK --> blend toward the targetPoses rotation
|
// this joint is affected by IK --> blend toward the targetPoses rotation
|
||||||
_relativePoses[i].rot() = glm::normalize(glm::lerp(_relativePoses[i].rot(), dotSign * targetPoses[i].rot(), blendFactor));
|
_relativePoses[i].rot() = safeLerp(_relativePoses[i].rot(), targetPoses[i].rot(), blendFactor);
|
||||||
} else {
|
} else {
|
||||||
// this joint is NOT affected by IK --> slam to underPoses rotation
|
// this joint is NOT affected by IK --> slam to underPoses rotation
|
||||||
_relativePoses[i].rot() = underPoses[i].rot();
|
_relativePoses[i].rot() = underPoses[i].rot();
|
||||||
|
|
|
@ -26,14 +26,21 @@ class RotationConstraint;
|
||||||
class AnimInverseKinematics : public AnimNode {
|
class AnimInverseKinematics : public AnimNode {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
struct JointChainInfo {
|
struct JointInfo {
|
||||||
glm::quat relRot;
|
glm::quat rot;
|
||||||
glm::vec3 relTrans;
|
glm::vec3 trans;
|
||||||
float weight;
|
|
||||||
int jointIndex;
|
int jointIndex;
|
||||||
bool constrained;
|
bool constrained;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct JointChainInfo {
|
||||||
|
std::vector<JointInfo> jointInfoVec;
|
||||||
|
IKTarget target;
|
||||||
|
float timer { 0.0f };
|
||||||
|
};
|
||||||
|
|
||||||
|
using JointChainInfoVec = std::vector<JointChainInfo>;
|
||||||
|
|
||||||
explicit AnimInverseKinematics(const QString& id);
|
explicit AnimInverseKinematics(const QString& id);
|
||||||
virtual ~AnimInverseKinematics() override;
|
virtual ~AnimInverseKinematics() override;
|
||||||
|
|
||||||
|
@ -66,23 +73,22 @@ public:
|
||||||
void setSolutionSource(SolutionSource solutionSource) { _solutionSource = solutionSource; }
|
void setSolutionSource(SolutionSource solutionSource) { _solutionSource = solutionSource; }
|
||||||
void setSolutionSourceVar(const QString& solutionSourceVar) { _solutionSourceVar = solutionSourceVar; }
|
void setSolutionSourceVar(const QString& solutionSourceVar) { _solutionSourceVar = solutionSourceVar; }
|
||||||
|
|
||||||
const AnimPose& getUncontrolledLeftHandPose() { return _uncontrolledLeftHandPose; }
|
|
||||||
const AnimPose& getUncontrolledRightHandPose() { return _uncontrolledRightHandPose; }
|
|
||||||
const AnimPose& getUncontrolledHipPose() { return _uncontrolledHipsPose; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
|
void computeTargets(const AnimVariantMap& animVars, std::vector<IKTarget>& targets, const AnimPoseVec& underPoses);
|
||||||
void solve(const AnimContext& context, const std::vector<IKTarget>& targets);
|
void solve(const AnimContext& context, const std::vector<IKTarget>& targets, float dt, JointChainInfoVec& jointChainInfoVec);
|
||||||
void solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug);
|
void solveTargetWithCCD(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
|
||||||
void solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses, bool debug);
|
bool debug, JointChainInfo& jointChainInfoOut) const;
|
||||||
|
void solveTargetWithSpline(const AnimContext& context, const IKTarget& target, const AnimPoseVec& absolutePoses,
|
||||||
|
bool debug, JointChainInfo& jointChainInfoOut) const;
|
||||||
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
|
virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton) override;
|
||||||
void debugDrawIKChain(JointChainInfo* jointChainInfos, size_t numJointChainInfos, const AnimContext& context) const;
|
void debugDrawIKChain(const JointChainInfo& jointChainInfo, const AnimContext& context) const;
|
||||||
void debugDrawRelativePoses(const AnimContext& context) const;
|
void debugDrawRelativePoses(const AnimContext& context) const;
|
||||||
void debugDrawConstraints(const AnimContext& context) const;
|
void debugDrawConstraints(const AnimContext& context) const;
|
||||||
void debugDrawSpineSplines(const AnimContext& context, const std::vector<IKTarget>& targets) const;
|
void debugDrawSpineSplines(const AnimContext& context, const std::vector<IKTarget>& targets) const;
|
||||||
void initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPose);
|
void initRelativePosesFromSolutionSource(SolutionSource solutionSource, const AnimPoseVec& underPose);
|
||||||
void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
|
void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
|
||||||
void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
|
void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
|
||||||
|
AnimPose applyHipsOffset() const;
|
||||||
|
|
||||||
// used to pre-compute information about each joint influeced by a spline IK target.
|
// used to pre-compute information about each joint influeced by a spline IK target.
|
||||||
struct SplineJointInfo {
|
struct SplineJointInfo {
|
||||||
|
@ -91,8 +97,8 @@ protected:
|
||||||
AnimPose offsetPose; // local offset from the spline to the joint.
|
AnimPose offsetPose; // local offset from the spline to the joint.
|
||||||
};
|
};
|
||||||
|
|
||||||
void computeSplineJointInfosForIKTarget(const AnimContext& context, const IKTarget& target);
|
void computeAndCacheSplineJointInfosForIKTarget(const AnimContext& context, const IKTarget& target) const;
|
||||||
const std::vector<SplineJointInfo>* findOrCreateSplineJointInfo(const AnimContext& context, const IKTarget& target);
|
const std::vector<SplineJointInfo>* findOrCreateSplineJointInfo(const AnimContext& context, const IKTarget& target) const;
|
||||||
|
|
||||||
// for AnimDebugDraw rendering
|
// for AnimDebugDraw rendering
|
||||||
virtual const AnimPoseVec& getPosesInternal() const override { return _relativePoses; }
|
virtual const AnimPoseVec& getPosesInternal() const override { return _relativePoses; }
|
||||||
|
@ -101,7 +107,7 @@ protected:
|
||||||
void clearConstraints();
|
void clearConstraints();
|
||||||
void initConstraints();
|
void initConstraints();
|
||||||
void initLimitCenterPoses();
|
void initLimitCenterPoses();
|
||||||
void computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt);
|
glm::vec3 computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const;
|
||||||
|
|
||||||
// no copies
|
// no copies
|
||||||
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
||||||
|
@ -136,7 +142,7 @@ protected:
|
||||||
AnimPoseVec _relativePoses; // current relative poses
|
AnimPoseVec _relativePoses; // current relative poses
|
||||||
AnimPoseVec _limitCenterPoses; // relative
|
AnimPoseVec _limitCenterPoses; // relative
|
||||||
|
|
||||||
std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
|
mutable std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
|
||||||
|
|
||||||
// experimental data for moving hips during IK
|
// experimental data for moving hips during IK
|
||||||
glm::vec3 _hipsOffset { Vectors::ZERO };
|
glm::vec3 _hipsOffset { Vectors::ZERO };
|
||||||
|
@ -148,18 +154,12 @@ protected:
|
||||||
int _leftHandIndex { -1 };
|
int _leftHandIndex { -1 };
|
||||||
int _rightHandIndex { -1 };
|
int _rightHandIndex { -1 };
|
||||||
|
|
||||||
// _maxTargetIndex is tracked to help optimize the recalculation of absolute poses
|
|
||||||
// during the the cyclic coordinate descent algorithm
|
|
||||||
int _maxTargetIndex { 0 };
|
|
||||||
|
|
||||||
float _maxErrorOnLastSolve { FLT_MAX };
|
float _maxErrorOnLastSolve { FLT_MAX };
|
||||||
bool _previousEnableDebugIKTargets { false };
|
bool _previousEnableDebugIKTargets { false };
|
||||||
SolutionSource _solutionSource { SolutionSource::RelaxToUnderPoses };
|
SolutionSource _solutionSource { SolutionSource::RelaxToUnderPoses };
|
||||||
QString _solutionSourceVar;
|
QString _solutionSourceVar;
|
||||||
|
|
||||||
AnimPose _uncontrolledLeftHandPose { AnimPose() };
|
JointChainInfoVec _prevJointChainInfoVec;
|
||||||
AnimPose _uncontrolledRightHandPose { AnimPose() };
|
|
||||||
AnimPose _uncontrolledHipsPose { AnimPose() };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AnimInverseKinematics_h
|
#endif // hifi_AnimInverseKinematics_h
|
||||||
|
|
|
@ -42,6 +42,20 @@ int AnimSkeleton::getNumJoints() const {
|
||||||
return _jointsSize;
|
return _jointsSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AnimSkeleton::getChainDepth(int jointIndex) const {
|
||||||
|
if (jointIndex >= 0) {
|
||||||
|
int chainDepth = 0;
|
||||||
|
int index = jointIndex;
|
||||||
|
do {
|
||||||
|
chainDepth++;
|
||||||
|
index = _joints[index].parentIndex;
|
||||||
|
} while (index != -1);
|
||||||
|
return chainDepth;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const AnimPose& AnimSkeleton::getAbsoluteBindPose(int jointIndex) const {
|
const AnimPose& AnimSkeleton::getAbsoluteBindPose(int jointIndex) const {
|
||||||
return _absoluteBindPoses[jointIndex];
|
return _absoluteBindPoses[jointIndex];
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ public:
|
||||||
int nameToJointIndex(const QString& jointName) const;
|
int nameToJointIndex(const QString& jointName) const;
|
||||||
const QString& getJointName(int jointIndex) const;
|
const QString& getJointName(int jointIndex) const;
|
||||||
int getNumJoints() const;
|
int getNumJoints() const;
|
||||||
|
int getChainDepth(int jointIndex) const;
|
||||||
|
|
||||||
// absolute pose, not relative to parent
|
// absolute pose, not relative to parent
|
||||||
const AnimPose& getAbsoluteBindPose(int jointIndex) const;
|
const AnimPose& getAbsoluteBindPose(int jointIndex) const;
|
||||||
|
|
|
@ -28,7 +28,7 @@ void blend(size_t numPoses, const AnimPose* a, const AnimPose* b, float alpha, A
|
||||||
}
|
}
|
||||||
|
|
||||||
result[i].scale() = lerp(aPose.scale(), bPose.scale(), alpha);
|
result[i].scale() = lerp(aPose.scale(), bPose.scale(), alpha);
|
||||||
result[i].rot() = glm::normalize(glm::lerp(aPose.rot(), q2, alpha));
|
result[i].rot() = safeLerp(aPose.rot(), bPose.rot(), alpha);
|
||||||
result[i].trans() = lerp(aPose.trans(), bPose.trans(), alpha);
|
result[i].trans() = lerp(aPose.trans(), bPose.trans(), alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,4 +21,14 @@ glm::quat averageQuats(size_t numQuats, const glm::quat* quats);
|
||||||
float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag,
|
float accumulateTime(float startFrame, float endFrame, float timeScale, float currentFrame, float dt, bool loopFlag,
|
||||||
const QString& id, AnimNode::Triggers& triggersOut);
|
const QString& id, AnimNode::Triggers& triggersOut);
|
||||||
|
|
||||||
|
inline glm::quat safeLerp(const glm::quat& a, const glm::quat& b, float alpha) {
|
||||||
|
// adjust signs if necessary
|
||||||
|
glm::quat bTemp = b;
|
||||||
|
float dot = glm::dot(a, bTemp);
|
||||||
|
if (dot < 0.0f) {
|
||||||
|
bTemp = -bTemp;
|
||||||
|
}
|
||||||
|
return glm::normalize(glm::lerp(a, bTemp, alpha));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,8 +56,8 @@ private:
|
||||||
glm::vec3 _poleReferenceVector;
|
glm::vec3 _poleReferenceVector;
|
||||||
bool _poleVectorEnabled { false };
|
bool _poleVectorEnabled { false };
|
||||||
int _index { -1 };
|
int _index { -1 };
|
||||||
Type _type { Type::RotationAndPosition };
|
Type _type { Type::Unknown };
|
||||||
float _weight;
|
float _weight { 0.0f };
|
||||||
float _flexCoefficients[MAX_FLEX_COEFFICIENTS];
|
float _flexCoefficients[MAX_FLEX_COEFFICIENTS];
|
||||||
size_t _numFlexCoefficients;
|
size_t _numFlexCoefficients;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1115,36 +1115,13 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
|
||||||
const glm::vec3 bodyCapsuleEnd = bodyCapsuleCenter + glm::vec3(0, bodyCapsuleHalfHeight, 0);
|
const glm::vec3 bodyCapsuleEnd = bodyCapsuleCenter + glm::vec3(0, bodyCapsuleHalfHeight, 0);
|
||||||
|
|
||||||
const float HAND_RADIUS = 0.05f;
|
const float HAND_RADIUS = 0.05f;
|
||||||
|
|
||||||
const float RELAX_DURATION = 0.6f;
|
|
||||||
const float CONTROL_DURATION = 0.4f;
|
|
||||||
const bool TO_CONTROLLED = true;
|
|
||||||
const bool FROM_CONTROLLED = false;
|
|
||||||
const bool LEFT_HAND = true;
|
|
||||||
const bool RIGHT_HAND = false;
|
|
||||||
|
|
||||||
const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f;
|
const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f;
|
||||||
|
|
||||||
if (leftHandEnabled) {
|
if (leftHandEnabled) {
|
||||||
if (!_isLeftHandControlled) {
|
|
||||||
_leftHandControlTimeRemaining = CONTROL_DURATION;
|
|
||||||
_isLeftHandControlled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 handPosition = leftHandPose.trans();
|
glm::vec3 handPosition = leftHandPose.trans();
|
||||||
glm::quat handRotation = leftHandPose.rot();
|
glm::quat handRotation = leftHandPose.rot();
|
||||||
|
|
||||||
if (_leftHandControlTimeRemaining > 0.0f) {
|
|
||||||
// Move hand from non-controlled position to controlled position.
|
|
||||||
_leftHandControlTimeRemaining = std::max(_leftHandControlTimeRemaining - dt, 0.0f);
|
|
||||||
AnimPose handPose(Vectors::ONE, handRotation, handPosition);
|
|
||||||
if (transitionHandPose(_leftHandControlTimeRemaining, CONTROL_DURATION, handPose,
|
|
||||||
LEFT_HAND, TO_CONTROLLED, handPose)) {
|
|
||||||
handPosition = handPose.trans();
|
|
||||||
handRotation = handPose.rot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hipsEnabled) {
|
if (!hipsEnabled) {
|
||||||
// prevent the hand IK targets from intersecting the body capsule
|
// prevent the hand IK targets from intersecting the body capsule
|
||||||
glm::vec3 displacement;
|
glm::vec3 displacement;
|
||||||
|
@ -1157,9 +1134,6 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
|
||||||
_animVars.set("leftHandRotation", handRotation);
|
_animVars.set("leftHandRotation", handRotation);
|
||||||
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
|
|
||||||
_lastLeftHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
|
|
||||||
_isLeftHandControlled = true;
|
|
||||||
|
|
||||||
// compute pole vector
|
// compute pole vector
|
||||||
int handJointIndex = _animSkeleton->nameToJointIndex("LeftHand");
|
int handJointIndex = _animSkeleton->nameToJointIndex("LeftHand");
|
||||||
int armJointIndex = _animSkeleton->nameToJointIndex("LeftArm");
|
int armJointIndex = _animSkeleton->nameToJointIndex("LeftArm");
|
||||||
|
@ -1187,47 +1161,17 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
|
||||||
_prevLeftHandPoleVectorValid = false;
|
_prevLeftHandPoleVectorValid = false;
|
||||||
_animVars.set("leftHandPoleVectorEnabled", false);
|
_animVars.set("leftHandPoleVectorEnabled", false);
|
||||||
|
|
||||||
if (_isLeftHandControlled) {
|
_animVars.unset("leftHandPosition");
|
||||||
_leftHandRelaxTimeRemaining = RELAX_DURATION;
|
_animVars.unset("leftHandRotation");
|
||||||
_isLeftHandControlled = false;
|
_animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
|
||||||
}
|
|
||||||
|
|
||||||
if (_leftHandRelaxTimeRemaining > 0.0f) {
|
|
||||||
// Move hand from controlled position to non-controlled position.
|
|
||||||
_leftHandRelaxTimeRemaining = std::max(_leftHandRelaxTimeRemaining - dt, 0.0f);
|
|
||||||
AnimPose handPose;
|
|
||||||
if (transitionHandPose(_leftHandRelaxTimeRemaining, RELAX_DURATION, _lastLeftHandControlledPose,
|
|
||||||
LEFT_HAND, FROM_CONTROLLED, handPose)) {
|
|
||||||
_animVars.set("leftHandPosition", handPose.trans());
|
|
||||||
_animVars.set("leftHandRotation", handPose.rot());
|
|
||||||
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_animVars.unset("leftHandPosition");
|
|
||||||
_animVars.unset("leftHandRotation");
|
|
||||||
_animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rightHandEnabled) {
|
if (rightHandEnabled) {
|
||||||
if (!_isRightHandControlled) {
|
|
||||||
_rightHandControlTimeRemaining = CONTROL_DURATION;
|
|
||||||
_isRightHandControlled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 handPosition = rightHandPose.trans();
|
glm::vec3 handPosition = rightHandPose.trans();
|
||||||
glm::quat handRotation = rightHandPose.rot();
|
glm::quat handRotation = rightHandPose.rot();
|
||||||
|
|
||||||
if (_rightHandControlTimeRemaining > 0.0f) {
|
|
||||||
// Move hand from non-controlled position to controlled position.
|
|
||||||
_rightHandControlTimeRemaining = std::max(_rightHandControlTimeRemaining - dt, 0.0f);
|
|
||||||
AnimPose handPose(Vectors::ONE, handRotation, handPosition);
|
|
||||||
if (transitionHandPose(_rightHandControlTimeRemaining, CONTROL_DURATION, handPose, RIGHT_HAND, TO_CONTROLLED, handPose)) {
|
|
||||||
handPosition = handPose.trans();
|
|
||||||
handRotation = handPose.rot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hipsEnabled) {
|
if (!hipsEnabled) {
|
||||||
// prevent the hand IK targets from intersecting the body capsule
|
// prevent the hand IK targets from intersecting the body capsule
|
||||||
glm::vec3 displacement;
|
glm::vec3 displacement;
|
||||||
|
@ -1240,9 +1184,6 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
|
||||||
_animVars.set("rightHandRotation", handRotation);
|
_animVars.set("rightHandRotation", handRotation);
|
||||||
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
|
|
||||||
_lastRightHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
|
|
||||||
_isRightHandControlled = true;
|
|
||||||
|
|
||||||
// compute pole vector
|
// compute pole vector
|
||||||
int handJointIndex = _animSkeleton->nameToJointIndex("RightHand");
|
int handJointIndex = _animSkeleton->nameToJointIndex("RightHand");
|
||||||
int armJointIndex = _animSkeleton->nameToJointIndex("RightArm");
|
int armJointIndex = _animSkeleton->nameToJointIndex("RightArm");
|
||||||
|
@ -1270,25 +1211,9 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab
|
||||||
_prevRightHandPoleVectorValid = false;
|
_prevRightHandPoleVectorValid = false;
|
||||||
_animVars.set("rightHandPoleVectorEnabled", false);
|
_animVars.set("rightHandPoleVectorEnabled", false);
|
||||||
|
|
||||||
if (_isRightHandControlled) {
|
_animVars.unset("rightHandPosition");
|
||||||
_rightHandRelaxTimeRemaining = RELAX_DURATION;
|
_animVars.unset("rightHandRotation");
|
||||||
_isRightHandControlled = false;
|
_animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
|
||||||
}
|
|
||||||
|
|
||||||
if (_rightHandRelaxTimeRemaining > 0.0f) {
|
|
||||||
// Move hand from controlled position to non-controlled position.
|
|
||||||
_rightHandRelaxTimeRemaining = std::max(_rightHandRelaxTimeRemaining - dt, 0.0f);
|
|
||||||
AnimPose handPose;
|
|
||||||
if (transitionHandPose(_rightHandRelaxTimeRemaining, RELAX_DURATION, _lastRightHandControlledPose, RIGHT_HAND, FROM_CONTROLLED, handPose)) {
|
|
||||||
_animVars.set("rightHandPosition", handPose.trans());
|
|
||||||
_animVars.set("rightHandRotation", handPose.rot());
|
|
||||||
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_animVars.unset("rightHandPosition");
|
|
||||||
_animVars.unset("rightHandRotation");
|
|
||||||
_animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1737,39 +1662,38 @@ void Rig::computeAvatarBoundingCapsule(
|
||||||
ikNode.setTargetVars("RightFoot", "rightFootPosition", "rightFootRotation",
|
ikNode.setTargetVars("RightFoot", "rightFootPosition", "rightFootRotation",
|
||||||
"rightFootType", "rightFootWeight", 1.0f, {},
|
"rightFootType", "rightFootWeight", 1.0f, {},
|
||||||
QString(), QString(), QString());
|
QString(), QString(), QString());
|
||||||
|
glm::vec3 hipsPosition(0.0f);
|
||||||
AnimPose geometryToRig = _modelOffset * _geometryOffset;
|
|
||||||
|
|
||||||
AnimPose hips(glm::vec3(1), glm::quat(), glm::vec3());
|
|
||||||
int hipsIndex = indexOfJoint("Hips");
|
int hipsIndex = indexOfJoint("Hips");
|
||||||
if (hipsIndex >= 0) {
|
if (hipsIndex >= 0) {
|
||||||
hips = geometryToRig * _animSkeleton->getAbsoluteBindPose(hipsIndex);
|
hipsPosition = transformPoint(_geometryToRigTransform, _animSkeleton->getAbsoluteDefaultPose(hipsIndex).trans());
|
||||||
}
|
}
|
||||||
AnimVariantMap animVars;
|
AnimVariantMap animVars;
|
||||||
|
animVars.setRigToGeometryTransform(_rigToGeometryTransform);
|
||||||
glm::quat handRotation = glm::angleAxis(PI, Vectors::UNIT_X);
|
glm::quat handRotation = glm::angleAxis(PI, Vectors::UNIT_X);
|
||||||
animVars.set("leftHandPosition", hips.trans());
|
animVars.set("leftHandPosition", hipsPosition);
|
||||||
animVars.set("leftHandRotation", handRotation);
|
animVars.set("leftHandRotation", handRotation);
|
||||||
animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
animVars.set("rightHandPosition", hips.trans());
|
animVars.set("rightHandPosition", hipsPosition);
|
||||||
animVars.set("rightHandRotation", handRotation);
|
animVars.set("rightHandRotation", handRotation);
|
||||||
animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
|
|
||||||
int rightFootIndex = indexOfJoint("RightFoot");
|
int rightFootIndex = indexOfJoint("RightFoot");
|
||||||
int leftFootIndex = indexOfJoint("LeftFoot");
|
int leftFootIndex = indexOfJoint("LeftFoot");
|
||||||
if (rightFootIndex != -1 && leftFootIndex != -1) {
|
if (rightFootIndex != -1 && leftFootIndex != -1) {
|
||||||
glm::vec3 foot = Vectors::ZERO;
|
glm::vec3 geomFootPosition = glm::vec3(0.0f, _animSkeleton->getAbsoluteDefaultPose(rightFootIndex).trans().y, 0.0f);
|
||||||
|
glm::vec3 footPosition = transformPoint(_geometryToRigTransform, geomFootPosition);
|
||||||
glm::quat footRotation = glm::angleAxis(0.5f * PI, Vectors::UNIT_X);
|
glm::quat footRotation = glm::angleAxis(0.5f * PI, Vectors::UNIT_X);
|
||||||
animVars.set("leftFootPosition", foot);
|
animVars.set("leftFootPosition", footPosition);
|
||||||
animVars.set("leftFootRotation", footRotation);
|
animVars.set("leftFootRotation", footRotation);
|
||||||
animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
|
animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
animVars.set("rightFootPosition", foot);
|
animVars.set("rightFootPosition", footPosition);
|
||||||
animVars.set("rightFootRotation", footRotation);
|
animVars.set("rightFootRotation", footRotation);
|
||||||
animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
|
animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
// call overlay twice: once to verify AnimPoseVec joints and again to do the IK
|
// call overlay twice: once to verify AnimPoseVec joints and again to do the IK
|
||||||
AnimNode::Triggers triggersOut;
|
AnimNode::Triggers triggersOut;
|
||||||
AnimContext context(false, false, false, glm::mat4(), glm::mat4());
|
AnimContext context(false, false, false, _geometryToRigTransform, _rigToGeometryTransform);
|
||||||
float dt = 1.0f; // the value of this does not matter
|
float dt = 1.0f; // the value of this does not matter
|
||||||
ikNode.overlay(animVars, context, dt, triggersOut, _animSkeleton->getRelativeBindPoses());
|
ikNode.overlay(animVars, context, dt, triggersOut, _animSkeleton->getRelativeBindPoses());
|
||||||
AnimPoseVec finalPoses = ikNode.overlay(animVars, context, dt, triggersOut, _animSkeleton->getRelativeBindPoses());
|
AnimPoseVec finalPoses = ikNode.overlay(animVars, context, dt, triggersOut, _animSkeleton->getRelativeBindPoses());
|
||||||
|
@ -1802,34 +1726,13 @@ void Rig::computeAvatarBoundingCapsule(
|
||||||
|
|
||||||
// compute bounding shape parameters
|
// compute bounding shape parameters
|
||||||
// NOTE: we assume that the longest side of totalExtents is the yAxis...
|
// NOTE: we assume that the longest side of totalExtents is the yAxis...
|
||||||
glm::vec3 diagonal = (geometryToRig * totalExtents.maximum) - (geometryToRig * totalExtents.minimum);
|
glm::vec3 diagonal = (transformPoint(_geometryToRigTransform, totalExtents.maximum) -
|
||||||
|
transformPoint(_geometryToRigTransform, totalExtents.minimum));
|
||||||
// ... and assume the radiusOut is half the RMS of the X and Z sides:
|
// ... and assume the radiusOut is half the RMS of the X and Z sides:
|
||||||
radiusOut = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z));
|
radiusOut = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z));
|
||||||
heightOut = diagonal.y - 2.0f * radiusOut;
|
heightOut = diagonal.y - 2.0f * radiusOut;
|
||||||
|
|
||||||
glm::vec3 rootPosition = finalPoses[geometry.rootJointIndex].trans();
|
glm::vec3 rootPosition = finalPoses[geometry.rootJointIndex].trans();
|
||||||
glm::vec3 rigCenter = (geometryToRig * (0.5f * (totalExtents.maximum + totalExtents.minimum)));
|
glm::vec3 rigCenter = transformPoint(_geometryToRigTransform, (0.5f * (totalExtents.maximum + totalExtents.minimum)));
|
||||||
localOffsetOut = rigCenter - (geometryToRig * rootPosition);
|
localOffsetOut = rigCenter - transformPoint(_geometryToRigTransform, rootPosition);
|
||||||
}
|
|
||||||
|
|
||||||
bool Rig::transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand,
|
|
||||||
bool isToControlled, AnimPose& returnHandPose) {
|
|
||||||
auto ikNode = getAnimInverseKinematicsNode();
|
|
||||||
if (ikNode) {
|
|
||||||
float alpha = 1.0f - deltaTime / totalDuration;
|
|
||||||
const AnimPose geometryToRigTransform(_geometryToRigTransform);
|
|
||||||
AnimPose uncontrolledHandPose;
|
|
||||||
if (isLeftHand) {
|
|
||||||
uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose();
|
|
||||||
} else {
|
|
||||||
uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose();
|
|
||||||
}
|
|
||||||
if (isToControlled) {
|
|
||||||
::blend(1, &uncontrolledHandPose, &controlledHandPose, alpha, &returnHandPose);
|
|
||||||
} else {
|
|
||||||
::blend(1, &controlledHandPose, &uncontrolledHandPose, alpha, &returnHandPose);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,18 +340,6 @@ protected:
|
||||||
int _nextStateHandlerId { 0 };
|
int _nextStateHandlerId { 0 };
|
||||||
QMutex _stateMutex;
|
QMutex _stateMutex;
|
||||||
|
|
||||||
bool transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand,
|
|
||||||
bool isToControlled, AnimPose& returnHandPose);
|
|
||||||
|
|
||||||
bool _isLeftHandControlled { false };
|
|
||||||
bool _isRightHandControlled { false };
|
|
||||||
float _leftHandControlTimeRemaining { 0.0f };
|
|
||||||
float _rightHandControlTimeRemaining { 0.0f };
|
|
||||||
float _leftHandRelaxTimeRemaining { 0.0f };
|
|
||||||
float _rightHandRelaxTimeRemaining { 0.0f };
|
|
||||||
AnimPose _lastLeftHandControlledPose;
|
|
||||||
AnimPose _lastRightHandControlledPose;
|
|
||||||
|
|
||||||
glm::vec3 _prevRightFootPoleVector { Vectors::UNIT_Z };
|
glm::vec3 _prevRightFootPoleVector { Vectors::UNIT_Z };
|
||||||
bool _prevRightFootPoleVectorValid { false };
|
bool _prevRightFootPoleVectorValid { false };
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <SceneScriptingInterface.h>
|
#include <SceneScriptingInterface.h>
|
||||||
#include <ScriptEngine.h>
|
#include <ScriptEngine.h>
|
||||||
|
#include <HoverOverlayInterface.h>
|
||||||
|
|
||||||
|
|
||||||
#include "RenderableEntityItem.h"
|
#include "RenderableEntityItem.h"
|
||||||
|
@ -452,6 +453,8 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
|
||||||
|
|
||||||
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
|
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
|
||||||
|
|
||||||
|
auto hoverOverlayInterface = DependencyManager::get<HoverOverlayInterface>().data();
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
|
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
|
||||||
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
|
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
|
||||||
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
|
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
|
||||||
|
@ -461,8 +464,12 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS
|
||||||
connect(this, &EntityTreeRenderer::clickReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickReleaseOnEntity);
|
connect(this, &EntityTreeRenderer::clickReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickReleaseOnEntity);
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::hoverEnterEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity);
|
connect(this, &EntityTreeRenderer::hoverEnterEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity);
|
||||||
|
connect(this, &EntityTreeRenderer::hoverEnterEntity, hoverOverlayInterface, &HoverOverlayInterface::createHoverOverlay);
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::hoverOverEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
|
connect(this, &EntityTreeRenderer::hoverOverEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::hoverLeaveEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
|
connect(this, &EntityTreeRenderer::hoverLeaveEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
|
||||||
|
connect(this, &EntityTreeRenderer::hoverLeaveEntity, hoverOverlayInterface, &HoverOverlayInterface::destroyHoverOverlay);
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
|
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
|
||||||
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
|
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
|
||||||
|
|
30
libraries/entities/src/HoverOverlayInterface.cpp
Normal file
30
libraries/entities/src/HoverOverlayInterface.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// HoverOverlayInterface.cpp
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2017-07-14.
|
||||||
|
// Copyright 2017 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 "HoverOverlayInterface.h"
|
||||||
|
|
||||||
|
HoverOverlayInterface::HoverOverlayInterface() {
|
||||||
|
// "hover_overlay" debug log category disabled by default.
|
||||||
|
// Create your own "qtlogging.ini" file and set your "QT_LOGGING_CONF" environment variable
|
||||||
|
// if you'd like to enable/disable certain categories.
|
||||||
|
// More details: http://doc.qt.io/qt-5/qloggingcategory.html#configuring-categories
|
||||||
|
QLoggingCategory::setFilterRules(QStringLiteral("hifi.hover_overlay.debug=false"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HoverOverlayInterface::createHoverOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||||
|
qCDebug(hover_overlay) << "Creating Hover Overlay on top of entity with ID: " << entityItemID;
|
||||||
|
setCurrentHoveredEntity(entityItemID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HoverOverlayInterface::destroyHoverOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||||
|
qCDebug(hover_overlay) << "Destroying Hover Overlay on top of entity with ID: " << entityItemID;
|
||||||
|
setCurrentHoveredEntity(QUuid());
|
||||||
|
}
|
44
libraries/entities/src/HoverOverlayInterface.h
Normal file
44
libraries/entities/src/HoverOverlayInterface.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//
|
||||||
|
// HoverOverlayInterface.h
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2017-07-14.
|
||||||
|
// Copyright 2017 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_HoverOverlayInterface_h
|
||||||
|
#define hifi_HoverOverlayInterface_h
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
#include <PointerEvent.h>
|
||||||
|
|
||||||
|
#include "EntityTree.h"
|
||||||
|
#include "HoverOverlayLogging.h"
|
||||||
|
|
||||||
|
class HoverOverlayInterface : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QUuid currentHoveredEntity READ getCurrentHoveredEntity WRITE setCurrentHoveredEntity)
|
||||||
|
public:
|
||||||
|
HoverOverlayInterface();
|
||||||
|
|
||||||
|
Q_INVOKABLE QUuid getCurrentHoveredEntity() { return _currentHoveredEntity; }
|
||||||
|
void setCurrentHoveredEntity(const QUuid& entityID) { _currentHoveredEntity = entityID; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void createHoverOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
void destroyHoverOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _verboseLogging { true };
|
||||||
|
QUuid _currentHoveredEntity{};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_HoverOverlayInterface_h
|
14
libraries/entities/src/HoverOverlayLogging.cpp
Normal file
14
libraries/entities/src/HoverOverlayLogging.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// HoverOverlayLogging.cpp
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2017-07-17
|
||||||
|
// Copyright 2017 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 "HoverOverlayLogging.h"
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(hover_overlay, "hifi.hover_overlay")
|
20
libraries/entities/src/HoverOverlayLogging.h
Normal file
20
libraries/entities/src/HoverOverlayLogging.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//
|
||||||
|
// HoverOverlayLogging.h
|
||||||
|
// libraries/entities/src
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2017-07-17
|
||||||
|
// Copyright 2017 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_HoverOverlayLogging_h
|
||||||
|
#define hifi_HoverOverlayLogging_h
|
||||||
|
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(hover_overlay)
|
||||||
|
|
||||||
|
#endif // hifi_HoverOverlayLogging_h
|
|
@ -264,9 +264,6 @@ QNetworkAccessManager* QmlNetworkAccessManagerFactory::create(QObject* parent) {
|
||||||
return new QmlNetworkAccessManager(parent);
|
return new QmlNetworkAccessManager(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QQmlEngine* globalEngine { nullptr };
|
|
||||||
static size_t globalEngineRefCount { 0 };
|
|
||||||
|
|
||||||
QString getEventBridgeJavascript() {
|
QString getEventBridgeJavascript() {
|
||||||
// FIXME: Refactor with similar code in RenderableWebEntityItem
|
// FIXME: Refactor with similar code in RenderableWebEntityItem
|
||||||
QString javaScriptToInject;
|
QString javaScriptToInject;
|
||||||
|
@ -300,9 +297,44 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define SINGLE_QML_ENGINE 0
|
||||||
|
|
||||||
|
#if SINGLE_QML_ENGINE
|
||||||
|
static QQmlEngine* globalEngine{ nullptr };
|
||||||
|
static size_t globalEngineRefCount{ 0 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) {
|
||||||
|
engine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
|
||||||
|
auto importList = engine->importPathList();
|
||||||
|
importList.insert(importList.begin(), PathUtils::resourcesPath());
|
||||||
|
engine->setImportPathList(importList);
|
||||||
|
for (const auto& path : importList) {
|
||||||
|
qDebug() << path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!engine->incubationController()) {
|
||||||
|
engine->setIncubationController(window->incubationController());
|
||||||
|
}
|
||||||
|
auto rootContext = engine->rootContext();
|
||||||
|
rootContext->setContextProperty("GL", ::getGLContextData());
|
||||||
|
rootContext->setContextProperty("urlHandler", new UrlHandler());
|
||||||
|
rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath()));
|
||||||
|
rootContext->setContextProperty("pathToFonts", "../../");
|
||||||
|
rootContext->setContextProperty("ApplicationInterface", qApp);
|
||||||
|
auto javaScriptToInject = getEventBridgeJavascript();
|
||||||
|
if (!javaScriptToInject.isEmpty()) {
|
||||||
|
rootContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
|
||||||
|
}
|
||||||
|
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
|
||||||
|
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
|
||||||
|
rootContext->setContextProperty("HFTabletWebEngineProfile", new HFTabletWebEngineProfile(rootContext));
|
||||||
|
}
|
||||||
|
|
||||||
QQmlEngine* acquireEngine(QQuickWindow* window) {
|
QQmlEngine* acquireEngine(QQuickWindow* window) {
|
||||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||||
|
|
||||||
|
QQmlEngine* result = nullptr;
|
||||||
if (QThread::currentThread() != qApp->thread()) {
|
if (QThread::currentThread() != qApp->thread()) {
|
||||||
qCWarning(uiLogging) << "Cannot acquire QML engine on any thread but the main thread";
|
qCWarning(uiLogging) << "Cannot acquire QML engine on any thread but the main thread";
|
||||||
}
|
}
|
||||||
|
@ -311,47 +343,34 @@ QQmlEngine* acquireEngine(QQuickWindow* window) {
|
||||||
qmlRegisterType<SoundEffect>("Hifi", 1, 0, "SoundEffect");
|
qmlRegisterType<SoundEffect>("Hifi", 1, 0, "SoundEffect");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
#if SINGLE_QML_ENGINE
|
||||||
if (!globalEngine) {
|
if (!globalEngine) {
|
||||||
Q_ASSERT(0 == globalEngineRefCount);
|
Q_ASSERT(0 == globalEngineRefCount);
|
||||||
globalEngine = new QQmlEngine();
|
globalEngine = new QQmlEngine();
|
||||||
globalEngine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory);
|
initializeQmlEngine(result, window);
|
||||||
|
++globalEngineRefCount;
|
||||||
auto importList = globalEngine->importPathList();
|
|
||||||
importList.insert(importList.begin(), PathUtils::resourcesPath());
|
|
||||||
globalEngine->setImportPathList(importList);
|
|
||||||
for (const auto& path : importList) {
|
|
||||||
qDebug() << path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!globalEngine->incubationController()) {
|
|
||||||
globalEngine->setIncubationController(window->incubationController());
|
|
||||||
}
|
|
||||||
auto rootContext = globalEngine->rootContext();
|
|
||||||
rootContext->setContextProperty("GL", ::getGLContextData());
|
|
||||||
rootContext->setContextProperty("urlHandler", new UrlHandler());
|
|
||||||
rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath()));
|
|
||||||
rootContext->setContextProperty("pathToFonts", "../../");
|
|
||||||
rootContext->setContextProperty("ApplicationInterface", qApp);
|
|
||||||
auto javaScriptToInject = getEventBridgeJavascript();
|
|
||||||
if (!javaScriptToInject.isEmpty()) {
|
|
||||||
rootContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
|
|
||||||
}
|
|
||||||
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
|
|
||||||
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
|
|
||||||
rootContext->setContextProperty("HFTabletWebEngineProfile", new HFTabletWebEngineProfile(rootContext));
|
|
||||||
}
|
}
|
||||||
|
result = globalEngine;
|
||||||
|
#else
|
||||||
|
result = new QQmlEngine();
|
||||||
|
initializeQmlEngine(result, window);
|
||||||
|
#endif
|
||||||
|
|
||||||
++globalEngineRefCount;
|
return result;
|
||||||
return globalEngine;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void releaseEngine() {
|
void releaseEngine(QQmlEngine* engine) {
|
||||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||||
|
#if SINGLE_QML_ENGINE
|
||||||
Q_ASSERT(0 != globalEngineRefCount);
|
Q_ASSERT(0 != globalEngineRefCount);
|
||||||
if (0 == --globalEngineRefCount) {
|
if (0 == --globalEngineRefCount) {
|
||||||
globalEngine->deleteLater();
|
globalEngine->deleteLater();
|
||||||
globalEngine = nullptr;
|
globalEngine = nullptr;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
engine->deleteLater();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::cleanup() {
|
void OffscreenQmlSurface::cleanup() {
|
||||||
|
@ -456,11 +475,11 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
|
||||||
QObject::disconnect(qApp);
|
QObject::disconnect(qApp);
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
|
auto engine = _qmlContext->engine();
|
||||||
_canvas->deleteLater();
|
_canvas->deleteLater();
|
||||||
_rootItem->deleteLater();
|
_rootItem->deleteLater();
|
||||||
_quickWindow->deleteLater();
|
_quickWindow->deleteLater();
|
||||||
releaseEngine();
|
releaseEngine(engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::onAboutToQuit() {
|
void OffscreenQmlSurface::onAboutToQuit() {
|
||||||
|
|
|
@ -227,7 +227,6 @@ void TabletProxy::setToolbarMode(bool toolbarMode) {
|
||||||
// forward qml surface events to interface js
|
// forward qml surface events to interface js
|
||||||
connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml);
|
connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml);
|
||||||
} else {
|
} else {
|
||||||
_state = State::Home;
|
|
||||||
removeButtonsFromToolbar();
|
removeButtonsFromToolbar();
|
||||||
addButtonsToHomeScreen();
|
addButtonsToHomeScreen();
|
||||||
emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL));
|
emit screenChanged(QVariant("Home"), QVariant(TABLET_SOURCE_URL));
|
||||||
|
|
Loading…
Reference in a new issue