mirror of
https://github.com/devZoGok/vb01.git
synced 2026-08-26 19:43:30 +00:00
144 lines
3.8 KiB
C++
144 lines
3.8 KiB
C++
#include"skeleton.h"
|
|
#include"animation.h"
|
|
#include"animationController.h"
|
|
#include"box.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace vb01{
|
|
Skeleton::Skeleton(string name){
|
|
this->name=name;
|
|
controller = new AnimationController(this);
|
|
}
|
|
|
|
void Skeleton::update(){
|
|
for(Bone *b : bones){
|
|
//b->update();
|
|
if(b->getIkTarget())
|
|
solveIk(b);
|
|
}
|
|
controller->update();
|
|
}
|
|
|
|
void Skeleton::solveIk(Bone *ikBone){
|
|
const int chainLength = ikBone->getIkChainLength();
|
|
Bone *rootBone = getRootBone();
|
|
Bone *ikTarget = ikBone->getIkTarget();
|
|
Bone *boneChain[chainLength];
|
|
Bone *ikBoneAncestor = ikBone;
|
|
Vector3 boneIkPos[chainLength];
|
|
Vector3 targetPos = rootBone->globalToLocalPosition(ikTarget->localToGlobalPosition(Vector3::VEC_ZERO));
|
|
|
|
for(int i = 0; i < chainLength; i++){
|
|
boneChain[i] = ikBoneAncestor;
|
|
ikBoneAncestor = (Bone*)ikBoneAncestor->getParent();
|
|
boneIkPos[i] = rootBone->globalToLocalPosition(boneChain[i]->localToGlobalPosition(Vector3::VEC_ZERO));
|
|
boneIkPos[i] = boneChain[i]->getModelSpacePos();
|
|
}
|
|
|
|
calculateFabrik(chainLength, boneChain, boneIkPos, targetPos);
|
|
|
|
transformIkChain(chainLength, boneChain, boneIkPos, targetPos);
|
|
}
|
|
|
|
void Skeleton::calculateFabrik(int chainLength, Bone *boneChain[], Vector3 boneIkPos[], Vector3 targetPos){
|
|
float sumLengths = 0;
|
|
for(int i = 0; i < chainLength; i++)
|
|
sumLengths += boneChain[i]->getLength();
|
|
|
|
Vector3 startPos = boneChain[chainLength - 1]->getModelSpacePos();
|
|
if(startPos.getDistanceFrom(targetPos) < sumLengths){
|
|
int numIterations = 500;
|
|
|
|
for(int i = 0 ; i < numIterations; i++){
|
|
bool backward = (i % 2 == 0);
|
|
for(int j = 0; j < chainLength; j++){
|
|
int boneId;
|
|
float length;
|
|
Vector3 ikPos, bonePos, fromBoneToIkPos;
|
|
if(backward){
|
|
boneId = j;
|
|
length = boneChain[boneId]->getLength();
|
|
ikPos = (j == 0 ? targetPos : boneIkPos[boneId - 1]);
|
|
}
|
|
else{
|
|
boneId = chainLength - 1 - j;
|
|
if(j == 0){
|
|
ikPos = startPos;
|
|
length = 0;
|
|
}
|
|
else{
|
|
ikPos = boneIkPos[boneId + 1];
|
|
length = boneChain[boneId + 0]->getLength();
|
|
}
|
|
}
|
|
bonePos = boneIkPos[boneId];
|
|
fromBoneToIkPos = (ikPos - bonePos).norm();
|
|
boneIkPos[boneId] = ikPos - fromBoneToIkPos * length;
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
Vector3 startToEndVec = (targetPos - startPos).norm();
|
|
for(int i = chainLength - 1; i >= 0; i--){
|
|
float length;
|
|
Vector3 bonePos;
|
|
if(i == chainLength - 1){
|
|
length = 0;
|
|
bonePos = boneIkPos[i];
|
|
}
|
|
else{
|
|
length = boneChain[i]->getLength();
|
|
bonePos = boneIkPos[i + 1];
|
|
}
|
|
boneIkPos[i] = bonePos + startToEndVec * length;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Skeleton::transformIkChain(int chainLength, Bone *boneChain[], Vector3 boneIkPos[], Vector3 targetPos){
|
|
Node *rootBone = getRootBone()->getParent();
|
|
float boneAngles[chainLength];
|
|
Vector3 axis[chainLength];
|
|
for(int i = chainLength - 1; i >= 0; i--){
|
|
boneChain[i]->setOrientation(boneChain[i]->getRestRot());
|
|
Vector3 dir = ((i == 0 ? targetPos : boneIkPos[i - 1]) - boneIkPos[i]).norm();
|
|
Vector3 boneAxis =
|
|
(rootBone->globalToLocalPosition(boneChain[i]->localToGlobalPosition(Vector3::VEC_J)) -
|
|
rootBone->globalToLocalPosition(boneChain[i]->localToGlobalPosition(Vector3::VEC_ZERO)))
|
|
.norm();
|
|
|
|
Vector3 rotAxis = boneAxis.cross(dir).norm();
|
|
float angle = boneAxis.getAngleBetween(dir);
|
|
|
|
if(rotAxis == Vector3::VEC_ZERO){
|
|
angle = 0;
|
|
rotAxis = Vector3::VEC_I;
|
|
}
|
|
|
|
boneAngles[i] = angle;
|
|
axis[i] = rotAxis;
|
|
|
|
boneChain[i]->setPoseRot(Quaternion(angle, rotAxis));
|
|
}
|
|
}
|
|
|
|
void Skeleton::addBone(Bone *bone, Bone *parent){
|
|
if(parent)
|
|
parent->attachChild(bone);
|
|
bone->setSkeleton(this);
|
|
bones.push_back(bone);
|
|
}
|
|
|
|
Bone* Skeleton::getBone(string name){
|
|
Bone *bone = nullptr;
|
|
for(Bone *b : bones)
|
|
if(b->getName() == name){
|
|
bone = b;
|
|
break;
|
|
}
|
|
return bone;
|
|
}
|
|
|
|
}
|