| 
									
										
										
										
											2011-02-23 10:52:22 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							| 
									
										
										
										
											2010-02-12 13:34:04 +00:00
										 |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * Original author: Benoit Bolsee | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup ikplugin | 
					
						
							| 
									
										
										
										
											2011-02-27 20:24:49 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-04 16:23:00 +02:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2020-12-04 11:28:09 +01:00
										 |  |  | #include <cstdlib>
 | 
					
						
							|  |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* iTaSC headers */ | 
					
						
							| 
									
										
										
										
											2010-09-12 12:27:12 +00:00
										 |  |  | #ifdef WITH_IK_ITASC
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | #  include "Armature.hpp"
 | 
					
						
							|  |  |  | #  include "Cache.hpp"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #  include "CopyPose.hpp"
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | #  include "Distance.hpp"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #  include "MovingFrame.hpp"
 | 
					
						
							|  |  |  | #  include "Scene.hpp"
 | 
					
						
							|  |  |  | #  include "WDLSSolver.hpp"
 | 
					
						
							|  |  |  | #  include "WSDLSSolver.hpp"
 | 
					
						
							| 
									
										
										
										
											2010-09-12 12:27:12 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BIK_api.h"
 | 
					
						
							|  |  |  | #include "BLI_blenlib.h"
 | 
					
						
							| 
									
										
										
										
											2009-11-10 20:43:45 +00:00
										 |  |  | #include "BLI_math.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-07 18:36:47 +00:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "BKE_action.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BKE_armature.h"
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | #include "BKE_constraint.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BKE_global.h"
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | #include "DNA_action_types.h"
 | 
					
						
							|  |  |  | #include "DNA_armature_types.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "DNA_constraint_types.h"
 | 
					
						
							|  |  |  | #include "DNA_object_types.h"
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | #include "DNA_scene_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "itasc_plugin.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* default parameters */ | 
					
						
							| 
									
										
										
										
											2014-09-16 09:06:56 +10:00
										 |  |  | static bItasc DefIKParam; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* in case of animation mode, feedback and timestep is fixed */ | 
					
						
							| 
									
										
										
										
											2013-12-30 10:53:09 +11:00
										 |  |  | // #define ANIM_TIMESTEP   1.0
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | #define ANIM_FEEDBACK 0.8
 | 
					
						
							| 
									
										
										
										
											2013-12-30 10:53:09 +11:00
										 |  |  | // #define ANIM_QMAX       0.52
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* Structure pointed by bPose.ikdata
 | 
					
						
							|  |  |  |  * It contains everything needed to simulate the armatures | 
					
						
							|  |  |  |  * There can be several simulation islands independent to each other */ | 
					
						
							| 
									
										
										
										
											2012-07-01 09:54:44 +00:00
										 |  |  | struct IK_Data { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   struct IK_Scene *first; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 12:46:43 +01:00
										 |  |  | using Vector3 = float[3]; | 
					
						
							|  |  |  | using Vector4 = float[4]; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | struct IK_Target; | 
					
						
							| 
									
										
										
										
											2020-12-09 16:29:11 +01:00
										 |  |  | using ErrorCallback = void (*)(const iTaSC::ConstraintValues *values, | 
					
						
							|  |  |  |                                unsigned int nvalues, | 
					
						
							|  |  |  |                                IK_Target *iktarget); | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* one structure for each target in the scene */ | 
					
						
							| 
									
										
										
										
											2015-04-07 11:25:42 +10:00
										 |  |  | struct IK_Target { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   struct Depsgraph *bldepsgraph; | 
					
						
							|  |  |  |   struct Scene *blscene; | 
					
						
							|  |  |  |   iTaSC::MovingFrame *target; | 
					
						
							|  |  |  |   iTaSC::ConstraintSet *constraint; | 
					
						
							|  |  |  |   struct bConstraint *blenderConstraint; | 
					
						
							|  |  |  |   struct bPoseChannel *rootChannel; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   Object *owner; /* for auto IK */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ErrorCallback errorCallback; | 
					
						
							|  |  |  |   std::string targetName; | 
					
						
							|  |  |  |   std::string constraintName; | 
					
						
							|  |  |  |   unsigned short controlType; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   short channel;      /* index in IK channel array of channel on which this target is defined */ | 
					
						
							|  |  |  |   short ee;           /* end effector number */ | 
					
						
							|  |  |  |   bool simulation;    /* true when simulation mode is used (update feedback) */ | 
					
						
							|  |  |  |   bool eeBlend;       /* end effector affected by enforce blending */ | 
					
						
							|  |  |  |   float eeRest[4][4]; /* end effector initial pose relative to armature */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   IK_Target() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     bldepsgraph = nullptr; | 
					
						
							|  |  |  |     blscene = nullptr; | 
					
						
							|  |  |  |     target = nullptr; | 
					
						
							|  |  |  |     constraint = nullptr; | 
					
						
							|  |  |  |     blenderConstraint = nullptr; | 
					
						
							|  |  |  |     rootChannel = nullptr; | 
					
						
							|  |  |  |     owner = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     controlType = 0; | 
					
						
							|  |  |  |     channel = 0; | 
					
						
							|  |  |  |     ee = 0; | 
					
						
							|  |  |  |     eeBlend = true; | 
					
						
							|  |  |  |     simulation = true; | 
					
						
							|  |  |  |     targetName.reserve(32); | 
					
						
							|  |  |  |     constraintName.reserve(32); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ~IK_Target() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-07-03 16:44:46 +02:00
										 |  |  |     delete constraint; | 
					
						
							|  |  |  |     delete target; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct IK_Channel { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   bPoseChannel *pchan; /* channel where we must copy matrix back */ | 
					
						
							|  |  |  |   KDL::Frame frame;    /* frame of the bone relative to object base, not armature base */ | 
					
						
							|  |  |  |   std::string tail;    /* segment name of the joint from which we get the bone tail */ | 
					
						
							|  |  |  |   std::string head;    /* segment name of the joint from which we get the bone head */ | 
					
						
							|  |  |  |   int parent;          /* index in this array of the parent channel */ | 
					
						
							|  |  |  |   short jointType;     /* type of joint, combination of IK_SegmentFlag */ | 
					
						
							|  |  |  |   char ndof;           /* number of joint angles for this channel */ | 
					
						
							|  |  |  |   char jointValid;     /* set to 1 when jointValue has been computed */ | 
					
						
							|  |  |  |   /* for joint constraint */ | 
					
						
							|  |  |  |   Object *owner;        /* for pose and IK param */ | 
					
						
							|  |  |  |   double jointValue[4]; /* computed joint value */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   IK_Channel() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     pchan = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     parent = -1; | 
					
						
							|  |  |  |     jointType = 0; | 
					
						
							|  |  |  |     ndof = 0; | 
					
						
							|  |  |  |     jointValid = 0; | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     owner = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     jointValue[0] = 0.0; | 
					
						
							|  |  |  |     jointValue[1] = 0.0; | 
					
						
							|  |  |  |     jointValue[2] = 0.0; | 
					
						
							|  |  |  |     jointValue[3] = 0.0; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-01 09:54:44 +00:00
										 |  |  | struct IK_Scene { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   struct Depsgraph *bldepsgraph; | 
					
						
							|  |  |  |   struct Scene *blscene; | 
					
						
							|  |  |  |   IK_Scene *next; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   int numchan;  /* number of channel in pchan */ | 
					
						
							|  |  |  |   int numjoint; /* number of joint in jointArray */ | 
					
						
							|  |  |  |   /* array of bone information, one per channel in the tree */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_Channel *channels; | 
					
						
							|  |  |  |   iTaSC::Armature *armature; | 
					
						
							|  |  |  |   iTaSC::Cache *cache; | 
					
						
							|  |  |  |   iTaSC::Scene *scene; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   iTaSC::MovingFrame *base; /* armature base object */ | 
					
						
							|  |  |  |   KDL::Frame baseFrame;     /* frame of armature base relative to blArmature */ | 
					
						
							|  |  |  |   KDL::JntArray jointArray; /* buffer for storing temporary joint array */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   iTaSC::Solver *solver; | 
					
						
							|  |  |  |   Object *blArmature; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   float blScale;    /* scale of the Armature object (assume uniform scaling) */ | 
					
						
							|  |  |  |   float blInvScale; /* inverse of Armature object scale */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   struct bConstraint *polarConstraint; | 
					
						
							|  |  |  |   std::vector<IK_Target *> targets; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   IK_Scene() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     bldepsgraph = nullptr; | 
					
						
							|  |  |  |     blscene = nullptr; | 
					
						
							|  |  |  |     next = nullptr; | 
					
						
							|  |  |  |     channels = nullptr; | 
					
						
							|  |  |  |     armature = nullptr; | 
					
						
							|  |  |  |     cache = nullptr; | 
					
						
							|  |  |  |     scene = nullptr; | 
					
						
							|  |  |  |     base = nullptr; | 
					
						
							|  |  |  |     solver = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     blScale = blInvScale = 1.0f; | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     blArmature = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     numchan = 0; | 
					
						
							|  |  |  |     numjoint = 0; | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     polarConstraint = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ~IK_Scene() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* delete scene first */ | 
					
						
							| 
									
										
										
										
											2020-07-03 16:44:46 +02:00
										 |  |  |     delete scene; | 
					
						
							| 
									
										
										
										
											2020-12-07 12:21:11 +01:00
										 |  |  |     for (IK_Target *target : targets) { | 
					
						
							|  |  |  |       delete target; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     targets.clear(); | 
					
						
							| 
									
										
										
										
											2020-07-03 16:44:46 +02:00
										 |  |  |     delete[] channels; | 
					
						
							|  |  |  |     delete solver; | 
					
						
							|  |  |  |     delete armature; | 
					
						
							|  |  |  |     delete base; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* delete cache last */ | 
					
						
							| 
									
										
										
										
											2020-07-03 16:44:46 +02:00
										 |  |  |     delete cache; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* type of IK joint, can be combined to list the joints corresponding to a bone */ | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | enum IK_SegmentFlag { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_XDOF = 1, | 
					
						
							|  |  |  |   IK_YDOF = 2, | 
					
						
							|  |  |  |   IK_ZDOF = 4, | 
					
						
							|  |  |  |   IK_SWING = 8, | 
					
						
							|  |  |  |   IK_REVOLUTE = 16, | 
					
						
							|  |  |  |   IK_TRANSY = 32, | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum IK_SegmentAxis { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_X = 0, | 
					
						
							|  |  |  |   IK_Y = 1, | 
					
						
							|  |  |  |   IK_Z = 2, | 
					
						
							|  |  |  |   IK_TRANS_X = 3, | 
					
						
							|  |  |  |   IK_TRANS_Y = 4, | 
					
						
							|  |  |  |   IK_TRANS_Z = 5, | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *con) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |   bPoseChannel *curchan, *pchan_root = nullptr, *chanlist[256], **oldchan; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PoseTree *tree; | 
					
						
							|  |  |  |   PoseTarget *target; | 
					
						
							|  |  |  |   bKinematicConstraint *data; | 
					
						
							|  |  |  |   int a, t, segcount = 0, size, newsize, *oldparent, parent, rootbone, treecount; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   data = (bKinematicConstraint *)con->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* exclude tip from chain? */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (!(data->flag & CONSTRAINT_IK_TIP)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     pchan_tip = pchan_tip->parent; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   rootbone = data->rootbone; | 
					
						
							|  |  |  |   /* Find the chain's root & count the segments needed */ | 
					
						
							|  |  |  |   for (curchan = pchan_tip; curchan; curchan = curchan->parent) { | 
					
						
							|  |  |  |     pchan_root = curchan; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     if (++segcount > 255) { /* 255 is weak */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (segcount == rootbone) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* reached this end of the chain but if the chain is overlapping with a
 | 
					
						
							|  |  |  |        * previous one, we must go back up to the root of the other chain */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       if ((curchan->flag & POSE_CHAIN) && BLI_listbase_is_empty(&curchan->iktree)) { | 
					
						
							|  |  |  |         rootbone++; | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (BLI_listbase_is_empty(&curchan->iktree) == false) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* Oh oh, there is already a chain starting from this channel and our chain is longer...
 | 
					
						
							|  |  |  |        * Should handle this by moving the previous chain up to the beginning of our chain | 
					
						
							|  |  |  |        * For now we just stop here */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (!segcount) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* we reached a limit and still not the end of a previous chain, quit */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if ((pchan_root->flag & POSE_CHAIN) && BLI_listbase_is_empty(&pchan_root->iktree)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* now that we know how many segment we have, set the flag */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (rootbone = segcount, segcount = 0, curchan = pchan_tip; segcount < rootbone; | 
					
						
							|  |  |  |        segcount++, curchan = curchan->parent) { | 
					
						
							|  |  |  |     chanlist[segcount] = curchan; | 
					
						
							|  |  |  |     curchan->flag |= POSE_CHAIN; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* setup the chain data */ | 
					
						
							|  |  |  |   /* create a target */ | 
					
						
							|  |  |  |   target = (PoseTarget *)MEM_callocN(sizeof(PoseTarget), "posetarget"); | 
					
						
							|  |  |  |   target->con = con; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* by construction there can be only one tree per channel
 | 
					
						
							|  |  |  |    * and each channel can be part of at most one tree. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   tree = (PoseTree *)pchan_root->iktree.first; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |   if (tree == nullptr) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     /* make new tree */ | 
					
						
							|  |  |  |     tree = (PoseTree *)MEM_callocN(sizeof(PoseTree), "posetree"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tree->iterations = data->iterations; | 
					
						
							|  |  |  |     tree->totchannel = segcount; | 
					
						
							|  |  |  |     tree->stretch = (data->flag & CONSTRAINT_IK_STRETCH); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tree->pchan = (bPoseChannel **)MEM_callocN(segcount * sizeof(void *), "ik tree pchan"); | 
					
						
							|  |  |  |     tree->parent = (int *)MEM_callocN(segcount * sizeof(int), "ik tree parent"); | 
					
						
							|  |  |  |     for (a = 0; a < segcount; a++) { | 
					
						
							|  |  |  |       tree->pchan[a] = chanlist[segcount - a - 1]; | 
					
						
							|  |  |  |       tree->parent[a] = a - 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     target->tip = segcount - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* AND! link the tree to the root */ | 
					
						
							|  |  |  |     BLI_addtail(&pchan_root->iktree, tree); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* new tree */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     treecount = 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     tree->iterations = MAX2(data->iterations, tree->iterations); | 
					
						
							|  |  |  |     tree->stretch = tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* skip common pose channels and add remaining*/ | 
					
						
							|  |  |  |     size = MIN2(segcount, tree->totchannel); | 
					
						
							|  |  |  |     a = t = 0; | 
					
						
							|  |  |  |     while (a < size && t < tree->totchannel) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* locate first matching channel */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       for (; t < tree->totchannel && tree->pchan[t] != chanlist[segcount - a - 1]; t++) { | 
					
						
							| 
									
										
										
										
											2019-06-06 10:16:18 +10:00
										 |  |  |         /* pass */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (t >= tree->totchannel) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       for (; a < size && t < tree->totchannel && tree->pchan[t] == chanlist[segcount - a - 1]; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |            a++, t++) { | 
					
						
							| 
									
										
										
										
											2019-06-06 10:16:18 +10:00
										 |  |  |         /* pass */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     segcount = segcount - a; | 
					
						
							|  |  |  |     target->tip = tree->totchannel + segcount - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (segcount > 0) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       for (parent = a - 1; parent < tree->totchannel; parent++) { | 
					
						
							|  |  |  |         if (tree->pchan[parent] == chanlist[segcount - 1]->parent) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       /* shouldn't happen, but could with dependency cycles */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (parent == tree->totchannel) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         parent = a - 1; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       /* resize array */ | 
					
						
							|  |  |  |       newsize = tree->totchannel + segcount; | 
					
						
							|  |  |  |       oldchan = tree->pchan; | 
					
						
							|  |  |  |       oldparent = tree->parent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tree->pchan = (bPoseChannel **)MEM_callocN(newsize * sizeof(void *), "ik tree pchan"); | 
					
						
							|  |  |  |       tree->parent = (int *)MEM_callocN(newsize * sizeof(int), "ik tree parent"); | 
					
						
							|  |  |  |       memcpy(tree->pchan, oldchan, sizeof(void *) * tree->totchannel); | 
					
						
							|  |  |  |       memcpy(tree->parent, oldparent, sizeof(int) * tree->totchannel); | 
					
						
							|  |  |  |       MEM_freeN(oldchan); | 
					
						
							|  |  |  |       MEM_freeN(oldparent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* add new pose channels at the end, in reverse order */ | 
					
						
							|  |  |  |       for (a = 0; a < segcount; a++) { | 
					
						
							|  |  |  |         tree->pchan[tree->totchannel + a] = chanlist[segcount - a - 1]; | 
					
						
							|  |  |  |         tree->parent[tree->totchannel + a] = tree->totchannel + a - 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       tree->parent[tree->totchannel] = parent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tree->totchannel = newsize; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* reusing tree */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     treecount = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* add target to the tree */ | 
					
						
							|  |  |  |   BLI_addtail(&tree->targets, target); | 
					
						
							|  |  |  |   /* mark root channel having an IK tree */ | 
					
						
							|  |  |  |   pchan_root->flag |= POSE_IKTREE; | 
					
						
							|  |  |  |   return treecount; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool is_cartesian_constraint(bConstraint *con) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-01 11:01:20 +10:00
										 |  |  |   // bKinematicConstraint* data=(bKinematicConstraint *)con->data;
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool constraint_valid(bConstraint *con) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bKinematicConstraint *data = (bKinematicConstraint *)con->data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (data->flag & CONSTRAINT_IK_AUTO) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (is_cartesian_constraint(con)) { | 
					
						
							|  |  |  |     /* cartesian space constraint */ | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     if (data->tar == nullptr) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-16 00:26:36 +00:00
										 |  |  | static int initialize_scene(Object *ob, bPoseChannel *pchan_tip) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bConstraint *con; | 
					
						
							|  |  |  |   int treecount; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* find all IK constraints and validate them */ | 
					
						
							|  |  |  |   treecount = 0; | 
					
						
							|  |  |  |   for (con = (bConstraint *)pchan_tip->constraints.first; con; con = (bConstraint *)con->next) { | 
					
						
							|  |  |  |     if (con->type == CONSTRAINT_TYPE_KINEMATIC) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (constraint_valid(con)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         treecount += initialize_chain(ob, pchan_tip, con); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return treecount; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-01 09:54:44 +00:00
										 |  |  | static IK_Data *get_ikdata(bPose *pose) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (pose->ikdata) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return (IK_Data *)pose->ikdata; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   pose->ikdata = MEM_callocN(sizeof(IK_Data), "iTaSC ikdata"); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* here init ikdata if needed
 | 
					
						
							|  |  |  |    * now that we have scene, make sure the default param are initialized */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (!DefIKParam.iksolver) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BKE_pose_itasc_init(&DefIKParam); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return (IK_Data *)pose->ikdata; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static double EulerAngleFromMatrix(const KDL::Rotation &R, int axis) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   double t = KDL::sqrt(R(0, 0) * R(0, 0) + R(0, 1) * R(0, 1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (t > 16.0 * KDL::epsilon) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (axis == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return -KDL::atan2(R(1, 2), R(2, 2)); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-07 13:37:22 +02:00
										 |  |  |     if (axis == 1) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return KDL::atan2(-R(0, 2), t); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-07 13:37:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return -KDL::atan2(R(0, 1), R(0, 0)); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-08-07 13:37:22 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (axis == 0) { | 
					
						
							|  |  |  |     return -KDL::atan2(-R(2, 1), R(1, 1)); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-08-07 13:37:22 +02:00
										 |  |  |   if (axis == 1) { | 
					
						
							|  |  |  |     return KDL::atan2(-R(0, 2), t); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0.0f; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static double ComputeTwist(const KDL::Rotation &R) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* qy and qw are the y and w components of the quaternion from R */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   double qy = R(0, 2) - R(2, 0); | 
					
						
							|  |  |  |   double qw = R(0, 0) + R(1, 1) + R(2, 2) + 1; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   double tau = 2 * KDL::atan2(qy, qw); | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return tau; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void RemoveEulerAngleFromMatrix(KDL::Rotation &R, double angle, int axis) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* compute twist parameter */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   KDL::Rotation T; | 
					
						
							|  |  |  |   switch (axis) { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |       T = KDL::Rotation::RotX(-angle); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 1: | 
					
						
							|  |  |  |       T = KDL::Rotation::RotY(-angle); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 2: | 
					
						
							|  |  |  |       T = KDL::Rotation::RotZ(-angle); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* remove angle */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   R = R * T; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-25 09:33:46 +00:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2019-04-17 08:24:14 +02:00
										 |  |  | static void GetEulerXZY(const KDL::Rotation &R, double &X, double &Z, double &Y) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (fabs(R(0, 1)) > 1.0 - KDL::epsilon) { | 
					
						
							|  |  |  |     X = -KDL::sign(R(0, 1)) * KDL::atan2(R(1, 2), R(1, 0)); | 
					
						
							|  |  |  |     Z = -KDL::sign(R(0, 1)) * KDL::PI / 2; | 
					
						
							|  |  |  |     Y = 0.0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     X = KDL::atan2(R(2, 1), R(1, 1)); | 
					
						
							|  |  |  |     Z = KDL::atan2(-R(0, 1), KDL::sqrt(KDL::sqr(R(0, 0)) + KDL::sqr(R(0, 2)))); | 
					
						
							|  |  |  |     Y = KDL::atan2(R(0, 2), R(0, 0)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 08:24:14 +02:00
										 |  |  | static void GetEulerXYZ(const KDL::Rotation &R, double &X, double &Y, double &Z) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (fabs(R(0, 2)) > 1.0 - KDL::epsilon) { | 
					
						
							|  |  |  |     X = KDL::sign(R(0, 2)) * KDL::atan2(-R(1, 0), R(1, 1)); | 
					
						
							|  |  |  |     Y = KDL::sign(R(0, 2)) * KDL::PI / 2; | 
					
						
							|  |  |  |     Z = 0.0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     X = KDL::atan2(-R(1, 2), R(2, 2)); | 
					
						
							|  |  |  |     Y = KDL::atan2(R(0, 2), KDL::sqrt(KDL::sqr(R(0, 0)) + KDL::sqr(R(0, 1)))); | 
					
						
							|  |  |  |     Z = KDL::atan2(-R(0, 1), R(0, 0)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-09-25 09:33:46 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void GetJointRotation(KDL::Rotation &boneRot, int type, double *rot) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   switch (type & ~IK_TRANSY) { | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* fixed bone, no joint */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case IK_XDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* RX only, get the X rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       rot[0] = EulerAngleFromMatrix(boneRot, 0); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_YDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* RY only, get the Y rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       rot[0] = ComputeTwist(boneRot); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* RZ only, get the Z rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       rot[0] = EulerAngleFromMatrix(boneRot, 2); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_XDOF | IK_YDOF: | 
					
						
							|  |  |  |       rot[1] = ComputeTwist(boneRot); | 
					
						
							|  |  |  |       RemoveEulerAngleFromMatrix(boneRot, rot[1], 1); | 
					
						
							|  |  |  |       rot[0] = EulerAngleFromMatrix(boneRot, 0); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_SWING: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* RX+RZ */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       boneRot.GetXZRot().GetValue(rot); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_YDOF | IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* RZ+RY */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       rot[1] = ComputeTwist(boneRot); | 
					
						
							|  |  |  |       RemoveEulerAngleFromMatrix(boneRot, rot[1], 1); | 
					
						
							|  |  |  |       rot[0] = EulerAngleFromMatrix(boneRot, 2); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_SWING | IK_YDOF: | 
					
						
							|  |  |  |       rot[2] = ComputeTwist(boneRot); | 
					
						
							|  |  |  |       RemoveEulerAngleFromMatrix(boneRot, rot[2], 1); | 
					
						
							|  |  |  |       boneRot.GetXZRot().GetValue(rot); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_REVOLUTE: | 
					
						
							|  |  |  |       boneRot.GetRot().GetValue(rot); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static bool target_callback(const iTaSC::Timestamp ×tamp, | 
					
						
							|  |  |  |                             const iTaSC::Frame ¤t, | 
					
						
							|  |  |  |                             iTaSC::Frame &next, | 
					
						
							|  |  |  |                             void *param) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_Target *target = (IK_Target *)param; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* compute next target position
 | 
					
						
							|  |  |  |    * get target matrix from constraint. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bConstraint *constraint = (bConstraint *)target->blenderConstraint; | 
					
						
							|  |  |  |   float tarmat[4][4]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BKE_constraint_target_matrix_get(target->bldepsgraph, | 
					
						
							|  |  |  |                                    target->blscene, | 
					
						
							|  |  |  |                                    constraint, | 
					
						
							|  |  |  |                                    0, | 
					
						
							|  |  |  |                                    CONSTRAINT_OBTYPE_OBJECT, | 
					
						
							|  |  |  |                                    target->owner, | 
					
						
							|  |  |  |                                    tarmat, | 
					
						
							|  |  |  |                                    1.0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* rootmat contains the target pose in world coordinate
 | 
					
						
							|  |  |  |    * if enforce is != 1.0, blend the target position with the end effector position | 
					
						
							|  |  |  |    * if the armature was in rest position. This information is available in eeRest */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (constraint->enforce != 1.0f && target->eeBlend) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* eeRest is relative to the reference frame of the IK root
 | 
					
						
							|  |  |  |      * get this frame in world reference */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     float restmat[4][4]; | 
					
						
							|  |  |  |     bPoseChannel *pchan = target->rootChannel; | 
					
						
							|  |  |  |     if (pchan->parent) { | 
					
						
							|  |  |  |       pchan = pchan->parent; | 
					
						
							|  |  |  |       float chanmat[4][4]; | 
					
						
							|  |  |  |       copy_m4_m4(chanmat, pchan->pose_mat); | 
					
						
							|  |  |  |       copy_v3_v3(chanmat[3], pchan->pose_tail); | 
					
						
							|  |  |  |       mul_m4_series(restmat, target->owner->obmat, chanmat, target->eeRest); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       mul_m4_m4m4(restmat, target->owner->obmat, target->eeRest); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* blend the target */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     blend_m4_m4m4(tarmat, restmat, tarmat, constraint->enforce); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   next.setValue(&tarmat[0][0]); | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static bool base_callback(const iTaSC::Timestamp ×tamp, | 
					
						
							|  |  |  |                           const iTaSC::Frame ¤t, | 
					
						
							|  |  |  |                           iTaSC::Frame &next, | 
					
						
							|  |  |  |                           void *param) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_Scene *ikscene = (IK_Scene *)param; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* compute next armature base pose
 | 
					
						
							|  |  |  |    * algorithm: | 
					
						
							|  |  |  |    * ikscene->pchan[0] is the root channel of the tree | 
					
						
							|  |  |  |    * if it has a parent, get the pose matrix from it and replace [3] by parent pchan->tail | 
					
						
							|  |  |  |    * then multiply by the armature matrix to get ikscene->armature base position */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bPoseChannel *pchan = ikscene->channels[0].pchan; | 
					
						
							|  |  |  |   float rootmat[4][4]; | 
					
						
							|  |  |  |   if (pchan->parent) { | 
					
						
							|  |  |  |     pchan = pchan->parent; | 
					
						
							|  |  |  |     float chanmat[4][4]; | 
					
						
							|  |  |  |     copy_m4_m4(chanmat, pchan->pose_mat); | 
					
						
							|  |  |  |     copy_v3_v3(chanmat[3], pchan->pose_tail); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* save the base as a frame too so that we can compute deformation after simulation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ikscene->baseFrame.setValue(&chanmat[0][0]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* iTaSC armature is scaled to object scale, scale the base frame too */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ikscene->baseFrame.p *= ikscene->blScale; | 
					
						
							|  |  |  |     mul_m4_m4m4(rootmat, ikscene->blArmature->obmat, chanmat); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     copy_m4_m4(rootmat, ikscene->blArmature->obmat); | 
					
						
							|  |  |  |     ikscene->baseFrame = iTaSC::F_identity; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   next.setValue(&rootmat[0][0]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* if there is a polar target (only during solving otherwise we don't have end efffector) */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (ikscene->polarConstraint && timestamp.update) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* compute additional rotation of base frame so that armature follows the polar target */ | 
					
						
							|  |  |  |     float imat[4][4];    /* IK tree base inverse matrix */ | 
					
						
							|  |  |  |     float polemat[4][4]; /* polar target in IK tree base frame */ | 
					
						
							|  |  |  |     float goalmat[4][4]; /* target in IK tree base frame */ | 
					
						
							|  |  |  |     float mat[4][4];     /* temp matrix */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     bKinematicConstraint *poledata = (bKinematicConstraint *)ikscene->polarConstraint->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     invert_m4_m4(imat, rootmat); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* polar constraint imply only one target */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     IK_Target *iktarget = ikscene->targets[0]; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* root channel from which we take the bone initial orientation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     IK_Channel &rootchan = ikscene->channels[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* get polar target matrix in world space */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BKE_constraint_target_matrix_get(ikscene->bldepsgraph, | 
					
						
							|  |  |  |                                      ikscene->blscene, | 
					
						
							|  |  |  |                                      ikscene->polarConstraint, | 
					
						
							|  |  |  |                                      1, | 
					
						
							|  |  |  |                                      CONSTRAINT_OBTYPE_OBJECT, | 
					
						
							|  |  |  |                                      ikscene->blArmature, | 
					
						
							|  |  |  |                                      mat, | 
					
						
							|  |  |  |                                      1.0); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* convert to armature space */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mul_m4_m4m4(polemat, imat, mat); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* get the target in world space
 | 
					
						
							|  |  |  |      * (was computed before as target object are defined before base object). */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     iktarget->target->getPose().getValue(mat[0]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* convert to armature space */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mul_m4_m4m4(goalmat, imat, mat); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* take position of target, polar target, end effector, in armature space */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     KDL::Vector goalpos(goalmat[3]); | 
					
						
							|  |  |  |     KDL::Vector polepos(polemat[3]); | 
					
						
							|  |  |  |     KDL::Vector endpos = ikscene->armature->getPose(iktarget->ee).p; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* get root bone orientation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     KDL::Frame rootframe; | 
					
						
							|  |  |  |     ikscene->armature->getRelativeFrame(rootframe, rootchan.tail); | 
					
						
							|  |  |  |     KDL::Vector rootx = rootframe.M.UnitX(); | 
					
						
							|  |  |  |     KDL::Vector rootz = rootframe.M.UnitZ(); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* and compute root bone head */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     double q_rest[3], q[3], length; | 
					
						
							|  |  |  |     const KDL::Joint *joint; | 
					
						
							|  |  |  |     const KDL::Frame *tip; | 
					
						
							|  |  |  |     ikscene->armature->getSegment(rootchan.tail, 3, joint, q_rest[0], q[0], tip); | 
					
						
							|  |  |  |     length = (joint->getType() == KDL::Joint::TransY) ? q[0] : tip->p(1); | 
					
						
							|  |  |  |     KDL::Vector rootpos = rootframe.p - length * rootframe.M.UnitY(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* compute main directions */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     KDL::Vector dir = KDL::Normalize(endpos - rootpos); | 
					
						
							|  |  |  |     KDL::Vector poledir = KDL::Normalize(goalpos - rootpos); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* compute up directions */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     KDL::Vector poleup = KDL::Normalize(polepos - rootpos); | 
					
						
							|  |  |  |     KDL::Vector up = rootx * KDL::cos(poledata->poleangle) + rootz * KDL::sin(poledata->poleangle); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* from which we build rotation matrix */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     KDL::Rotation endrot, polerot; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* for the armature, using the root bone orientation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     KDL::Vector x = KDL::Normalize(dir * up); | 
					
						
							|  |  |  |     endrot.UnitX(x); | 
					
						
							|  |  |  |     endrot.UnitY(KDL::Normalize(x * dir)); | 
					
						
							|  |  |  |     endrot.UnitZ(-dir); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* for the polar target */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     x = KDL::Normalize(poledir * poleup); | 
					
						
							|  |  |  |     polerot.UnitX(x); | 
					
						
							|  |  |  |     polerot.UnitY(KDL::Normalize(x * poledir)); | 
					
						
							|  |  |  |     polerot.UnitZ(-poledir); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* the difference between the two is the rotation we want to apply */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     KDL::Rotation result(polerot * endrot.Inverse()); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* apply on base frame as this is an artificial additional rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     next.M = next.M * result; | 
					
						
							|  |  |  |     ikscene->baseFrame.M = ikscene->baseFrame.M * result; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static bool copypose_callback(const iTaSC::Timestamp ×tamp, | 
					
						
							|  |  |  |                               iTaSC::ConstraintValues *const _values, | 
					
						
							|  |  |  |                               unsigned int _nvalues, | 
					
						
							|  |  |  |                               void *_param) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_Target *iktarget = (IK_Target *)_param; | 
					
						
							|  |  |  |   bKinematicConstraint *condata = (bKinematicConstraint *)iktarget->blenderConstraint->data; | 
					
						
							|  |  |  |   iTaSC::ConstraintValues *values = _values; | 
					
						
							|  |  |  |   bItasc *ikparam = (bItasc *)iktarget->owner->pose->ikparam; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* we need default parameters */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (!ikparam) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ikparam = &DefIKParam; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (iktarget->blenderConstraint->flag & CONSTRAINT_OFF) { | 
					
						
							|  |  |  |     if (iktarget->controlType & iTaSC::CopyPose::CTL_POSITION) { | 
					
						
							|  |  |  |       values->alpha = 0.0; | 
					
						
							|  |  |  |       values->action = iTaSC::ACT_ALPHA; | 
					
						
							|  |  |  |       values++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (iktarget->controlType & iTaSC::CopyPose::CTL_ROTATION) { | 
					
						
							|  |  |  |       values->alpha = 0.0; | 
					
						
							|  |  |  |       values->action = iTaSC::ACT_ALPHA; | 
					
						
							|  |  |  |       values++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     if (iktarget->controlType & iTaSC::CopyPose::CTL_POSITION) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* update error */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       values->alpha = condata->weight; | 
					
						
							|  |  |  |       values->action = iTaSC::ACT_ALPHA | iTaSC::ACT_FEEDBACK; | 
					
						
							|  |  |  |       values->feedback = (iktarget->simulation) ? ikparam->feedback : ANIM_FEEDBACK; | 
					
						
							|  |  |  |       values++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (iktarget->controlType & iTaSC::CopyPose::CTL_ROTATION) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* update error */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       values->alpha = condata->orientweight; | 
					
						
							|  |  |  |       values->action = iTaSC::ACT_ALPHA | iTaSC::ACT_FEEDBACK; | 
					
						
							|  |  |  |       values->feedback = (iktarget->simulation) ? ikparam->feedback : ANIM_FEEDBACK; | 
					
						
							|  |  |  |       values++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void copypose_error(const iTaSC::ConstraintValues *values, | 
					
						
							|  |  |  |                            unsigned int nvalues, | 
					
						
							|  |  |  |                            IK_Target *iktarget) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   iTaSC::ConstraintSingleValue *value; | 
					
						
							|  |  |  |   double error; | 
					
						
							|  |  |  |   int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (iktarget->controlType & iTaSC::CopyPose::CTL_POSITION) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* update error */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0, error = 0.0, value = values->values; i < values->number; i++, value++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       error += KDL::sqr(value->y - value->yd); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     iktarget->blenderConstraint->lin_error = (float)KDL::sqrt(error); | 
					
						
							|  |  |  |     values++; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (iktarget->controlType & iTaSC::CopyPose::CTL_ROTATION) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* update error */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0, error = 0.0, value = values->values; i < values->number; i++, value++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       error += KDL::sqr(value->y - value->yd); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     iktarget->blenderConstraint->rot_error = (float)KDL::sqrt(error); | 
					
						
							|  |  |  |     values++; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static bool distance_callback(const iTaSC::Timestamp ×tamp, | 
					
						
							|  |  |  |                               iTaSC::ConstraintValues *const _values, | 
					
						
							|  |  |  |                               unsigned int _nvalues, | 
					
						
							|  |  |  |                               void *_param) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_Target *iktarget = (IK_Target *)_param; | 
					
						
							|  |  |  |   bKinematicConstraint *condata = (bKinematicConstraint *)iktarget->blenderConstraint->data; | 
					
						
							|  |  |  |   iTaSC::ConstraintValues *values = _values; | 
					
						
							|  |  |  |   bItasc *ikparam = (bItasc *)iktarget->owner->pose->ikparam; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* we need default parameters */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (!ikparam) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ikparam = &DefIKParam; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* update weight according to mode */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (iktarget->blenderConstraint->flag & CONSTRAINT_OFF) { | 
					
						
							|  |  |  |     values->alpha = 0.0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     switch (condata->mode) { | 
					
						
							|  |  |  |       case LIMITDIST_INSIDE: | 
					
						
							|  |  |  |         values->alpha = (values->values[0].y > condata->dist) ? condata->weight : 0.0; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case LIMITDIST_OUTSIDE: | 
					
						
							|  |  |  |         values->alpha = (values->values[0].y < condata->dist) ? condata->weight : 0.0; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         values->alpha = condata->weight; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!timestamp.substep) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* only update value on first timestep */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       switch (condata->mode) { | 
					
						
							|  |  |  |         case LIMITDIST_INSIDE: | 
					
						
							|  |  |  |           values->values[0].yd = condata->dist * 0.95; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         case LIMITDIST_OUTSIDE: | 
					
						
							|  |  |  |           values->values[0].yd = condata->dist * 1.05; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |           values->values[0].yd = condata->dist; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       values->values[0].action = iTaSC::ACT_VALUE | iTaSC::ACT_FEEDBACK; | 
					
						
							|  |  |  |       values->feedback = (iktarget->simulation) ? ikparam->feedback : ANIM_FEEDBACK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   values->action |= iTaSC::ACT_ALPHA; | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void distance_error(const iTaSC::ConstraintValues *values, | 
					
						
							|  |  |  |                            unsigned int _nvalues, | 
					
						
							|  |  |  |                            IK_Target *iktarget) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   iktarget->blenderConstraint->lin_error = (float)(values->values[0].y - values->values[0].yd); | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static bool joint_callback(const iTaSC::Timestamp ×tamp, | 
					
						
							|  |  |  |                            iTaSC::ConstraintValues *const _values, | 
					
						
							|  |  |  |                            unsigned int _nvalues, | 
					
						
							|  |  |  |                            void *_param) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_Channel *ikchan = (IK_Channel *)_param; | 
					
						
							|  |  |  |   bItasc *ikparam = (bItasc *)ikchan->owner->pose->ikparam; | 
					
						
							|  |  |  |   bPoseChannel *chan = ikchan->pchan; | 
					
						
							|  |  |  |   int dof; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* a channel can be split into multiple joints, so we get called multiple
 | 
					
						
							|  |  |  |    * times for one channel (this callback is only for 1 joint in the armature) | 
					
						
							|  |  |  |    * the IK_JointTarget structure is shared between multiple joint constraint | 
					
						
							|  |  |  |    * and the target joint values is computed only once, remember this in jointValid | 
					
						
							|  |  |  |    * Don't forget to reset it before each frame */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!ikchan->jointValid) { | 
					
						
							|  |  |  |     float rmat[3][3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (chan->rotmode > 0) { | 
					
						
							| 
									
										
										
										
											2021-01-04 11:29:11 +11:00
										 |  |  |       /* Euler rotations (will cause gimbal lock, but this can be alleviated a bit with rotation
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:01:20 +10:00
										 |  |  |        * orders) */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       eulO_to_mat3(rmat, chan->eul, chan->rotmode); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (chan->rotmode == ROT_MODE_AXISANGLE) { | 
					
						
							| 
									
										
										
										
											2019-05-01 11:01:20 +10:00
										 |  |  |       /* axis-angle - stored in quaternion data,
 | 
					
						
							|  |  |  |        * but not really that great for 3D-changing orientations */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       axis_angle_to_mat3(rmat, &chan->quat[1], chan->quat[0]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       /* quats are normalized before use to eliminate scaling issues */ | 
					
						
							|  |  |  |       normalize_qt(chan->quat); | 
					
						
							|  |  |  |       quat_to_mat3(rmat, chan->quat); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     KDL::Rotation jointRot(rmat[0][0], | 
					
						
							|  |  |  |                            rmat[1][0], | 
					
						
							|  |  |  |                            rmat[2][0], | 
					
						
							|  |  |  |                            rmat[0][1], | 
					
						
							|  |  |  |                            rmat[1][1], | 
					
						
							|  |  |  |                            rmat[2][1], | 
					
						
							|  |  |  |                            rmat[0][2], | 
					
						
							|  |  |  |                            rmat[1][2], | 
					
						
							|  |  |  |                            rmat[2][2]); | 
					
						
							|  |  |  |     GetJointRotation(jointRot, ikchan->jointType, ikchan->jointValue); | 
					
						
							|  |  |  |     ikchan->jointValid = 1; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* determine which part of jointValue is used for this joint
 | 
					
						
							|  |  |  |    * closely related to the way the joints are defined */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   switch (ikchan->jointType & ~IK_TRANSY) { | 
					
						
							|  |  |  |     case IK_XDOF: | 
					
						
							|  |  |  |     case IK_YDOF: | 
					
						
							|  |  |  |     case IK_ZDOF: | 
					
						
							|  |  |  |       dof = 0; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_XDOF | IK_YDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* X + Y */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       dof = (_values[0].id == iTaSC::Armature::ID_JOINT_RX) ? 0 : 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_SWING: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* XZ */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       dof = 0; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_YDOF | IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* Z + Y */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       dof = (_values[0].id == iTaSC::Armature::ID_JOINT_RZ) ? 0 : 1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_SWING | IK_YDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* XZ + Y */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       dof = (_values[0].id == iTaSC::Armature::ID_JOINT_RY) ? 2 : 0; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case IK_REVOLUTE: | 
					
						
							|  |  |  |       dof = 0; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       dof = -1; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (dof >= 0) { | 
					
						
							|  |  |  |     for (unsigned int i = 0; i < _nvalues; i++, dof++) { | 
					
						
							|  |  |  |       _values[i].values[0].yd = ikchan->jointValue[dof]; | 
					
						
							|  |  |  |       _values[i].alpha = chan->ikrotweight; | 
					
						
							|  |  |  |       _values[i].feedback = ikparam->feedback; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* build array of joint corresponding to IK chain */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static int convert_channels(struct Depsgraph *depsgraph, | 
					
						
							|  |  |  |                             IK_Scene *ikscene, | 
					
						
							|  |  |  |                             PoseTree *tree, | 
					
						
							|  |  |  |                             float ctime) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IK_Channel *ikchan; | 
					
						
							|  |  |  |   bPoseChannel *pchan; | 
					
						
							|  |  |  |   int a, flag, njoint; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   njoint = 0; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (a = 0, ikchan = ikscene->channels; a < ikscene->numchan; a++, ikchan++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     pchan = tree->pchan[a]; | 
					
						
							|  |  |  |     ikchan->pchan = pchan; | 
					
						
							|  |  |  |     ikchan->parent = (a > 0) ? tree->parent[a] : -1; | 
					
						
							|  |  |  |     ikchan->owner = ikscene->blArmature; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* the constraint and channels must be applied before we build the iTaSC scene,
 | 
					
						
							|  |  |  |      * this is because some of the pose data (e.g. pose head) don't have corresponding | 
					
						
							|  |  |  |      * joint angles and can't be applied to the iTaSC armature dynamically */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (!(pchan->flag & POSE_DONE)) { | 
					
						
							| 
									
										
										
										
											2020-11-06 14:25:30 +01:00
										 |  |  |       BKE_pose_where_is_bone(depsgraph, ikscene->blscene, ikscene->blArmature, pchan, ctime, true); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* tell blender that this channel was controlled by IK,
 | 
					
						
							|  |  |  |      * it's cleared on each BKE_pose_where_is() */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     pchan->flag |= (POSE_DONE | POSE_CHAIN); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* set DoF flag */ | 
					
						
							|  |  |  |     flag = 0; | 
					
						
							|  |  |  |     if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP) && | 
					
						
							| 
									
										
										
										
											2020-11-06 11:25:27 +11:00
										 |  |  |         (!(pchan->ikflag & BONE_IK_XLIMIT) || pchan->limitmin[0] < 0.0f || | 
					
						
							|  |  |  |          pchan->limitmax[0] > 0.0f)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       flag |= IK_XDOF; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP) && | 
					
						
							| 
									
										
										
										
											2020-11-06 11:25:27 +11:00
										 |  |  |         (!(pchan->ikflag & BONE_IK_YLIMIT) || pchan->limitmin[1] < 0.0f || | 
					
						
							|  |  |  |          pchan->limitmax[1] > 0.0f)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       flag |= IK_YDOF; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP) && | 
					
						
							| 
									
										
										
										
											2020-11-06 11:25:27 +11:00
										 |  |  |         (!(pchan->ikflag & BONE_IK_ZLIMIT) || pchan->limitmin[2] < 0.0f || | 
					
						
							|  |  |  |          pchan->limitmax[2] > 0.0f)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       flag |= IK_ZDOF; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (tree->stretch && (pchan->ikstretch > 0.0)) { | 
					
						
							|  |  |  |       flag |= IK_TRANSY; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Logic to create the segments: | 
					
						
							|  |  |  |      * RX,RY,RZ = rotational joints with no length | 
					
						
							|  |  |  |      * RY(tip) = rotational joints with a fixed length arm = (0,length,0) | 
					
						
							|  |  |  |      * TY = translational joint on Y axis | 
					
						
							|  |  |  |      * F(pos) = fixed joint with an arm at position pos | 
					
						
							|  |  |  |      * Conversion rule of the above flags: | 
					
						
							|  |  |  |      * -   ==> F(tip) | 
					
						
							|  |  |  |      * X   ==> RX(tip) | 
					
						
							|  |  |  |      * Y   ==> RY(tip) | 
					
						
							|  |  |  |      * Z   ==> RZ(tip) | 
					
						
							|  |  |  |      * XY  ==> RX+RY(tip) | 
					
						
							|  |  |  |      * XZ  ==> RX+RZ(tip) | 
					
						
							|  |  |  |      * YZ  ==> RZ+RY(tip) | 
					
						
							|  |  |  |      * XYZ ==> full spherical unless there are limits, in which case RX+RZ+RY(tip) | 
					
						
							|  |  |  |      * In case of stretch, tip=(0,0,0) and there is an additional TY joint | 
					
						
							|  |  |  |      * The frame at last of these joints represents the tail of the bone. | 
					
						
							|  |  |  |      * The head is computed by a reverse translation on Y axis of the bone length | 
					
						
							|  |  |  |      * or in case of TY joint, by the frame at previous joint. | 
					
						
							|  |  |  |      * In case of separation of bones, there is an additional F(head) joint | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Computing rest pose and length is complicated: the solver works in world space | 
					
						
							|  |  |  |      * Here is the logic: | 
					
						
							|  |  |  |      * rest position is computed only from bone->bone_mat. | 
					
						
							|  |  |  |      * bone length is computed from bone->length multiplied by the scaling factor of | 
					
						
							|  |  |  |      * the armature. Non-uniform scaling will give bad result! | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     switch (flag & (IK_XDOF | IK_YDOF | IK_ZDOF)) { | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         ikchan->jointType = 0; | 
					
						
							|  |  |  |         ikchan->ndof = 0; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_XDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RX only, get the X rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ikchan->jointType = IK_XDOF; | 
					
						
							|  |  |  |         ikchan->ndof = 1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_YDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RY only, get the Y rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ikchan->jointType = IK_YDOF; | 
					
						
							|  |  |  |         ikchan->ndof = 1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RZ only, get the Zz rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ikchan->jointType = IK_ZDOF; | 
					
						
							|  |  |  |         ikchan->ndof = 1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_XDOF | IK_YDOF: | 
					
						
							|  |  |  |         ikchan->jointType = IK_XDOF | IK_YDOF; | 
					
						
							|  |  |  |         ikchan->ndof = 2; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_XDOF | IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RX+RZ */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ikchan->jointType = IK_SWING; | 
					
						
							|  |  |  |         ikchan->ndof = 2; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_YDOF | IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RZ+RY */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ikchan->jointType = IK_ZDOF | IK_YDOF; | 
					
						
							|  |  |  |         ikchan->ndof = 2; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_XDOF | IK_YDOF | IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* spherical joint */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_YLIMIT | BONE_IK_ZLIMIT)) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |           /* decompose in a Swing+RotY joint */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           ikchan->jointType = IK_SWING | IK_YDOF; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           ikchan->jointType = IK_REVOLUTE; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ikchan->ndof = 3; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (flag & IK_TRANSY) { | 
					
						
							|  |  |  |       ikchan->jointType |= IK_TRANSY; | 
					
						
							|  |  |  |       ikchan->ndof++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     njoint += ikchan->ndof; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* njoint is the joint coordinate, create the Joint Array */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ikscene->jointArray.resize(njoint); | 
					
						
							|  |  |  |   ikscene->numjoint = njoint; | 
					
						
							|  |  |  |   return njoint; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* compute array of joint value corresponding to current pose */ | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | static void convert_pose(IK_Scene *ikscene) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   KDL::Rotation boneRot; | 
					
						
							|  |  |  |   bPoseChannel *pchan; | 
					
						
							|  |  |  |   IK_Channel *ikchan; | 
					
						
							|  |  |  |   Bone *bone; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   float rmat[4][4]; /* rest pose of bone with parent taken into account */ | 
					
						
							|  |  |  |   float bmat[4][4]; /* difference */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   float scale; | 
					
						
							|  |  |  |   double *rot; | 
					
						
							|  |  |  |   int a, joint; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* assume uniform scaling and take Y scale as general scale for the armature */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   scale = len_v3(ikscene->blArmature->obmat[1]); | 
					
						
							|  |  |  |   rot = ikscene->jointArray(0); | 
					
						
							|  |  |  |   for (joint = a = 0, ikchan = ikscene->channels; | 
					
						
							|  |  |  |        a < ikscene->numchan && joint < ikscene->numjoint; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |        a++, ikchan++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     pchan = ikchan->pchan; | 
					
						
							|  |  |  |     bone = pchan->bone; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (pchan->parent) { | 
					
						
							|  |  |  |       unit_m4(bmat); | 
					
						
							|  |  |  |       mul_m4_m4m3(bmat, pchan->parent->pose_mat, bone->bone_mat); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       copy_m4_m4(bmat, bone->arm_mat); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     invert_m4_m4(rmat, bmat); | 
					
						
							|  |  |  |     mul_m4_m4m4(bmat, rmat, pchan->pose_mat); | 
					
						
							|  |  |  |     normalize_m4(bmat); | 
					
						
							|  |  |  |     boneRot.setValue(bmat[0]); | 
					
						
							|  |  |  |     GetJointRotation(boneRot, ikchan->jointType, rot); | 
					
						
							|  |  |  |     if (ikchan->jointType & IK_TRANSY) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* compute actual length */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       rot[ikchan->ndof - 1] = len_v3v3(pchan->pose_tail, pchan->pose_head) * scale; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     rot += ikchan->ndof; | 
					
						
							|  |  |  |     joint += ikchan->ndof; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /* compute array of joint value corresponding to current pose */ | 
					
						
							| 
									
										
										
										
											2012-05-05 16:03:57 +00:00
										 |  |  | static void BKE_pose_rest(IK_Scene *ikscene) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bPoseChannel *pchan; | 
					
						
							|  |  |  |   IK_Channel *ikchan; | 
					
						
							|  |  |  |   Bone *bone; | 
					
						
							|  |  |  |   float scale; | 
					
						
							|  |  |  |   double *rot; | 
					
						
							|  |  |  |   int a, joint; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* assume uniform scaling and take Y scale as general scale for the armature */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   scale = len_v3(ikscene->blArmature->obmat[1]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* rest pose is 0 */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   SetToZero(ikscene->jointArray); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* except for transY joints */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   rot = ikscene->jointArray(0); | 
					
						
							|  |  |  |   for (joint = a = 0, ikchan = ikscene->channels; | 
					
						
							|  |  |  |        a < ikscene->numchan && joint < ikscene->numjoint; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |        a++, ikchan++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     pchan = ikchan->pchan; | 
					
						
							|  |  |  |     bone = pchan->bone; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (ikchan->jointType & IK_TRANSY) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       rot[ikchan->ndof - 1] = bone->length * scale; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     rot += ikchan->ndof; | 
					
						
							|  |  |  |     joint += ikchan->ndof; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static IK_Scene *convert_tree( | 
					
						
							|  |  |  |     struct Depsgraph *depsgraph, Scene *blscene, Object *ob, bPoseChannel *pchan, float ctime) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   PoseTree *tree = (PoseTree *)pchan->iktree.first; | 
					
						
							|  |  |  |   PoseTarget *target; | 
					
						
							|  |  |  |   bKinematicConstraint *condata; | 
					
						
							|  |  |  |   bConstraint *polarcon; | 
					
						
							|  |  |  |   bItasc *ikparam; | 
					
						
							|  |  |  |   iTaSC::Armature *arm; | 
					
						
							|  |  |  |   iTaSC::Scene *scene; | 
					
						
							|  |  |  |   IK_Scene *ikscene; | 
					
						
							|  |  |  |   IK_Channel *ikchan; | 
					
						
							|  |  |  |   KDL::Frame initPose; | 
					
						
							|  |  |  |   Bone *bone; | 
					
						
							|  |  |  |   int a, numtarget; | 
					
						
							|  |  |  |   unsigned int t; | 
					
						
							|  |  |  |   float length; | 
					
						
							|  |  |  |   bool ret = true; | 
					
						
							|  |  |  |   double *rot; | 
					
						
							|  |  |  |   float start[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (tree->totchannel == 0) { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     return nullptr; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   ikscene = new IK_Scene; | 
					
						
							|  |  |  |   ikscene->blscene = blscene; | 
					
						
							|  |  |  |   ikscene->bldepsgraph = depsgraph; | 
					
						
							|  |  |  |   arm = new iTaSC::Armature(); | 
					
						
							|  |  |  |   scene = new iTaSC::Scene(); | 
					
						
							|  |  |  |   ikscene->channels = new IK_Channel[tree->totchannel]; | 
					
						
							|  |  |  |   ikscene->numchan = tree->totchannel; | 
					
						
							|  |  |  |   ikscene->armature = arm; | 
					
						
							|  |  |  |   ikscene->scene = scene; | 
					
						
							|  |  |  |   ikparam = (bItasc *)ob->pose->ikparam; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!ikparam) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* you must have our own copy */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ikparam = &DefIKParam; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (ikparam->flag & ITASC_SIMULATION) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* no cache in animation mode */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ikscene->cache = new iTaSC::Cache(); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   switch (ikparam->solver) { | 
					
						
							|  |  |  |     case ITASC_SOLVER_SDLS: | 
					
						
							|  |  |  |       ikscene->solver = new iTaSC::WSDLSSolver(); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case ITASC_SOLVER_DLS: | 
					
						
							|  |  |  |       ikscene->solver = new iTaSC::WDLSSolver(); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       delete ikscene; | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |       return nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   ikscene->blArmature = ob; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* assume uniform scaling and take Y scale as general scale for the armature */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ikscene->blScale = len_v3(ob->obmat[1]); | 
					
						
							|  |  |  |   ikscene->blInvScale = (ikscene->blScale < KDL::epsilon) ? 0.0f : 1.0f / ikscene->blScale; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::string joint; | 
					
						
							|  |  |  |   std::string root("root"); | 
					
						
							|  |  |  |   std::string parent; | 
					
						
							|  |  |  |   std::vector<double> weights; | 
					
						
							|  |  |  |   double weight[3]; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* build the array of joints corresponding to the IK chain */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   convert_channels(depsgraph, ikscene, tree, ctime); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* in Blender, the rest pose is always 0 for joints */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BKE_pose_rest(ikscene); | 
					
						
							|  |  |  |   rot = ikscene->jointArray(0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (a = 0, ikchan = ikscene->channels; a < tree->totchannel; a++, ikchan++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     pchan = ikchan->pchan; | 
					
						
							|  |  |  |     bone = pchan->bone; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     KDL::Frame tip(iTaSC::F_identity); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* compute the position and rotation of the head from previous segment */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     Vector3 *fl = bone->bone_mat; | 
					
						
							|  |  |  |     KDL::Rotation brot( | 
					
						
							|  |  |  |         fl[0][0], fl[1][0], fl[2][0], fl[0][1], fl[1][1], fl[2][1], fl[0][2], fl[1][2], fl[2][2]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* if the bone is disconnected, the head is movable in pose mode
 | 
					
						
							|  |  |  |      * take that into account by using pose matrix instead of bone | 
					
						
							|  |  |  |      * Note that pose is expressed in armature space, convert to previous bone space */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |       float R_parmat[3][3]; | 
					
						
							|  |  |  |       float iR_parmat[3][3]; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (pchan->parent) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         copy_m3_m4(R_parmat, pchan->parent->pose_mat); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         unit_m3(R_parmat); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (pchan->parent) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         start[0] = start[1] = start[2] = 0.0f; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       invert_m3_m3(iR_parmat, R_parmat); | 
					
						
							|  |  |  |       normalize_m3(iR_parmat); | 
					
						
							|  |  |  |       mul_m3_v3(iR_parmat, start); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     KDL::Vector bpos(start[0], start[1], start[2]); | 
					
						
							|  |  |  |     bpos *= ikscene->blScale; | 
					
						
							|  |  |  |     KDL::Frame head(brot, bpos); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* rest pose length of the bone taking scaling into account */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     length = bone->length * ikscene->blScale; | 
					
						
							|  |  |  |     parent = (a > 0) ? ikscene->channels[tree->parent[a]].tail : root; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* first the fixed segment to the bone head */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     if (!(ikchan->pchan->bone->flag & BONE_CONNECTED) || head.M.GetRot().Norm() > KDL::epsilon) { | 
					
						
							|  |  |  |       joint = bone->name; | 
					
						
							|  |  |  |       joint += ":H"; | 
					
						
							|  |  |  |       ret = arm->addSegment(joint, parent, KDL::Joint::None, 0.0, head); | 
					
						
							|  |  |  |       parent = joint; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!(ikchan->jointType & IK_TRANSY)) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* fixed length, put it in tip */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       tip.p[1] = length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     joint = bone->name; | 
					
						
							|  |  |  |     weight[0] = (1.0 - pchan->stiffness[0]); | 
					
						
							|  |  |  |     weight[1] = (1.0 - pchan->stiffness[1]); | 
					
						
							|  |  |  |     weight[2] = (1.0 - pchan->stiffness[2]); | 
					
						
							|  |  |  |     switch (ikchan->jointType & ~IK_TRANSY) { | 
					
						
							|  |  |  |       case 0: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* fixed bone */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         joint += ":F"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::None, 0.0, tip); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_XDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RX only, get the X rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         joint += ":RX"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::RotX, rot[0], tip); | 
					
						
							|  |  |  |         weights.push_back(weight[0]); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_YDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RY only, get the Y rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         joint += ":RY"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::RotY, rot[0], tip); | 
					
						
							|  |  |  |         weights.push_back(weight[1]); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RZ only, get the Zz rotation */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         joint += ":RZ"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::RotZ, rot[0], tip); | 
					
						
							|  |  |  |         weights.push_back(weight[2]); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_XDOF | IK_YDOF: | 
					
						
							|  |  |  |         joint += ":RX"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::RotX, rot[0]); | 
					
						
							|  |  |  |         weights.push_back(weight[0]); | 
					
						
							|  |  |  |         if (ret) { | 
					
						
							|  |  |  |           parent = joint; | 
					
						
							|  |  |  |           joint = bone->name; | 
					
						
							|  |  |  |           joint += ":RY"; | 
					
						
							|  |  |  |           ret = arm->addSegment(joint, parent, KDL::Joint::RotY, rot[1], tip); | 
					
						
							|  |  |  |           weights.push_back(weight[1]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_SWING: | 
					
						
							|  |  |  |         joint += ":SW"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::Swing, rot[0], tip); | 
					
						
							|  |  |  |         weights.push_back(weight[0]); | 
					
						
							|  |  |  |         weights.push_back(weight[2]); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_YDOF | IK_ZDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* RZ+RY */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         joint += ":RZ"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::RotZ, rot[0]); | 
					
						
							|  |  |  |         weights.push_back(weight[2]); | 
					
						
							|  |  |  |         if (ret) { | 
					
						
							|  |  |  |           parent = joint; | 
					
						
							|  |  |  |           joint = bone->name; | 
					
						
							|  |  |  |           joint += ":RY"; | 
					
						
							|  |  |  |           ret = arm->addSegment(joint, parent, KDL::Joint::RotY, rot[1], tip); | 
					
						
							|  |  |  |           weights.push_back(weight[1]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_SWING | IK_YDOF: | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* decompose in a Swing+RotY joint */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         joint += ":SW"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::Swing, rot[0]); | 
					
						
							|  |  |  |         weights.push_back(weight[0]); | 
					
						
							|  |  |  |         weights.push_back(weight[2]); | 
					
						
							|  |  |  |         if (ret) { | 
					
						
							|  |  |  |           parent = joint; | 
					
						
							|  |  |  |           joint = bone->name; | 
					
						
							|  |  |  |           joint += ":RY"; | 
					
						
							|  |  |  |           ret = arm->addSegment(joint, parent, KDL::Joint::RotY, rot[2], tip); | 
					
						
							|  |  |  |           weights.push_back(weight[1]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case IK_REVOLUTE: | 
					
						
							|  |  |  |         joint += ":SJ"; | 
					
						
							|  |  |  |         ret = arm->addSegment(joint, parent, KDL::Joint::Sphere, rot[0], tip); | 
					
						
							|  |  |  |         weights.push_back(weight[0]); | 
					
						
							|  |  |  |         weights.push_back(weight[1]); | 
					
						
							|  |  |  |         weights.push_back(weight[2]); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (ret && (ikchan->jointType & IK_TRANSY)) { | 
					
						
							|  |  |  |       parent = joint; | 
					
						
							|  |  |  |       joint = bone->name; | 
					
						
							|  |  |  |       joint += ":TY"; | 
					
						
							|  |  |  |       ret = arm->addSegment(joint, parent, KDL::Joint::TransY, rot[ikchan->ndof - 1]); | 
					
						
							|  |  |  |       const float ikstretch = pchan->ikstretch * pchan->ikstretch; | 
					
						
							|  |  |  |       /* why invert twice here? */ | 
					
						
							|  |  |  |       weight[1] = (1.0 - min_ff(1.0 - ikstretch, 1.0f - 0.001f)); | 
					
						
							|  |  |  |       weights.push_back(weight[1]); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (!ret) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* error making the armature?? */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* joint points to the segment that correspond to the bone per say */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ikchan->tail = joint; | 
					
						
							|  |  |  |     ikchan->head = parent; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* in case of error */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ret = false; | 
					
						
							|  |  |  |     if ((ikchan->jointType & IK_XDOF) && (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ROTCTL))) { | 
					
						
							|  |  |  |       joint = bone->name; | 
					
						
							|  |  |  |       joint += ":RX"; | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_XLIMIT) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addLimitConstraint(joint, 0, pchan->limitmin[0], pchan->limitmax[0]) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_ROTCTL) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((ikchan->jointType & IK_YDOF) && (pchan->ikflag & (BONE_IK_YLIMIT | BONE_IK_ROTCTL))) { | 
					
						
							|  |  |  |       joint = bone->name; | 
					
						
							|  |  |  |       joint += ":RY"; | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_YLIMIT) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addLimitConstraint(joint, 0, pchan->limitmin[1], pchan->limitmax[1]) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_ROTCTL) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((ikchan->jointType & IK_ZDOF) && (pchan->ikflag & (BONE_IK_ZLIMIT | BONE_IK_ROTCTL))) { | 
					
						
							|  |  |  |       joint = bone->name; | 
					
						
							|  |  |  |       joint += ":RZ"; | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_ZLIMIT) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addLimitConstraint(joint, 0, pchan->limitmin[2], pchan->limitmax[2]) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_ROTCTL) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((ikchan->jointType & IK_SWING) && | 
					
						
							|  |  |  |         (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT | BONE_IK_ROTCTL))) { | 
					
						
							|  |  |  |       joint = bone->name; | 
					
						
							|  |  |  |       joint += ":SW"; | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_XLIMIT) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addLimitConstraint(joint, 0, pchan->limitmin[0], pchan->limitmax[0]) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_ZLIMIT) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addLimitConstraint(joint, 1, pchan->limitmin[2], pchan->limitmax[2]) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (pchan->ikflag & BONE_IK_ROTCTL) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((ikchan->jointType & IK_REVOLUTE) && (pchan->ikflag & BONE_IK_ROTCTL)) { | 
					
						
							|  |  |  |       joint = bone->name; | 
					
						
							|  |  |  |       joint += ":SJ"; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (arm->addConstraint(joint, joint_callback, ikchan, false, false) < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* no error, so restore */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ret = true; | 
					
						
							|  |  |  |     rot += ikchan->ndof; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!ret) { | 
					
						
							|  |  |  |     delete ikscene; | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     return nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* for each target, we need to add an end effector in the armature */ | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |   for (numtarget = 0, polarcon = nullptr, ret = true, target = (PoseTarget *)tree->targets.first; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |        target; | 
					
						
							|  |  |  |        target = (PoseTarget *)target->next) { | 
					
						
							|  |  |  |     condata = (bKinematicConstraint *)target->con->data; | 
					
						
							|  |  |  |     pchan = tree->pchan[target->tip]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (is_cartesian_constraint(target->con)) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* add the end effector */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       IK_Target *iktarget = new IK_Target(); | 
					
						
							|  |  |  |       ikscene->targets.push_back(iktarget); | 
					
						
							|  |  |  |       iktarget->ee = arm->addEndEffector(ikscene->channels[target->tip].tail); | 
					
						
							|  |  |  |       if (iktarget->ee == -1) { | 
					
						
							|  |  |  |         ret = false; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* initialize all the fields that we can set at this time */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       iktarget->blenderConstraint = target->con; | 
					
						
							|  |  |  |       iktarget->channel = target->tip; | 
					
						
							|  |  |  |       iktarget->simulation = (ikparam->flag & ITASC_SIMULATION); | 
					
						
							|  |  |  |       iktarget->rootChannel = ikscene->channels[0].pchan; | 
					
						
							|  |  |  |       iktarget->owner = ob; | 
					
						
							|  |  |  |       iktarget->targetName = pchan->bone->name; | 
					
						
							|  |  |  |       iktarget->targetName += ":T:"; | 
					
						
							|  |  |  |       iktarget->targetName += target->con->name; | 
					
						
							|  |  |  |       iktarget->constraintName = pchan->bone->name; | 
					
						
							|  |  |  |       iktarget->constraintName += ":C:"; | 
					
						
							|  |  |  |       iktarget->constraintName += target->con->name; | 
					
						
							|  |  |  |       numtarget++; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (condata->poletar) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* this constraint has a polar target */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         polarcon = target->con; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* deal with polar target if any */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (numtarget == 1 && polarcon) { | 
					
						
							|  |  |  |     ikscene->polarConstraint = polarcon; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* we can now add the armature
 | 
					
						
							|  |  |  |    * the armature is based on a moving frame. | 
					
						
							|  |  |  |    * initialize with the correct position in case there is no cache */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   base_callback(iTaSC::Timestamp(), iTaSC::F_identity, initPose, ikscene); | 
					
						
							|  |  |  |   ikscene->base = new iTaSC::MovingFrame(initPose); | 
					
						
							|  |  |  |   ikscene->base->setCallback(base_callback, ikscene); | 
					
						
							|  |  |  |   std::string armname; | 
					
						
							|  |  |  |   armname = ob->id.name; | 
					
						
							|  |  |  |   armname += ":B"; | 
					
						
							|  |  |  |   ret = scene->addObject(armname, ikscene->base); | 
					
						
							|  |  |  |   armname = ob->id.name; | 
					
						
							|  |  |  |   armname += ":AR"; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (ret) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ret = scene->addObject(armname, ikscene->armature, ikscene->base); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!ret) { | 
					
						
							|  |  |  |     delete ikscene; | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     return nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* set the weight */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   e_matrix &Wq = arm->getWq(); | 
					
						
							|  |  |  |   assert(Wq.cols() == (int)weights.size()); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   for (int q = 0; q < Wq.cols(); q++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     Wq(q, q) = weights[q]; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* get the inverse rest pose frame of the base to compute relative rest pose of end effectors
 | 
					
						
							|  |  |  |    * this is needed to handle the enforce parameter | 
					
						
							|  |  |  |    * ikscene->pchan[0] is the root channel of the tree | 
					
						
							|  |  |  |    * if it has no parent, then it's just the identify Frame */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   float invBaseFrame[4][4]; | 
					
						
							|  |  |  |   pchan = ikscene->channels[0].pchan; | 
					
						
							|  |  |  |   if (pchan->parent) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* it has a parent, get the pose matrix from it */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     float baseFrame[4][4]; | 
					
						
							|  |  |  |     pchan = pchan->parent; | 
					
						
							|  |  |  |     copy_m4_m4(baseFrame, pchan->bone->arm_mat); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* move to the tail and scale to get rest pose of armature base */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     copy_v3_v3(baseFrame[3], pchan->bone->arm_tail); | 
					
						
							|  |  |  |     invert_m4_m4(invBaseFrame, baseFrame); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     unit_m4(invBaseFrame); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* finally add the constraint */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (t = 0; t < ikscene->targets.size(); t++) { | 
					
						
							|  |  |  |     IK_Target *iktarget = ikscene->targets[t]; | 
					
						
							|  |  |  |     iktarget->blscene = blscene; | 
					
						
							|  |  |  |     iktarget->bldepsgraph = depsgraph; | 
					
						
							|  |  |  |     condata = (bKinematicConstraint *)iktarget->blenderConstraint->data; | 
					
						
							|  |  |  |     pchan = tree->pchan[iktarget->channel]; | 
					
						
							|  |  |  |     unsigned int controltype, bonecnt; | 
					
						
							|  |  |  |     double bonelen; | 
					
						
							|  |  |  |     float mat[4][4]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* add the end effector
 | 
					
						
							|  |  |  |      * estimate the average bone length, used to clamp feedback error */ | 
					
						
							| 
									
										
										
										
											2020-11-06 11:25:27 +11:00
										 |  |  |     for (bonecnt = 0, bonelen = 0.0f, a = iktarget->channel; a >= 0; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |          a = tree->parent[a], bonecnt++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       bonelen += ikscene->blScale * tree->pchan[a]->bone->length; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     bonelen /= bonecnt; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* store the rest pose of the end effector to compute enforce target */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     copy_m4_m4(mat, pchan->bone->arm_mat); | 
					
						
							|  |  |  |     copy_v3_v3(mat[3], pchan->bone->arm_tail); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* get the rest pose relative to the armature base */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mul_m4_m4m4(iktarget->eeRest, invBaseFrame, mat); | 
					
						
							|  |  |  |     iktarget->eeBlend = (!ikscene->polarConstraint && condata->type == CONSTRAINT_IK_COPYPOSE) ? | 
					
						
							|  |  |  |                             true : | 
					
						
							|  |  |  |                             false; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* use target_callback to make sure the initPose includes enforce coefficient */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     target_callback(iTaSC::Timestamp(), iTaSC::F_identity, initPose, iktarget); | 
					
						
							|  |  |  |     iktarget->target = new iTaSC::MovingFrame(initPose); | 
					
						
							|  |  |  |     iktarget->target->setCallback(target_callback, iktarget); | 
					
						
							|  |  |  |     ret = scene->addObject(iktarget->targetName, iktarget->target); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (!ret) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (condata->type) { | 
					
						
							|  |  |  |       case CONSTRAINT_IK_COPYPOSE: | 
					
						
							|  |  |  |         controltype = 0; | 
					
						
							|  |  |  |         if (condata->flag & CONSTRAINT_IK_ROT) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           if (!(condata->flag & CONSTRAINT_IK_NO_ROT_X)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             controltype |= iTaSC::CopyPose::CTL_ROTATIONX; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							|  |  |  |           if (!(condata->flag & CONSTRAINT_IK_NO_ROT_Y)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             controltype |= iTaSC::CopyPose::CTL_ROTATIONY; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							|  |  |  |           if (!(condata->flag & CONSTRAINT_IK_NO_ROT_Z)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             controltype |= iTaSC::CopyPose::CTL_ROTATIONZ; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (condata->flag & CONSTRAINT_IK_POS) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           if (!(condata->flag & CONSTRAINT_IK_NO_POS_X)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             controltype |= iTaSC::CopyPose::CTL_POSITIONX; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							|  |  |  |           if (!(condata->flag & CONSTRAINT_IK_NO_POS_Y)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             controltype |= iTaSC::CopyPose::CTL_POSITIONY; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							|  |  |  |           if (!(condata->flag & CONSTRAINT_IK_NO_POS_Z)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             controltype |= iTaSC::CopyPose::CTL_POSITIONZ; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (controltype) { | 
					
						
							|  |  |  |           iktarget->constraint = new iTaSC::CopyPose(controltype, controltype, bonelen); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |           /* set the gain */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           if (controltype & iTaSC::CopyPose::CTL_POSITION) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             iktarget->constraint->setControlParameter( | 
					
						
							|  |  |  |                 iTaSC::CopyPose::ID_POSITION, iTaSC::ACT_ALPHA, condata->weight); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							|  |  |  |           if (controltype & iTaSC::CopyPose::CTL_ROTATION) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             iktarget->constraint->setControlParameter( | 
					
						
							|  |  |  |                 iTaSC::CopyPose::ID_ROTATION, iTaSC::ACT_ALPHA, condata->orientweight); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           iktarget->constraint->registerCallback(copypose_callback, iktarget); | 
					
						
							|  |  |  |           iktarget->errorCallback = copypose_error; | 
					
						
							|  |  |  |           iktarget->controlType = controltype; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |           /* add the constraint */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           if (condata->flag & CONSTRAINT_IK_TARGETAXIS) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             ret = scene->addConstraintSet(iktarget->constraintName, | 
					
						
							|  |  |  |                                           iktarget->constraint, | 
					
						
							|  |  |  |                                           iktarget->targetName, | 
					
						
							|  |  |  |                                           armname, | 
					
						
							|  |  |  |                                           "", | 
					
						
							|  |  |  |                                           ikscene->channels[iktarget->channel].tail); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							|  |  |  |           else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             ret = scene->addConstraintSet(iktarget->constraintName, | 
					
						
							|  |  |  |                                           iktarget->constraint, | 
					
						
							|  |  |  |                                           armname, | 
					
						
							|  |  |  |                                           iktarget->targetName, | 
					
						
							|  |  |  |                                           ikscene->channels[iktarget->channel].tail); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case CONSTRAINT_IK_DISTANCE: | 
					
						
							|  |  |  |         iktarget->constraint = new iTaSC::Distance(bonelen); | 
					
						
							|  |  |  |         iktarget->constraint->setControlParameter( | 
					
						
							|  |  |  |             iTaSC::Distance::ID_DISTANCE, iTaSC::ACT_VALUE, condata->dist); | 
					
						
							|  |  |  |         iktarget->constraint->registerCallback(distance_callback, iktarget); | 
					
						
							|  |  |  |         iktarget->errorCallback = distance_error; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* we can update the weight on each substep */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         iktarget->constraint->substep(true); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* add the constraint */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ret = scene->addConstraintSet(iktarget->constraintName, | 
					
						
							|  |  |  |                                       iktarget->constraint, | 
					
						
							|  |  |  |                                       armname, | 
					
						
							|  |  |  |                                       iktarget->targetName, | 
					
						
							|  |  |  |                                       ikscene->channels[iktarget->channel].tail); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (!ret) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (!ret || !scene->addCache(ikscene->cache) || !scene->addSolver(ikscene->solver) || | 
					
						
							|  |  |  |       !scene->initialize()) { | 
					
						
							|  |  |  |     delete ikscene; | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     ikscene = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   return ikscene; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 12:07:27 +02:00
										 |  |  | static void create_scene(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bPoseChannel *pchan; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* create the IK scene */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; | 
					
						
							|  |  |  |        pchan = (bPoseChannel *)pchan->next) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* by construction there is only one tree */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     PoseTree *tree = (PoseTree *)pchan->iktree.first; | 
					
						
							|  |  |  |     if (tree) { | 
					
						
							|  |  |  |       IK_Data *ikdata = get_ikdata(ob->pose); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* convert tree in iTaSC::Scene */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       IK_Scene *ikscene = convert_tree(depsgraph, scene, ob, pchan, ctime); | 
					
						
							|  |  |  |       if (ikscene) { | 
					
						
							|  |  |  |         ikscene->next = ikdata->first; | 
					
						
							|  |  |  |         ikdata->first = ikscene; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* delete the trees once we are done */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       while (tree) { | 
					
						
							|  |  |  |         BLI_remlink(&pchan->iktree, tree); | 
					
						
							|  |  |  |         BLI_freelistN(&tree->targets); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         if (tree->pchan) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           MEM_freeN(tree->pchan); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (tree->parent) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           MEM_freeN(tree->parent); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (tree->basis_change) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           MEM_freeN(tree->basis_change); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         MEM_freeN(tree); | 
					
						
							|  |  |  |         tree = (PoseTree *)pchan->iktree.first; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-03 12:06:42 +00:00
										 |  |  | /* returns 1 if scaling has changed and tree must be reinitialized */ | 
					
						
							|  |  |  | static int init_scene(Object *ob) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* check also if scaling has changed */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   float scale = len_v3(ob->obmat[1]); | 
					
						
							|  |  |  |   IK_Scene *scene; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ob->pose->ikdata) { | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     for (scene = ((IK_Data *)ob->pose->ikdata)->first; scene != nullptr; scene = scene->next) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (fabs(scene->blScale - scale) > KDL::epsilon) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         return 1; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       scene->channels[0].pchan->flag |= POSE_IKTREE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return 0; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void execute_scene(struct Depsgraph *depsgraph, | 
					
						
							|  |  |  |                           Scene *blscene, | 
					
						
							|  |  |  |                           IK_Scene *ikscene, | 
					
						
							|  |  |  |                           bItasc *ikparam, | 
					
						
							|  |  |  |                           float ctime, | 
					
						
							|  |  |  |                           float frtime) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int i; | 
					
						
							|  |  |  |   IK_Channel *ikchan; | 
					
						
							|  |  |  |   if (ikparam->flag & ITASC_SIMULATION) { | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* In simulation mode we don't allow external constraint to change our bones,
 | 
					
						
							|  |  |  |        * mark the channel done also tell Blender that this channel is part of IK tree. | 
					
						
							|  |  |  |        * Cleared on each BKE_pose_where_is() */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       ikchan->pchan->flag |= (POSE_DONE | POSE_CHAIN); | 
					
						
							|  |  |  |       ikchan->jointValid = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* in animation mode, we must get the bone position from action and constraints */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (!(ikchan->pchan->flag & POSE_DONE)) { | 
					
						
							| 
									
										
										
										
											2020-11-06 14:25:30 +01:00
										 |  |  |         BKE_pose_where_is_bone( | 
					
						
							|  |  |  |             depsgraph, blscene, ikscene->blArmature, ikchan->pchan, ctime, true); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* tell blender that this channel was controlled by IK,
 | 
					
						
							|  |  |  |        * it's cleared on each BKE_pose_where_is() */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       ikchan->pchan->flag |= (POSE_DONE | POSE_CHAIN); | 
					
						
							|  |  |  |       ikchan->jointValid = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* only run execute the scene if at least one of our target is enabled */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = ikscene->targets.size(); i > 0; i--) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     IK_Target *iktarget = ikscene->targets[i - 1]; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (i == 0 && ikscene->armature->getNrOfConstraints() == 0) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* all constraint disabled */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* compute timestep */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   double timestamp = ctime * frtime + 2147483.648; | 
					
						
							|  |  |  |   double timestep = frtime; | 
					
						
							|  |  |  |   bool reiterate = (ikparam->flag & ITASC_REITERATION) ? true : false; | 
					
						
							|  |  |  |   int numstep = (ikparam->flag & ITASC_AUTO_STEP) ? 0 : ikparam->numstep; | 
					
						
							|  |  |  |   bool simulation = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ikparam->flag & ITASC_SIMULATION) { | 
					
						
							|  |  |  |     ikscene->solver->setParam(iTaSC::Solver::DLS_QMAX, ikparam->maxvel); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* in animation mode we start from the pose after action and constraint */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     convert_pose(ikscene); | 
					
						
							|  |  |  |     ikscene->armature->setJointArray(ikscene->jointArray); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* and we don't handle velocity */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     reiterate = true; | 
					
						
							|  |  |  |     simulation = false; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* time is virtual, so take fixed value for velocity parameters (see itasc_update_param)
 | 
					
						
							|  |  |  |      * and choose 1s timestep to allow having velocity parameters in radiant */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     timestep = 1.0; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* use auto setup to let the solver test the variation of the joints */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     numstep = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ikscene->cache && !reiterate && simulation) { | 
					
						
							|  |  |  |     iTaSC::CacheTS sts, cts; | 
					
						
							| 
									
										
										
										
											2020-09-04 16:23:00 +02:00
										 |  |  |     sts = cts = (iTaSC::CacheTS)std::round(timestamp * 1000.0); | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     if (ikscene->cache->getPreviousCacheItem(ikscene->armature, 0, &cts) == nullptr || cts == 0) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* the cache is empty before this time, reiterate */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (ikparam->flag & ITASC_INITIAL_REITERATION) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         reiterate = true; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* can take the cache as a start point. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       sts -= cts; | 
					
						
							|  |  |  |       timestep = sts / 1000.0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* don't cache if we are reiterating because we don't want to destroy the cache unnecessarily */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ikscene->scene->update(timestamp, timestep, numstep, false, !reiterate, simulation); | 
					
						
							|  |  |  |   if (reiterate) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* how many times do we reiterate? */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     for (i = 0; i < ikparam->numiter; i++) { | 
					
						
							|  |  |  |       if (ikscene->armature->getMaxJointChange() < ikparam->precision || | 
					
						
							|  |  |  |           ikscene->armature->getMaxEndEffectorChange() < ikparam->precision) { | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       ikscene->scene->update(timestamp, timestep, numstep, true, false, simulation); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (simulation) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* one more fake iteration to cache */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       ikscene->scene->update(timestamp, 0.0, 1, true, true, true); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* compute constraint error */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = ikscene->targets.size(); i > 0; i--) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     IK_Target *iktarget = ikscene->targets[i - 1]; | 
					
						
							|  |  |  |     if (!(iktarget->blenderConstraint->flag & CONSTRAINT_OFF) && iktarget->constraint) { | 
					
						
							|  |  |  |       unsigned int nvalues; | 
					
						
							|  |  |  |       const iTaSC::ConstraintValues *values; | 
					
						
							|  |  |  |       values = iktarget->constraint->getControlParameters(&nvalues); | 
					
						
							|  |  |  |       iktarget->errorCallback(values, nvalues, iktarget); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* Apply result to bone:
 | 
					
						
							|  |  |  |    * walk the ikscene->channels | 
					
						
							|  |  |  |    * for each, get the Frame of the joint corresponding to the bone relative to its parent | 
					
						
							|  |  |  |    * combine the parent and the joint frame to get the frame relative to armature | 
					
						
							|  |  |  |    * a backward translation of the bone length gives the head | 
					
						
							|  |  |  |    * if TY, compute the scale as the ratio of the joint length with rest pose length */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   iTaSC::Armature *arm = ikscene->armature; | 
					
						
							|  |  |  |   KDL::Frame frame; | 
					
						
							|  |  |  |   double q_rest[3], q[3]; | 
					
						
							|  |  |  |   const KDL::Joint *joint; | 
					
						
							|  |  |  |   const KDL::Frame *tip; | 
					
						
							|  |  |  |   bPoseChannel *pchan; | 
					
						
							|  |  |  |   float scale; | 
					
						
							|  |  |  |   float length; | 
					
						
							|  |  |  |   float yaxis[3]; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0, ikchan = ikscene->channels; i < ikscene->numchan; i++, ikchan++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     if (i == 0) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (!arm->getRelativeFrame(frame, ikchan->tail)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* this frame is relative to base, make it relative to object */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       ikchan->frame = ikscene->baseFrame * frame; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (!arm->getRelativeFrame(frame, ikchan->tail, ikscene->channels[ikchan->parent].tail)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* combine with parent frame to get frame relative to object */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       ikchan->frame = ikscene->channels[ikchan->parent].frame * frame; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* ikchan->frame is the tail frame relative to object
 | 
					
						
							|  |  |  |      * get bone length */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (!arm->getSegment(ikchan->tail, 3, joint, q_rest[0], q[0], tip)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     if (joint->getType() == KDL::Joint::TransY) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* stretch bones have a TY joint, compute the scale */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       scale = (float)(q[0] / q_rest[0]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* the length is the joint itself */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       length = (float)q[0]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       scale = 1.0f; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |       /* for fixed bone, the length is in the tip (always along Y axis) */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       length = tip->p(1); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* ready to compute the pose mat */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     pchan = ikchan->pchan; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* tail mat */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     ikchan->frame.getValue(&pchan->pose_mat[0][0]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* the scale of the object was included in the ik scene, take it out now
 | 
					
						
							|  |  |  |      * because the pose channels are relative to the object */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mul_v3_fl(pchan->pose_mat[3], ikscene->blInvScale); | 
					
						
							|  |  |  |     length *= ikscene->blInvScale; | 
					
						
							|  |  |  |     copy_v3_v3(pchan->pose_tail, pchan->pose_mat[3]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* shift to head */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     copy_v3_v3(yaxis, pchan->pose_mat[1]); | 
					
						
							|  |  |  |     mul_v3_fl(yaxis, length); | 
					
						
							|  |  |  |     sub_v3_v3v3(pchan->pose_mat[3], pchan->pose_mat[3], yaxis); | 
					
						
							|  |  |  |     copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* add scale */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mul_v3_fl(pchan->pose_mat[0], scale); | 
					
						
							|  |  |  |     mul_v3_fl(pchan->pose_mat[1], scale); | 
					
						
							|  |  |  |     mul_v3_fl(pchan->pose_mat[2], scale); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (i < ikscene->numchan) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* big problem */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  | /*---------------------------------------------------
 | 
					
						
							|  |  |  |  * plugin interface | 
					
						
							| 
									
										
										
										
											2021-01-20 15:15:38 +11:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void itasc_initialize_tree(struct Depsgraph *depsgraph, | 
					
						
							|  |  |  |                            struct Scene *scene, | 
					
						
							|  |  |  |                            Object *ob, | 
					
						
							|  |  |  |                            float ctime) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bPoseChannel *pchan; | 
					
						
							|  |  |  |   int count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |   if (ob->pose->ikdata != nullptr && !(ob->pose->flag & POSE_WAS_REBUILT)) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (!init_scene(ob)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* first remove old scene */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   itasc_clear_data(ob->pose); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* we should handle all the constraint and mark them all disabled
 | 
					
						
							|  |  |  |    * for blender but we'll start with the IK constraint alone */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; | 
					
						
							|  |  |  |        pchan = (bPoseChannel *)pchan->next) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (pchan->constflag & PCHAN_HAS_IK) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       count += initialize_scene(ob, pchan); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* if at least one tree, create the scenes from the PoseTree stored in the channels
 | 
					
						
							|  |  |  |    * postpone until execute_tree: this way the pose constraint are included */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   if (count) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     create_scene(depsgraph, scene, ob, ctime); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   itasc_update_param(ob->pose); | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* make sure we don't rebuilt until the user changes something important */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ob->pose->flag &= ~POSE_WAS_REBUILT; | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void itasc_execute_tree(struct Depsgraph *depsgraph, | 
					
						
							|  |  |  |                         struct Scene *scene, | 
					
						
							|  |  |  |                         Object *ob, | 
					
						
							|  |  |  |                         bPoseChannel *pchan_root, | 
					
						
							|  |  |  |                         float ctime) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (ob->pose->ikdata) { | 
					
						
							|  |  |  |     IK_Data *ikdata = (IK_Data *)ob->pose->ikdata; | 
					
						
							|  |  |  |     bItasc *ikparam = (bItasc *)ob->pose->ikparam; | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |     /* we need default parameters */ | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     if (!ikparam) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       ikparam = &DefIKParam; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (IK_Scene *ikscene = ikdata->first; ikscene; ikscene = ikscene->next) { | 
					
						
							|  |  |  |       if (ikscene->channels[0].pchan == pchan_root) { | 
					
						
							|  |  |  |         float timestep = scene->r.frs_sec_base / scene->r.frs_sec; | 
					
						
							|  |  |  |         execute_scene(depsgraph, scene, ikscene, ikparam, ctime, timestep); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void itasc_release_tree(struct Scene *scene, struct Object *ob, float ctime) | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |   /* not used for iTaSC */ | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void itasc_clear_data(struct bPose *pose) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (pose->ikdata) { | 
					
						
							|  |  |  |     IK_Data *ikdata = (IK_Data *)pose->ikdata; | 
					
						
							|  |  |  |     for (IK_Scene *scene = ikdata->first; scene; scene = ikdata->first) { | 
					
						
							|  |  |  |       ikdata->first = scene->next; | 
					
						
							|  |  |  |       delete scene; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     MEM_freeN(ikdata); | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |     pose->ikdata = nullptr; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void itasc_clear_cache(struct bPose *pose) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (pose->ikdata) { | 
					
						
							|  |  |  |     IK_Data *ikdata = (IK_Data *)pose->ikdata; | 
					
						
							|  |  |  |     for (IK_Scene *scene = ikdata->first; scene; scene = scene->next) { | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       if (scene->cache) { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* clear all cache but leaving the timestamp 0 (=rest pose) */ | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |         scene->cache->clearCacheFrom(nullptr, 1); | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void itasc_update_param(struct bPose *pose) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (pose->ikdata && pose->ikparam) { | 
					
						
							|  |  |  |     IK_Data *ikdata = (IK_Data *)pose->ikdata; | 
					
						
							|  |  |  |     bItasc *ikparam = (bItasc *)pose->ikparam; | 
					
						
							|  |  |  |     for (IK_Scene *ikscene = ikdata->first; ikscene; ikscene = ikscene->next) { | 
					
						
							|  |  |  |       double armlength = ikscene->armature->getArmLength(); | 
					
						
							|  |  |  |       ikscene->solver->setParam(iTaSC::Solver::DLS_LAMBDA_MAX, ikparam->dampmax * armlength); | 
					
						
							|  |  |  |       ikscene->solver->setParam(iTaSC::Solver::DLS_EPSILON, ikparam->dampeps * armlength); | 
					
						
							|  |  |  |       if (ikparam->flag & ITASC_SIMULATION) { | 
					
						
							|  |  |  |         ikscene->scene->setParam(iTaSC::Scene::MIN_TIMESTEP, ikparam->minstep); | 
					
						
							|  |  |  |         ikscene->scene->setParam(iTaSC::Scene::MAX_TIMESTEP, ikparam->maxstep); | 
					
						
							|  |  |  |         ikscene->solver->setParam(iTaSC::Solver::DLS_QMAX, ikparam->maxvel); | 
					
						
							|  |  |  |         ikscene->armature->setControlParameter( | 
					
						
							|  |  |  |             CONSTRAINT_ID_ALL, iTaSC::Armature::ID_JOINT, iTaSC::ACT_FEEDBACK, ikparam->feedback); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2020-10-10 18:19:55 +11:00
										 |  |  |         /* in animation mode timestep is 1s by convention => qmax becomes radiant and feedback
 | 
					
						
							|  |  |  |          * becomes fraction of error gap corrected in one iteration. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ikscene->scene->setParam(iTaSC::Scene::MIN_TIMESTEP, 1.0); | 
					
						
							|  |  |  |         ikscene->scene->setParam(iTaSC::Scene::MAX_TIMESTEP, 1.0); | 
					
						
							|  |  |  |         ikscene->solver->setParam(iTaSC::Solver::DLS_QMAX, 0.52); | 
					
						
							|  |  |  |         ikscene->armature->setControlParameter( | 
					
						
							|  |  |  |             CONSTRAINT_ID_ALL, iTaSC::Armature::ID_JOINT, iTaSC::ACT_FEEDBACK, 0.8); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void itasc_test_constraint(struct Object *ob, struct bConstraint *cons) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   struct bKinematicConstraint *data = (struct bKinematicConstraint *)cons->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* only for IK constraint */ | 
					
						
							| 
									
										
										
										
											2020-11-06 17:49:09 +01:00
										 |  |  |   if (cons->type != CONSTRAINT_TYPE_KINEMATIC || data == nullptr) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-05-31 22:51:19 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   switch (data->type) { | 
					
						
							|  |  |  |     case CONSTRAINT_IK_COPYPOSE: | 
					
						
							|  |  |  |     case CONSTRAINT_IK_DISTANCE: | 
					
						
							|  |  |  |       /* cartesian space constraint */ | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-09-24 21:22:24 +00:00
										 |  |  | } |