Importing skeleton and setting up the solver

A skeleton is imported into the solver by using a vector of ImportBone structures (defined in IKSolver.h). The structure defines all the information that is needed:

struct DLL_EXPORT ImportBone
{
    const char* name;
    const char* parentname;//set NULL if no parent
    Real rest_orientation[4]; //local orientation of the bone in the "bind pose", format: quaternion {w,x,y,z}
    Real rest_offset[3];//offset vector from parent (parent space)in the "bind pose", format: vector{x,y,z}
				//use current scale for positions

    Real limits[4][2]; //limits: x, y, z, delta roll (degrees)
    int projection_axis;
    int rotation_axis;
    Real rotation_axis_vector[3];
    bool enforce_limit;

    ImportBone();
    ImportBone& operator=(const ImportBone& other);
    ImportBone(const ImportBone& other);
};

The following example code is extracted from Hello IKinema Demo project to import skeleton data from file:

IKSolver* mSolver = FIK::IKSolver::create();
// The file describes all bones from the source skeleton structure in the
// following format:
//	[bone name]
//	[parent bone name] - The string "0" is reserved in our demo to mark bones with no parent.
//	[bone rest offset X], [bone rest offset Y], [bone rest offset Z]
//	[bone rest orientation X], [bone rest orientation Y], [bone rest orientation Z], [bone rest orientation W]
std::ifstream skeletonFile( /*NAME OF THE FILE WITH OUR SKELETON DATA*/ );
std::vector< FIK::ImportBone > vecSkeletonData;
while( skeletonFile.good() )
{
    FIK::ImportBone curBone;
    std::string strBoneName, strBoneParentName;
    skeletonFile >> strBoneName >> strBoneParentName;
    skeletonFile >> curBone.rest_offset[0] >> curBone.rest_offset[1] >> curBone.rest_offset[2];
    skeletonFile >> curBone.rest_orientation[1] >> curBone.rest_orientation[2] >> curBone.rest_orientation[3] >> curBone.rest_orientation[0];	
    curBone.name = strBoneName.c_str();
    curBone.parentname = 0;
    if( strBoneParentName != "0" )
        curBone.parentname = strBoneParentName.c_str();
    if( ! skeletonFile.good() )
        break;
    vecSkeletonData.push_back( curBone );
}
skeletonFile.close();
mSolver->importBones(mImportSkeleton.begin(), (unsigned int) mImportSkeleton.size());


The resulting order of segments will be in the order of mImportSkeleton. Each segment will have an id that derives from the position in the ImportBone vector. It can be checked with

IKSegment::SegmentId().

To modify the skeleton structure loaded into IKinema RunTime, the functions

IKSegment::setRestOrientation(x,y,z,w), and IKSegment::setRestTranslation(x,y,z) 

can be called subsequently if the source bone parameters change. The hierarchy can only be changed by re-importing the skeleton through

IKSolver::importBones(ImportBone* first_bone, unsigned int count)

Each segment will also have a target orientation associated with it to comply with joint limits if there is no target orientation set from animation/motion capture via retargeting. By default, this will be the orientation in the rest configuration for all bones. This is not always the optimal target as some rest orientations are near a joint limit (as for the knee) and custom limits might be required for each skeleton. Target Orientation and Target Translation can be used to specify rotation and translation outside the solver.

Custom limits can be set with

IKSegment::setLimits(int axis, Real min, Real max) 

for limits expressed as maximum/minimum projections of the bone axis onto the parent axes, which is the native IKinema format. Further details on the format are given in IKSegment.h.

Alternatively, 

IKSegment::setEulerLimits(EulerLimits &limits, bool relative_rest=true) 

can be used instead if the limit information is in the conventional Euler rotations format. The rotations are taken about the local bone axes in the rest configuration for relative_rest==true and about the current local axes for relative_rest==false.


Each of the 4 rotations (min/max for three axes) is considered separately, it is not required to give the order of the rotations. The function

IKSegment::enableLimits(false) 

will remove limits solving from the segment in question and

IKSegment::enableLimits(true) 

will enable solving for limits.

Note that if a bone has retargeting information set by setTargetOrientation, then the limits are not used. 

One can dynamically change the number of solved bones via setting the bone active/non-active. For example 

mSolver->getSegment("Hips")->setActive(false);

In this way a bone is removed from solving. Bones can be also excluded on a degree-of-freedom basis, for one, two or all three DOF.