link_containers.py 86 KB

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