link_containers.py 85 KB

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