Files
vb01/skeleton.cpp
T

121 lines
3.3 KiB
C++

#include "skeleton.h"
#include "animation.h"
#include "animationController.h"
#include "box.h"
#include "ikSolver.h"
#include <glm.hpp>
#include <glm/gtc/matrix_inverse.hpp>
using namespace std;
using namespace glm;
namespace vb01{
void Skeleton::update(){
updateIk();
}
void Skeleton::updateIk(){
for(Bone *b : bones){
if(b->getIkTarget() != ""){
const int chainLength = b->getIkChainLength();
Bone **boneChain = getIkBoneChain(b);
for(int i = 0; i < chainLength; i++){
boneChain[i]->setPosePos(Vector3::VEC_ZERO);
boneChain[i]->setPoseRot(Quaternion::QUAT_W);
boneChain[i]->setPoseScale(Vector3::VEC_IJK);
}
delete[] boneChain;
}
}
for(Bone *b : bones)
if(getBone(b->getIkTarget()))
solveIk(b);
}
void Skeleton::solveIk(Bone *ikBone){
const int chainLength = ikBone->getIkChainLength();
Bone *ikTarget = getBone(ikBone->getIkTarget());
Bone *subBase = (Bone*)ikTarget->getParent();
Bone **boneChain = getIkBoneChain(ikBone);
Vector3 *boneIkPos = new Vector3[chainLength];
for(int i = chainLength - 1; i >= 0; i--)
boneIkPos[i] = subBase->globalToLocalPosition(boneChain[i]->localToGlobalPosition(Vector3::VEC_ZERO));
Vector3 targetPos = subBase->globalToLocalPosition(ikTarget->localToGlobalPosition(Vector3::VEC_ZERO));
IkSolver::calculateFabrik(chainLength, boneChain, boneIkPos, targetPos);
transformIkChain(chainLength, boneChain, boneIkPos, ikTarget);
delete[] boneIkPos;
delete[] boneChain;
}
void Skeleton::transformIkChain(int chainLength, Bone **boneChain, Vector3 boneIkPos[], Bone* ikTarget){
Bone *subBase = (Bone*)ikTarget->getParent();
for(int i = chainLength - 1; i >= 0; i--){
boneChain[i]->setPoseRot(Quaternion::QUAT_W);
Vector3 tailPosBoneSpace;
if(i == 0)
tailPosBoneSpace = subBase->globalToLocalPosition(ikTarget->localToGlobalPosition(Vector3::VEC_ZERO));
else
tailPosBoneSpace = boneIkPos[i - 1];
Vector3 tailRestPosBoneSpace = subBase->globalToLocalPosition(boneChain[i]->localToGlobalPosition(Vector3(0, boneChain[i]->getLength(), 0)));
Vector3 headRestPosBoneSpace = subBase->globalToLocalPosition(boneChain[i]->localToGlobalPosition(Vector3::VEC_ZERO));
Vector3 headDir = (tailPosBoneSpace - headRestPosBoneSpace).norm();
Vector3 boneDir = (tailRestPosBoneSpace - headRestPosBoneSpace).norm();
Vector3 axis = boneDir.cross(headDir).norm();
axis =
boneChain[i]->globalToLocalPosition(subBase->localToGlobalPosition(axis)) -
boneChain[i]->globalToLocalPosition(subBase->localToGlobalPosition(Vector3::VEC_ZERO));
if(axis == Vector3::VEC_ZERO)
axis = Vector3::VEC_I;
float angle = boneDir.getAngleBetween(headDir);
boneChain[i]->setPoseRot(Quaternion(angle, axis));
}
}
void Skeleton::addBone(Bone *bone, Bone *parent){
if(parent)
parent->attachChild(bone);
bones.push_back(bone);
bone->setSkeleton(this);
}
Bone* Skeleton::getBone(string name){
Bone *bone = nullptr;
for(Bone *b : bones)
if(b->getName() == name){
bone = b;
break;
}
return bone;
}
Bone** Skeleton::getIkBoneChain(Bone *ikBone){
int chainLength = ikBone->getIkChainLength();
Bone **chain = new Bone*[chainLength];
Bone *ikBoneAncestor = ikBone;
for(int i = 0; i < chainLength; i++){
chain[i] = ikBoneAncestor;
ikBoneAncestor = (Bone*)ikBoneAncestor->getParent();
}
return chain;
}
}