constraints/CharacterSolver/HIK2014Solver/orcharactersolver_hik.cxx

constraints/CharacterSolver/HIK2014Solver/orcharactersolver_hik.cxx
/***************************************************************************************
Autodesk(R) Open Reality(R) Samples
(C) 2012 Autodesk, Inc. and/or its licensors
All rights reserved.
AUTODESK SOFTWARE LICENSE AGREEMENT
Autodesk, Inc. licenses this Software to you only upon the condition that
you accept all of the terms contained in the Software License Agreement ("Agreement")
that is embedded in or that is delivered with this Software. By selecting
the "I ACCEPT" button at the end of the Agreement or by copying, installing,
uploading, accessing or using all or any portion of the Software you agree
to enter into the Agreement. A contract is then formed between Autodesk and
either you personally, if you acquire the Software for yourself, or the company
or other legal entity for which you are acquiring the software.
AUTODESK, INC., MAKES NO WARRANTY, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
PURPOSE REGARDING THESE MATERIALS, AND MAKES SUCH MATERIALS AVAILABLE SOLELY ON AN
"AS-IS" BASIS.
IN NO EVENT SHALL AUTODESK, INC., BE LIABLE TO ANYONE FOR SPECIAL, COLLATERAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF PURCHASE
OR USE OF THESE MATERIALS. THE SOLE AND EXCLUSIVE LIABILITY TO AUTODESK, INC.,
REGARDLESS OF THE FORM OF ACTION, SHALL NOT EXCEED THE PURCHASE PRICE OF THE
MATERIALS DESCRIBED HEREIN.
Autodesk, Inc., reserves the right to revise and improve its products as it sees fit.
Autodesk and Open Reality are registered trademarks or trademarks of Autodesk, Inc.,
in the U.S.A. and/or other countries. All other brand names, product names, or
trademarks belong to their respective holders.
GOVERNMENT USE
Use, duplication, or disclosure by the U.S. Government is subject to restrictions as
set forth in FAR 12.212 (Commercial Computer Software-Restricted Rights) and
DFAR 227.7202 (Rights in Technical Data and Computer Software), as applicable.
Manufacturer is Autodesk, Inc., 10 Duke Street, Montreal, Quebec, Canada, H3C 2L7.
***************************************************************************************/
//--- Class declarations
#include "orcharactersolver_hik.h"
#include "filterset2fbcharacter.h"
#ifdef _DEBUG
// humanik includes
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4324) // 'HIKCharacterStateStream': structure was padded due to alignment specifier
#pragma warning (disable: 4267) // 'argument': conversion from 'size_t' to 'long', possible loss of data
#endif
#include <humanik/hikdump.h>
#ifdef _MSC_VER
#pragma warning (pop)
#endif
#define MAX_PATH_LENGTH 2048
#endif
//--- implementation and registration
FBCharacterSolverImplementation ( ORCONSTRAINTHIK__CLASS );
FBRegisterCharacterSolver ( ORCONSTRAINTHIK__NAME,
ORCONSTRAINTHIK__CLASS,
ORCONSTRAINTHIK__LABEL,
ORCONSTRAINTHIK__DESC,
"character_solver.tif" ); // Icon filename (default=Open Reality icon)
FBProfiler_CreateTaskCycle( HIK, 0.5f, 0.1f, 0.5f )
// keep synchronicity between Tables, if there is a compilation error, it's because there is a mismatch in the number of Index in the table and the FBSkeletonNodeId Enum
K_STATIC_ASSERT( sizeof(gActor2HIK)/sizeof(int) == kFBSkeletonLastIndex );
#ifdef _DEBUG
//Support for 'Dump' exports (HIK, HIKS, HIKES, HIKPS files)
static void SaveHIKChar(HIObject pObject, bool pValue)
{
if(pValue)
{
FBFilePopup lFilePopup;
lFilePopup.Caption = "Save HIK Character";
lFilePopup.Filter = "*.hik";
lFilePopup.Path = "";
lFilePopup.Style = kFBFilePopupSave;
if(lFilePopup.Execute())
{
ORCharacterSolver_HIK* lCharacterSolver = FBCast<ORCharacterSolver_HIK>(pObject);
HIKCharacter *lHIKCharacter = NULL;
if(lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst != 0)
{
lHIKCharacter = lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst;
}
else if(lCharacterSolver->mHIKControlRigHostEvaluator.mHIKCharacter != 0)
{
lHIKCharacter = lCharacterSolver->mHIKControlRigHostEvaluator.mHIKCharacter;
}
if(lHIKCharacter )
{
HIKSaveCharacter(lFilePopup.FullFilename, lHIKCharacter, &malloc, &free);
// Also save source character when in retargeting mode
if(lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst != 0 &&
lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterSrc != 0)
{
lHIKCharacter = lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterSrc;
char sourceFileName[MAX_PATH_LENGTH];
strcpy(sourceFileName, lFilePopup.FullFilename);
strcat(sourceFileName, "_src");
HIKSaveCharacter(sourceFileName, lHIKCharacter, &malloc, &free);
}
}
}
}
}
static void SaveHIKState(HIObject pObject, bool pValue)
{
if(pValue)
{
FBFilePopup lFilePopup;
lFilePopup.Caption = "Save HIK State";
lFilePopup.Filter = "*.hiks";
lFilePopup.Path = "";
lFilePopup.Style = kFBFilePopupSave;
if(lFilePopup.Execute())
{
ORCharacterSolver_HIK* lCharacterSolver = FBCast<ORCharacterSolver_HIK>(pObject);
HIKCharacter *lHIKCharacter = NULL;
HIKCharacterState *lHIKCharacterState = NULL;
if(lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst != 0)
{
lHIKCharacter = lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst;
lHIKCharacterState = lCharacterSolver->GetState(0)->mState;
}
else if(lCharacterSolver->mHIKControlRigHostEvaluator.mHIKCharacter != 0)
{
lHIKCharacter = lCharacterSolver->mHIKControlRigHostEvaluator.mHIKCharacter;
lHIKCharacterState = lCharacterSolver->GetState(0)->mState;
}
if(lHIKCharacter && lHIKCharacterState)
{
HIKSaveCharacterState(lFilePopup.FullFilename,lHIKCharacter, lHIKCharacterState, HIKDataDescription::HIKGlobalSpace);
// Also save source state when in retargeting mode
if(lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst != 0 &&
lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterSrc != 0)
{
lHIKCharacter = lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterSrc;
lHIKCharacterState = lCharacterSolver->GetState(0)->mSrcState;
char sourceFileName[MAX_PATH_LENGTH];
strcpy(sourceFileName, lFilePopup.FullFilename);
strcat(sourceFileName, "_src");
HIKSaveCharacterState(sourceFileName,lHIKCharacter, lHIKCharacterState, HIKDataDescription::HIKGlobalSpace);
}
}
}
}
}
static void SaveHIKEffectors(HIObject pObject, bool pValue)
{
if(pValue)
{
FBFilePopup lFilePopup;
lFilePopup.Caption = "Save HIK Effectors state";
lFilePopup.Filter = "*.hikes";
lFilePopup.Path = "";
lFilePopup.Style = kFBFilePopupSave;
if(lFilePopup.Execute())
{
ORCharacterSolver_HIK* lCharacterSolver = FBCast<ORCharacterSolver_HIK>(pObject);
HIKCharacter *lHIKCharacter = NULL;
HIKEffectorSetState *lHIKCharacterEffectorState = NULL;
if(lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst != 0)
{
lHIKCharacter = lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst;
lHIKCharacterEffectorState = lCharacterSolver->GetState(0)->mEffectorSetState;
}
else if(lCharacterSolver->mHIKControlRigHostEvaluator.mHIKCharacter != 0)
{
lHIKCharacter = lCharacterSolver->mHIKControlRigHostEvaluator.mHIKCharacter;
lHIKCharacterEffectorState = lCharacterSolver->GetState(0)->mEffectorSetState;
}
if(lHIKCharacter && lHIKCharacterEffectorState)
{
HIKSaveEffectorState(lFilePopup.FullFilename, lHIKCharacterEffectorState);
}
}
}
}
static void SaveHIKProperties(HIObject pObject, bool pValue)
{
if(pValue)
{
FBFilePopup lFilePopup;
lFilePopup.Caption = "Save HIK Properties state";
lFilePopup.Filter = "*.hikps";
lFilePopup.Path = "";
lFilePopup.Style = kFBFilePopupSave;
if(lFilePopup.Execute())
{
ORCharacterSolver_HIK* lCharacterSolver = FBCast<ORCharacterSolver_HIK>(pObject);
HIKCharacter *lHIKCharacter = NULL;
HIKPropertySetState *lHIKCharacterPropertyState = NULL;
if(lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst != 0)
{
lHIKCharacter = lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst;
lHIKCharacterPropertyState = lCharacterSolver->GetState(0)->mPropertySetState;
}
else if(lCharacterSolver->mHIKControlRigHostEvaluator.mHIKCharacter != 0)
{
lHIKCharacter = lCharacterSolver->mHIKControlRigHostEvaluator.mHIKCharacter;
lHIKCharacterPropertyState = lCharacterSolver->GetState(0)->mPropertySetState;
}
if(lHIKCharacter && lHIKCharacterPropertyState)
{
HIKSavePropertySetState(lFilePopup.FullFilename, lHIKCharacterPropertyState);
// Also save source state when in retargeting mode
if(lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst != 0 &&
lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterSrc != 0)
{
lHIKCharacter = lCharacterSolver->mHIKCharacterHostEvaluator.mHIKCharacterDst;
lHIKCharacterPropertyState = lCharacterSolver->GetState(0)->mSrcPropertySetState;
char sourceFileName[MAX_PATH_LENGTH];
strcpy(sourceFileName, lFilePopup.FullFilename);
strcat(sourceFileName, "_src");
HIKSavePropertySetState(sourceFileName, lHIKCharacterPropertyState);
}
}
}
}
}
#if 0
// debug function to be added where HIK dump is needed
static void DumpHIK(const FBString &pFilepath, HIKCharacter *pCharacter, HIKCharacter *pCharacterSrc,
HIKCharacterState *pCharacterState, HIKCharacterState *pCharacterStateSrc,
HIKEffectorSetState *pEffectorSetState, HIKPropertySetState *pPropertySetState,
HIKPropertySetState *pPropertySetStateSrc)
{
FBString lFilename;
if (pCharacter)
{
lFilename = pFilepath + ".hik";
HIKSaveCharacter(lFilename, pCharacter, &malloc, &free);
}
if (pCharacterSrc)
{
lFilename = pFilepath + "_src.hik";
HIKSaveCharacter(lFilename, pCharacterSrc, &malloc, &free);
}
if (pCharacterState)
{
lFilename = pFilepath + ".hiks";
HIKSaveCharacterState(lFilename, pCharacter, pCharacterState, HIKDataDescription::HIKGlobalSpace);
}
if (pCharacterStateSrc)
{
lFilename = pFilepath + "_src.hiks";
HIKSaveCharacterState(lFilename, pCharacterSrc, pCharacterStateSrc, HIKDataDescription::HIKGlobalSpace);
}
if (pEffectorSetState)
{
lFilename = pFilepath + ".hikes";
HIKSaveEffectorState(lFilename, pEffectorSetState);
}
if (pPropertySetState)
{
lFilename = pFilepath + ".hikps";
HIKSavePropertySetState(lFilename, pPropertySetState);
}
if (pPropertySetStateSrc)
{
lFilename = pFilepath + "_src.hikps";
HIKSavePropertySetState(lFilename, pPropertySetStateSrc);
}
}
#endif
#define DefOverwriteHIKSolvingStepFunc(Step) \
static void OverwriteHIK##Step(HIObject pObject, bool pValue) \
{ \
ORCharacterSolver_HIK* lCharacterSolver = FBCast<ORCharacterSolver_HIK>(pObject);\
if (!lCharacterSolver) \
return; \
lCharacterSolver->ModifySolvingStep(pValue, HIK##Step); \
lCharacterSolver->Step.SetPropertyValue(pValue); \
} \
DefOverwriteHIKSolvingStepFunc(SolvingStepBodyPull)
DefOverwriteHIKSolvingStepFunc(SolvingStepContact)
DefOverwriteHIKSolvingStepFunc(SolvingStepContactApprox)
DefOverwriteHIKSolvingStepFunc(SolvingStepLeftShoulder)
DefOverwriteHIKSolvingStepFunc(SolvingStepRightShoulder)
DefOverwriteHIKSolvingStepFunc(SolvingStepLeftArm)
DefOverwriteHIKSolvingStepFunc(SolvingStepRightArm)
DefOverwriteHIKSolvingStepFunc(SolvingStepLeftLeg)
DefOverwriteHIKSolvingStepFunc(SolvingStepRightLeg)
DefOverwriteHIKSolvingStepFunc(SolvingStepLeftHand)
DefOverwriteHIKSolvingStepFunc(SolvingStepRightHand)
DefOverwriteHIKSolvingStepFunc(SolvingStepLeftFoot)
DefOverwriteHIKSolvingStepFunc(SolvingStepRightFoot)
DefOverwriteHIKSolvingStepFunc(SolvingStepHead)
DefOverwriteHIKSolvingStepFunc(SolvingStepSpine)
DefOverwriteHIKSolvingStepFunc(SolvingStepHipsTranslation)
DefOverwriteHIKSolvingStepFunc(SolvingStepRollExtraction)
DefOverwriteHIKSolvingStepFunc(SolvingStepLeftArmSnS)
DefOverwriteHIKSolvingStepFunc(SolvingStepRightArmSnS)
DefOverwriteHIKSolvingStepFunc(SolvingStepLeftLegSnS)
DefOverwriteHIKSolvingStepFunc(SolvingStepRightLegSnS)
DefOverwriteHIKSolvingStepFunc(SolvingStepModifiers)
DefOverwriteHIKSolvingStepFunc(SolvingStepAllParts)
#endif
static void LegSNSSet(HIObject pObject, bool pValue)
{
ORCharacterSolver_HIK* lConstraint = FBCast<ORCharacterSolver_HIK>(pObject);
lConstraint->ModifySolvingStep(pValue, LegFilter);
lConstraint->LegSNS.SetPropertyValue(pValue);
}
static void ArmSNSSet(HIObject pObject, bool pValue)
{
ORCharacterSolver_HIK* lConstraint = FBCast<ORCharacterSolver_HIK>(pObject);
lConstraint->ModifySolvingStep(pValue, ArmFilter);
lConstraint->ArmSNS.SetPropertyValue(pValue);
}
static const char* HIKLibraryVersionGet(HIObject pObject)
{
//
// Increment ".X" below for each HIK 2014 fix delivered
//
// HIK 2014 in MotionBuilder 2015, 2016, and 2017 is based on the same version: HIK 2014.2.2.
// HUMANIK_VERSION_STRING is "2014.2.2".
//
// We won't be upgrading HIK 2014 to provide user consistent behavior with the HIK 2014 in the
// previously released version of MotionBuilder.
//
// As we won't be upgrading HIK, the above version stay unchanged. However, we do integrate fixes
// (e.g. for escalations) into 2014.2.2 version. For tracking purposes we add another version number
// that increments for each fix delivered. The full version string becomes "2014.2.2.X".
//
// For the record:
// - HIK 2014.2.2.1 = 2014.2.2 (CL#222997) + MOBU-8375 (CL#235155)
//
}
bool ORCharacterSolver_HIK::FBCreate()
{
mInternalPropertiesCount = PropertyList.GetCount();
mHIKCharacter = NULL;
mHIKCharacterSrc = NULL;
mHIKActorSrc = NULL;
mControlSetManipulator = NULL;
mEvaluationId = -1;
HIKHostPropertiesInit(mHIKCharacterHost);
HIKHostPropertiesInit(mHIKCharacterHostSrc);
FBPropertyPublish(this, HIKLibraryVersion, "HIK Library Version", HIKLibraryVersionGet, NULL);
HIKLibraryVersion.ModifyPropertyFlag( kFBPropertyFlagReadOnly , true );
HIKLibraryVersion.ModifyPropertyFlag( kFBPropertyFlagNotSavable , true );
HIKLibraryVersion.ModifyPropertyFlag( kFBPropertyFlagForceStaticProperty , true );
FBPropertyPublish(this, ExtraCollarRatio,"Extra Collar Ratio", NULL, NULL);
ExtraCollarRatio.SetMinMax(0.,100.);
FBPropertyPublish(this, LegSNS, "Leg SNS", NULL, LegSNSSet);
FBPropertyPublish(this, ArmSNS, "Arm SNS", NULL, ArmSNSSet);
FBPropertyPublish(this, CollarStiffnessX, "Collar Stiffness X", NULL, NULL);
FBPropertyPublish(this, CollarStiffnessY, "Collar Stiffness Y", NULL, NULL);
FBPropertyPublish(this, CollarStiffnessZ, "Collar Stiffness Z", NULL, NULL);
// SnS
FBPropertyPublish(this, SnSReachHead,"Stretch Neck", NULL, NULL);
FBPropertyPublish(this, SnSReachChestEnd,"Stretch Spine", NULL, NULL);
FBPropertyPublish(this, SnSSmoothReach, "Stretch Damping", NULL, NULL);
char namebuffer[50];
for(int i = 0; i < 10; ++i)
{
sprintf(namebuffer,"Spine %i Min Length", i);
FBPropertyPublish(this, SpineMinLength[i], namebuffer, NULL, NULL);
sprintf(namebuffer,"Spine %i Max Length", i);
FBPropertyPublish(this, SpineMaxLength[i], namebuffer, NULL, NULL);
SpineMinLength[i].SetMinMax(0.0, 500.0);
SpineMaxLength[i].SetMinMax(0.0, 500.0);
}
for(int i = 0; i < 10; ++i)
{
sprintf(namebuffer,"Neck %i Min Length", i);
FBPropertyPublish(this, NeckMinLength[i], namebuffer, NULL, NULL);
sprintf(namebuffer,"Neck %i Max Length", i);
FBPropertyPublish(this, NeckMaxLength[i], namebuffer, NULL, NULL);
NeckMinLength[i].SetMinMax(0.0, 500.0);
NeckMaxLength[i].SetMinMax(0.0, 500.0);
}
FBPropertyPublish(this, HeadMinLength, "Head Min Length", NULL, NULL);
FBPropertyPublish(this, HeadMaxLength, "Head Max Length", NULL, NULL);
HeadMinLength.SetMinMax(0.0, 500.0);
HeadMaxLength.SetMinMax(0.0, 500.0);
CollarStiffnessX.SetMinMax(-100.,100.);
CollarStiffnessY.SetMinMax(-100.,100.);
CollarStiffnessZ.SetMinMax(-100.,100.);
FBPropertyPublish(this, ReachLeftShoulder,"Reach Left Shoulder", NULL, NULL);
FBPropertyPublish(this, ReachRightShoulder,"Reach Right Shoulder", NULL, NULL);
ReachLeftShoulder.SetMinMax(0, 100);
ReachRightShoulder.SetMinMax(0, 100);
FBPropertyPublish(this, FingerSolvingPropagation, "Finger Propagation", NULL, NULL);
FBPropertyPublish(this, RealisticLeftKneeSolving, "Realistic Left Knee Solving", NULL, NULL);
FBPropertyPublish(this, RealisticRightKneeSolving, "Realistic Right Knee Solving", NULL, NULL);
RealisticLeftKneeSolving.SetMinMax(0, 100);
RealisticRightKneeSolving.SetMinMax(0, 100);
FBPropertyPublish(this, RealisticArmSolving, "Realistic Arm Solving", NULL, NULL);
FBPropertyPublish(this, TopSpineCorrection,"Top Spine Correction", NULL, NULL);
FBPropertyPublish(this, LowerSpineCorrection,"Lower Spine Correction", NULL, NULL);
TopSpineCorrection.SetMinMax(0, 100);
LowerSpineCorrection.SetMinMax(0, 100);
//Sns deprecated
FBPropertyPublish(this, StretchStartArmsAndLegs,"StretchStartArmsAndLegs", NULL, NULL);
FBPropertyPublish(this, StretchStopArmsAndLegs,"StretchStopArmsAndLegs", NULL, NULL);
FBPropertyPublish(this, SnSScaleArmsAndLegs,"SnSScaleArmsAndLegs", NULL, NULL);
FBPropertyPublish(this, SnSReachLeftWrist,"SnSReachLeftWrist", NULL, NULL);
FBPropertyPublish(this, SnSReachRightWrist,"SnSReachRightWrist", NULL, NULL);
FBPropertyPublish(this, SnSReachLeftAnkle,"SnSReachLeftAnkle", NULL, NULL);
FBPropertyPublish(this, SnSReachRightAnkle,"SnSReachRightAnkle", NULL, NULL);
FBPropertyPublish(this, SnSScaleSpine,"SnSScaleSpine", NULL, NULL);
FBPropertyPublish(this, SnSScaleSpineChildren,"SnSScaleSpineChildren", NULL, NULL);
FBPropertyPublish(this, SnSScaleNeck,"SnSScaleNeck", NULL, NULL);
StretchStartArmsAndLegs.SetMinMax(0,100);
StretchStopArmsAndLegs.SetMinMax(100,200);
SnSScaleArmsAndLegs.SetMinMax(0,100);
SnSReachLeftWrist.SetMinMax(0,100);
SnSReachRightWrist.SetMinMax(0,100);
SnSReachLeftAnkle.SetMinMax(0,100);
SnSReachRightAnkle.SetMinMax(0,100);
SnSScaleSpine.SetMinMax(0,100);
SnSScaleSpineChildren.SetMinMax(0,100);
SnSReachChestEnd.SetMinMax(0,100);
SnSScaleNeck.SetMinMax(0,100);
SnSReachHead.SetMinMax(0,100);
ResetPropertiesToDefault();
#ifdef _DEBUG
FBPropertyPublish(this, ActionSaveHIKCharacter, "Save Characer (HIK)", NULL, SaveHIKChar);
FBPropertyPublish(this, ActionSaveHIKState, "Save State (HIKS)", NULL, SaveHIKState);
FBPropertyPublish(this, ActionSaveHIKEffectors, "Save Effectors (HIKES)", NULL, SaveHIKEffectors);
FBPropertyPublish(this, ActionSaveHIKProperties, "Save Properties (HIKPS)", NULL, SaveHIKProperties);
InitSolvingProperties();
#endif
mSolvingStepFilter = HIKSolvingStepAll;
//hide the active property
Active.ModifyPropertyFlag(kFBPropertyFlagHideProperty, true);
mSolverPropertiesCount = PropertyList.GetCount();
return true;
}
void ORCharacterSolver_HIK::FBDestroy()
{
if(mHIKCharacter != NULL)
{
HIKCharacterDestroy(mHIKCharacter,&free);
mHIKCharacter = NULL;
}
if(mHIKCharacterSrc != NULL)
{
HIKCharacterDestroy(mHIKCharacterSrc,&free);
mHIKCharacterSrc = NULL;
}
if(mHIKCharacterSrc != NULL)
{
HIKCharacterDestroy(mHIKCharacterSrc,&free);
mHIKCharacterSrc = NULL;
}
if(mHIKActorSrc != NULL)
{
HIKCharacterDestroy(mHIKActorSrc,&free);
mHIKActorSrc = NULL;
}
RemoveAllAnimationNodes();
}
void ORCharacterSolver_HIK::SetupAllAnimationNodes()
{
FBCharacter* lCharacter = TargetCharacter;
if(lCharacter != NULL && lCharacter->GetCharacterize())
{
FBComponent* lSource = Source;
FBCharacter* lCharacterSrc = dynamic_cast<FBCharacter*>(lSource);
FBControlSet* lControlRig = dynamic_cast<FBControlSet*>(lSource);
mActorSrc = dynamic_cast<FBActor*>(lSource);
//call the manipulator to update the state
if(mControlSetManipulator)
{
mControlSetManipulator->DeallocateState();
mControlSetManipulator->AllocateState(lCharacter);
}
SetupTargetCharacter(lCharacter);
SetupAutoProperties(lCharacter);
ResetSnSPropertiesVisibility(lCharacter);
if(lControlRig != NULL)
{
SetupInputControlRig( lControlRig, GetRigAlign() || GetDoubleSolve() );
}
else if(lCharacterSrc != NULL)
{
// set source hierarchy
HIKCharacterHostFromFBCharacter(mHIKCharacterHostSrc, lCharacterSrc);
// create mHIKCharacterSrc and characterize it
HIKCharacterFromFBCharacter(mHIKCharacterHostSrc, mHIKCharacterSrc, lCharacterSrc);
// setup properties
HIKHostPropertiesFromCharacter(mHIKCharacterHostSrc,lCharacterSrc);
// kxl: here we should setup properties from src solver!!! this is a mistake.
RegisterExtraProperties(mHIKCharacterHostSrc);
mHIKCharacterHostEvaluator.Init(mHIKCharacter,&mHIKCharacterHost,mHIKCharacterSrc,&mHIKCharacterHostSrc,&malloc);
}
else if(mActorSrc != NULL)
{
HIKCharacterFromFBActor(mHIKActorSrc, mActorSrc);
mHIKCharacterHostEvaluator.Init(mHIKCharacter,&mHIKCharacterHost,mHIKActorSrc,NULL,&malloc);
}
else
{
mHIKCharacterHostEvaluator.Init(mHIKCharacter,&mHIKCharacterHost,NULL,NULL,&malloc);
}
bool lPlotToRig = (lCharacter->InputType == kFBCharacterOutputMarkerSet || lCharacter->IsPlottingActorToCtrlRig());
if (lPlotToRig)
{
SetupInputControlRig( lCharacter->GetCurrentControlSet(true), true );
}
}
// update solving step
mHIKCharacterHostEvaluator.SetSolvingStep( mSolvingStepFilter );
mHIKControlRigHostEvaluator.SetSolvingStep( mSolvingStepFilter );
// we need at least two buffers for evaluation and rendering
GetState(0);
GetState(1);
}
void ORCharacterSolver_HIK::ResetSnSPropertiesVisibility(FBCharacter* lCharacter)
{
for(int i =0; i < 10; ++i)
{
bool spineHidden = !(i == 0 || HIKGetNodeUse(mHIKCharacter, Spine1NodeId + (i-1)));
SpineMinLength[i].ModifyPropertyFlag(kFBPropertyFlagHideProperty, spineHidden);
SpineMaxLength[i].ModifyPropertyFlag(kFBPropertyFlagHideProperty, spineHidden);
bool neckHidden = i == 0 || !HIKGetNodeUse(mHIKCharacter, Neck1NodeId + (i-1)); //always hide first neck bone
NeckMinLength[i].ModifyPropertyFlag(kFBPropertyFlagHideProperty, neckHidden);
NeckMaxLength[i].ModifyPropertyFlag(kFBPropertyFlagHideProperty, neckHidden);
SyncVisibilitySolverPropertiesOnCharacters(&SpineMinLength[i]);
SyncVisibilitySolverPropertiesOnCharacters(&SpineMaxLength[i]);
SyncVisibilitySolverPropertiesOnCharacters(&NeckMinLength[i]);
SyncVisibilitySolverPropertiesOnCharacters(&NeckMaxLength[i]);
}
}
void ORCharacterSolver_HIK::SetupTargetCharacter(FBCharacter* pCharacter)
{
// set hierarchy
HIKCharacterHostFromFBCharacterSolver(mHIKCharacterHost, this, this, true);
// create mHIKCharacter and characterize it
HIKCharacterFromFBCharacterSolver(mHIKCharacterHost, mHIKCharacter, this);
// setup properties
HIKHostPropertiesFromCharacter(mHIKCharacterHost,pCharacter);
RegisterExtraProperties(mHIKCharacterHost);
}
void ORCharacterSolver_HIK::CreateExtraFKIfNeeded(FBCharacter* pCharacter, int pExtraBoneId, HIKEvaluationState* pStanceState)
{
OR_HIK_ASSERT(GetExtraBoneModelAt(pExtraBoneId) != NULL);
FBModel *lParentShoulderFK = pCharacter->GetCtrlRigModel(pExtraBoneId == LEFT_EXTRA_COLLAR ? kFBLeftCollarNodeId : kFBRightCollarNodeId);
OR_HIK_ASSERT(lParentShoulderFK != NULL);
if(lParentShoulderFK)
{
FBModelMarker* lExtraFK = dynamic_cast<FBModelMarker*>(GetExtraFKModelAt(pExtraBoneId));
// create if marker doesn't exist
if(lExtraFK == NULL)
{
lExtraFK = new FBModelMarker(pExtraBoneId == LEFT_EXTRA_COLLAR ? "Left Shoulder Extra FK" : "Right Shoulder Extra FK");
SetExtraFKModelAt(lExtraFK, pExtraBoneId );
}
// check if we need to reset hierarchy
if(lExtraFK->Children.GetCount() == 0)
{
// set parent
lExtraFK->Parent = lParentShoulderFK;
// update position
HIKNodeId lHIKId = ExtraIndexToHIKNodeId(pExtraBoneId);
ResetControRigModelTransformation(mHIKCharacter, pStanceState, lHIKId, lExtraFK);
// check hierarchy - reconnect everything that is not lExtraFK (we do it after having correct position candidated for lExtraFK)
for (int lIter = lParentShoulderFK->Children.GetCount()-1; lIter >= 0; lIter--)
{
FBModel* lChild = dynamic_cast<FBModel*>(lParentShoulderFK->Children.GetAt(lIter));
if(lChild != lExtraFK)
{
// make sure it's valid character bone
FBBodyNodeId lChildBodyNodeId = pCharacter->GetCtrlRigIndexByModel(lChild);
if(lChildBodyNodeId != kFBInvalidNodeId)
{
// don't reset parent, because it candidate global position of child which we want to update.
// if this doesn't work, we need to use background evaluation
lParentShoulderFK->Children.RemoveAt(lIter);
lExtraFK->Children.Add(lChild);
lHIKId = FBBodyNodeIdToHIKNodeId(lChildBodyNodeId);
ResetControRigModelTransformation(mHIKCharacter, pStanceState, lHIKId, lChild);
}
}
}
// we just invalidated evaluation DAG, make sure it will get schedule again (important for MultiThreading)
FBEvaluateManager::TheOne().InvalidateDAG();
}
// this assert can be removed, it's more to warn about potential problems - all because users may parent something to control rig shoulder markers
OR_HIK_ASSERT(lParentShoulderFK->Children.GetCount() == 1);
}
}
void ORCharacterSolver_HIK::SetupInputControlRig(FBControlSet* pControlRig, bool pConstraintRig /*=false*/)
{
FBCharacter* lCharacter = TargetCharacter;
HIKEvaluationState* lDisplayState = GetState(FBGetDisplayInfo(), this);
HIKGetDefaultState(mHIKCharacter, lDisplayState->mState);
// we create(if needed) Extra Shoulder FK models
const int lExtraCount = GetExtraBoneCount();
for( int lExtraIndex=0; lExtraIndex < lExtraCount; lExtraIndex++)
{
FBModel* lExtraBone = GetExtraBoneModelAt(lExtraIndex);
if(lExtraBone)
{
CreateExtraFKIfNeeded(lCharacter, lExtraIndex, lDisplayState);
}
}
HIKControlRigHostFromFBCharacterSolver(mHIKControlRigHost, this, pControlRig, (pConstraintRig) ? this : NULL);
mHIKControlRigHostEvaluator.Init(mHIKCharacter,&mHIKCharacterHost,&mHIKControlRigHost, &malloc, pControlRig ? (pControlRig->ControlSetType == kFBControlSetTypeFKIK) : true);
}
void ORCharacterSolver_HIK::SetupAutoProperties(FBCharacter* pCharacter)
{
for (int i = 0; i < HIKLastPropertyId; i++ )
{
{
// this property may be in automatic Mode
AnimationNodeInCreate( 2000+i, mHIKCharacterHost.GetProperty(i).Get().mValueP );
}
}
}
void ORCharacterSolver_HIK::ModifySolvingStep(bool pEnable, int pStep)
{
if(pEnable)
mSolvingStepFilter |= pStep;
else
mSolvingStepFilter &= ~pStep;
mHIKCharacterHostEvaluator.SetSolvingStep( mSolvingStepFilter );
mHIKControlRigHostEvaluator.SetSolvingStep( mSolvingStepFilter );
}
void ORCharacterSolver_HIK::RemoveAllAnimationNodes()
{
// all animation Nodes are cleared by the system
mActorSrc = NULL;
// lean HIK
if(mHIKCharacter != NULL)
{
HIKCharacterDestroy(mHIKCharacter,&free);
mHIKCharacter = NULL;
}
if(mHIKCharacterSrc != NULL)
{
HIKCharacterDestroy(mHIKCharacterSrc,&free);
mHIKCharacterSrc = NULL;
}
if(mHIKActorSrc != NULL)
{
HIKCharacterDestroy(mHIKActorSrc,&free);
mHIKActorSrc = NULL;
}
for(int lNodeIter = 0; lNodeIter < LastNodeId; lNodeIter++)
{
mHIKCharacterHost.GetNode(lNodeIter).Get().Clear();
mHIKCharacterHostSrc.GetNode(lNodeIter).Get().Clear();
mHIKControlRigHost.GetNode(lNodeIter).Get().Clear();
}
for(int lEffIter = 0; lEffIter < kFBLastEffectorId; lEffIter++)
{
for(int lSetIter = 0; lSetIter < FBLastEffectorSetIndex; lSetIter++)
{
mHIKControlRigHost.GetEffector(lEffIter,lSetIter).Get().Clear();
}
}
mHIKControlRigHostEvaluator.Clear(&free);
mHIKCharacterHostEvaluator.Clear(&free);
ClearStates();
}
HIKEvaluationState* ORCharacterSolver_HIK::EvaluationStateCreator()
{
HIKEvaluationState* lNewState = new HIKEvaluationState();
if(mHIKActorSrc != NULL)
{
lNewState->Init(mHIKCharacter, mHIKActorSrc, &malloc);
}
else
{
lNewState->Init(mHIKCharacter, mHIKCharacterSrc, &malloc);
}
return lNewState;
}
bool ORCharacterSolver_HIK::AnimationNodeNotify(FBAnimationNode* pConnector,FBEvaluateInfo* pEvaluateInfo,FBConstraintInfo* pConstraintInfo)
{
// because we want to catch all possible patch for double solve we allow constraint to loop back.
if(pEvaluateInfo->GetRecursionLevel(this) > 0)
{
// there should only one level of recursion be allowed.
OR_HIK_ASSERT( pEvaluateInfo->GetRecursionLevel(this) == 1);
return false;
}
//we constraint character reference but not write any data. This makes problem for MT Advance, because without writing data we don't build dependency link.
//we will do similar to internal character and catch that special case.
if(mHIKCharacterHost.GetNode(ReferenceNodeId).Valid())
{
if( mHIKCharacterHost.GetNode(ReferenceNodeId).Get().IsDestinationConn(pConnector) )
return false;
}
if(mHIKControlRigHostEvaluator.mHIKControlRigHost)
{
if(mHIKControlRigHostEvaluator.mHIKControlRigHost->GetNode(ReferenceNodeId).Valid())
{
if( mHIKControlRigHostEvaluator.mHIKControlRigHost->GetNode(ReferenceNodeId).Get().IsDestinationConn(pConnector) )
return false;
}
}
//actual solve
FBProfilerHelper lProfiling( FBProfiling_TaskCycleIndex( HIK ), pEvaluateInfo );
//get state for this evaluation
HIKEvaluationState* lCurrentState = GetState(pEvaluateInfo, this);
if(lCurrentState->mEvaluateId != pEvaluateInfo->GetEvaluationID())
{
lCurrentState->mEvaluateId = pEvaluateInfo->GetEvaluationID();
//retarget from actor or character (that's why we check if source is valid)
if(mHIKCharacterHostEvaluator.mHIKCharacterSrc != 0)
{
if(mHIKActorSrc != NULL)
{
mHIKCharacterHostEvaluator.ReadFromActor(pEvaluateInfo, lCurrentState, mActorSrc);
}
mHIKCharacterHostEvaluator.Read(pEvaluateInfo, lCurrentState);
mHIKCharacterHostEvaluator.SolveRetarget(lCurrentState);
if(TargetCharacter->IsPlottingActorToCtrlRig() && mHIKControlRigHostEvaluator.mHIKControlRigHost)
{
mHIKControlRigHostEvaluator.WriteRig(pEvaluateInfo, lCurrentState, true, true);
}
else
{
mHIKCharacterHostEvaluator.Write(pEvaluateInfo, lCurrentState);
}
// re-target extension
if ( mHIKCharacterSrc )
{
RetargetExtensions( pEvaluateInfo );
}
}
//character marker set
else if(TargetCharacter->InputType == kFBCharacterInputMoCap)
{
FBCharacterMarkerSet* lMarkerSet = TargetCharacter->GetCharacterMarkerSet();
if(lMarkerSet && mHIKCharacterHostEvaluator.mHIKCharacterDst)
{
FBControlSetState* lFKState = TargetCharacter->GetControlSetEvaluationCache(pEvaluateInfo);
FBEffectorSetState* lIKState = TargetCharacter->GetEffectorEvaluationCache(pEvaluateInfo);
lMarkerSet->ReadCtrlSetAndEffectorState(lFKState,lIKState,pEvaluateInfo);
mHIKCharacterHostEvaluator.ReadFromFKIK(pEvaluateInfo, lCurrentState, lFKState, lIKState);
// For CharacterMarkerSet we force realistic arm solving to get precise reach with dof's.
HIKSetPropertyValue(lCurrentState->mPropertySetState,HIKRealisticArmSolvingId,1.0f);
mHIKCharacterHostEvaluator.SolveIK(lCurrentState);
const bool lPlotToRig = (TargetCharacter->InputType == kFBCharacterOutputMarkerSet || TargetCharacter->IsPlottingActorToCtrlRig());
if(lPlotToRig && mHIKControlRigHostEvaluator.mHIKControlRigHost)
{
mHIKControlRigHostEvaluator.WriteRig(pEvaluateInfo, lCurrentState, true, true);
}
else
{
mHIKCharacterHostEvaluator.Write(pEvaluateInfo, lCurrentState);
}
}
}
//control rig
else if(mHIKControlRigHostEvaluator.mHIKCharacter != 0)
{
const bool lPlotToRig = (TargetCharacter->InputType == kFBCharacterOutputMarkerSet || TargetCharacter->IsPlottingActorToCtrlRig());
if (lPlotToRig)
{
mHIKControlRigHostEvaluator.ReadSkeletonSolveOnRig(pEvaluateInfo,lCurrentState,TargetCharacter);
mHIKControlRigHostEvaluator.WriteRig(pEvaluateInfo,lCurrentState,true);
}
else
{
ControlRigInputEvaluateAndWrite(pEvaluateInfo, lCurrentState, GetRigAlign(), GetDoubleSolve(), true);
mHIKControlRigHostEvaluator.ApplyLock(lCurrentState, TargetCharacter->LockX, TargetCharacter->LockY, TargetCharacter->LockZ);
mHIKControlRigHostEvaluator.Write(pEvaluateInfo, lCurrentState);
}
}
//stance
else
{
// get reference position - this is not the best way in the world, but we are missing some exposition from HIK
FBTVector lGT;
mHIKCharacterHost.ReadReference(mHIKCharacter, lCurrentState->mState, pEvaluateInfo);
HIKGetNodeNormalizedStateTQSdv(mHIKCharacter, lCurrentState->mState, ReferenceNodeId, lGT.mValue, lGQ.mValue, lGS.mValue);
// get stance
HIKGetDefaultState(mHIKCharacter, lCurrentState->mState);
// move with reference
HIKNodeStatePreMultTQSUpdv(mHIKCharacter, lCurrentState->mState, lGT.mValue, lGQ.mValue, lGS.mValue, false);
// write to character
mHIKCharacterHost.WriteState(mHIKCharacter, lCurrentState->mState, pEvaluateInfo, false);
}
// we are done for this pEvaluateInfo->GetEvaluationID(), what was not written, won't be writen, so let evaluation thread know it.
// only exception to this is for properties that are not read during evaluation.
AnimationNodesOutDisableIfNotWritten(pEvaluateInfo);
}
// we constrain properties, because some of them may be in Auto mode.
// we don't write to all constrained properties as long as we don't get call.
int lHIKPropIndex = pConnector->Reference - 2000;
if ( lHIKPropIndex >= 0 && lHIKPropIndex < HIKLastPropertyId)
{
HIKPropertySetState * lPropState = lCurrentState->mPropertySetState;
if( HIKIsPropertyAuto(lPropState, lHIKPropIndex) )
{
double lValue = HIKGetPropertyValue( lPropState, lHIKPropIndex );
pConnector->WriteData(&lValue, pEvaluateInfo);
}
}
return true;
}
void ORCharacterSolver_HIK::ControlRigInputEvaluateAndWrite( FBEvaluateInfo* pEvaluateInfo, HIKEvaluationState* pState, const bool pRigAlign, const bool pDoubleSolve, const bool pWriteRig, const int pDisableSolvingStep )
{
if(pRigAlign || pDoubleSolve)
{
bool lRecursionDetected = false;
// background evaluation
FBEvaluateInfo* lEvaluation = pDoubleSolve ? BackgroundEvaluateInfoRecursiveBegin(pEvaluateInfo) : BackgroundEvaluateInfoBegin(pEvaluateInfo);
{
mHIKControlRigHostEvaluator.Read(lEvaluation,pState, pDoubleSolve ? &lRecursionDetected : NULL, GetBlendAuxiliaryWithEffector());
}
BackgroundEvaluateInfoEnd(lEvaluation); //we don't need this evaluation info anymore, release, so other threads can pick it instead of creating new.
// if we detected that something is recursive, we need to perform additional solve just to feed into recursive effectors.
if(lRecursionDetected)
{
// background evaluation
FBEvaluateInfo* lDoubleEvaluation = BackgroundEvaluateInfoRecursiveBegin(pEvaluateInfo, true);
{
mHIKControlRigHostEvaluator.SolveAndWriteControlRig(lDoubleEvaluation, pState, true, true);
mHIKControlRigHostEvaluator.Write(lDoubleEvaluation, pState);
ReadDoubleSolve(lDoubleEvaluation,pState);
}
BackgroundEvaluateInfoEnd(lDoubleEvaluation); //we don't need this evaluation info anymore, release, so other threads can pick it instead of creating new.
}
mHIKControlRigHostEvaluator.SolveAndWriteControlRig(pEvaluateInfo, pState, pWriteRig, false, pDisableSolvingStep);
}
else
{
mHIKControlRigHostEvaluator.Read(pEvaluateInfo, pState, NULL, GetBlendAuxiliaryWithEffector());
mHIKControlRigHostEvaluator.Solve(pState);
}
}
void ORCharacterSolver_HIK::ReadDoubleSolve( FBEvaluateInfo* pEvalInfo, HIKEvaluationState* pState )
{
BackgroundEvaluateInfoNotify(pEvalInfo, &ORCharacterSolver_HIK::BackgroundEvaluateInfoNotification, pState);
// read effectors
mHIKControlRigHostEvaluator.ReadRecursiveEffectors(pEvalInfo,pState);
BackgroundEvaluateInfoNotify(pEvalInfo, NULL);
}
void ORCharacterSolver_HIK::BackgroundEvaluateInfoNotification(const FBAnimationNode* pDst, const FBAnimationNode* pThisSrc, void* pCustomData)
{
const AnimationNode_Id lConnectorId = pCustomData ? (AnimationNode_Id)pThisSrc->Reference : AnimationNode_Id();
// need to update reach for those connectors that were inputs for recursion.
if(lConnectorId.IsValidEffectorId())
{
// get state for this evaluation
HIKEvaluationState* lCurrentState = (HIKEvaluationState*)pCustomData;
// check if we have valid information about
if(lCurrentState->mEvaluatedEffectorId >= 0 && lCurrentState->mEvaluatedEffectorId < LastEffectorId)
{
const int lEffectorId = lConnectorId.GetEffectorId();
if(lEffectorId != lCurrentState->mEvaluatedEffectorId)
{
const int lType = lConnectorId.GetType();
if(lType == kModelTranslation)
{
HIKSetTranslationActive( lCurrentState->mEffectorSetState, lEffectorId, 1.0f);
HIKSetPull( lCurrentState->mEffectorSetState, lEffectorId, 1.0f );
}
else if(lType == kModelRotation)
{
HIKSetRotationActive( lCurrentState->mEffectorSetState, lEffectorId, 1.0f);
HIKSetResist( lCurrentState->mEffectorSetState, lEffectorId, 1.0f );
}
}
}
}
}
FBCharacterManipulatorCtrlSet* ORCharacterSolver_HIK::CreateCharacterManipulatorCtrlSet(const char* pName)
{
mControlSetManipulator = new ORCharacterManipulatorCtrlSet(pName);
mControlSetManipulator->FBCreate();
return mControlSetManipulator;
}
int ORCharacterSolver_HIK::GetExtraFKCount()
{
return 2;
}
const char* ORCharacterSolver_HIK::GetExtraFKNameAt(int pIndex)
{
static const FBString gLeftExtraCollar_FK = FBString(HIKNodeNameFromNodeId(LeftCollarExtraNodeId)) + "_FK";
static const FBString gRightExtraCollar_FK = FBString(HIKNodeNameFromNodeId(RightCollarExtraNodeId)) + "_FK";
switch (pIndex)
{
case LEFT_EXTRA_COLLAR:
return gLeftExtraCollar_FK;
break;
case RIGHT_EXTRA_COLLAR:
return gRightExtraCollar_FK;
break;
}
return NULL;
}
FBBodyPartId ORCharacterSolver_HIK::GetExtraFKBodyPartAt(int pIndex)
{
switch (pIndex)
{
case LEFT_EXTRA_COLLAR:
break;
case RIGHT_EXTRA_COLLAR:
break;
}
}
int ORCharacterSolver_HIK::GetExtraBoneCount()
{
return 2;
}
const char* ORCharacterSolver_HIK::GetExtraBoneNameAt(int pIndex)
{
switch (pIndex)
{
case LEFT_EXTRA_COLLAR:
break;
case RIGHT_EXTRA_COLLAR:
break;
}
return NULL;
}
FBBodyPartId ORCharacterSolver_HIK::GetExtraBoneBodyPartAt(int pIndex)
{
switch (pIndex)
{
case LEFT_EXTRA_COLLAR:
break;
case RIGHT_EXTRA_COLLAR:
break;
}
}
void ORCharacterSolver_HIK::RegisterExtraProperties(HIKCharacterHost<HIKHostNodeMB,HIKHostPropertyMB> &pHIKCharacterHost)
{
// extra HIK 3.6 Properties
pHIKCharacterHost.GetProperty(HIKExtraCollarRatioId).Get().Init(NULL, &ExtraCollarRatio, 0,100.f, false);
pHIKCharacterHost.GetProperty(HIKCollarStiffnessX).Get().Init(NULL, &CollarStiffnessX, 0, 100.f, false);
pHIKCharacterHost.GetProperty(HIKCollarStiffnessY).Get().Init(NULL, &CollarStiffnessY, 0,100.f, false);
pHIKCharacterHost.GetProperty(HIKCollarStiffnessZ).Get().Init(NULL, &CollarStiffnessZ, 0, 100.f, false);
pHIKCharacterHost.GetProperty(HIKReachActorLeftShoulderId).Get().Init(NULL, &ReachLeftShoulder, 0, 100.f, false);
pHIKCharacterHost.GetProperty(HIKReachActorRightShoulderId).Get().Init(NULL, &ReachRightShoulder, 0, 100.f, false);
// HIK 4.0 properties
pHIKCharacterHost.GetProperty(HIKFingerPropagationId).Get().Init(&FingerSolvingPropagation, NULL, 0, 1.f, false);
pHIKCharacterHost.GetProperty(HIKRealisticLeftKneeSolvingId).Get().Init(NULL, &RealisticLeftKneeSolving, 0, 100.f, false);
pHIKCharacterHost.GetProperty(HIKRealisticRightKneeSolvingId).Get().Init(NULL, &RealisticRightKneeSolving, 0, 100.f, false);
pHIKCharacterHost.GetProperty(HIKRealisticArmSolvingId).Get().Init(NULL,&RealisticArmSolving,0,1.f,false);
pHIKCharacterHost.GetProperty(HIKTopSpineCorrectionId).Get().Init(NULL,&TopSpineCorrection,0,100,false);
pHIKCharacterHost.GetProperty(HIKLowerSpineCorrectionId).Get().Init(NULL,&LowerSpineCorrection,0,100,false);
// SnS
pHIKCharacterHost.GetProperty(HIKStretchStartArmsAndLegs).Get().Init(NULL, &StretchStartArmsAndLegs,0,100,false);
pHIKCharacterHost.GetProperty(HIKStretchStopArmsAndLegs).Get().Init(NULL, &StretchStopArmsAndLegs,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSScaleArmsAndLegs).Get().Init(NULL, &SnSScaleArmsAndLegs,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSReachLeftWrist).Get().Init(NULL, &SnSReachLeftWrist,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSReachRightWrist).Get().Init(NULL, &SnSReachRightWrist,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSReachLeftAnkle).Get().Init(NULL, &SnSReachLeftAnkle,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSReachRightAnkle).Get().Init(NULL, &SnSReachRightAnkle,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSScaleSpine).Get().Init(NULL, &SnSScaleSpine,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSScaleSpineChildren).Get().Init(NULL, &SnSScaleSpineChildren,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSReachChestEnd).Get().Init(NULL, &SnSReachChestEnd,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSScaleNeck).Get().Init(NULL, &SnSScaleNeck,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSReachHead).Get().Init(NULL, &SnSReachHead,0,100,false);
// 2014
for(int i = 0; i < 10; ++i)
{
pHIKCharacterHost.GetSpineMinLength(i).Get().Init(NULL, &SpineMinLength[i],0,100,false);
pHIKCharacterHost.GetSpineMaxLength(i).Get().Init(NULL, &SpineMaxLength[i],0,100,false);
pHIKCharacterHost.GetNeckMinLength(i).Get().Init(NULL, &NeckMinLength[i],0,100,false);
pHIKCharacterHost.GetNeckMaxLength(i).Get().Init(NULL, &NeckMaxLength[i],0,100,false);
}
pHIKCharacterHost.GetHeadMinLength().Get().Init(NULL, &HeadMinLength,0,100,false);
pHIKCharacterHost.GetHeadMaxLength().Get().Init(NULL, &HeadMaxLength,0,100,false);
pHIKCharacterHost.GetProperty(HIKSnSSmoothReach).Get().Init(NULL, &SnSSmoothReach,0,1.0f,false);
}
void ORCharacterSolver_HIK::ResetExtraProperties()
{
RemoveAnimations();
ResetPropertiesToDefault();
}
void ORCharacterSolver_HIK::ResetPropertiesToDefault()
{
Weight = 100;
ExtraCollarRatio = 50;
for(int i = 0; i < 10; ++i)
{
SpineMaxLength[i] = 110.0;
SpineMinLength[i] = 90.0;
NeckMaxLength[i] = 110.0;
NeckMinLength[i] = 90.0;
}
HeadMaxLength = 110.0;
HeadMinLength = 90.0;
CollarStiffnessX = 0;
CollarStiffnessY = 0;
CollarStiffnessZ = 0;
ReachLeftShoulder = 0;
ReachRightShoulder = 0;
FingerSolvingPropagation = false;
RealisticLeftKneeSolving = 0;
RealisticRightKneeSolving = 0;
RealisticArmSolving = false;
//Sns deprecated
LegSNS = false;
ArmSNS = false;
SnSSmoothReach = true;
}
void ORCharacterSolver_HIK::RemoveAnimations()
{
FBUndoManager lUndoManager;
//Clears animation for the properties defined in this class(excludes those defined in the parent classes)
const int lPropertyCount = mSolverPropertiesCount < PropertyList.GetCount() ? mSolverPropertiesCount : PropertyList.GetCount();
for( int lPropID = mInternalPropertiesCount; lPropID < lPropertyCount; ++lPropID )
{
FBProperty* lProp = PropertyList[lPropID];
//Don't touch the ones that are hidden
if( lProp->GetPropertyFlag(kFBPropertyFlagHideProperty) == false )
{
if( lUndoManager.TransactionIsOpen() )
lUndoManager.TransactionAddProperty(lProp);
if( lProp->IsAnimatable() )
{
FBPropertyAnimatable* lEvalProp = (FBPropertyAnimatable*) lProp;
if(lEvalProp)
lEvalProp->SetAnimated(false);
}
}
}
if( lUndoManager.TransactionIsOpen() )
lUndoManager.TransactionAddProperty( &Weight );
Weight.SetAnimated(false);
}
void ORCharacterSolver_HIK::RetargetExtensions( FBEvaluateInfo* pEvalInfo )
{
int lCharacterExtensionCount = TargetCharacter->CharacterExtensions.GetCount();
for(int i = 0; i < lCharacterExtensionCount; i++)
{
FBCharacterExtension* lCharacterExtension = (FBCharacterExtension*)TargetCharacter->CharacterExtensions.GetAt(i);
lCharacterExtension->RetargetAnimation( pEvalInfo );
}
}
void ORCharacterSolver_HIK::FilterBodyParts(HIKEvaluationState* pPasteState, HIKEvaluationState* pCurrentState)
{
// get active body parts
bool lActiveBodyPart[kFBLastCtrlSetPartIndex];
TargetCharacter->GetActiveBodyPart(lActiveBodyPart);
//Get character description and state data description
int lNodeIdDesc[LastNodeId + 1];
HIKDataDescription lDescription = {
HIKDataDescription::HIKLocalSpace,
offsetof(KHIKNodeState, mTfv),
offsetof(KHIKNodeState, mQfv),
offsetof(KHIKNodeState, mSfv),
sizeof(KHIKNodeState),
lNodeIdDesc
};
// get character description
HIKFillCharacterDescription(mHIKCharacter, lNodeIdDesc);
// get original state set
HIKGetCharacterStateTransformTQS( mHIKCharacter, pCurrentState->mState, &lDescription, pCurrentState->mDataSet);
// get pasted state set
HIKGetCharacterStateTransformTQS( mHIKCharacter, pPasteState->mState, &lDescription, pPasteState->mDataSet);
// override pasted state with original if not active
for(int lNodeCounter = 0; lNodeCounter < kFBLastNodeId_Old; lNodeCounter++)
{
HIKNodeId lHIKNodeId = FBBodyNodeIdToHIKNodeId((FBBodyNodeId)lNodeCounter);
if( HIKGetNodeUse(mHIKCharacter, lHIKNodeId) && lActiveBodyPart[FBGetBodyNodeBodyPart((FBBodyNodeId)lNodeCounter)] == false )
{
CopyNormalizedState(pPasteState->mDataSet, pCurrentState->mDataSet, lHIKNodeId);
}
}
// override pasted state with original if not active for extra bones
const int lExtraBoneCount = GetExtraBoneCount();
for(int lExtraIndex = 0; lExtraIndex < lExtraBoneCount; lExtraIndex++)
{
HIKNodeId lHIKNodeId = ExtraIndexToHIKNodeId(lExtraIndex);
if(HIKGetNodeUse(mHIKCharacter, lHIKNodeId) && GetExtraBoneModelAt(lExtraIndex) && lActiveBodyPart[GetExtraBoneBodyPartAt(lExtraIndex)] == false)
{
CopyNormalizedState(pPasteState->mDataSet, pCurrentState->mDataSet, lHIKNodeId);
}
}
// set back to pasted pose state
HIKSetCharacterStateTransformTQS(mHIKCharacter, pPasteState->mState, &lDescription, pPasteState->mDataSet);
}
void PropagateTranslationChange(HIKCharacter* pHIKCharacter, HIKCharacter* pHIKFromCharacter, int pNodeID, HIKEvaluationState* pPoseCharacterState, HIKEvaluationState* pOriginalControlSet, HIKCharacterState* pCopyPoseCharacterState)
{
FBQuaternion lNodeQ;
FBVector4d lNodeT, lNodeParentT, lNodeS;
//get the bone current position
HIKGetNodeStateTQSdv(pHIKFromCharacter, pOriginalControlSet->mState, pNodeID, lNodeT.mValue, lNodeQ.mValue, lNodeS.mValue);
HIKGetNodeStateTQSdv(pHIKFromCharacter, pOriginalControlSet->mState, HIKGetParentNodeId(pHIKFromCharacter, pNodeID), lNodeParentT.mValue, lNodeQ.mValue, lNodeS.mValue);
//get the bone length
FBTVector lVector;
FBSub(lVector, lNodeT.mValue, lNodeParentT.mValue);
double lLength = FBLength(lVector);
//change the length of the original character
//get the pasted bone position
FBQuaternion lPoseNodeQ;
FBVector4d lOriginalNodeT, lOriginalNodeParentT, lPoseNodeS;
HIKGetNodeStateTQSdv(pHIKFromCharacter, pCopyPoseCharacterState, pNodeID, lOriginalNodeT.mValue, lPoseNodeQ.mValue, lPoseNodeS.mValue);
HIKGetNodeStateTQSdv(pHIKFromCharacter, pCopyPoseCharacterState, HIKGetParentNodeId(pHIKFromCharacter, pNodeID), lOriginalNodeParentT.mValue, lPoseNodeQ.mValue, lPoseNodeS.mValue);
//get the bone length
FBTVector lOriginalVector;
FBSub(lOriginalVector, lOriginalNodeT.mValue, lOriginalNodeParentT.mValue);
double lOriginalLength = FBLength(lOriginalVector);
//find out if we must change the length of the bone
double lRatio = lLength/lOriginalLength;
//Get T/R/S value of the parent
HIKGetNodeStateTQSdv(pHIKCharacter, pPoseCharacterState->mState,HIKGetParentNodeId(pHIKFromCharacter, pNodeID),lVector.mValue, lNodeQ.mValue, lNodeS.mValue);
FBTVector lNewVector;
FBMult(lNewVector, lOriginalVector, lRatio);
FBAdd(lNewVector, lNewVector, lVector.mValue);
//Get R/S value
HIKGetNodeStateTQSdv(pHIKCharacter, pPoseCharacterState->mState,pNodeID,lVector.mValue, lNodeQ.mValue, lNodeS.mValue);
//Apply new T value
HIKSetNodeStateTQSdv(pHIKCharacter, pPoseCharacterState->mState,pNodeID,lNewVector.mValue, lNodeQ.mValue, lNodeS.mValue);
for(int i = 0; i < HIKGetChildNodeCount(pHIKCharacter, pNodeID); i++)
{
int lChildID = HIKGetChildNodeId(pHIKCharacter, pNodeID, i);
PropagateTranslationChange(pHIKCharacter, pHIKFromCharacter, lChildID, pPoseCharacterState, pOriginalControlSet, pCopyPoseCharacterState);
}
}
void ORCharacterSolver_HIK::ApplyFKTranslation( HIKCharacter* pHIKCharacter,
HIKEvaluationState* pPasteState,
HIKCharacter* pHIKFromCharacter,
HIKEvaluationState* pFromState )
{
//create a copy of the current pasted pose, copy will be used to check the limb length
//the translation modification will be applied on the original pasted pose
HIKCharacterState* lPasteStateCopy = HIKCharacterStateCreate(pHIKCharacter, &malloc);
for(int lNodeCounter = 0; lNodeCounter < kFBLastNodeId_Old; lNodeCounter++)
{
HIKNodeId lHIKNodeId = FBBodyNodeIdToHIKNodeId((FBBodyNodeId)lNodeCounter);
if( HIKGetNodeUse(mHIKCharacter, lHIKNodeId) )
{
FBQuaternion lNodeQ;
FBVector4d lNodeT, lNodeS;
HIKGetNodeStateTQSdv(pHIKCharacter, pPasteState->mState,lHIKNodeId,lNodeT.mValue, lNodeQ.mValue, lNodeS.mValue);
HIKSetNodeStateTQSdv(pHIKCharacter, lPasteStateCopy,lHIKNodeId,lNodeT.mValue, lNodeQ.mValue, lNodeS.mValue);
}
}
//apply the translation offset on each bone recursively, starting from the hips
if(HIKGetNodeUse(pHIKFromCharacter, HipsNodeId))
{
for(int i = 0; i < HIKGetChildNodeCount(pHIKCharacter, HipsNodeId); i++)
{
int lChildID = HIKGetChildNodeId(pHIKCharacter, HipsNodeId, i);
PropagateTranslationChange(pHIKCharacter, pHIKFromCharacter, lChildID, pPasteState, pFromState, lPasteStateCopy);
}
}
HIKCharacterStateDestroy(lPasteStateCopy,&free);
}
void ORCharacterSolver_HIK::SolverPasteCharacterPose( HIKCharacter* pHIKCharacter,
HIKEvaluationState* pPasteState, HIKEvaluationState* pCurrentState,
HIKCharacter* pHIKFromCharacter, HIKEvaluationState* pFromState,
FBCharacterPose* pPose, FBCharacterPoseOptions& pCharacterPoseOptions,
FBMatrix& pHipsOffsetGX, FBEvaluateInfo* pPasteEvaluateInfo)
{
// copy pFromCharacterState and paste to lPoseState
HIKPasteState( pHIKCharacter, pPasteState->mState, pCurrentState->mState,
pHIKFromCharacter, pFromState->mState,
pCurrentState->mPropertySetState, pFromState->mPropertySetState,
(double*)pHipsOffsetGX );
//if we are in body part mode, replace paste parts with pCurrentState
if(pCharacterPoseOptions.mCharacterPoseKeyingMode == kFBCharacterPoseKeyingModeBodyPart)
{
FilterBodyParts(pPasteState, pCurrentState);
}
//update effectors to align with control rig
HIKEffectorSetFromCharacter(pHIKCharacter, pPasteState->mEffectorSetState, pPasteState->mState, pCurrentState->mPropertySetState);
// candidate whole character and control rig and effectors
mHIKControlRigHostEvaluator.WriteRigCandidate(pPasteEvaluateInfo, pPasteState, true);
mHIKControlRigHostEvaluator.WriteCandidate(pPasteEvaluateInfo, pPasteState);
// candidate extensions
DoPasteCharacterExtension(pPose, pCharacterPoseOptions, pPasteState, pPasteEvaluateInfo);
}
void ORCharacterSolver_HIK::CharacterPasteState( FBCharacter* pFromCharacter, FBCharacterPose* pPose, FBCharacterPoseOptions& pCharacterPoseOptions )
{
//no pose without a control rig
if(mHIKControlRigHostEvaluator.mHIKCharacter == 0) return;
// get HIK character and state from Pose
HIKCharacter* lHIKFromCharacter = NULL;
HIKEvaluationState lFromState;
PastePoseToTempHikCharacter( pFromCharacter, pPose, pCharacterPoseOptions, lHIKFromCharacter, &lFromState );
// get match options
const bool lMatchRotation = pCharacterPoseOptions.GetFlag( kFBCharacterPoseMatchR ) && pCharacterPoseOptions.mModelToMatch != NULL;
const bool lMatchTranslation = pCharacterPoseOptions.GetFlag( (FBCharacterPoseFlag)(kFBCharacterPoseMatchTX | kFBCharacterPoseMatchTY | kFBCharacterPoseMatchTZ) ) && pCharacterPoseOptions.mModelToMatch != NULL;
const bool lMatchFKTranslation = pCharacterPoseOptions.GetFlag( (FBCharacterPoseFlag)(kFBCharacterPoseMatchFKTranslation) ) && pCharacterPoseOptions.mModelToMatch != NULL;
FBMatrix lHipsOffset_GX;
FBMatrix lMatchModel_GX;
FBMatrix lMatchModel_PoseGX;
// get match position
if(pCharacterPoseOptions.mModelToMatch)
{
pCharacterPoseOptions.mModelToMatch->GetMatrix(lMatchModel_GX, kModelTransformation, true, FBGetDisplayInfo());
}
// get background evaluation for this pose pasting
FBEvaluateInfo* lEvaluation = BackgroundEvaluateInfoBegin(FBGetDisplayInfo(), true);
HIKEvaluationState* lCurrentState = GetState(FBGetDisplayInfo(), this);
HIKEvaluationState* lPasteState = GetState(lEvaluation, this);
// tweak properties for pose paste
HIKSetPropertyValue(lCurrentState->mPropertySetState, HIKSnSSmoothReach, 0.0f);
HIKSetPropertyValue(lCurrentState->mPropertySetState, HIKPullIterationCount, 30.0f);
HIKSetPropertyMode(lCurrentState->mPropertySetState, HIKMirrorId, 0.0f);
// paste character
SolverPasteCharacterPose( mHIKCharacter, lPasteState, lCurrentState, lHIKFromCharacter, &lFromState, pPose, pCharacterPoseOptions, lHipsOffset_GX, lEvaluation );
if(lMatchRotation)
{
OR_HIK_ASSERT(pCharacterPoseOptions.mModelToMatch);
// reset cache
BackgroundEvaluateInfoEnd(lEvaluation);
lEvaluation = BackgroundEvaluateInfoBegin(FBGetDisplayInfo(), true);
// because we are having background resolving evaluation info and this is first read, we will get proper solved data
pCharacterPoseOptions.mModelToMatch->GetMatrix(lMatchModel_PoseGX, kModelTransformation, true, lEvaluation);
GetRotationOffset( lMatchModel_GX, lMatchModel_PoseGX, pCharacterPoseOptions, lHipsOffset_GX );
// reset cache
BackgroundEvaluateInfoEnd(lEvaluation);
lEvaluation = BackgroundEvaluateInfoBegin(FBGetDisplayInfo(), true);
// paste character with correct rotation
SolverPasteCharacterPose( mHIKCharacter, lPasteState, lCurrentState, lHIKFromCharacter, &lFromState, pPose, pCharacterPoseOptions, lHipsOffset_GX, lEvaluation );
}
if(lMatchTranslation)
{
OR_HIK_ASSERT(pCharacterPoseOptions.mModelToMatch);
// reset cache
BackgroundEvaluateInfoEnd(lEvaluation);
lEvaluation = BackgroundEvaluateInfoBegin(FBGetDisplayInfo(), true);
// because we are having background resolving evaluation info and this is first read, we will get proper solved data
pCharacterPoseOptions.mModelToMatch->GetMatrix(lMatchModel_PoseGX, kModelTransformation, true, lEvaluation);
GetTranslationOffset( lMatchModel_GX, lMatchModel_PoseGX, pCharacterPoseOptions, lHipsOffset_GX );
// reset cache
BackgroundEvaluateInfoEnd(lEvaluation);
lEvaluation = BackgroundEvaluateInfoBegin(FBGetDisplayInfo(), true);
// paste character with correct translation (doesn't affect previous rotation offset)
SolverPasteCharacterPose( mHIKCharacter, lPasteState, lCurrentState, lHIKFromCharacter, &lFromState, pPose, pCharacterPoseOptions, lHipsOffset_GX, lEvaluation );
}
if(lMatchFKTranslation)
{
// reset cache
BackgroundEvaluateInfoEnd(lEvaluation);
lEvaluation = BackgroundEvaluateInfoBegin(FBGetDisplayInfo(), true);
// because we are having background resolving evaluation info and this is first read, we will get proper solved data
ApplyFKTranslation( mHIKCharacter, lPasteState, lHIKFromCharacter, &lFromState );
//if we are in body part mode, replace paste parts with pCurrentState
if(pCharacterPoseOptions.mCharacterPoseKeyingMode == kFBCharacterPoseKeyingModeBodyPart)
{
FilterBodyParts(lPasteState, lCurrentState);
}
//update effectors to align with control rig
HIKEffectorSetFromCharacter(mHIKCharacter, lPasteState->mEffectorSetState, lPasteState->mState, lCurrentState->mPropertySetState);
// candidate whole character and control rig and effectors
mHIKControlRigHostEvaluator.WriteRigCandidate(lEvaluation, lPasteState, true);
mHIKControlRigHostEvaluator.WriteCandidate(lEvaluation, lPasteState);
}
// release background evaluation info!
BackgroundEvaluateInfoEnd(lEvaluation);
}
void ORCharacterSolver_HIK::DoPasteCharacterExtension(FBCharacterPose* pPose, FBCharacterPoseOptions& pCharacterPoseOptions, HIKEvaluationState* pCurrentState, FBEvaluateInfo* pPasteEvaluateInfo)
{
FBCharacter* lToCharacter = TargetCharacter;
int lCharacterExtensionCount = lToCharacter->CharacterExtensions.GetCount();
for(int i = 0; i < lCharacterExtensionCount; i++)
{
//
// Ignore the unselected extension in Body Part
//
FBCharacterExtension* lCharacterExtension = (FBCharacterExtension*)lToCharacter->CharacterExtensions.GetAt(i);
if( pCharacterPoseOptions.mCharacterPoseKeyingMode == kFBCharacterPoseKeyingModeBodyPart )
{
if( lCharacterExtension != NULL && !lCharacterExtension->IsElementSelected() )
continue;
}
FBObjectPose* lCharacterExtPose = NULL;
if(lCharacterExtension != NULL)
{
lCharacterExtPose = pPose->GetCharacterExtensionPose(lCharacterExtension->Label);
}
if(lCharacterExtension && lCharacterExtPose)
{
FBObjectPoseOptions* lObjectPoseOptions = new FBObjectPoseOptions();
//
// Set the transform type
//
if( pCharacterPoseOptions.mCharacterPoseKeyingMode == kFBCharacterPoseKeyingModeFullBody )
{
//
// Full body, paste the local transform relative to the reference.
// If the extension has no reference, it will be relative to the hips.
//
lObjectPoseOptions->mPoseTransformType = kFBPoseTransformLocalRef;
}
else if( pCharacterPoseOptions.mCharacterPoseKeyingMode == kFBCharacterPoseKeyingModeBodyPart )
{
//
// Body Part, paste the local transform relative to the reference if there's a reference or if we mirror.
// Otherwise paste the pure local transform.
//
if( lCharacterExtension->ReferenceModel != 0 || pCharacterPoseOptions.GetFlag( kFBCharacterPoseMirror ) )
{
lObjectPoseOptions->mPoseTransformType = kFBPoseTransformLocalRef;
}
else
{
lObjectPoseOptions->mPoseTransformType = kFBPoseTransformLocal;
}
}
//
// Paste extension
// Mirroring logic follows KCharacterPose::MirrorCharacterExtension
//
FBModel* lReferenceModel = lCharacterExtension->ReferenceModel != NULL ? lCharacterExtension->ReferenceModel : lToCharacter->GetModel( kFBHipsNodeId );
if(lReferenceModel)
{
lReferenceModel->GetVector(*(FBVector3d*)(&lObjectPoseOptions->mReferenceGT), kModelTranslation, true, pPasteEvaluateInfo);
lReferenceModel->GetMatrix(lObjectPoseOptions->mReferenceGRM, kModelRotation, true, pPasteEvaluateInfo);
lReferenceModel->GetMatrix(lObjectPoseOptions->mReferenceGSM, kModelScaling, true, pPasteEvaluateInfo);
}
else
{
lObjectPoseOptions->mReferenceGT.Init();
lObjectPoseOptions->mReferenceGRM.Identity();
lObjectPoseOptions->mReferenceGSM.Identity();
}
if(pCharacterPoseOptions.GetFlag(kFBCharacterPoseMirror) &&
lCharacterExtension->GetMirrorExtension() && // source extension i.e. "mirror partner"
pPose->GetCharacterExtensionPose(lCharacterExtension->GetMirrorExtension()->Label)) // source extension pose
{
FBVector4<double> lMirrorPlaneEquation;
pPose->GetMirrorPlaneEquation(lMirrorPlaneEquation, *lToCharacter, pCharacterPoseOptions);
FBObjectPose lMirrorExtensionPose(FBComponentGetLongName(lCharacterExtPose));
//
// Get source extension i.e. "mirror partner"
//
FBCharacterExtension* lSrcCharacterExtension = lCharacterExtension->GetMirrorExtension();
OR_HIK_ASSERT(lSrcCharacterExtension);
//
// Get source extension pose
//
FBObjectPose* lSrcExtensionPose = pPose->GetCharacterExtensionPose(lSrcCharacterExtension->Label);
OR_HIK_ASSERT(lSrcExtensionPose);
int lObjectIter = 0;
for( lObjectIter = 0; lObjectIter < lCharacterExtension->GetSubObjectCount(); lObjectIter++ )
{
FBModel* lObject = (FBModel*)(lCharacterExtension->GetSubObject(lObjectIter));
if( lObject )
{
FBString lObjectLabel;
lCharacterExtension->GetLabelNameWithExtensionObject(lObjectLabel,lObject,true);
//
// Retarget the non-transform properties from the SrcPose to the ResultPose.
// ** This will actually copy all the stored properties from the SrcPose.
//
FBObjectPose::RetargetPose
(
lMirrorExtensionPose,
*lSrcExtensionPose,
lObjectLabel,
lObjectLabel
);
//
// Get the stance poses.
//
FBObjectPose* lSrcStancePose = lSrcCharacterExtension->GetStancePose();
FBObjectPose* lDstStancePose = lCharacterExtension->GetStancePose();
if( lSrcStancePose && lDstStancePose )
{
//
// Mirror re-target the transform properties.
//
FBObjectPose::MirrorRetargetPose
(
lMirrorExtensionPose,
*lSrcExtensionPose,
*lDstStancePose,
*lSrcStancePose,
lMirrorPlaneEquation,
lObjectLabel,
lObjectLabel
);
}
lMirrorExtensionPose.PasteTransform( (char*)lObjectLabel, *lObject, *lObjectPoseOptions, pPasteEvaluateInfo );
}
}
}
else
{
int lObjectIter = 0;
for( lObjectIter = 0; lObjectIter < lCharacterExtension->GetSubObjectCount(); lObjectIter++ )
{
FBModel* lObject = (FBModel*)(lCharacterExtension->GetSubObject(lObjectIter));
if( lObject )
{
FBString lObjectLabel;
lCharacterExtension->GetLabelNameWithExtensionObject(lObjectLabel,lObject,true);
lCharacterExtPose->PasteTransform( (char*)lObjectLabel, *lObject, *lObjectPoseOptions, pPasteEvaluateInfo );
}
}
}
}
}
}
void ORCharacterSolver_HIK::GetRotationOffset( const FBMatrix& pMatchModel_GX, const FBMatrix& pMatchMode_PoseTRSM, const FBCharacterPoseOptions& pCharacterPoseOptions, FBMatrix& pHipsOffsetGX )
{
FBMatrix lOffsetRM;
FBMatrixInverse( lOffsetRM, pMatchMode_PoseTRSM );
FBMatrixMult( lOffsetRM, pMatchModel_GX, lOffsetRM );
if( pCharacterPoseOptions.GetFlag( kFBCharacterPoseGravity ) )
{
FBTVector lFloorUp( 0.0, 1.0, 0.0, 0.0 );
FBMatrix lRM;
FBTVector lTempVector = (FBTVector &)lOffsetRM(1,0);
FBMult((FBTVector &)lQ,lTempVector,lFloorUp);
lQ[3] = FBDot(lTempVector,lFloorUp) + FBLength(lTempVector) * FBLength(lFloorUp);
FBMatrixMult( lOffsetRM, lRM, lOffsetRM );
}
// this is done this way to make sure that hips offset only receive rotation without scale.
FBRVector lTempRVector;
FBMatrixToRotation(lTempRVector, lOffsetRM);
FBRotationToMatrix(pHipsOffsetGX, lTempRVector);
}
void ORCharacterSolver_HIK::GetTranslationOffset( const FBMatrix& pMatchModel_GX, const FBMatrix& pMatchMode_PoseTRSM, const FBCharacterPoseOptions& pCharacterPoseOptions, FBMatrix& pHipsOffsetGX )
{
//
// Compute the offset.
//
FBTVector lMatch_GT;
FBTVector lOffsetT;
FBTVector lPastedVector;
FBMatrixToTranslation(lPastedVector, pMatchMode_PoseTRSM);
FBMatrixToTranslation( lMatch_GT, pMatchModel_GX );
FBSub( lOffsetT, lMatch_GT, lPastedVector );
// Keep only the component(s) we should match
if( !pCharacterPoseOptions.GetFlag( kFBCharacterPoseMatchTX ) )
{
lOffsetT[0] = 0.0;
}
if( !pCharacterPoseOptions.GetFlag( kFBCharacterPoseMatchTY ) || pCharacterPoseOptions.GetFlag( kFBCharacterPoseGravity ) )
{
lOffsetT[1] = 0.0;
}
if( !pCharacterPoseOptions.GetFlag( kFBCharacterPoseMatchTZ ) )
{
lOffsetT[2] = 0.0;
}
// make sure we only add rotation part
pHipsOffsetGX(3,0) = lOffsetT[0];
pHipsOffsetGX(3,1) = lOffsetT[1];
pHipsOffsetGX(3,2) = lOffsetT[2];
pHipsOffsetGX(3,3) = lOffsetT[3];
}
void ORCharacterSolver_HIK::PastePoseToTempHikCharacter( FBCharacter* pFromCharacter, FBCharacterPose* pPose, FBCharacterPoseOptions& pCharacterPoseOptions,
HIKCharacter*& pHIKFromCharacter, HIKEvaluationState* pTempState )
{
//Get the destination character
FBCharacter* lToCharacter = TargetCharacter;
//undo support
UndoSetup(lToCharacter);
HIKCharacterHost<HIKHostNodeMB,HIKHostPropertyMB> lHIKFromCharacterHost;
HIKHostPropertiesInit(lHIKFromCharacterHost);
HIKCharacterHostFromFBCharacterPose(lHIKFromCharacterHost, pFromCharacter, pPose);
HIKCharacterFromFBCharacterPose(lHIKFromCharacterHost, pHIKFromCharacter, pFromCharacter, pPose);
HIKHostPropertiesFromCharacter(lHIKFromCharacterHost, pFromCharacter);
RegisterExtraProperties(lHIKFromCharacterHost); //kxl: those properties should come from source solver!
pTempState->Init(pHIKFromCharacter, NULL, &malloc);
lHIKFromCharacterHost.ReadFromPose(pHIKFromCharacter, FBGetDisplayInfo(), pTempState->mState, pPose);
lHIKFromCharacterHost.ReadCharacterAndPropertiesForSolve(pHIKFromCharacter, pTempState->mPropertySetState, FBGetDisplayInfo());
//Apply the mirror if necessary
if(pCharacterPoseOptions.GetFlag(kFBCharacterPoseMirror))
{
FBMatrix lMirrorPlaneMatrix;
pPose->GetMirrorPlaneEquation(lMirrorPlaneMatrix, *lToCharacter, pCharacterPoseOptions);
FBQuaternion lMirrorPlaneEquationQ;
FBMatrixToQuaternion(lMirrorPlaneEquationQ, lMirrorPlaneMatrix);
HIKMirrorState( pHIKFromCharacter, pTempState->mState, pTempState->mState, pHIKFromCharacter, lMirrorPlaneEquationQ.mValue);
}
}
bool ORCharacterSolver_HIK::FbxStore( FBFbxObject* pFbxObject, kFbxObjectStore pStoreWhat )
{
return true;
}
bool ORCharacterSolver_HIK::FbxRetrieve( FBFbxObject* pFbxObject, kFbxObjectStore pStoreWhat )
{
return true;
}
void ORCharacterSolver_HIK::FreezeSuggested()
{
FBConstraint::FreezeSuggested();
if( ReferenceGet( 0,0 ) )
{
FreezeSRT( (FBModel*)ReferenceGet( 0, 0), true, true, true );
}
}
static FBPlug* FindDstPropertyWithOwner(FBPlug* pPlug, FBPlug* pOwner)
{
OR_HIK_ASSERT(pPlug && pOwner);
const int lDstCount = pPlug->GetDstCount();
for(int lDstIndex = 0; lDstIndex < lDstCount; lDstIndex++)
{
FBPlug* lDstPlug = pPlug->GetDst(lDstIndex);
// if plug has an owner, then it's for sure property, but to make it safe
if(lDstPlug->GetOwner() == pOwner && FBIS(lDstPlug, FBProperty))
{
return lDstPlug;
}
}
return NULL;
}
void ORCharacterSolver_HIK::AddSolverPropertiesToCharacter(FBCharacter* pDstCharacter)
{
if(FBUndoManager().ActiveOperation()) return;
const int lPropertyCount = mSolverPropertiesCount < PropertyList.GetCount() ? mSolverPropertiesCount : PropertyList.GetCount();
for(int i = mInternalPropertiesCount; i < lPropertyCount; i++)
{
FBProperty* lProp = PropertyList[i];
if(lProp->GetPropertyFlag(kFBPropertyFlagNotSavable) == false)
{
// make sure not to add it twice
if(FindDstPropertyWithOwner(lProp, pDstCharacter) == NULL)
{
pDstCharacter->PropertyAddReferenceProperty(lProp);
}
}
}
}
void ORCharacterSolver_HIK::RemoveSolverPropertiesFromCharacter(FBCharacter* pDstCharacter)
{
const int lPropertyCount = mSolverPropertiesCount < PropertyList.GetCount() ? mSolverPropertiesCount : PropertyList.GetCount();
for(int i = mInternalPropertiesCount; i < lPropertyCount; i++)
{
FBProperty* lProp = PropertyList[i];
if(lProp->GetPropertyFlag(kFBPropertyFlagNotSavable) == false)
{
FBProperty* lRefProp = (FBProperty*)FindDstPropertyWithOwner(lProp, pDstCharacter);
if(lRefProp)
{
pDstCharacter->PropertyRemove(lRefProp);
}
}
}
}
void ORCharacterSolver_HIK::RenameSolverPropertiesOnCharacters()
{
FBString lNewName;
const int lPropertyCount = mSolverPropertiesCount < PropertyList.GetCount() ? mSolverPropertiesCount : PropertyList.GetCount();
for(int i = mInternalPropertiesCount; i < lPropertyCount; i++)
{
FBProperty* lSourceProp = PropertyList[i];
if(lSourceProp->GetPropertyFlag(kFBPropertyFlagNotSavable) == false)
{
const int lDstCount = lSourceProp->GetDstCount();
for(int lDstIndex = 0; lDstIndex < lDstCount; lDstIndex++)
{
FBPlug* lDstPlug = lSourceProp->GetDst(lDstIndex);
// if plug has an owner, then it's for sure property, but to make it safe
if(FBIS(lDstPlug->GetOwner(), FBCharacter) && FBIS(lDstPlug, FBProperty))
{
FBProperty* lRefProperty = (FBProperty*)lDstPlug;
if(lRefProperty->IsReferenceProperty())
{
lNewName = (const char*)this->Name;
lNewName += ".";
lNewName += lSourceProp->GetName();
lRefProperty->SetName((const char*)lNewName);
}
}
}
}
}
}
void ORCharacterSolver_HIK::SyncVisibilitySolverPropertiesOnCharacters(FBProperty* pSourceProperty, FBProperty* pRefProperty)
{
const bool lSourceHidden = pSourceProperty->GetPropertyFlag(kFBPropertyFlagHideProperty);
if(pRefProperty)
{
OR_HIK_ASSERT(pRefProperty->IsReferenceProperty() && pRefProperty->GetSrcCount() > 0);
pRefProperty->ModifyPropertyFlag(kFBPropertyFlagNotSavable, true);
pRefProperty->ModifyPropertyFlag((FBPropertyFlag)(kFBPropertyFlagHideProperty | kFBDynamicHidden), lSourceHidden);
}
else
{
const int lDstCount = pSourceProperty->GetDstCount();
for(int lDstIndex = 0; lDstIndex < lDstCount; lDstIndex++)
{
FBPlug* lDstPlug = pSourceProperty->GetDst(lDstIndex);
// if plug has an owner, then it's for sure property, but to make it safe
if(FBIS(lDstPlug->GetOwner(), FBCharacter) && FBIS(lDstPlug, FBProperty))
{
FBProperty* lRefProperty = (FBProperty*)lDstPlug;
if(lRefProperty->IsReferenceProperty())
{
lRefProperty->ModifyPropertyFlag(kFBPropertyFlagNotSavable, true);
lRefProperty->ModifyPropertyFlag((FBPropertyFlag)(kFBPropertyFlagHideProperty | kFBDynamicHidden), lSourceHidden);
}
}
}
}
}
bool ORCharacterSolver_HIK::PlugNotify(FBConnectionAction pAction,FBPlug* pThis,int pIndex,FBPlug* pPlug,FBConnectionType pConnectionType,FBPlug* pNewPlug )
{
if(pThis == this && FBIS(pPlug, FBCharacter))
{
switch (pAction)
{
{
AddSolverPropertiesToCharacter((FBCharacter*)pPlug);
}
break;
{
RemoveSolverPropertiesFromCharacter((FBCharacter*)pPlug);
}
break;
}
}
else if(pAction == kFBConnectedDst && pThis->GetOwner() == this && FBIS(pThis, FBProperty) && FBIS(pPlug, FBProperty) )
{
FBProperty* lThisProperty = (FBProperty*)pThis;
FBProperty* lRefProperty = (FBProperty*)pPlug;
if(lRefProperty->IsReferenceProperty())
{
SyncVisibilitySolverPropertiesOnCharacters(lThisProperty, lRefProperty);
}
}
return __FBParentClass::PlugNotify(pAction, pThis, pIndex, pPlug, pConnectionType, pNewPlug);
}
bool ORCharacterSolver_HIK::PlugStateNotify(FBConnectionAction pAction,FBPlug* pThis,void* pData,void* pDataOld,int pDataSize)
{
if(pThis == this)
{
switch (pAction)
{
case kFBRenamed:
{
RenameSolverPropertiesOnCharacters();
}
break;
}
}
return __FBParentClass::PlugStateNotify(pAction, pThis, pData, pDataOld, pDataSize);
}
static void AddPropertyViewForSolverAndCharacter(const char* pPropertyName, const char* pHierarchy, bool pAddToCharacter, bool pIsFolder=false)
{
FBPropertyViewManager::TheOne().AddPropertyView(ORCONSTRAINTHIK__CLASSNAME, pPropertyName, pHierarchy);
if(pAddToCharacter)
{
if(!pIsFolder)
{
FBString lPropertyNameWithAnyPrefix = FBString("*.") + pPropertyName;
FBPropertyViewManager::TheOne().AddPropertyView("KCharacter", (const char*)lPropertyNameWithAnyPrefix, pHierarchy);
}
}
}
void ORCharacterSolver_HIK::AddPropertiesToPropertyViewManager()
{
char lNameBuffer[50];
AddPropertyViewForSolverAndCharacter("HIK Library Version", "", false);
AddPropertyViewForSolverAndCharacter("Weight", "", false);
// Solving
AddPropertyViewForSolverAndCharacter("Solving", "", true, true);
AddPropertyViewForSolverAndCharacter("Realistic Left Knee Solving", "Solving", true);
AddPropertyViewForSolverAndCharacter("Realistic Right Knee Solving", "Solving", true);
AddPropertyViewForSolverAndCharacter("Realistic Arm Solving", "Solving", true);
AddPropertyViewForSolverAndCharacter("Extra Collar Ratio", "Solving", true);
//Retargeting
AddPropertyViewForSolverAndCharacter("Retargeting", "", true, true);
AddPropertyViewForSolverAndCharacter("Finger Propagation", "Retargeting", true);
AddPropertyViewForSolverAndCharacter("Top Spine Correction", "Retargeting", true);
AddPropertyViewForSolverAndCharacter("Lower Spine Correction", "Retargeting", true);
//Reach
AddPropertyViewForSolverAndCharacter("Reach", "", true, true);
AddPropertyViewForSolverAndCharacter("Reach Left Shoulder", "Reach", true);
AddPropertyViewForSolverAndCharacter("Reach Right Shoulder", "Reach", true);
//Stretch
AddPropertyViewForSolverAndCharacter("Stretch", "", true, true);
AddPropertyViewForSolverAndCharacter("Stretch Neck", "Stretch", true);
AddPropertyViewForSolverAndCharacter("Stretch Spine", "Stretch", true);
AddPropertyViewForSolverAndCharacter("Stretch Damping", "Stretch", true);
for(int i = 0; i < 10; ++i)
{
sprintf(lNameBuffer,"Spine %i Min Length", i);
AddPropertyViewForSolverAndCharacter(lNameBuffer, "Stretch", true);
sprintf(lNameBuffer,"Spine %i Max Length", i);
AddPropertyViewForSolverAndCharacter(lNameBuffer, "Stretch", true);
}
for(int i = 0; i < 10; ++i)
{
sprintf(lNameBuffer,"Neck %i Min Length", i);
AddPropertyViewForSolverAndCharacter(lNameBuffer, "Stretch", true);
sprintf(lNameBuffer,"Neck %i Max Length", i);
AddPropertyViewForSolverAndCharacter(lNameBuffer, "Stretch", true);
}
AddPropertyViewForSolverAndCharacter("Head Min Length", "Stretch", true);
AddPropertyViewForSolverAndCharacter("Head Max Length", "Stretch", true);
//Stiffness
AddPropertyViewForSolverAndCharacter("Stiffness", "", true, true);
AddPropertyViewForSolverAndCharacter("Collar Stiffness X", "Stiffness", true);
AddPropertyViewForSolverAndCharacter("Collar Stiffness Y", "Stiffness", true);
AddPropertyViewForSolverAndCharacter("Collar Stiffness Z", "Stiffness", true);
//Scale (deprecated)
AddPropertyViewForSolverAndCharacter("Scale (deprecated)", "", true, true);
AddPropertyViewForSolverAndCharacter("Leg SNS", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("Arm SNS", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("StretchStartArmsAndLegs", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("StretchStopArmsAndLegs", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSScaleArmsAndLegs", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSReachLeftWrist", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSReachRightWrist", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSReachLeftAnkle", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSReachRightAnkle", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSScaleSpine", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSScaleSpineChildren", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSScaleNeck", "Scale (deprecated)", true);
//old solvers stuff (we should register this in other solvers, but because all share the same name, lets do it for now in here)
AddPropertyViewForSolverAndCharacter("SnSReachChestEnd", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSReachHead", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSSpineFreedom", "Scale (deprecated)", true);
AddPropertyViewForSolverAndCharacter("SnSNeckFreedom", "Scale (deprecated)", true);
#ifdef _DEBUG
AddPropertyViewForSolverAndCharacter("SolvingStep", "", true, true);
#define AddSolvingStepPropertyView(Step) \
AddPropertyViewForSolverAndCharacter(#Step, "SolvingStep", true); \
AddSolvingStepPropertyView(SolvingStepBodyPull)
AddSolvingStepPropertyView(SolvingStepContact)
AddSolvingStepPropertyView(SolvingStepContactApprox)
AddSolvingStepPropertyView(SolvingStepLeftShoulder)
AddSolvingStepPropertyView(SolvingStepRightShoulder)
AddSolvingStepPropertyView(SolvingStepLeftArm)
AddSolvingStepPropertyView(SolvingStepRightArm)
AddSolvingStepPropertyView(SolvingStepLeftLeg)
AddSolvingStepPropertyView(SolvingStepRightLeg)
AddSolvingStepPropertyView(SolvingStepLeftHand)
AddSolvingStepPropertyView(SolvingStepRightHand)
AddSolvingStepPropertyView(SolvingStepLeftFoot)
AddSolvingStepPropertyView(SolvingStepRightFoot)
AddSolvingStepPropertyView(SolvingStepHead)
AddSolvingStepPropertyView(SolvingStepSpine)
AddSolvingStepPropertyView(SolvingStepHipsTranslation)
AddSolvingStepPropertyView(SolvingStepRollExtraction)
AddSolvingStepPropertyView(SolvingStepLeftArmSnS)
AddSolvingStepPropertyView(SolvingStepRightArmSnS)
AddSolvingStepPropertyView(SolvingStepLeftLegSnS)
AddSolvingStepPropertyView(SolvingStepRightLegSnS)
AddSolvingStepPropertyView(SolvingStepModifiers)
AddSolvingStepPropertyView(SolvingStepAllParts)
#endif
}
#ifdef _DEBUG
#define InitSolvingStep(Step) \
FBPropertyPublish(this, Step, #Step, NULL, OverwriteHIK##Step); \
Step = true; \
void ORCharacterSolver_HIK::InitSolvingProperties()
{
InitSolvingStep(SolvingStepBodyPull)
InitSolvingStep(SolvingStepContact)
InitSolvingStep(SolvingStepContactApprox)
InitSolvingStep(SolvingStepLeftShoulder)
InitSolvingStep(SolvingStepRightShoulder)
InitSolvingStep(SolvingStepLeftArm)
InitSolvingStep(SolvingStepRightArm)
InitSolvingStep(SolvingStepLeftLeg)
InitSolvingStep(SolvingStepRightLeg)
InitSolvingStep(SolvingStepLeftHand)
InitSolvingStep(SolvingStepRightHand)
InitSolvingStep(SolvingStepLeftFoot)
InitSolvingStep(SolvingStepRightFoot)
InitSolvingStep(SolvingStepHead)
InitSolvingStep(SolvingStepSpine)
InitSolvingStep(SolvingStepHipsTranslation)
InitSolvingStep(SolvingStepRollExtraction)
InitSolvingStep(SolvingStepLeftArmSnS)
InitSolvingStep(SolvingStepRightArmSnS)
InitSolvingStep(SolvingStepLeftLegSnS)
InitSolvingStep(SolvingStepRightLegSnS)
InitSolvingStep(SolvingStepModifiers)
InitSolvingStep(SolvingStepAllParts)
}
#endif