link_containers.py 86 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  1. from .node_container_common import *
  2. from bpy.types import Node, Bone
  3. from .base_definitions import MantisNode, GraphError
  4. #TODO: get rid of this, it's unnecesary here, we always want to import
  5. # all classes in this file
  6. def TellClasses():
  7. return [
  8. # special
  9. LinkInherit,
  10. # copy
  11. LinkCopyLocation,
  12. LinkCopyRotation,
  13. LinkCopyScale,
  14. LinkCopyTransforms,
  15. LinkTransformation,
  16. # limit
  17. LinkLimitLocation,
  18. LinkLimitRotation,
  19. LinkLimitScale,
  20. LinkLimitDistance,
  21. # tracking
  22. LinkStretchTo,
  23. LinkDampedTrack,
  24. LinkLockedTrack,
  25. LinkTrackTo,
  26. #misc
  27. LinkInheritConstraint,
  28. LinkArmature,
  29. # IK
  30. LinkInverseKinematics,
  31. LinkSplineIK,
  32. # Drivers
  33. LinkDrivenParameter,
  34. ]
  35. def default_evaluate_input(nc, input_name):
  36. # should catch 'Target', 'Pole Target' and ArmatureConstraint targets, too
  37. if ('Target' in input_name) and input_name not in ["Target Space", "Use Target Z"]:
  38. socket = nc.inputs.get(input_name)
  39. if socket.is_linked:
  40. return socket.links[0].from_node
  41. return None
  42. else:
  43. return evaluate_input(nc, input_name)
  44. # def set_constraint_name(nc):
  45. # if name := nc.evaluate_input("Name"):
  46. # return name
  47. # return nc.__class__.__name__
  48. # set the name if it is available, otherwise just use the constraint's nice name
  49. set_constraint_name = lambda nc : nc.evaluate_input("Name") if nc.evaluate_input("Name") else nc.__class__.__name__
  50. #*#-------------------------------#++#-------------------------------#*#
  51. # L I N K N O D E S
  52. #*#-------------------------------#++#-------------------------------#*#
  53. def GetxForm(nc):
  54. trace = trace_single_line_up(nc, "Output Relationship")
  55. for node in trace[0]:
  56. if (node.node_type == 'XFORM'):
  57. return node
  58. raise GraphError("%s is not connected to a downstream xForm" % nc)
  59. class LinkInherit:
  60. '''A node representing inheritance'''
  61. def __init__(self, signature, base_tree):
  62. self.base_tree=base_tree
  63. self.signature = signature
  64. self.inputs = {
  65. "Parent" : NodeSocket(is_input = True, name = "Parent", node = self,),
  66. # bone only:
  67. "Inherit Rotation" : NodeSocket(is_input = True, name = "Inherit Rotation", node = self,),
  68. "Inherit Scale" : NodeSocket(is_input = True, name = "Inherit Scale", node = self,),
  69. "Connected" : NodeSocket(is_input = True, name = "Connected", node = self,),
  70. }
  71. self.outputs = { "Inheritance" : NodeSocket(name = "Inheritance", node = self) }
  72. self.parameters = {
  73. "Parent":None,
  74. # bone only:
  75. "Inherit Rotation":None,
  76. "Inherit Scale":None,
  77. "Connected":None,
  78. }
  79. self.links = {} # leave this empty for now!
  80. # now set up the traverse target...
  81. self.inputs["Parent"].set_traverse_target(self.outputs["Inheritance"])
  82. self.outputs["Inheritance"].set_traverse_target(self.inputs["Parent"])
  83. self.node_type = 'LINK'
  84. self.hierarchy_connections = []
  85. self.connections = []
  86. self.hierarchy_dependencies = []
  87. self.dependencies = []
  88. self.prepared = True
  89. self.executed = True
  90. def evaluate_input(self, input_name):
  91. return default_evaluate_input(self, input_name)
  92. def GetxForm(self): # DUPLICATED, TODO fix this
  93. # I think this is only run in display update.
  94. trace = trace_single_line_up(self, "Inheritance")
  95. for node in trace[0]:
  96. if (node.node_type == 'XFORM'):
  97. return node
  98. raise GraphError("%s is not connected to a downstream xForm" % self)
  99. class LinkCopyLocation:
  100. '''A node representing Copy Location'''
  101. def __init__(self, signature, base_tree):
  102. self.base_tree=base_tree
  103. self.signature = signature
  104. self.inputs = {
  105. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  106. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  107. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  108. "Axes" : NodeSocket(is_input = True, name = "Axes", node = self,),
  109. "Invert" : NodeSocket(is_input = True, name = "Invert", node = self,),
  110. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  111. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  112. "Offset" : NodeSocket(is_input = True, name = "Offset", node = self,),
  113. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  114. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  115. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  116. self.outputs = {
  117. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  118. self.parameters = {
  119. "Name":None,
  120. "Input Relationship":None,
  121. "Head/Tail":None,
  122. "UseBBone":None,
  123. "Axes":None,
  124. "Invert":None,
  125. "Target Space":None,
  126. "Owner Space":None,
  127. "Offset":None,
  128. "Influence":None,
  129. "Target":None,
  130. "Enable":None, }
  131. # now set up the traverse target...
  132. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  133. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  134. self.node_type = 'LINK'
  135. self.hierarchy_connections = []
  136. self.connections = []
  137. self.hierarchy_dependencies = []
  138. self.dependencies = []
  139. self.prepared = True
  140. self.executed = False
  141. def evaluate_input(self, input_name):
  142. return default_evaluate_input(self, input_name)
  143. def GetxForm(self):
  144. return GetxForm(self)
  145. def bExecute(self, context):
  146. prepare_parameters(self)
  147. c = self.GetxForm().bGetObject().constraints.new('COPY_LOCATION')
  148. get_target_and_subtarget(self, c)
  149. print(wrapGreen("Creating ")+wrapWhite("Copy Location")+
  150. wrapGreen(" Constraint for bone: ") +
  151. wrapOrange(self.GetxForm().bGetObject().name))
  152. if constraint_name := self.evaluate_input("Name"):
  153. c.name = constraint_name
  154. self.bObject = c
  155. custom_space_owner, custom_space_target = False, False
  156. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  157. custom_space_owner=True
  158. c.owner_space='CUSTOM'
  159. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  160. if isinstance(xf, Bone):
  161. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  162. else:
  163. c.space_object=xf
  164. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  165. custom_space_target=True
  166. c.target_space='CUSTOM'
  167. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  168. if isinstance(xf, Bone):
  169. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  170. else:
  171. c.space_object=xf
  172. props_sockets = {
  173. 'use_offset' : ("Offset", False),
  174. 'head_tail' : ("Head/Tail", 0),
  175. 'use_bbone_shape' : ("UseBBone", False),
  176. 'invert_x' : ( ("Invert", 0), False),
  177. 'invert_y' : ( ("Invert", 1), False),
  178. 'invert_z' : ( ("Invert", 2), False),
  179. 'use_x' : ( ("Axes", 0), False),
  180. 'use_y' : ( ("Axes", 1), False),
  181. 'use_z' : ( ("Axes", 2), False),
  182. 'owner_space' : ("Owner Space", 'WORLD'),
  183. 'target_space' : ("Target Space", 'WORLD'),
  184. 'influence' : ("Influence", 1),
  185. 'mute' : ("Enable", True),
  186. }
  187. if custom_space_owner: del props_sockets['owner_space']
  188. if custom_space_target: del props_sockets['target_space']
  189. #
  190. evaluate_sockets(self, c, props_sockets)
  191. self.executed = True
  192. def bFinalize(self, bContext = None):
  193. finish_drivers(self)
  194. class LinkCopyRotation:
  195. '''A node representing Copy Rotation'''
  196. def __init__(self, signature, base_tree):
  197. self.base_tree=base_tree
  198. self.signature = signature
  199. self.inputs = {
  200. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  201. "RotationOrder" : NodeSocket(is_input = True, name = "RotationOrder", node = self,),
  202. "Rotation Mix" : NodeSocket(is_input = True, name = "Rotation Mix", node = self,),
  203. "Axes" : NodeSocket(is_input = True, name = "Axes", node = self,),
  204. "Invert" : NodeSocket(is_input = True, name = "Invert", node = self,),
  205. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  206. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  207. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  208. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  209. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  210. self.outputs = {
  211. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  212. self.parameters = {
  213. "Name":None,
  214. "Input Relationship":None,
  215. "RotationOrder":None,
  216. "Rotation Mix":None,
  217. "Axes":None,
  218. "Invert":None,
  219. "Target Space":None,
  220. "Owner Space":None,
  221. "Influence":None,
  222. "Target":None,
  223. "Enable":None, }
  224. # now set up the traverse target...
  225. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  226. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  227. self.node_type = 'LINK'
  228. self.hierarchy_connections = []
  229. self.connections = []
  230. self.hierarchy_dependencies = []
  231. self.dependencies = []
  232. self.prepared = True
  233. self.executed = False
  234. def evaluate_input(self, input_name):
  235. return default_evaluate_input(self, input_name)
  236. def GetxForm(self):
  237. return GetxForm(self)
  238. def bExecute(self, context):
  239. prepare_parameters(self)
  240. c = self.GetxForm().bGetObject().constraints.new('COPY_ROTATION')
  241. get_target_and_subtarget(self, c)
  242. print(wrapGreen("Creating ")+wrapWhite("Copy Rotation")+
  243. wrapGreen(" Constraint for bone: ") +
  244. wrapOrange(self.GetxForm().bGetObject().name))
  245. rotation_order = self.evaluate_input("RotationOrder")
  246. if ((rotation_order == 'QUATERNION') or (rotation_order == 'AXIS_ANGLE')):
  247. c.euler_order = 'AUTO'
  248. else:
  249. try:
  250. c.euler_order = rotation_order
  251. except TypeError: # it's a driver or incorrect
  252. c.euler_order = 'AUTO'
  253. if constraint_name := self.evaluate_input("Name"):
  254. c.name = constraint_name
  255. self.bObject = c
  256. custom_space_owner, custom_space_target = False, False
  257. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  258. custom_space_owner=True
  259. c.owner_space='CUSTOM'
  260. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  261. if isinstance(xf, Bone):
  262. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  263. else:
  264. c.space_object=xf
  265. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  266. custom_space_target=True
  267. c.target_space='CUSTOM'
  268. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  269. if isinstance(xf, Bone):
  270. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  271. else:
  272. c.space_object=xf
  273. props_sockets = {
  274. 'euler_order' : ("RotationOrder", 'AUTO'),
  275. 'mix_mode' : ("Rotation Mix", 'REPLACE'),
  276. 'invert_x' : ( ("Invert", 0), False),
  277. 'invert_y' : ( ("Invert", 1), False),
  278. 'invert_z' : ( ("Invert", 2), False),
  279. 'use_x' : ( ("Axes", 0), False),
  280. 'use_y' : ( ("Axes", 1), False),
  281. 'use_z' : ( ("Axes", 2), False),
  282. 'owner_space' : ("Owner Space", 'WORLD'),
  283. 'target_space' : ("Target Space", 'WORLD'),
  284. 'influence' : ("Influence", 1),
  285. 'mute' : ("Enable", True),
  286. }
  287. if custom_space_owner: del props_sockets['owner_space']
  288. if custom_space_target: del props_sockets['target_space']
  289. #
  290. evaluate_sockets(self, c, props_sockets)
  291. self.executed = True
  292. def bFinalize(self, bContext = None):
  293. finish_drivers(self)
  294. class LinkCopyScale:
  295. '''A node representing Copy Scale'''
  296. def __init__(self, signature, base_tree):
  297. self.base_tree=base_tree
  298. self.signature = signature
  299. self.inputs = {
  300. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  301. "Offset" : NodeSocket(is_input = True, name = "Offset", node = self,),
  302. "Average" : NodeSocket(is_input = True, name = "Average", node = self,),
  303. "Additive" : NodeSocket(is_input = True, name = "Additive", node = self,),
  304. "Axes" : NodeSocket(is_input = True, name = "Axes", node = self,),
  305. #"Invert" : NodeSocket(is_input = True, name = "Invert", node = self,),
  306. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  307. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  308. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  309. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  310. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  311. self.outputs = {
  312. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  313. self.parameters = {
  314. "Name":None,
  315. "Input Relationship":None,
  316. "Offset":None,
  317. "Average":None,
  318. "Axes":None,
  319. #"Invert":None,
  320. "Target Space":None,
  321. "Owner Space":None,
  322. "Influence":None,
  323. "Target":None,
  324. "Enable":None,}
  325. # now set up the traverse target...
  326. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  327. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  328. self.node_type = 'LINK'
  329. self.hierarchy_connections = []
  330. self.connections = []
  331. self.hierarchy_dependencies = []
  332. self.dependencies = []
  333. self.prepared = True
  334. self.executed = False
  335. def evaluate_input(self, input_name):
  336. return default_evaluate_input(self, input_name)
  337. def GetxForm(self):
  338. return GetxForm(self)
  339. def bExecute(self, context):
  340. prepare_parameters(self)
  341. c = self.GetxForm().bGetObject().constraints.new('COPY_SCALE')
  342. get_target_and_subtarget(self, c)
  343. print(wrapGreen("Creating ")+wrapWhite("Copy Scale")+
  344. wrapGreen(" Constraint for bone: ") +
  345. wrapOrange(self.GetxForm().bGetObject().name))
  346. if constraint_name := self.evaluate_input("Name"):
  347. c.name = constraint_name
  348. self.bObject = c
  349. custom_space_owner, custom_space_target = False, False
  350. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  351. custom_space_owner=True
  352. c.owner_space='CUSTOM'
  353. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  354. if isinstance(xf, Bone):
  355. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  356. else:
  357. c.space_object=xf
  358. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  359. custom_space_target=True
  360. c.target_space='CUSTOM'
  361. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  362. if isinstance(xf, Bone):
  363. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  364. else:
  365. c.space_object=xf
  366. props_sockets = {
  367. 'use_offset' : ("Offset", False),
  368. 'use_make_uniform' : ("Average", False),
  369. 'owner_space' : ("Owner Space", 'WORLD'),
  370. 'target_space' : ("Target Space", 'WORLD'),
  371. 'use_x' : ( ("Axes", 0), False),
  372. 'use_y' : ( ("Axes", 1), False),
  373. 'use_z' : ( ("Axes", 2), False),
  374. 'influence' : ("Influence", 1),
  375. 'mute' : ("Enable", True),
  376. }
  377. if custom_space_owner: del props_sockets['owner_space']
  378. if custom_space_target: del props_sockets['target_space']
  379. #
  380. evaluate_sockets(self, c, props_sockets)
  381. self.executed = True
  382. def bFinalize(self, bContext = None):
  383. finish_drivers(self)
  384. class LinkCopyTransforms:
  385. '''A node representing Copy Transfoms'''
  386. def __init__(self, signature, base_tree):
  387. self.base_tree=base_tree
  388. self.signature = signature
  389. self.inputs = {
  390. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  391. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  392. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  393. "Additive" : NodeSocket(is_input = True, name = "Additive", node = self,),
  394. "Mix" : NodeSocket(is_input = True, name = "Mix", node = self,),
  395. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  396. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  397. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  398. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  399. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  400. self.outputs = {
  401. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  402. self.parameters = {
  403. "Name":None,
  404. "Input Relationship":None,
  405. "Head/Tail":None,
  406. "UseBBone":None,
  407. "Mix":None,
  408. "Target Space":None,
  409. "Owner Space":None,
  410. "Influence":None,
  411. "Target":None,
  412. "Enable":None,}
  413. # now set up the traverse target...
  414. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  415. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  416. self.node_type = 'LINK'
  417. self.hierarchy_connections = []
  418. self.connections = []
  419. self.hierarchy_dependencies = []
  420. self.dependencies = []
  421. self.prepared = True
  422. self.executed = False
  423. def evaluate_input(self, input_name):
  424. return default_evaluate_input(self, input_name)
  425. def GetxForm(self):
  426. return GetxForm(self)
  427. def bExecute(self, context):
  428. prepare_parameters(self)
  429. c = self.GetxForm().bGetObject().constraints.new('COPY_TRANSFORMS')
  430. get_target_and_subtarget(self, c)
  431. print(wrapGreen("Creating ")+wrapWhite("Copy Transforms")+
  432. wrapGreen(" Constraint for bone: ") +
  433. wrapOrange(self.GetxForm().bGetObject().name))
  434. if constraint_name := self.evaluate_input("Name"):
  435. c.name = constraint_name
  436. self.bObject = c
  437. custom_space_owner, custom_space_target = False, False
  438. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  439. custom_space_owner=True
  440. c.owner_space='CUSTOM'
  441. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  442. if isinstance(xf, Bone):
  443. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  444. else:
  445. c.space_object=xf
  446. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  447. custom_space_target=True
  448. c.target_space='CUSTOM'
  449. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  450. if isinstance(xf, Bone):
  451. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  452. else:
  453. c.space_object=xf
  454. props_sockets = {
  455. 'head_tail' : ("Head/Tail", 0),
  456. 'use_bbone_shape' : ("UseBBone", False),
  457. 'mix_mode' : ("Mix", 'REPLACE'),
  458. 'owner_space' : ("Owner Space", 'WORLD'),
  459. 'target_space' : ("Target Space", 'WORLD'),
  460. 'influence' : ("Influence", 1),
  461. 'mute' : ("Enable", False)
  462. }
  463. if custom_space_owner: del props_sockets['owner_space']
  464. if custom_space_target: del props_sockets['target_space']
  465. #
  466. evaluate_sockets(self, c, props_sockets)
  467. self.executed = True
  468. def bFinalize(self, bContext = None):
  469. finish_drivers(self)
  470. transformation_props_sockets = {
  471. 'use_motion_extrapolate' : ("Extrapolate", False),
  472. 'map_from' : ("Map From", 'LOCATION'),
  473. 'from_rotation_mode' : ("Rotation Mode", 'AUTO'),
  474. 'from_min_x' : ("X Min From", 0.0),
  475. 'from_max_x' : ("X Max From", 0.0),
  476. 'from_min_y' : ("Y Min From", 0.0),
  477. 'from_max_y' : ("Y Max From", 0.0),
  478. 'from_min_z' : ("Z Min From", 0.0),
  479. 'from_max_z' : ("Z Max From", 0.0),
  480. 'from_min_x_rot' : ("X Min From", 0.0),
  481. 'from_max_x_rot' : ("X Max From", 0.0),
  482. 'from_min_y_rot' : ("Y Min From", 0.0),
  483. 'from_max_y_rot' : ("Y Max From", 0.0),
  484. 'from_min_z_rot' : ("Z Min From", 0.0),
  485. 'from_max_z_rot' : ("Z Max From", 0.0),
  486. 'from_min_x_scale' : ("X Min From", 0.0),
  487. 'from_max_x_scale' : ("X Max From", 0.0),
  488. 'from_min_y_scale' : ("Y Min From", 0.0),
  489. 'from_max_y_scale' : ("Y Max From", 0.0),
  490. 'from_min_z_scale' : ("Z Min From", 0.0),
  491. 'from_max_z_scale' : ("Z Max From", 0.0),
  492. 'map_to' : ("Map To", "LOCATION"),
  493. 'map_to_x_from' : ("X Source Axis", "X"),
  494. 'map_to_y_from' : ("Y Source Axis", "Y"),
  495. 'map_to_z_from' : ("Z Source Axis", "Z"),
  496. 'to_min_x' : ("X Min To", 0.0),
  497. 'to_max_x' : ("X Max To", 0.0),
  498. 'to_min_y' : ("Y Min To", 0.0),
  499. 'to_max_y' : ("Y Max To", 0.0),
  500. 'to_min_z' : ("Z Min To", 0.0),
  501. 'to_max_z' : ("Z Max To", 0.0),
  502. 'to_min_x_rot' : ("X Min To", 0.0),
  503. 'to_max_x_rot' : ("X Max To", 0.0),
  504. 'to_min_y_rot' : ("Y Min To", 0.0),
  505. 'to_max_y_rot' : ("Y Max To", 0.0),
  506. 'to_min_z_rot' : ("Z Min To", 0.0),
  507. 'to_max_z_rot' : ("Z Max To", 0.0),
  508. 'to_min_x_scale' : ("X Min To", 0.0),
  509. 'to_max_x_scale' : ("X Max To", 0.0),
  510. 'to_min_y_scale' : ("Y Min To", 0.0),
  511. 'to_max_y_scale' : ("Y Max To", 0.0),
  512. 'to_min_z_scale' : ("Z Min To", 0.0),
  513. 'to_max_z_scale' : ("Z Max To", 0.0),
  514. 'to_euler_order' : ("Rotation Mode", "AUTO"),
  515. 'mix_mode' : ("Mix Mode (Translation)", "ADD"),
  516. 'mix_mode_rot' : ("Mix Mode (Rotation)", "ADD"),
  517. 'mix_mode_scale' : ("Mix Mode (Scale)", "MULTIPLY"),
  518. 'owner_space' : ("Owner Space", 'WORLD'),
  519. 'target_space' : ("Target Space", 'WORLD'),
  520. 'influence' : ("Influence", 1),
  521. 'mute' : ("Enable", False),
  522. }
  523. class LinkTransformation:
  524. '''A node representing Copy Transfoms'''
  525. def __init__(self, signature, base_tree):
  526. self.base_tree=base_tree
  527. self.signature = signature
  528. self.inputs = {
  529. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  530. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  531. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  532. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  533. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  534. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,),
  535. "Extrapolate" : NodeSocket(is_input = True, name = "Extrapolate", node = self,),
  536. "Map From" : NodeSocket(is_input = True, name = "Map From", node = self,),
  537. "Rotation Mode" : NodeSocket(is_input = True, name = "Rotation Mode", node = self,),
  538. "X Min From" : NodeSocket(is_input = True, name = "X Min From", node = self,),
  539. "X Max From" : NodeSocket(is_input = True, name = "X Max From", node = self,),
  540. "Y Min From" : NodeSocket(is_input = True, name = "Y Min From", node = self,),
  541. "Y Max From" : NodeSocket(is_input = True, name = "Y Max From", node = self,),
  542. "Z Min From" : NodeSocket(is_input = True, name = "Z Min From", node = self,),
  543. "Z Max From" : NodeSocket(is_input = True, name = "Z Max From", node = self,),
  544. "Map To" : NodeSocket(is_input = True, name = "Map To", node = self,),
  545. "X Source Axis" : NodeSocket(is_input = True, name = "X Source Axis", node = self,),
  546. "X Min To" : NodeSocket(is_input = True, name = "X Min To", node = self,),
  547. "X Max To" : NodeSocket(is_input = True, name = "X Max To", node = self,),
  548. "Y Source Axis" : NodeSocket(is_input = True, name = "Y Source Axis", node = self,),
  549. "Y Min To" : NodeSocket(is_input = True, name = "Y Min To", node = self,),
  550. "Y Max To" : NodeSocket(is_input = True, name = "Y Max To", node = self,),
  551. "Z Source Axis" : NodeSocket(is_input = True, name = "Z Source Axis", node = self,),
  552. "Z Min To" : NodeSocket(is_input = True, name = "Z Min To", node = self,),
  553. "Z Max To" : NodeSocket(is_input = True, name = "Z Max To", node = self,),
  554. "Rotation Mode" : NodeSocket(is_input = True, name = "Rotation Mode", node = self,),
  555. "Mix Mode (Translation)" : NodeSocket(is_input = True, name = "Mix Mode (Translation)", node = self,),
  556. "Mix Mode (Rotation)" : NodeSocket(is_input = True, name = "Mix Mode (Rotation)", node = self,),
  557. "Mix Mode (Scale)" : NodeSocket(is_input = True, name = "Mix Mode (Scale)", node = self,),
  558. }
  559. self.outputs = {
  560. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  561. self.parameters = {
  562. "Name" : None,
  563. "Input Relationship" : None,
  564. "Target Space" : None,
  565. "Owner Space" : None,
  566. "Influence" : None,
  567. "Target" : None,
  568. "Enable" : None,
  569. "Extrapolate" : None,
  570. "Map From" : None,
  571. "Rotation Mode" : None,
  572. "X Min From" : None,
  573. "X Max From" : None,
  574. "Y Min From" : None,
  575. "Y Max From" : None,
  576. "Z Min From" : None,
  577. "Z Max From" : None,
  578. "Map To" : None,
  579. "X Source Axis" : None,
  580. "X Min To" : None,
  581. "X Max To" : None,
  582. "Y Source Axis" : None,
  583. "Y Min To" : None,
  584. "Y Max To" : None,
  585. "Z Source Axis" : None,
  586. "Z Min To" : None,
  587. "Z Max To" : None,
  588. "Rotation Order" : None,
  589. "Mix Mode (Translation)" : None,
  590. "Mix Mode (Rotation)" : None,
  591. "Mix Mode (Scale)" : None,}
  592. # now set up the traverse target...
  593. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  594. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  595. self.node_type = 'LINK'
  596. self.hierarchy_connections = []
  597. self.connections = []
  598. self.hierarchy_dependencies = []
  599. self.dependencies = []
  600. self.prepared = True
  601. self.executed = False
  602. def evaluate_input(self, input_name):
  603. return default_evaluate_input(self, input_name)
  604. def GetxForm(self):
  605. return GetxForm(self)
  606. def bExecute(self, context):
  607. prepare_parameters(self)
  608. c = self.GetxForm().bGetObject().constraints.new('TRANSFORM')
  609. get_target_and_subtarget(self, c)
  610. print(wrapGreen("Creating ")+wrapWhite("Transformation")+
  611. wrapGreen(" Constraint for bone: ") +
  612. wrapOrange(self.GetxForm().bGetObject().name))
  613. if constraint_name := self.evaluate_input("Name"):
  614. c.name = constraint_name
  615. self.bObject = c
  616. custom_space_owner, custom_space_target = False, False
  617. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  618. custom_space_owner=True
  619. c.owner_space='CUSTOM'
  620. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  621. if isinstance(xf, Bone):
  622. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  623. else:
  624. c.space_object=xf
  625. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  626. custom_space_target=True
  627. c.target_space='CUSTOM'
  628. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  629. if isinstance(xf, Bone):
  630. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  631. else:
  632. c.space_object=xf
  633. props_sockets = transformation_props_sockets.copy()
  634. if custom_space_owner: del props_sockets['owner_space']
  635. if custom_space_target: del props_sockets['target_space']
  636. #
  637. evaluate_sockets(self, c, props_sockets)
  638. self.executed = True
  639. def bFinalize(self, bContext = None):
  640. finish_drivers(self)
  641. class LinkLimitLocation:
  642. def __init__(self, signature, base_tree):
  643. self.base_tree=base_tree
  644. self.signature = signature
  645. self.inputs = {
  646. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  647. "Use Max X" : NodeSocket(is_input = True, name = "Use Max X", node = self,),
  648. "Max X" : NodeSocket(is_input = True, name = "Max X", node = self,),
  649. "Use Max Y" : NodeSocket(is_input = True, name = "Use Max Y", node = self,),
  650. "Max Y" : NodeSocket(is_input = True, name = "Max Y", node = self,),
  651. "Use Max Z" : NodeSocket(is_input = True, name = "Use Max Z", node = self,),
  652. "Max Z" : NodeSocket(is_input = True, name = "Max Z", node = self,),
  653. "Use Min X" : NodeSocket(is_input = True, name = "Use Min X", node = self,),
  654. "Min X" : NodeSocket(is_input = True, name = "Min X", node = self,),
  655. "Use Min Y" : NodeSocket(is_input = True, name = "Use Min Y", node = self,),
  656. "Min Y" : NodeSocket(is_input = True, name = "Min Y", node = self,),
  657. "Use Min Z" : NodeSocket(is_input = True, name = "Use Min Z", node = self,),
  658. "Min Z" : NodeSocket(is_input = True, name = "Min Z", node = self,),
  659. "Affect Transform" : NodeSocket(is_input = True, name = "Affect Transform", node = self,),
  660. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  661. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  662. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  663. self.outputs = {
  664. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  665. self.parameters = {
  666. "Name":None,
  667. "Input Relationship":None,
  668. "Use Max X":None,
  669. "Max X":None,
  670. "Use Max Y":None,
  671. "Max Y":None,
  672. "Use Max Z":None,
  673. "Max Z":None,
  674. "Use Min X":None,
  675. "Min X":None,
  676. "Use Min Y":None,
  677. "Min Y":None,
  678. "Use Min Z":None,
  679. "Min Z":None,
  680. "Affect Transform":None,
  681. "Owner Space":None,
  682. "Influence":None,
  683. "Enable":None,}
  684. # now set up the traverse target...
  685. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  686. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  687. self.node_type = 'LINK'
  688. self.hierarchy_connections = []
  689. self.connections = []
  690. self.hierarchy_dependencies = []
  691. self.dependencies = []
  692. self.prepared = True
  693. self.executed = False
  694. def evaluate_input(self, input_name):
  695. return default_evaluate_input(self, input_name)
  696. def GetxForm(self):
  697. return GetxForm(self)
  698. def bExecute(self, context):
  699. prepare_parameters(self)
  700. c = self.GetxForm().bGetObject().constraints.new('LIMIT_LOCATION')
  701. #
  702. print(wrapGreen("Creating ")+wrapWhite("Limit Location")+
  703. wrapGreen(" Constraint for bone: ") +
  704. wrapOrange(self.GetxForm().bGetObject().name))
  705. if constraint_name := self.evaluate_input("Name"):
  706. c.name = constraint_name
  707. self.bObject = c
  708. custom_space_owner = False
  709. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  710. custom_space_owner=True
  711. c.owner_space='CUSTOM'
  712. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  713. if isinstance(xf, Bone):
  714. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  715. else:
  716. c.space_object=xf
  717. props_sockets = {
  718. 'use_transform_limit' : ("Affect Transform", False),
  719. 'use_max_x' : ("Use Max X", False),
  720. 'use_max_y' : ("Use Max Y", False),
  721. 'use_max_z' : ("Use Max Z", False),
  722. 'use_min_x' : ("Use Min X", False),
  723. 'use_min_y' : ("Use Min Y", False),
  724. 'use_min_z' : ("Use Min Z", False),
  725. 'max_x' : ("Max X", 0),
  726. 'max_y' : ("Max Y", 0),
  727. 'max_z' : ("Max Z", 0),
  728. 'min_x' : ("Min X", 0),
  729. 'min_y' : ("Min Y", 0),
  730. 'min_z' : ("Min Z", 0),
  731. 'owner_space' : ("Owner Space", 'WORLD'),
  732. 'influence' : ("Influence", 1),
  733. 'mute' : ("Enable", True),
  734. }
  735. if custom_space_owner: del props_sockets['owner_space']
  736. #
  737. evaluate_sockets(self, c, props_sockets)
  738. self.executed = True
  739. def bFinalize(self, bContext = None):
  740. finish_drivers(self)
  741. class LinkLimitRotation:
  742. def __init__(self, signature, base_tree):
  743. self.base_tree=base_tree
  744. self.signature = signature
  745. self.inputs = {
  746. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  747. "Use X" : NodeSocket(is_input = True, name = "Use X", node = self,),
  748. "Use Y" : NodeSocket(is_input = True, name = "Use Y", node = self,),
  749. "Use Z" : NodeSocket(is_input = True, name = "Use Z", node = self,),
  750. "Max X" : NodeSocket(is_input = True, name = "Max X", node = self,),
  751. "Max Y" : NodeSocket(is_input = True, name = "Max Y", node = self,),
  752. "Max Z" : NodeSocket(is_input = True, name = "Max Z", node = self,),
  753. "Min X" : NodeSocket(is_input = True, name = "Min X", node = self,),
  754. "Min Y" : NodeSocket(is_input = True, name = "Min Y", node = self,),
  755. "Min Z" : NodeSocket(is_input = True, name = "Min Z", node = self,),
  756. "Affect Transform" : NodeSocket(is_input = True, name = "Affect Transform", node = self,),
  757. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  758. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  759. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  760. self.outputs = {
  761. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  762. self.parameters = {
  763. "Name":None,
  764. "Input Relationship":None,
  765. "Use X":None,
  766. "Use Y":None,
  767. "Use Z":None,
  768. "Max X":None,
  769. "Max Y":None,
  770. "Max Z":None,
  771. "Min X":None,
  772. "Min Y":None,
  773. "Min Z":None,
  774. "Affect Transform":None,
  775. "Owner Space":None,
  776. "Influence":None,
  777. "Enable":None,}
  778. # now set up the traverse target...
  779. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  780. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  781. self.node_type = 'LINK'
  782. self.hierarchy_connections = []
  783. self.connections = []
  784. self.hierarchy_dependencies = []
  785. self.dependencies = []
  786. self.prepared = True
  787. self.executed = False
  788. def evaluate_input(self, input_name):
  789. return default_evaluate_input(self, input_name)
  790. def GetxForm(self):
  791. return GetxForm(self)
  792. def bExecute(self, context):
  793. prepare_parameters(self)
  794. c = self.GetxForm().bGetObject().constraints.new('LIMIT_ROTATION')
  795. print(wrapGreen("Creating ")+wrapWhite("Limit Rotation")+
  796. wrapGreen(" Constraint for bone: ") +
  797. wrapOrange(self.GetxForm().bGetObject().name))
  798. if constraint_name := self.evaluate_input("Name"):
  799. c.name = constraint_name
  800. self.bObject = c
  801. custom_space_owner = False
  802. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  803. custom_space_owner=True
  804. c.owner_space='CUSTOM'
  805. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  806. if isinstance(xf, Bone):
  807. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  808. else:
  809. c.space_object=xf
  810. props_sockets = {
  811. 'use_transform_limit' : ("Affect Transform", False),
  812. 'use_limit_x' : ("Use X", False),
  813. 'use_limit_y' : ("Use Y", False),
  814. 'use_limit_z' : ("Use Z", False),
  815. 'max_x' : ("Max X", 0),
  816. 'max_y' : ("Max Y", 0),
  817. 'max_z' : ("Max Z", 0),
  818. 'min_x' : ("Min X", 0),
  819. 'min_y' : ("Min Y", 0),
  820. 'min_z' : ("Min Z", 0),
  821. 'owner_space' : ("Owner Space", 'WORLD'),
  822. 'influence' : ("Influence", 1),
  823. 'mute' : ("Enable", True),
  824. }
  825. if custom_space_owner: del props_sockets['owner_space']
  826. #
  827. evaluate_sockets(self, c, props_sockets)
  828. self.executed = True
  829. def bFinalize(self, bContext = None):
  830. finish_drivers(self)
  831. class LinkLimitScale:
  832. def __init__(self, signature, base_tree):
  833. self.base_tree=base_tree
  834. self.signature = signature
  835. self.inputs = {
  836. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  837. "Use Max X" : NodeSocket(is_input = True, name = "Use Max X", node = self,),
  838. "Max X" : NodeSocket(is_input = True, name = "Max X", node = self,),
  839. "Use Max Y" : NodeSocket(is_input = True, name = "Use Max Y", node = self,),
  840. "Max Y" : NodeSocket(is_input = True, name = "Max Y", node = self,),
  841. "Use Max Z" : NodeSocket(is_input = True, name = "Use Max Z", node = self,),
  842. "Max Z" : NodeSocket(is_input = True, name = "Max Z", node = self,),
  843. "Use Min X" : NodeSocket(is_input = True, name = "Use Min X", node = self,),
  844. "Min X" : NodeSocket(is_input = True, name = "Min X", node = self,),
  845. "Use Min Y" : NodeSocket(is_input = True, name = "Use Min Y", node = self,),
  846. "Min Y" : NodeSocket(is_input = True, name = "Min Y", node = self,),
  847. "Use Min Z" : NodeSocket(is_input = True, name = "Use Min Z", node = self,),
  848. "Min Z" : NodeSocket(is_input = True, name = "Min Z", node = self,),
  849. "Affect Transform" : NodeSocket(is_input = True, name = "Affect Transform", node = self,),
  850. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  851. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  852. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  853. self.outputs = {
  854. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  855. self.parameters = {
  856. "Name":None,
  857. "Input Relationship":None,
  858. "Use Max X":None,
  859. "Max X":None,
  860. "Use Max Y":None,
  861. "Max Y":None,
  862. "Use Max Z":None,
  863. "Max Z":None,
  864. "Use Min X":None,
  865. "Min X":None,
  866. "Use Min Y":None,
  867. "Min Y":None,
  868. "Use Min Z":None,
  869. "Min Z":None,
  870. "Affect Transform":None,
  871. "Owner Space":None,
  872. "Influence":None,
  873. "Enable":None,}
  874. # now set up the traverse target...
  875. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  876. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  877. self.node_type = 'LINK'
  878. self.hierarchy_connections = []
  879. self.connections = []
  880. self.hierarchy_dependencies = []
  881. self.dependencies = []
  882. self.prepared = True
  883. self.executed = False
  884. def evaluate_input(self, input_name):
  885. return default_evaluate_input(self, input_name)
  886. def GetxForm(self):
  887. return GetxForm(self)
  888. def bExecute(self, context):
  889. prepare_parameters(self)
  890. c = self.GetxForm().bGetObject().constraints.new('LIMIT_SCALE')
  891. print(wrapGreen("Creating ")+wrapWhite("Limit Scale")+
  892. wrapGreen(" Constraint for bone: ") +
  893. wrapOrange(self.GetxForm().bGetObject().name))
  894. if constraint_name := self.evaluate_input("Name"):
  895. c.name = constraint_name
  896. self.bObject = c
  897. custom_space_owner = False
  898. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  899. custom_space_owner=True
  900. c.owner_space='CUSTOM'
  901. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  902. if isinstance(xf, Bone):
  903. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  904. else:
  905. c.space_object=xf
  906. props_sockets = {
  907. 'use_transform_limit' : ("Affect Transform", False),
  908. 'use_max_x' : ("Use Max X", False),
  909. 'use_max_y' : ("Use Max Y", False),
  910. 'use_max_z' : ("Use Max Z", False),
  911. 'use_min_x' : ("Use Min X", False),
  912. 'use_min_y' : ("Use Min Y", False),
  913. 'use_min_z' : ("Use Min Z", False),
  914. 'max_x' : ("Max X", 0),
  915. 'max_y' : ("Max Y", 0),
  916. 'max_z' : ("Max Z", 0),
  917. 'min_x' : ("Min X", 0),
  918. 'min_y' : ("Min Y", 0),
  919. 'min_z' : ("Min Z", 0),
  920. 'owner_space' : ("Owner Space", 'WORLD'),
  921. 'influence' : ("Influence", 1),
  922. 'mute' : ("Enable", True),
  923. }
  924. if custom_space_owner: del props_sockets['owner_space']
  925. #
  926. evaluate_sockets(self, c, props_sockets)
  927. self.executed = True
  928. def bFinalize(self, bContext = None):
  929. finish_drivers(self)
  930. class LinkLimitDistance:
  931. def __init__(self, signature, base_tree):
  932. self.base_tree=base_tree
  933. self.signature = signature
  934. self.inputs = {
  935. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  936. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  937. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  938. "Distance" : NodeSocket(is_input = True, name = "Distance", node = self,),
  939. "Clamp Region" : NodeSocket(is_input = True, name = "Clamp Region", node = self,),
  940. "Affect Transform" : NodeSocket(is_input = True, name = "Affect Transform", node = self,),
  941. "Owner Space" : NodeSocket(is_input = True, name = "Owner Space", node = self,),
  942. "Target Space" : NodeSocket(is_input = True, name = "Target Space", node = self,),
  943. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  944. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  945. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  946. self.outputs = {
  947. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  948. self.parameters = {
  949. "Name":None,
  950. "Input Relationship":None,
  951. "Head/Tail":None,
  952. "UseBBone":None,
  953. "Distance":None,
  954. "Clamp Region":None,
  955. "Affect Transform":None,
  956. "Owner Space":None,
  957. "Target Space":None,
  958. "Influence":None,
  959. "Target":None,
  960. "Enable":None,}
  961. # now set up the traverse target...
  962. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  963. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  964. self.node_type = 'LINK'
  965. self.hierarchy_connections = []
  966. self.connections = []
  967. self.hierarchy_dependencies = []
  968. self.dependencies = []
  969. self.prepared = True
  970. self.executed = False
  971. def evaluate_input(self, input_name):
  972. return default_evaluate_input(self, input_name)
  973. def GetxForm(self):
  974. return GetxForm(self)
  975. def bExecute(self, context):
  976. prepare_parameters(self)
  977. print(wrapGreen("Creating ")+wrapWhite("Limit Distance")+
  978. wrapGreen(" Constraint for bone: ") +
  979. wrapOrange(self.GetxForm().bGetObject().name))
  980. c = self.GetxForm().bGetObject().constraints.new('LIMIT_DISTANCE')
  981. get_target_and_subtarget(self, c)
  982. if constraint_name := self.evaluate_input("Name"):
  983. c.name = constraint_name
  984. self.bObject = c
  985. #
  986. # TODO: set distance automagically
  987. # IMPORTANT TODO BUG
  988. custom_space_owner, custom_space_target = False, False
  989. if self.inputs["Owner Space"].is_connected and self.inputs["Owner Space"].links[0].from_node.node_type == 'XFORM':
  990. custom_space_owner=True
  991. c.owner_space='CUSTOM'
  992. xf = self.inputs["Owner Space"].links[0].from_node.bGetObject(mode="OBJECT")
  993. if isinstance(xf, Bone):
  994. c.space_object=self.inputs["Owner Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  995. else:
  996. c.space_object=xf
  997. if self.inputs["Target Space"].is_connected and self.inputs["Target Space"].links[0].from_node.node_type == 'XFORM':
  998. custom_space_target=True
  999. c.target_space='CUSTOM'
  1000. xf = self.inputs["Target Space"].links[0].from_node.bGetObject(mode="OBJECT")
  1001. if isinstance(xf, Bone):
  1002. c.space_object=self.inputs["Target Space"].links[0].from_node.bGetParentArmature(); c.space_subtarget=xf.name
  1003. else:
  1004. c.space_object=xf
  1005. props_sockets = {
  1006. 'distance' : ("Distance", 0),
  1007. 'head_tail' : ("Head/Tail", 0),
  1008. 'limit_mode' : ("Clamp Region", "LIMITDIST_INSIDE"),
  1009. 'use_bbone_shape' : ("UseBBone", False),
  1010. 'use_transform_limit' : ("Affect Transform", 1),
  1011. 'owner_space' : ("Owner Space", 1),
  1012. 'target_space' : ("Target Space", 1),
  1013. 'influence' : ("Influence", 1),
  1014. 'mute' : ("Enable", True),
  1015. }
  1016. if custom_space_owner: del props_sockets['owner_space']
  1017. if custom_space_target: del props_sockets['target_space']
  1018. #
  1019. evaluate_sockets(self, c, props_sockets)
  1020. self.executed = True
  1021. def bFinalize(self, bContext = None):
  1022. finish_drivers(self)
  1023. # Tracking
  1024. class LinkStretchTo:
  1025. def __init__(self, signature, base_tree):
  1026. self.base_tree=base_tree
  1027. self.signature = signature
  1028. self.inputs = {
  1029. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1030. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  1031. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  1032. "Original Length" : NodeSocket(is_input = True, name = "Original Length", node = self,),
  1033. "Volume Variation" : NodeSocket(is_input = True, name = "Volume Variation", node = self,),
  1034. "Use Volume Min" : NodeSocket(is_input = True, name = "Use Volume Min", node = self,),
  1035. "Volume Min" : NodeSocket(is_input = True, name = "Volume Min", node = self,),
  1036. "Use Volume Max" : NodeSocket(is_input = True, name = "Use Volume Max", node = self,),
  1037. "Volume Max" : NodeSocket(is_input = True, name = "Volume Max", node = self,),
  1038. "Smooth" : NodeSocket(is_input = True, name = "Smooth", node = self,),
  1039. "Maintain Volume" : NodeSocket(is_input = True, name = "Maintain Volume", node = self,),
  1040. "Rotation" : NodeSocket(is_input = True, name = "Rotation", node = self,),
  1041. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1042. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1043. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1044. self.outputs = {
  1045. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1046. self.parameters = {
  1047. "Name":None,
  1048. "Input Relationship":None,
  1049. "Head/Tail":None,
  1050. "UseBBone":None,
  1051. "Original Length":None,
  1052. "Volume Variation":None,
  1053. "Use Volume Min":None,
  1054. "Volume Min":None,
  1055. "Use Volume Max":None,
  1056. "Volume Max":None,
  1057. "Smooth":None,
  1058. "Maintain Volume":None,
  1059. "Rotation":None,
  1060. "Influence":None,
  1061. "Target":None,
  1062. "Enable":None,}
  1063. # now set up the traverse target...
  1064. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1065. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1066. self.node_type = 'LINK'
  1067. self.hierarchy_connections = []
  1068. self.connections = []
  1069. self.hierarchy_dependencies = []
  1070. self.dependencies = []
  1071. self.prepared = True
  1072. self.executed = False
  1073. def evaluate_input(self, input_name):
  1074. return default_evaluate_input(self, input_name)
  1075. def GetxForm(self):
  1076. return GetxForm(self)
  1077. def bExecute(self, context):
  1078. prepare_parameters(self)
  1079. print(wrapGreen("Creating ")+wrapWhite("Stretch-To")+
  1080. wrapGreen(" Constraint for bone: ") +
  1081. wrapOrange(self.GetxForm().bGetObject().name))
  1082. c = self.GetxForm().bGetObject().constraints.new('STRETCH_TO')
  1083. get_target_and_subtarget(self, c)
  1084. if constraint_name := self.evaluate_input("Name"):
  1085. c.name = constraint_name
  1086. self.bObject = c
  1087. props_sockets = {
  1088. 'head_tail' : ("Head/Tail", 0),
  1089. 'use_bbone_shape' : ("UseBBone", False),
  1090. 'bulge' : ("Volume Variation", 0),
  1091. 'use_bulge_min' : ("Use Volume Min", False),
  1092. 'bulge_min' : ("Volume Min", 0),
  1093. 'use_bulge_max' : ("Use Volume Max", False),
  1094. 'bulge_max' : ("Volume Max", 0),
  1095. 'bulge_smooth' : ("Smooth", 0),
  1096. 'volume' : ("Maintain Volume", 'VOLUME_XZX'),
  1097. 'keep_axis' : ("Rotation", 'PLANE_X'),
  1098. 'rest_length' : ("Original Length", self.GetxForm().bGetObject().bone.length),
  1099. 'influence' : ("Influence", 1),
  1100. 'mute' : ("Enable", True),
  1101. }
  1102. evaluate_sockets(self, c, props_sockets)
  1103. if (self.evaluate_input("Original Length") == 0):
  1104. # this is meant to be set automatically.
  1105. c.rest_length = self.GetxForm().bGetObject().bone.length
  1106. self.executed = True
  1107. def bFinalize(self, bContext = None):
  1108. finish_drivers(self)
  1109. class LinkDampedTrack:
  1110. def __init__(self, signature, base_tree):
  1111. self.base_tree=base_tree
  1112. self.signature = signature
  1113. self.inputs = {
  1114. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1115. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  1116. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  1117. "Track Axis" : NodeSocket(is_input = True, name = "Track Axis", node = self,),
  1118. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1119. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1120. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1121. self.outputs = {
  1122. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1123. self.parameters = {
  1124. "Name":None,
  1125. "Input Relationship":None,
  1126. "Head/Tail":None,
  1127. "UseBBone":None,
  1128. "Track Axis":None,
  1129. "Influence":None,
  1130. "Target":None,
  1131. "Enable":None,}
  1132. # now set up the traverse target...
  1133. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1134. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1135. self.node_type = 'LINK'
  1136. self.hierarchy_connections = []
  1137. self.connections = []
  1138. self.hierarchy_dependencies = []
  1139. self.dependencies = []
  1140. self.prepared = True
  1141. self.executed = False
  1142. def evaluate_input(self, input_name):
  1143. return default_evaluate_input(self, input_name)
  1144. def GetxForm(self):
  1145. return GetxForm(self)
  1146. def bExecute(self, context):
  1147. prepare_parameters(self)
  1148. print(wrapGreen("Creating ")+wrapWhite("Damped Track")+
  1149. wrapGreen(" Constraint for bone: ") +
  1150. wrapOrange(self.GetxForm().bGetObject().name))
  1151. c = self.GetxForm().bGetObject().constraints.new('DAMPED_TRACK')
  1152. get_target_and_subtarget(self, c)
  1153. if constraint_name := self.evaluate_input("Name"):
  1154. c.name = constraint_name
  1155. self.bObject = c
  1156. props_sockets = {
  1157. 'head_tail' : ("Head/Tail", 0),
  1158. 'use_bbone_shape' : ("UseBBone", False),
  1159. 'track_axis' : ("Track Axis", 'TRACK_Y'),
  1160. 'influence' : ("Influence", 1),
  1161. 'mute' : ("Enable", True),
  1162. }
  1163. evaluate_sockets(self, c, props_sockets)
  1164. self.executed = True
  1165. def bFinalize(self, bContext = None):
  1166. finish_drivers(self)
  1167. class LinkLockedTrack:
  1168. def __init__(self, signature, base_tree):
  1169. self.base_tree=base_tree
  1170. self.signature = signature
  1171. self.inputs = {
  1172. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1173. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  1174. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  1175. "Track Axis" : NodeSocket(is_input = True, name = "Track Axis", node = self,),
  1176. "Lock Axis" : NodeSocket(is_input = True, name = "Lock Axis", node = self,),
  1177. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1178. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1179. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1180. self.outputs = {
  1181. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1182. self.parameters = {
  1183. "Name":None,
  1184. "Input Relationship":None,
  1185. "Head/Tail":None,
  1186. "UseBBone":None,
  1187. "Track Axis":None,
  1188. "Lock Axis":None,
  1189. "Influence":None,
  1190. "Target":None,
  1191. "Enable":None,}
  1192. # now set up the traverse target...
  1193. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1194. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1195. self.node_type = 'LINK'
  1196. self.hierarchy_connections = []
  1197. self.connections = []
  1198. self.hierarchy_dependencies = []
  1199. self.dependencies = []
  1200. self.prepared = True
  1201. self.executed = False
  1202. def evaluate_input(self, input_name):
  1203. return default_evaluate_input(self, input_name)
  1204. def GetxForm(self):
  1205. return GetxForm(self)
  1206. def bExecute(self, context):
  1207. prepare_parameters(self)
  1208. print(wrapGreen("Creating ")+wrapWhite("Locked Track")+
  1209. wrapGreen(" Constraint for bone: ") +
  1210. wrapOrange(self.GetxForm().bGetObject().name))
  1211. c = self.GetxForm().bGetObject().constraints.new('LOCKED_TRACK')
  1212. get_target_and_subtarget(self, c)
  1213. if constraint_name := self.evaluate_input("Name"):
  1214. c.name = constraint_name
  1215. self.bObject = c
  1216. props_sockets = {
  1217. 'head_tail' : ("Head/Tail", 0),
  1218. 'use_bbone_shape' : ("UseBBone", False),
  1219. 'track_axis' : ("Track Axis", 'TRACK_Y'),
  1220. 'lock_axis' : ("Lock Axis", 'UP_X'),
  1221. 'influence' : ("Influence", 1),
  1222. 'mute' : ("Enable", True),
  1223. }
  1224. evaluate_sockets(self, c, props_sockets)
  1225. self.executed = True
  1226. def bFinalize(self, bContext = None):
  1227. finish_drivers(self)
  1228. class LinkTrackTo:
  1229. def __init__(self, signature, base_tree):
  1230. self.base_tree=base_tree
  1231. self.signature = signature
  1232. self.inputs = {
  1233. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1234. "Head/Tail" : NodeSocket(is_input = True, name = "Head/Tail", node = self,),
  1235. "UseBBone" : NodeSocket(is_input = True, name = "UseBBone", node = self,),
  1236. "Track Axis" : NodeSocket(is_input = True, name = "Track Axis", node = self,),
  1237. "Up Axis" : NodeSocket(is_input = True, name = "Up Axis", node = self,),
  1238. "Use Target Z" : NodeSocket(is_input = True, name = "Use Target Z", node = self,),
  1239. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1240. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1241. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1242. self.outputs = {
  1243. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1244. self.parameters = {
  1245. "Name":None,
  1246. "Input Relationship":None,
  1247. "Head/Tail":None,
  1248. "UseBBone":None,
  1249. "Track Axis":None,
  1250. "Up Axis":None,
  1251. "Use Target Z":None,
  1252. "Influence":None,
  1253. "Target":None,
  1254. "Enable":None,}
  1255. # now set up the traverse target...
  1256. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1257. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1258. self.node_type = 'LINK'
  1259. self.hierarchy_connections = []
  1260. self.connections = []
  1261. self.hierarchy_dependencies = []
  1262. self.dependencies = []
  1263. self.prepared = True
  1264. self.executed = False
  1265. def evaluate_input(self, input_name):
  1266. return default_evaluate_input(self, input_name)
  1267. def GetxForm(self):
  1268. return GetxForm(self)
  1269. def bExecute(self, context):
  1270. prepare_parameters(self)
  1271. print(wrapGreen("Creating ")+wrapWhite("Track-To")+
  1272. wrapGreen(" Constraint for bone: ") +
  1273. wrapOrange(self.GetxForm().bGetObject().name))
  1274. c = self.GetxForm().bGetObject().constraints.new('TRACK_TO')
  1275. get_target_and_subtarget(self, c)
  1276. if constraint_name := self.evaluate_input("Name"):
  1277. c.name = constraint_name
  1278. self.bObject = c
  1279. props_sockets = {
  1280. 'head_tail' : ("Head/Tail", 0),
  1281. 'use_bbone_shape' : ("UseBBone", False),
  1282. 'track_axis' : ("Track Axis", "TRACK_Y"),
  1283. 'up_axis' : ("Up Axis", "UP_Z"),
  1284. 'use_target_z' : ("Use Target Z", False),
  1285. 'influence' : ("Influence", 1),
  1286. 'mute' : ("Enable", True),
  1287. }
  1288. evaluate_sockets(self, c, props_sockets)
  1289. self.executed = True
  1290. def bFinalize(self, bContext = None):
  1291. finish_drivers(self)
  1292. # relationships & misc.
  1293. class LinkInheritConstraint:
  1294. def __init__(self, signature, base_tree):
  1295. self.base_tree=base_tree
  1296. self.signature = signature
  1297. self.inputs = {
  1298. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1299. "Location" : NodeSocket(is_input = True, name = "Location", node = self,),
  1300. "Rotation" : NodeSocket(is_input = True, name = "Rotation", node = self,),
  1301. "Scale" : NodeSocket(is_input = True, name = "Scale", node = self,),
  1302. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1303. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1304. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1305. self.outputs = {
  1306. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1307. self.parameters = {
  1308. "Name":None,
  1309. "Input Relationship":None,
  1310. "Location":None,
  1311. "Rotation":None,
  1312. "Scale":None,
  1313. "Influence":None,
  1314. "Target":None,
  1315. "Enable":None,}
  1316. self.drivers = {}
  1317. # now set up the traverse target...
  1318. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1319. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1320. self.node_type = 'LINK'
  1321. self.hierarchy_connections = []
  1322. self.connections = []
  1323. self.hierarchy_dependencies = []
  1324. self.dependencies = []
  1325. self.prepared = True
  1326. self.executed = False
  1327. def evaluate_input(self, input_name):
  1328. return default_evaluate_input(self, input_name)
  1329. def GetxForm(self):
  1330. return GetxForm(self)
  1331. def bExecute(self, context):
  1332. prepare_parameters(self)
  1333. print(wrapGreen("Creating ")+wrapWhite("Child-Of")+
  1334. wrapGreen(" Constraint for bone: ") +
  1335. wrapOrange(self.GetxForm().bGetObject().name))
  1336. c = self.GetxForm().bGetObject().constraints.new('CHILD_OF')
  1337. get_target_and_subtarget(self, c)
  1338. if constraint_name := self.evaluate_input("Name"):
  1339. c.name = constraint_name
  1340. self.bObject = c
  1341. props_sockets = {
  1342. 'use_location_x' : (("Location", 0) , 1),
  1343. 'use_location_y' : (("Location", 1) , 1),
  1344. 'use_location_z' : (("Location", 2) , 1),
  1345. 'use_rotation_x' : (("Rotation", 0) , 1),
  1346. 'use_rotation_y' : (("Rotation", 1) , 1),
  1347. 'use_rotation_z' : (("Rotation", 2) , 1),
  1348. 'use_scale_x' : (("Scale" , 0) , 1),
  1349. 'use_scale_y' : (("Scale" , 1) , 1),
  1350. 'use_scale_z' : (("Scale" , 2) , 1),
  1351. 'influence' : ( "Influence" , 1),
  1352. 'mute' : ("Enable", True),
  1353. }
  1354. evaluate_sockets(self, c, props_sockets)
  1355. c.set_inverse_pending
  1356. self.executed = True
  1357. def bFinalize(self, bContext = None):
  1358. finish_drivers(self)
  1359. class LinkInverseKinematics:
  1360. def __init__(self, signature, base_tree):
  1361. self.base_tree=base_tree
  1362. self.signature = signature
  1363. self.inputs = {
  1364. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1365. "Chain Length" : NodeSocket(is_input = True, name = "Chain Length", node = self,),
  1366. "Use Tail" : NodeSocket(is_input = True, name = "Use Tail", node = self,),
  1367. "Stretch" : NodeSocket(is_input = True, name = "Stretch", node = self,),
  1368. "Position" : NodeSocket(is_input = True, name = "Position", node = self,),
  1369. "Rotation" : NodeSocket(is_input = True, name = "Rotation", node = self,),
  1370. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self,),
  1371. "Target" : NodeSocket(is_input = True, name = "Target", node = self,),
  1372. "Pole Target" : NodeSocket(is_input = True, name = "Pole Target", node = self,),
  1373. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self,), }
  1374. self.outputs = {
  1375. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self) }
  1376. self.parameters = {
  1377. "Name":None,
  1378. "Connected":None,
  1379. "Chain Length":None,
  1380. "Use Tail":None,
  1381. "Stretch":None,
  1382. "Position":None,
  1383. "Rotation":None,
  1384. "Influence":None,
  1385. "Target":None,
  1386. "Pole Target":None,
  1387. "Enable":None,}
  1388. # now set up the traverse target...
  1389. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1390. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1391. self.node_type = 'LINK'
  1392. self.bObject = None
  1393. self.drivers = {}
  1394. self.hierarchy_connections = []
  1395. self.connections = []
  1396. self.hierarchy_dependencies = []
  1397. self.dependencies = []
  1398. self.prepared = True
  1399. self.executed = False
  1400. def evaluate_input(self, input_name):
  1401. return default_evaluate_input(self, input_name)
  1402. def GetxForm(self):
  1403. return GetxForm(self)
  1404. def bExecute(self, context):
  1405. prepare_parameters(self)
  1406. print(wrapGreen("Creating ")+wrapOrange("Inverse Kinematics")+
  1407. wrapGreen(" Constraint for bone: ") +
  1408. wrapOrange(self.GetxForm().bGetObject().name))
  1409. ik_bone = self.GetxForm().bGetObject()
  1410. c = self.GetxForm().bGetObject().constraints.new('IK')
  1411. get_target_and_subtarget(self, c)
  1412. get_target_and_subtarget(self, c, input_name = 'Pole Target')
  1413. if constraint_name := self.evaluate_input("Name"):
  1414. c.name = constraint_name
  1415. self.bObject = c
  1416. c.chain_count = 1 # so that, if there are errors, this doesn't print a whole bunch of circular dependency crap from having infinite chain length
  1417. if (c.pole_target): # Calculate the pole angle, the user shouldn't have to.
  1418. pole_object = c.pole_target
  1419. assert pole_object == c.target, f"Error with {self}: Pole Target must be bone within the same Armature as IK Bone -- for now."
  1420. pole_location = None
  1421. if (c.pole_subtarget):
  1422. pole_object = c.pole_target.pose.bones[c.pole_subtarget]
  1423. pole_location = pole_object.bone.head_local
  1424. else: #TODO this is a dumb limitation but I don't want to convert to the armature's local space so that some idiot can rig in a stupid way
  1425. raise RuntimeError(f"Error with {self}: Pole Target must be bones within the same Armature as IK Bone -- for now.")
  1426. #HACK HACK
  1427. handle_location = ik_bone.bone.tail_local if (self.evaluate_input("Use Tail")) else ik_bone.bone.head_local
  1428. counter = 0
  1429. parent = ik_bone
  1430. base_bone = ik_bone
  1431. while (parent is not None):
  1432. counter+=1
  1433. if ((self.evaluate_input("Chain Length") != 0) and (counter > self.evaluate_input("Chain Length"))):
  1434. break
  1435. base_bone = parent
  1436. parent = parent.parent
  1437. def get_main_axis(bone, knee_location):
  1438. # To decide whether the IK mainly bends around the x or z axis....
  1439. x_axis = bone.matrix_local.to_3x3() @ Vector((1,0,0))
  1440. y_axis = bone.matrix_local.to_3x3() @ Vector((0,1,0))
  1441. z_axis = bone.matrix_local.to_3x3() @ Vector((0,0,1))
  1442. # project the knee location onto the plane of the bone.
  1443. from .utilities import project_point_to_plane
  1444. planar_projection = project_point_to_plane(knee_location, bone.head_local, y_axis)
  1445. # and get the dot between the X and Z axes to find which one the knee is displaced on.
  1446. x_dot = x_axis.dot(planar_projection) # whichever axis' dot-product is closer to zero
  1447. z_dot = z_axis.dot(planar_projection) # with the base_bone's axis is in-line with it.
  1448. prWhite(bone.name, z_dot, x_dot)
  1449. # knee is in-line with this axis vector, the bend is happening on the perpendicular axis.
  1450. if abs(z_dot) < abs(x_dot): return x_axis # so we return X if Z is in-line with the knee
  1451. else: return z_axis # and visa versa
  1452. # modified from https://blender.stackexchange.com/questions/19754/how-to-set-calculate-pole-angle-of-ik-constraint-so-the-chain-does-not-move
  1453. from mathutils import Vector
  1454. def signed_angle(vector_u, vector_v, normal):
  1455. # Normal specifies orientation
  1456. angle = vector_u.angle(vector_v)
  1457. if vector_u.cross(vector_v).angle(normal) < 1:
  1458. angle = -angle
  1459. return angle
  1460. def get_pole_angle(base_bone, ik_bone, pole_location, main_axis):
  1461. pole_normal = (ik_bone.bone.tail_local - base_bone.bone.head_local).cross(pole_location - base_bone.bone.head_local)
  1462. projected_pole_axis = pole_normal.cross(base_bone.bone.tail_local - base_bone.bone.head_local)
  1463. # note that this normal-axis is the y-axis but flipped
  1464. return signed_angle(main_axis, projected_pole_axis, base_bone.bone.tail_local - base_bone.bone.head_local)
  1465. if self.evaluate_input("Use Tail") == True:
  1466. main_axis = get_main_axis(ik_bone.bone, ik_bone.bone.tail_local)
  1467. # pole angle to the PV:
  1468. pole_angle_in_radians = get_pole_angle(base_bone, ik_bone, pole_location, main_axis)
  1469. elif ik_bone.bone.parent:
  1470. main_axis = get_main_axis(ik_bone.bone.parent, ik_bone.bone.tail_local)
  1471. pole_angle_in_radians = get_pole_angle(base_bone, ik_bone, pole_location, main_axis)
  1472. else: # the bone is not using "Use Tail" and it has no parent -- meaningless.
  1473. pole_angle_in_radians = 0
  1474. c.pole_angle = pole_angle_in_radians
  1475. # TODO: the pole target should be a bone in a well-designed rig, but I don't want to force this, so....
  1476. # in future, calculate all this in world-space so we can use other objects as the pole.
  1477. props_sockets = {
  1478. 'chain_count' : ("Chain Length", 1),
  1479. 'use_tail' : ("Use Tail", True),
  1480. 'use_stretch' : ("Stretch", True),
  1481. "weight" : ("Position", 1.0),
  1482. "orient_weight" : ("Rotation", 0.0),
  1483. "influence" : ("Influence", 1.0),
  1484. 'mute' : ("Enable", True),
  1485. }
  1486. evaluate_sockets(self, c, props_sockets)
  1487. # TODO: handle drivers
  1488. # (it should be assumed we want it on if it's plugged
  1489. # into a driver).
  1490. c.use_location = self.evaluate_input("Position") > 0
  1491. c.use_rotation = self.evaluate_input("Rotation") > 0
  1492. self.executed = True
  1493. def bFinalize(self, bContext = None):
  1494. finish_drivers(self)
  1495. # This is kinda a weird design decision?
  1496. class LinkDrivenParameter:
  1497. '''A node representing an armature object'''
  1498. def __init__(self, signature, base_tree):
  1499. self.base_tree=base_tree
  1500. self.executed = False
  1501. self.signature = signature
  1502. self.inputs = {
  1503. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1504. "Driver" : NodeSocket(is_input = True, name = "Driver", node = self),
  1505. "Parameter" : NodeSocket(is_input = True, name = "Parameter", node = self),
  1506. "Index" : NodeSocket(is_input = True, name = "Index", node = self),
  1507. }
  1508. self.outputs = {
  1509. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self), }
  1510. self.parameters = {
  1511. "Input Relationship":None,
  1512. "Driver":None,
  1513. "Parameter":None,
  1514. "Index":None,
  1515. }
  1516. # now set up the traverse target...
  1517. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1518. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1519. self.node_type = "LINK"
  1520. self.hierarchy_connections = []
  1521. self.connections = []
  1522. self.hierarchy_dependencies = []
  1523. self.dependencies = []
  1524. self.prepared = True
  1525. self.executed = False
  1526. def GetxForm(self):
  1527. return GetxForm(self)
  1528. def evaluate_input(self, input_name):
  1529. return default_evaluate_input(self, input_name)
  1530. def bExecute(self, bContext = None,):
  1531. prepare_parameters(self)
  1532. prGreen("Executing Driven Parameter node")
  1533. # example_ driver ={
  1534. # "owner":None,
  1535. # "prop":None, # will be filled out in the node that uses the driver
  1536. # "ind":-1, # same here
  1537. # "type": self.evaluate_input("Driver Type"),
  1538. # "vars": my_vars,
  1539. # "keys": self.evaluate_input("fCurve"),}
  1540. driver = self.evaluate_input("Driver")
  1541. driver["owner"] = self.GetxForm().bGetObject()
  1542. driver["prop"] = self.evaluate_input("Parameter")
  1543. driver["ind"] = self.evaluate_input("Index")
  1544. self.parameters["Driver"] = driver
  1545. self.executed = True
  1546. def bFinalize(self, bContext = None):
  1547. # TODO HACK BUG
  1548. # This probably no longer works
  1549. from .drivers import CreateDrivers
  1550. CreateDrivers( [ self.parameters["Driver"] ] )
  1551. class LinkArmature:
  1552. '''A node representing an armature object'''
  1553. def __init__(self, signature, base_tree,):
  1554. self.base_tree=base_tree
  1555. self.signature = signature
  1556. self.inputs = {
  1557. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1558. "Preserve Volume" : NodeSocket(is_input = True, name = "Preserve Volume", node = self),
  1559. "Use Envelopes" : NodeSocket(is_input = True, name = "Use Envelopes", node = self),
  1560. "Use Current Location" : NodeSocket(is_input = True, name = "Use Current Location", node = self),
  1561. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self),
  1562. "Enable" : NodeSocket(is_input = True, name = "Enable", node = self),
  1563. }
  1564. self.outputs = {
  1565. "Output Relationship" : NodeSocket(name = "Output Relationship", node=self), }
  1566. self.parameters = {
  1567. "Name":None,
  1568. "Input Relationship":None,
  1569. "Preserve Volume":None,
  1570. "Use Envelopes":None,
  1571. "Use Current Location":None,
  1572. "Influence":None,
  1573. "Enable":None,
  1574. }
  1575. # now set up the traverse target...
  1576. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1577. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1578. self.node_type = "LINK"
  1579. setup_custom_props(self)
  1580. self.hierarchy_connections = []
  1581. self.connections = []
  1582. self.hierarchy_dependencies = []
  1583. self.dependencies = []
  1584. self.prepared = True
  1585. self.executed = False
  1586. def GetxForm(self):
  1587. return GetxForm(self)
  1588. def evaluate_input(self, input_name):
  1589. return default_evaluate_input(self, input_name)
  1590. def bExecute(self, bContext = None,):
  1591. prGreen("Creating Armature Constraint for bone: \""+ self.GetxForm().bGetObject().name + "\"")
  1592. prepare_parameters(self)
  1593. c = self.GetxForm().bGetObject().constraints.new('ARMATURE')
  1594. if constraint_name := self.evaluate_input("Name"):
  1595. c.name = constraint_name
  1596. self.bObject = c
  1597. # get number of targets
  1598. num_targets = len( list(self.inputs.values())[6:] )//2
  1599. props_sockets = {
  1600. 'use_deform_preserve_volume' : ("Preserve Volume", 0),
  1601. 'use_bone_envelopes' : ("Use Envelopes", 0),
  1602. 'use_current_location' : ("Use Current Location", 0),
  1603. 'influence' : ( "Influence" , 1),
  1604. 'mute' : ("Enable", True),
  1605. }
  1606. targets_weights = {}
  1607. for i in range(num_targets):
  1608. target = c.targets.new()
  1609. target_input_name = list(self.inputs.keys())[i*2+6 ]
  1610. weight_input_name = list(self.inputs.keys())[i*2+6+1]
  1611. get_target_and_subtarget(self, target, target_input_name)
  1612. weight_value=self.evaluate_input(weight_input_name)
  1613. if not isinstance(weight_value, float):
  1614. weight_value=0
  1615. targets_weights[i]=weight_value
  1616. props_sockets["targets[%d].weight" % i] = (weight_input_name, 0)
  1617. # targets_weights.append({"weight":(weight_input_name, 0)})
  1618. evaluate_sockets(self, c, props_sockets)
  1619. for target, value in targets_weights.items():
  1620. c.targets[target].weight=value
  1621. # for i, (target, weight) in enumerate(zip(c.targets, targets_weights)):
  1622. # evaluate_sockets(self, target, weight)
  1623. self.executed = True
  1624. def bFinalize(self, bContext = None):
  1625. finish_drivers(self)
  1626. class LinkSplineIK:
  1627. '''A node representing an armature object'''
  1628. def __init__(self, signature, base_tree):
  1629. self.base_tree=base_tree
  1630. self.signature = signature
  1631. self.inputs = {
  1632. "Input Relationship" : NodeSocket(is_input = True, name = "Input Relationship", node = self,),
  1633. "Target" : NodeSocket(is_input = True, name = "Target", node = self),
  1634. "Chain Length" : NodeSocket(is_input = True, name = "Chain Length", node = self),
  1635. "Even Divisions" : NodeSocket(is_input = True, name = "Even Divisions", node = self),
  1636. "Chain Offset" : NodeSocket(is_input = True, name = "Chain Offset", node = self),
  1637. "Use Curve Radius" : NodeSocket(is_input = True, name = "Use Curve Radius", node = self),
  1638. "Y Scale Mode" : NodeSocket(is_input = True, name = "Y Scale Mode", node = self),
  1639. "XZ Scale Mode" : NodeSocket(is_input = True, name = "XZ Scale Mode", node = self),
  1640. "Use Original Scale" : NodeSocket(is_input = True, name = "Use Original Scale", node = self),
  1641. "Influence" : NodeSocket(is_input = True, name = "Influence", node = self),
  1642. }
  1643. self.outputs = {
  1644. "Output Relationship" : NodeSocket(is_input = False, name = "Output Relationship", node=self), }
  1645. self.parameters = {
  1646. "Name":None,
  1647. "Input Relationship":None,
  1648. "Target":None,
  1649. "Chain Length":None,
  1650. "Even Divisions":None,
  1651. "Chain Offset":None,
  1652. "Use Curve Radius":None,
  1653. "Y Scale Mode":None,
  1654. "XZ Scale Mode":None,
  1655. "Use Original Scale":None,
  1656. "Influence":None,
  1657. }
  1658. # now set up the traverse target...
  1659. self.inputs["Input Relationship"].set_traverse_target(self.outputs["Output Relationship"])
  1660. self.outputs["Output Relationship"].set_traverse_target(self.inputs["Input Relationship"])
  1661. self.node_type = "LINK"
  1662. self.hierarchy_connections = []
  1663. self.connections = []
  1664. self.hierarchy_dependencies = []
  1665. self.dependencies = []
  1666. self.prepared = True
  1667. self.executed = False
  1668. def evaluate_input(self, input_name):
  1669. return default_evaluate_input(self, input_name)
  1670. def GetxForm(self):
  1671. return GetxForm(self)
  1672. def bExecute(self, bContext = None,):
  1673. prepare_parameters(self)
  1674. prGreen("Creating Spline-IK Constraint for bone: \""+ self.GetxForm().bGetObject().name + "\"")
  1675. c = self.GetxForm().bGetObject().constraints.new('SPLINE_IK')
  1676. get_target_and_subtarget(self, c)
  1677. if constraint_name := self.evaluate_input("Name"):
  1678. c.name = constraint_name
  1679. self.bObject = c
  1680. props_sockets = {
  1681. 'chain_count' : ("Chain Length", 0),
  1682. 'use_even_divisions' : ("Even Divisions", False),
  1683. 'use_chain_offset' : ("Chain Offset", False),
  1684. 'use_curve_radius' : ("Use Curve Radius", False),
  1685. 'y_scale_mode' : ("Y Scale Mode", "FIT_CURVE"),
  1686. 'xz_scale_mode' : ("XZ Scale Mode", "NONE"),
  1687. 'use_original_scale' : ("Use Original Scale", False),
  1688. 'influence' : ("Influence", 1),
  1689. }
  1690. evaluate_sockets(self, c, props_sockets)
  1691. self.executed = True
  1692. for c in TellClasses():
  1693. setup_container(c)