|
|
An updated version. Can now initialise the FABRIK without giving a
target. Add a target with
#declare Spine = FABRIK(somearraywithvectorsthatarejoints);
#declare Spine.Target = SetTarget(Spine, T);
and it calculates the new positions of the joints
ingo
//==
// Pov-Ray : 3.8
// Scene File: FABRIK.inc
// Author : Ingo Janssen
// Date : 01-12-2018
// Version : 1a1
//--
// Forward And Backward Reaching Inverse Kinematics (FABRIK) by Andreas
Aristidou.
// http://www.andreasaristidou.com/FABRIK.html
// http://www.andreasaristidou.com/publications/papers/FABRIK.pdf
//
http://www.andreasaristidou.com/publications/papers/Extending_FABRIK_wit
h_Model_C%CE%BFnstraints.pdf
// Excellent code inspiration & guide, by unknown author:
// https://developer.roblox.com/articles/Inverse-Kinematics-for-
Animation#FABRIK
//
#version 3.8;
#macro FABRIK(VecArr)
#local self = dictionary {};
#macro Init(self, VecArr)
#macro LengthsArr(self, VecArr)
#local self._Lengths = array[self._N-1];
#local i = 0;
#while (i < (self._N-1))
#local self._Lengths[i] = vlength(VecArr[i]-VecArr[i+1]);
#local i = i + 1;
#end
#end
#macro LengthsSum(self)
#local self._Length = 0;
#local i = 0;
#while (i < dimension_size(self._Lengths,1))
#local self._Length = self._Length + self._Lengths[i];
#local i = i + 1;
#end
#end
#local self.Joints = VecArr;
#local self.Tolerance = 0.1;
#local self.MaxIter = 100;
#local self._O = VecArr[0];
#local self._N = dimension_size(VecArr, 1);
#local self._M = self._N-1; //max index of array
LengthsArr(self, VecArr)
LengthsSum(self)
#end
Init(self, VecArr)
// internals
#macro _Reach(self)
#debug "Reach : "
#if (vlength(self._O-self.Target) > self._Length)
#local self._Reachable = false;
#debug "False\n"
#else
#local self._Reachable = true;
#debug "True\n"
#end
#end
#macro _Backwards(self)
#debug " Backwards :\n"
#local self.Joints[self._M] = self.Target;
#for (i, self._M-1, 0, -1)
#local l = self._Lengths[i]/vlength(self.Joints[i+1]-self.Joints
[i]);
#local Pos = (1-l) * self.Joints[i+1] + l * self.Joints[i];
#local self.Joints[i] = Pos;
#debug concat(" i : ",str(i,0,0)," pos : ", vstr
(3,Pos,",",0,3),"\n")
#end
#end
#macro _Forward(self)
#debug " Forward :\n"
// set first point back to its original position
#local self.Joints[0] = self._O;
#for (i, 0, self._M-1, 1)
#local l = self._Lengths[i]/vlength(self.Joints[i+1]-self.Joints
[i]);
#local Pos = (1-l) * self.Joints[i] + l * self.Joints[i+1];
#local self.Joints[i+1] = Pos;
#debug concat(" i : ",str(i,0,0)," pos : ", vstr
(3,Pos,",",0,3),"\n")
#end
#end
#macro _Stretch(self)
#debug "Stretch :\n"
#for (i, 0, self._M-1, 1)
#local l = self._Lengths[i]/vlength(self.Target-self.Joints[i]);
#local self.Joints[i+1] = (1-l) * self.Joints[i] + l *
self.Target;
#debug concat("i : ",str(i,0,0), " pos : ", vstr(3,self.Joints[i+
1],",",0,3),"\n")
#end
#end
#macro _Solve(self)
#debug "Solving :\n"
#if (self._Reachable = false)
_Stretch(self)
#else
#local itercount = 0;
#local dif = vlength(self.Joints[self._M] - self.Target);
#while (dif > self.Tolerance)
#debug concat(" dif : ",str(dif,0,3)," iter : ",str
(itercount,0,0),"\n")
_Backwards(self)
_Forward(self)
#local dif = vlength(self.Joints[self._M] - self.Target);
#local itercount = itercount + 1;
#if (itercount > self.MaxIter)
#local dif = 0;
#end
#end
#debug concat("\n dif : ",str(dif,0,3)," end iter\n\n")
#end
true
#end
// external
#macro SetTarget (self, Target)
#local self.Target = Target;
_Reach(self)
_Solve(self)
#end
self
#end
//==
// testscene
//
#global_settings {assumed_gamma 1.0 }
#default {pigment{rgb 1} finish{ ambient 0.2 diffuse 0.9 }}
light_source{<1000,1000,-1000>, rgb 1}
plane{-z,0 pigment{checker rgb 0.8 rgb 0.5}}
camera {location <0, 0,-20> look_at <0,0,0>}
#macro Connect(Arr, RGB, r)
#local l = dimension_size(Arr,1);
#local i = 0;
union{
#while (i < l-1)
sphere{Arr[i],r pigment{rgb RGB}}
cylinder{Arr[i],Arr[i+1],r/2 pigment{rgb RGB}}
#local i=i+1;
#end
sphere{Arr[l-1],r pigment{rgb <0,1,0>}}
}
#end
#declare S = array[10]{
<0,0,0>,<1,1,0>,<2,2,0>,
<3,3,0>,<4,4,0>,<5,5,0>,
<6,6,0>,<7,7,0>,<8,8,0>,
<9,9,0>
};
#declare Spine = FABRIK(S);
#macro Draw(T)
#declare Spine.Target = SetTarget(Spine, T);
Connect(Spine.Joints, <0,0,1>, 0.2)
#end
#for (i,0,3,1)
#switch(i)
#case(0)
#for (n,9,-9,-1)
#declare T = <n,9,0>;
Draw(T)
#end
#break
#case(1)
#for (n,9,-9,-1)
#declare T = <-9,n,0>;
Draw(T)
#end
#break
#case(2)
#for (n,-9,9,1)
#declare T = <n,-9,0>;
Draw(T)
#end
#break
#case(3)
#for (n,-9,9,1)
#declare T = <9,n,0>;
Draw(T)
#end
#break
#end
#end
Post a reply to this message
|
|