POV-Ray : Newsgroups : povray.general : [3.8] Forward And Backward Reaching Inverse Kinematics : Re: [3.8] Forward And Backward Reaching Inverse Kinematics Server Time
13 Jun 2024 09:37:47 EDT (-0400)
  Re: [3.8] Forward And Backward Reaching Inverse Kinematics  
From: ingo
Date: 1 Dec 2018 11:18:41
Message: <XnsA9ABB01AD9149seed7@news.povray.org>
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

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.