deformer_nodes.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. from .utilities.node_common import *
  2. from .xForm_nodes import xFormGeometryObject, xFormObjectInstance
  3. from .misc_nodes import InputExistingGeometryObject
  4. from .base_definitions import MantisNode
  5. from .mantis_dataclasses import MantisSocketTemplate
  6. from .utilities.utilities import (prRed, prGreen, prPurple, prWhite, prOrange,
  7. wrapRed, wrapGreen, wrapPurple, wrapWhite,
  8. wrapOrange,)
  9. from .deformer_socket_templates import *
  10. from bpy.types import NodeTree
  11. def TellClasses():
  12. return [
  13. DeformerArmature,
  14. DeformerHook,
  15. DeformerMorphTarget,
  16. DeformerMorphTargetDeform,
  17. DeformerSurfaceDeform,
  18. DeformerMeshDeform,
  19. DeformerLatticeDeform,
  20. DeformerSmoothCorrectiveDeform,
  21. ]
  22. # object instance probably can't use the deformer but it doesn't hurt to try.
  23. deformable_types= (xFormGeometryObject, InputExistingGeometryObject, xFormObjectInstance)
  24. def trace_xForm_back(mantis_node, socket):
  25. if (trace := trace_single_line(mantis_node, socket)[0] ) :
  26. for i in range(len(trace)): # have to look in reverse, actually
  27. if ( isinstance(trace[ i ], deformable_types ) ):
  28. return trace[ i ].bGetObject()
  29. raise GraphError(wrapRed(f"No other object found for {mantis_node}."))
  30. class MantisDeformerNode(MantisNode):
  31. node_type = 'LINK'
  32. __slots__ = ()
  33. def __init__(self, signature : tuple,
  34. base_tree : NodeTree,
  35. socket_templates : list[MantisSocketTemplate]=[]):
  36. super().__init__(signature, base_tree, socket_templates)
  37. self.prepared = True
  38. self.bObject=[]
  39. # we need evaluate_input to have the same behaviour as links.
  40. def evaluate_input(self, input_name, index=0):
  41. if (input_name in ['Target', 'Object', 'Hook Target']):
  42. socket = self.inputs.get(input_name)
  43. if socket.is_linked:
  44. return socket.links[0].from_node
  45. return None
  46. else:
  47. return super().evaluate_input(input_name, index)
  48. def GetxForm(mantis_node, output_name="Deformer"):
  49. break_condition= lambda node : node.__class__ in deformable_types
  50. xforms = trace_line_up_branching(mantis_node, output_name, break_condition)
  51. return_me=[]
  52. for xf in xforms:
  53. if xf.node_type != 'XFORM':
  54. continue
  55. if xf in return_me:
  56. continue
  57. return_me.append(xf)
  58. return return_me
  59. def reset_execution(self):
  60. super().reset_execution()
  61. self.bObject=[]; self.prepared=True
  62. def standard_modifier_bind(self, bContext=None, operator=None):
  63. for d in self.bObject:
  64. # we'll only bind it if it is un-muted.
  65. if self.evaluate_input("Enable in Viewport") == False:
  66. continue
  67. from .utilities.utilities import bind_modifier_operator
  68. bind_modifier_operator(d, operator)
  69. class DeformerArmature(MantisDeformerNode):
  70. '''A node representing an armature deformer'''
  71. __slots__ = ()
  72. def __init__(self, signature, base_tree):
  73. super().__init__(signature, base_tree, DeformArmatureSockets)
  74. self.init_parameters(additional_parameters={"Name":None})
  75. self.set_traverse([("Deformer", "Deformer")])
  76. self.prepared = True
  77. def GetxForm(self, socket="Deformer"):
  78. if socket == "Deformer":
  79. return super().GetxForm()
  80. else:
  81. trace_xForm_back(self, socket)
  82. # DUPLICATED FROM xForm_nodes::xFormBone
  83. # DEDUP HACK HACK HACK HACK HACK
  84. def bGetParentArmature(self):
  85. from .xForm_nodes import xFormArmature
  86. from .misc_nodes import InputExistingGeometryObject
  87. from bpy.types import Object
  88. if (trace := trace_single_line(self, "Armature Object")[0] ) :
  89. for i in range(len(trace)):
  90. # have to look in reverse, actually
  91. if ( isinstance(trace[ i ], xFormArmature ) ):
  92. return trace[ i ].bGetObject()
  93. elif ( isinstance(trace[i], InputExistingGeometryObject)):
  94. if (ob := trace[i].bGetObject()).type == "ARMATURE":
  95. return ob
  96. raise RuntimeError(f"Cannot find armature for node {self}")
  97. return None
  98. #should do the trick...
  99. def bRelationshipPass(self, bContext = None,):
  100. self.executed = True
  101. def initialize_vgroups(self, xf):
  102. ob = xf.bGetObject()
  103. armOb = self.bGetParentArmature()
  104. for b in armOb.data.bones:
  105. if b.use_deform == False:
  106. continue
  107. vg = ob.vertex_groups.get(b.name)
  108. if not vg:
  109. vg = ob.vertex_groups.new(name=b.name)
  110. if ob.type == 'MESH':
  111. num_verts = len(ob.data.vertices)
  112. elif ob.type == 'LATTICE':
  113. num_verts = len(ob.data.points)
  114. vg.add(range(num_verts), 0, 'REPLACE')
  115. def copy_weights(self, xf):
  116. # we'll use modifiers for this, maybe use GN for it in the future tho
  117. import bpy
  118. ob = xf.bGetObject()
  119. try:
  120. copy_from = self.GetxForm(socket="Copy Skin Weights From")
  121. except GraphError:
  122. copy_from = None
  123. prRed(f"No object found for copying weights in {self}, continuing anyway.")
  124. m = ob.modifiers.new(type="DATA_TRANSFER", name="Mantis_temp_data_transfer")
  125. m.object = None; m.use_vert_data = True
  126. m.data_types_verts = {'VGROUP_WEIGHTS'}
  127. m.vert_mapping = 'POLYINTERP_NEAREST'
  128. m.layers_vgroup_select_src = 'ALL'
  129. m.layers_vgroup_select_dst = 'NAME'
  130. m.object = copy_from
  131. # m.use_object_transform = False # testing reveals that this is undesirable - since the objects may not have their transforms applied.
  132. ob.modifiers.move(len(ob.modifiers)-1, 0)
  133. # ob.data = ob.data.copy()
  134. if False: #MAYBE the mouse needs to be in the 3D viewport, no idea how to set this in an override
  135. # TODO: figure out how to apply this, context is incorrect because armature is still in pose mode
  136. original_active = bpy.context.active_object
  137. original_mode = original_active.mode
  138. bpy.ops.object.mode_set(mode='OBJECT')
  139. with bpy.context.temp_override(**{'active_object':ob, 'selected_objects':[ob, copy_from]}):
  140. # bpy.ops.object.datalayout_transfer(modifier=m.name) # note: this operator is used by the modifier or stand-alone in the UI
  141. # the poll for this operator is defined in blender/source/blender/editors/object/object_data_transfer.cc
  142. # and blender/source/blender/editors/object/object_modifier.cc
  143. # bpy.ops.object.modifier_apply(modifier=m.name, single_user=True)
  144. bpy.ops.object.datalayout_transfer(data_type='VGROUP_WEIGHTS')
  145. bpy.ops.object.data_transfer(data_type='VGROUP_WEIGHTS')
  146. bpy.ops.object.mode_set(mode=original_mode)
  147. def do_automatic_skinning_mesh(self, ob, xf, bContext):
  148. # This is bad and leads to somewhat unpredictable
  149. # behaviour, e.g. what object will be selected? What mode?
  150. # also bpy.ops is ugly and prone to error when used in
  151. # scripts. I don't intend to use bpy.ops when I can avoid it.
  152. import bpy
  153. self.initialize_vgroups(xf)
  154. armOb = self.bGetParentArmature()
  155. armOb.data.pose_position = 'REST'
  156. bContext.view_layer.depsgraph.update()
  157. deform_bones = []
  158. for pb in armOb.pose.bones:
  159. if pb.bone.use_deform == True:
  160. deform_bones.append(pb)
  161. if not deform_bones:
  162. prPurple("Warning: No deform bones in armature. Cancelling.")
  163. return
  164. context_override = {
  165. 'active_object':ob,
  166. 'selected_objects':[ob, armOb],
  167. 'active_pose_bone':deform_bones[0],
  168. 'selected_pose_bones':deform_bones,}
  169. from .utilities.utilities import set_bone_selection
  170. for pb in armOb.pose.bones:
  171. set_bone_selection(pose_bone=pb, selection_state=True)
  172. with bContext.temp_override(**context_override):
  173. bpy.ops.paint.weight_paint_toggle()
  174. bpy.ops.paint.weight_from_bones(type='AUTOMATIC')
  175. bpy.ops.paint.weight_paint_toggle()
  176. for pb in armOb.pose.bones:
  177. set_bone_selection(pose_bone=pb, selection_state=False)
  178. armOb.data.pose_position = 'POSE'
  179. # TODO: modify Blender to make this available as a Python API function.
  180. def do_automatic_skinning_lattice(self, ob, xf, bContext):
  181. # Temporarily, I am making a very simple and ugly automatic skinning algo for lattice points
  182. import bpy
  183. from mathutils.geometry import intersect_point_line
  184. self.initialize_vgroups(xf)
  185. armOb = self.bGetParentArmature()
  186. armOb.data.pose_position = 'REST'
  187. bContext.view_layer.depsgraph.update()
  188. deform_bones = []
  189. for pb in armOb.pose.bones:
  190. if pb.bone.use_deform == True: deform_bones.append(pb)
  191. # How this works:
  192. # - Calculates the weights based on proximity and angle
  193. # - we'll make a vector of the point and the nearest point on the bone
  194. # - dot (point_displacement, bone_y_axis) to get the angle
  195. # - weight the bone's value by this dot product and distance
  196. # - distance should prevail when both bones are within the angle
  197. mat = ob.matrix_world; mat_arm = armOb.matrix_world
  198. for p_index, p in enumerate(ob.data.points):
  199. loc = mat @ p.co_deform # co_deform is the position in edit mode
  200. pt_distance, pt_dot = {}, {}
  201. for b in deform_bones:
  202. bone_vec = ((mat_arm @ b.tail) - (mat_arm @ b.head)).normalized()
  203. nearest_point_on_bone, factor = intersect_point_line(
  204. loc, mat_arm @ b.head, mat_arm @ b.tail) # 0 is point, 1 is factor
  205. if factor > 1.0: nearest_point_on_bone = mat_arm @ b.tail
  206. if factor < 0.0: nearest_point_on_bone = mat_arm @ b.head
  207. point_vec = nearest_point_on_bone - loc
  208. distance = point_vec.length_squared # no need to sqrt, this is faster and
  209. # the quadratic falloff is better than linear falloff.
  210. dot = 1-abs(point_vec.normalized().dot(bone_vec))
  211. # we want to weight zero at 1.0 so that it favors points in its "envelope"
  212. pt_distance[b.name]=distance; pt_dot[b.name] = dot
  213. # now we can assign weights
  214. distance_pairs = [(k,v) for k,v in pt_distance.items()]
  215. distance_pairs.sort(key = lambda a : a[1])
  216. i=0; max_distance = 0.0; near_enough_bones = []
  217. while (i < 4): # TODO: limit-total should be exposed to the user.
  218. if i+1 > len(distance_pairs): break # in case there are fewer than 4 deform bones
  219. near_enough_bones.append(distance_pairs[i][0])
  220. if distance_pairs[i][1] > max_distance: max_distance = distance_pairs[i][1]
  221. i+=1
  222. max_pre_normalized_weight = 0.0
  223. weights = {}
  224. if max_distance == 0.0: max_distance = 1.0
  225. for b_name in near_enough_bones:
  226. w = 1.0
  227. if pt_distance[b_name] > 0:
  228. w*= 1/(pt_distance[b_name]/max_distance) # weight by inverse-distance
  229. w*= pt_dot[b_name]**4 # NOTE: **4 is arbitrary but feels good to me.
  230. if w > max_pre_normalized_weight: max_pre_normalized_weight = w
  231. weights[b_name] = w
  232. if max_pre_normalized_weight == 0.0: max_pre_normalized_weight = 1.0
  233. for b_name in near_enough_bones:
  234. vg = ob.vertex_groups.get(b_name)
  235. vg.add([p_index], weights[b_name]/max_pre_normalized_weight, 'REPLACE')
  236. armOb.data.pose_position = 'POSE'
  237. def bFinalize(self, bContext=None):
  238. prGreen("Executing Armature Deform Node")
  239. mod_name = self.evaluate_input("Name")
  240. for xf in self.GetxForm():
  241. ob = xf.bGetObject()
  242. d = ob.modifiers.new(mod_name, type='ARMATURE')
  243. if d is None:
  244. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  245. self.bObject.append(d)
  246. d.object = self.bGetParentArmature()
  247. props_sockets = self.gen_property_socket_map()
  248. evaluate_sockets(self, d, props_sockets)
  249. #
  250. if (skin_method := self.evaluate_input("Skinning Method")) == "AUTOMATIC_HEAT":
  251. match ob.type:
  252. case "MESH":
  253. self.do_automatic_skinning_mesh(ob, xf, bContext)
  254. case "LATTICE":
  255. self.do_automatic_skinning_lattice(ob, xf, bContext)
  256. elif skin_method == "COPY_FROM_OBJECT":
  257. self.initialize_vgroups(xf)
  258. self.copy_weights(xf)
  259. # elif skin_method == "EXISTING_GROUPS":
  260. # pass
  261. class DeformerHook(MantisDeformerNode):
  262. '''A node representing a hook deformer'''
  263. __slots__ = ()
  264. def __init__(self, signature, base_tree):
  265. super().__init__(signature, base_tree, HookSockets)
  266. # now set up the traverse target...
  267. self.init_parameters(additional_parameters={"Name":None})
  268. self.set_traverse([("Deformer", "Deformer")])
  269. self.prepared = True
  270. def driver_for_radius(self, object, hook, index, influence, bezier=True):
  271. """ Creates a driver to control the radius of a curve point with the hook."""
  272. from bpy.types import Bone, PoseBone
  273. var_template = {"owner":hook,
  274. "name":"a",
  275. "type":"TRANSFORMS",
  276. "space":'WORLD_SPACE',
  277. "channel":'SCALE_X',}
  278. var1_template = {"owner":hook.id_data,
  279. "name":"b",
  280. "type":"TRANSFORMS",
  281. "space":'WORLD_SPACE',
  282. "channel":'SCALE_X',}
  283. keys_template = [{"co":(0,0),
  284. "interpolation": "LINEAR",
  285. "type":"KEYFRAME",},
  286. {"co":(1,influence),
  287. "interpolation": "LINEAR",
  288. "type":"KEYFRAME",},]
  289. if bezier:
  290. owner=object.data.splines[0].bezier_points
  291. else:
  292. owner=object.data.splines[0].points
  293. driver = {
  294. "owner":owner[index],
  295. "prop":"radius",
  296. "ind":-1,
  297. "extrapolation":"LINEAR",
  298. "type":"AVERAGE",
  299. "vars":[],
  300. "keys":keys_template,
  301. }
  302. if isinstance(hook, (Bone, PoseBone)):
  303. driver['type']='SCRIPTED'
  304. driver['expression']="(((1/b)*a)+((1/b_001)*a_001)+((1/b_002)*a_002))/3"
  305. from .utilities.drivers import CreateDrivers
  306. axes='XYZ'
  307. for i in range(3):
  308. suffix = "" if i == 0 else f"_{i:03d}" # explicit names -- 5.2 no longer uniquifies duplicates
  309. var = var_template.copy()
  310. var["name"]="a"+suffix
  311. var["channel"]="SCALE_"+axes[i]
  312. driver["vars"].append(var)
  313. if isinstance(hook, (Bone, PoseBone)):
  314. var1=var1_template.copy()
  315. var1['name']="b"+suffix
  316. var1['channel']="SCALE_"+axes[i]
  317. driver['vars'].append(var1)
  318. CreateDrivers([driver])
  319. def bRelationshipPass(self, bContext = None,):
  320. self.executed = True
  321. def bFinalize(self, bContext=None):
  322. from bpy.types import Bone, PoseBone, Object
  323. prGreen(f"Executing Hook Deform Node: {self}")
  324. mod_name = self.evaluate_input("Name")
  325. affect_radius = self.evaluate_input("Affect Curve Radius")
  326. auto_bezier = self.evaluate_input("Auto-Bezier")
  327. target_node = self.evaluate_input('Hook Target')
  328. target = target_node.bGetObject(); subtarget = ""
  329. props_sockets = self.gen_property_socket_map()
  330. if isinstance(target, Bone) or isinstance(target, PoseBone):
  331. subtarget = target.name; target = target.id_data
  332. for xf in self.GetxForm():
  333. ob=xf.bGetObject()
  334. if ob.type == 'CURVE':
  335. spline_index = self.evaluate_input("Spline Index")
  336. from .utilities.utilities import get_extracted_spline_object
  337. ob = get_extracted_spline_object(ob, spline_index, self.mContext)
  338. reuse = False
  339. for m in ob.modifiers:
  340. if m.type == 'HOOK' and m.object == target and m.subtarget == subtarget:
  341. if self.evaluate_input("Influence") != m.strength:
  342. continue # make a new modifier so they can have different strengths
  343. if ob.animation_data: # this can be None
  344. drivers = ob.animation_data.drivers
  345. for k in props_sockets.keys():
  346. if driver := drivers.find(k):
  347. # TODO: I should check to see if the drivers are the same...
  348. break # continue searching for an equivalent modifier
  349. else: # There was no driver - use this one.
  350. d = m; reuse = True; break
  351. else: # use this one, there can't be drivers without animation_data.
  352. d = m; reuse = True; break
  353. else:
  354. d = ob.modifiers.new(mod_name, type='HOOK')
  355. if d is None:
  356. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  357. self.bObject.append(d)
  358. self.get_target_and_subtarget(d, input_name="Hook Target")
  359. vertices_used=[]
  360. if reuse: # Get the verts in the list... filter out all the unneeded 0's
  361. vertices_used = list(d.vertex_indices)
  362. include_0 = 0 in vertices_used
  363. vertices_used = list(filter(lambda a : a != 0, vertices_used))
  364. if include_0: vertices_used.append(0)
  365. # now we add the selected vertex to the list, too
  366. vertex = self.evaluate_input("Point Index")
  367. if ob.type == 'CURVE' and ob.data.splines[0].type == 'BEZIER' and auto_bezier:
  368. if affect_radius:
  369. self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength)
  370. vertex*=3
  371. vertices_used.extend([vertex, vertex+1, vertex+2])
  372. else:
  373. vertices_used.append(vertex)
  374. # if we have a curve and it is NOT using auto-bezier for the verts..
  375. if ob.type == 'CURVE' and ob.data.splines[0].type == 'BEZIER' and affect_radius and not auto_bezier:
  376. print (f"WARN: {self}: \"Affect Radius\" may not behave as expected"
  377. " when used on Bezier curves without Auto-Bezier")
  378. #bezier point starts at 1, and then every third vert, so 4, 7, 10...
  379. if vertex%3==1:
  380. self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength)
  381. if ob.type == 'CURVE' and ob.data.splines[0].type != 'BEZIER' and \
  382. affect_radius:
  383. self.driver_for_radius(ob, target_node.bGetObject(), vertex, d.strength, bezier=False)
  384. d.vertex_indices_set(vertices_used)
  385. evaluate_sockets(self, d, props_sockets)
  386. finish_drivers(self)
  387. # todo: this node should be able to take many indices in the future.
  388. # Also: I have a Geometry Nodes implementation of this I can use... maybe...
  389. class DeformerMorphTarget(MantisDeformerNode):
  390. '''A node representing an armature deformer'''
  391. __slots__ = ()
  392. def __init__(self, signature, base_tree):
  393. super().__init__(signature, base_tree, MorphTargetSockets)
  394. self.init_parameters(additional_parameters={"Name":None})
  395. self.prepared = True
  396. def GetxForm(self, trace_input="Object"):
  397. trace = trace_single_line(self, trace_input)
  398. for node in trace[0]:
  399. if (isinstance(node, deformable_types)):
  400. return node
  401. raise GraphError("%s is not connected to an upstream xForm" % self)
  402. def bRelationshipPass(self, bContext = None,):
  403. prGreen("Executing Morph Target Node")
  404. ob = None; relative = None
  405. # do NOT check if the object exists here. Just let the next node deal with that.
  406. try:
  407. ob = self.GetxForm().bGetObject().name
  408. except Exception as e: # this will and should throw an error if it fails
  409. ob = self.GetxForm().evaluate_input("Name")
  410. if self.inputs["Relative to"].is_linked:
  411. try:
  412. relative = self.GetxForm("Relative to").bGetObject().name
  413. except Exception as e: # same here
  414. prRed(f"Execution failed at {self}: no relative object found for morph target, despite link existing.")
  415. raise e
  416. vg = self.evaluate_input("Vertex Group") if self.evaluate_input("Vertex Group") else "" # just make sure it is a string
  417. mt={"object":ob, "vertex_group":vg, "relative_shape":relative}
  418. self.parameters["Morph Target"] = mt
  419. self.parameters["Name"] = ob # this is redundant but it's OK since accessing the mt is tedious
  420. self.executed = True
  421. class DeformerMorphTargetDeform(MantisDeformerNode):
  422. '''A node representing an armature deformer'''
  423. __slots__ = ()
  424. def __init__(self, signature, base_tree):
  425. super().__init__(signature, base_tree)
  426. inputs = [
  427. "Deformer",
  428. "Use Shape Key",
  429. "Use Offset",
  430. ]
  431. outputs = [
  432. "Deformer",
  433. ]
  434. self.outputs.init_sockets(outputs)
  435. self.inputs.init_sockets(inputs)
  436. self.init_parameters(additional_parameters={"Name":None})
  437. self.set_traverse([("Deformer", "Deformer")])
  438. self.prepared = True
  439. self.executed = True
  440. setup_custom_property_inputs_outputs(self)
  441. # bpy.data.node_groups["Morph Deform.045"].nodes["Named Attribute.020"].data_type = 'FLOAT_VECTOR'
  442. # bpy.context.object.add_rest_position_attribute = True
  443. def reset_execution(self):
  444. return super().reset_execution()
  445. self.executed=True
  446. def gen_morph_target_modifier(self, xf, context):
  447. # first let's see if this is a no-op
  448. targets = []
  449. for k,v in self.inputs.items():
  450. if "Target" in k:
  451. targets.append(v)
  452. if not targets:
  453. return # nothing to do here.
  454. # at this point we make the node tree
  455. from .utilities.geometry_node_graphgen import gen_morph_target_nodes
  456. m, props_sockets = gen_morph_target_nodes(
  457. self.evaluate_input("Name"),
  458. xf.bGetObject(),
  459. targets,
  460. context,
  461. use_offset=self.evaluate_input("Use Offset"))
  462. self.bObject.append(m)
  463. evaluate_sockets(self, m, props_sockets)
  464. finish_drivers(self)
  465. def gen_shape_key_lattice(self, xf, context):
  466. # first check if we need to do anything
  467. targets = []
  468. for k,v in self.inputs.items():
  469. if "Target" in k:
  470. targets.append(v)
  471. if not targets:
  472. return # nothing to do here
  473. # TODO: deduplicate the code above here
  474. from time import time
  475. start_time = time()
  476. from bpy import data
  477. ob = xf.bGetObject()
  478. dg = context.view_layer.depsgraph
  479. dg.update()
  480. if xf.has_shape_keys == False:
  481. lat = ob.data.copy()
  482. ob.data = lat
  483. ob.add_rest_position_attribute = True
  484. ob.shape_key_clear()
  485. ob.shape_key_add(name='Basis', from_mix=False)
  486. else:
  487. lat = ob.data
  488. xf.has_shape_keys = True
  489. # first make a basis shape key
  490. keys, props_sockets, ={}, {}
  491. for i, t in enumerate(targets):
  492. mt_node = t.links[0].from_node; sk_ob = mt_node.GetxForm().bGetObject()
  493. if sk_ob is None:
  494. sk_ob = data.objects.new(mt_node.evaluate_input("Name"), data.meshes.new_from_object(ob))
  495. context.collection.objects.link(sk_ob)
  496. prOrange(f"WARN: no object found for f{mt_node}; creating duplicate of current object ")
  497. sk_ob = dg.id_eval_get(sk_ob)
  498. mt_name = sk_ob.name
  499. vg = mt_node.parameters["Morph Target"]["vertex_group"]
  500. if vg: mt_name = mt_name+"."+vg
  501. sk = ob.shape_key_add(name=mt_name, from_mix=False)
  502. # the shapekey data is absolute point data for each vertex, in order, very simple
  503. # SERIOUSLY IMPORTANT:
  504. # use the current position of the vertex AFTER SHAPE KEYS AND DEFORMERS
  505. # easiest way to do it is to eval the depsgraph
  506. # TODO: try and get it without depsgraph update, since that may be (very) slow
  507. sk_m = sk_ob.data#data.meshes.new_from_object(sk_ob, preserve_all_data_layers=True, depsgraph=dg)
  508. for j in range(len(m.vertices)):
  509. sk.data[j].co = sk_m.vertices[j].co # assume they match
  510. # data.meshes.remove(sk_m)
  511. sk.vertex_group = vg
  512. sk.slider_min = -10
  513. sk.slider_max = 10
  514. keys[mt_name]=sk
  515. from .mantis_dataclasses import MantisSocketFiller
  516. socket_value = MantisSocketFiller(
  517. property_name=mt_name,
  518. socket_name = "Value."+str(i).zfill(3),
  519. default_value= 1.0,
  520. )
  521. props_sockets[mt_name]= socket_value
  522. for i, t in enumerate(targets):
  523. mt_node = t.links[0].from_node; sk_ob = mt_node.GetxForm().bGetObject()
  524. if sk_ob is None: continue
  525. if rel := mt_node.parameters["Morph Target"]["relative_shape"]:
  526. sk = keys.get(mt_name)
  527. sk.relative_key = keys.get(rel)
  528. self.bObject.append(sk.id_data)
  529. evaluate_sockets(self, sk.id_data, props_sockets)
  530. finish_drivers(self)
  531. prWhite(f"Initializing morph target took {time() -start_time} seconds")
  532. def gen_shape_key(self, xf, context):
  533. # TODO: make this a feature of the node definition that appears only when there are no prior deformers - and shows a warning!
  534. # TODO: the below works well, but it is quite slow. It does not seem to have better performence. Its only advantage is export to FBX.
  535. # there are a number of things I need to fix here
  536. # - reuse shape keys if possible
  537. # - figure out how to make this a lot faster
  538. # - edit the xForm stuff to delete drivers from shape key ID's, since they belong to the Key, not the Object.
  539. # first check if we need to do anythign
  540. targets = []
  541. for k,v in self.inputs.items():
  542. if "Target" in k:
  543. targets.append(v)
  544. if not targets:
  545. return # nothing to do here
  546. from time import time
  547. start_time = time()
  548. from bpy import data
  549. ob = xf.bGetObject()
  550. dg = context.view_layer.depsgraph
  551. dg.update()
  552. if xf.has_shape_keys == False:
  553. match ob.type:
  554. case 'MESH':
  555. ob_data = data.meshes.new_from_object(ob, preserve_all_data_layers=True, depsgraph=dg)
  556. case 'LATTICE':
  557. ob_data = ob.data.copy()
  558. ob.data = ob_data
  559. ob.add_rest_position_attribute = True
  560. ob.shape_key_clear()
  561. ob.shape_key_add(name='Basis', from_mix=False)
  562. else:
  563. ob_data = ob.data
  564. xf.has_shape_keys = True
  565. # using the built-in shapekey feature is actually a lot harder in terms of programming because I need...
  566. # min/max, as it is just not a feature of the GN version
  567. # to carry info from the morph target node regarding relative shapes and vertex groups and all that
  568. # the drivers may be more difficult to apply, too.
  569. # hafta make new geometry for the object and add shape keys and all that
  570. # the benefit to all this being exporting to game engines via .fbx
  571. # first make a basis shape key
  572. keys={}
  573. props_sockets={}
  574. for i, t in enumerate(targets):
  575. mt_node = t.links[0].from_node; sk_ob = mt_node.GetxForm().bGetObject()
  576. if sk_ob is None:
  577. sk_ob = data.objects.new(mt_node.evaluate_input("Name"), data.meshes.new_from_object(ob))
  578. context.collection.objects.link(sk_ob)
  579. prOrange(f"WARN: no object found for f{mt_node}; creating duplicate of current object ")
  580. sk_ob = dg.id_eval_get(sk_ob)
  581. mt_name = sk_ob.name
  582. vg = mt_node.parameters["Morph Target"]["vertex_group"]
  583. if vg: mt_name = mt_name+"."+vg
  584. sk = ob.shape_key_add(name=mt_name, from_mix=False)
  585. # the shapekey data is absolute point data for each vertex, in order, very simple
  586. # SERIOUSLY IMPORTANT:
  587. # use the current position of the vertex AFTER SHAPE KEYS AND DEFORMERS
  588. # easiest way to do it is to eval the depsgraph
  589. # TODO: try and get it without depsgraph update, since that may be (very) slow
  590. sk_m = sk_ob.data#data.meshes.new_from_object(sk_ob, preserve_all_data_layers=True, depsgraph=dg)
  591. match ob.type:
  592. case 'MESH':
  593. for j in range(len(ob_data.vertices)):
  594. sk.data[j].co = sk_m.vertices[j].co # assume they match
  595. case 'LATTICE':
  596. for j in range(len(ob.data.points)):
  597. sk.data[j].co = sk_m.points[j].co_deform
  598. # data.meshes.remove(sk_m)
  599. sk.vertex_group = vg
  600. sk.slider_min = -10
  601. sk.slider_max = 10
  602. keys[mt_name]=sk
  603. from .mantis_dataclasses import MantisSocketFiller
  604. socket_value = MantisSocketFiller(
  605. property_name=mt_name,
  606. socket_name = "Value."+str(i).zfill(3),
  607. default_value= 1.0,
  608. )
  609. props_sockets[mt_name]= socket_value
  610. for i, t in enumerate(targets):
  611. mt_node = t.links[0].from_node; sk_ob = mt_node.GetxForm().bGetObject()
  612. if sk_ob is None: continue
  613. if rel := mt_node.parameters["Morph Target"]["relative_shape"]:
  614. sk = keys.get(mt_name)
  615. sk.relative_key = keys.get(rel)
  616. self.bObject.append(sk.id_data)
  617. evaluate_sockets(self, sk.id_data, props_sockets)
  618. finish_drivers(self)
  619. prWhite(f"Initializing morph target took {time() -start_time} seconds")
  620. def bFinalize(self, bContext=None):
  621. prGreen(f"Executing Morph Deform node {self}")
  622. use_shape_keys = self.evaluate_input("Use Shape Key")
  623. # if there is a not a prior deformer then there should be an option to use plain 'ol shape keys
  624. # GN is always desirable as an option though because it can be baked & many other reasons
  625. if use_shape_keys: # check and see if we can.
  626. if self.inputs.get("Deformer"): # I guess this isn't available in some node group contexts... bad. FIXME
  627. if (links := self.inputs["Deformer"].links):
  628. if not links[0].from_node.parameters.get("Use Shape Key"):
  629. use_shape_keys = False
  630. elif links[0].from_node.parameters.get("Use Shape Key") == False:
  631. use_shape_keys = False
  632. self.parameters["Use Shape Key"] = use_shape_keys
  633. for xf in self.GetxForm():
  634. # Lattice objects do not support geometry nodes at this time.
  635. ob = xf.bGetObject()
  636. if ob and ob.type == 'LATTICE':
  637. if not use_shape_keys:
  638. raise NotImplementedError("Blender does not support Geometry Nodes for Lattices. "
  639. "Enable 'Shape Key' and execute again.")
  640. self.gen_shape_key(xf, bContext)
  641. elif use_shape_keys:
  642. self.gen_shape_key(xf, bContext)
  643. else:
  644. self.gen_morph_target_modifier(xf, bContext)
  645. class DeformerSurfaceDeform(MantisDeformerNode):
  646. '''A node representing an surface deform modifier'''
  647. __slots__ = ()
  648. def __init__(self, signature, base_tree):
  649. super().__init__(signature, base_tree, SurfaceDeformSockets)
  650. # now set up the traverse target...
  651. self.init_parameters(additional_parameters={"Name":None})
  652. self.set_traverse([("Deformer", "Deformer")])
  653. self.prepared = True
  654. def GetxForm(self, socket="Deformer"):
  655. if socket == "Deformer":
  656. return super().GetxForm()
  657. else:
  658. trace_xForm_back(self, socket)
  659. def bRelationshipPass(self, bContext = None,):
  660. self.executed = True
  661. def bFinalize(self, bContext=None):
  662. prGreen("Executing Surface Deform Node")
  663. mod_name = self.evaluate_input("Name")
  664. for xf in self.GetxForm():
  665. ob = xf.bGetObject()
  666. d = ob.modifiers.new(mod_name, type='SURFACE_DEFORM')
  667. if d is None:
  668. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  669. self.bObject.append(d)
  670. self.get_target_and_subtarget(d, input_name="Target")
  671. props_sockets = self.gen_property_socket_map()
  672. evaluate_sockets(self, d, props_sockets)
  673. def bModifierApply(self, bContext=None):
  674. from bpy import ops
  675. standard_modifier_bind(self, bContext, ops.object.surfacedeform_bind)
  676. class DeformerMeshDeform(MantisDeformerNode):
  677. '''A node representing a mesh deform modifier'''
  678. __slots__ = ()
  679. def __init__(self, signature, base_tree):
  680. super().__init__(signature, base_tree, MeshDeformSockets)
  681. # now set up the traverse target...
  682. self.init_parameters(additional_parameters={"Name":None})
  683. self.set_traverse([("Deformer", "Deformer")])
  684. self.prepared = True
  685. def GetxForm(self, socket="Deformer"):
  686. if socket == "Deformer":
  687. return super().GetxForm()
  688. else:
  689. trace_xForm_back(self, socket)
  690. def bRelationshipPass(self, bContext = None,):
  691. self.executed = True
  692. def bFinalize(self, bContext=None):
  693. prGreen("Executing Mesh Deform Node")
  694. mod_name = self.evaluate_input("Name")
  695. for xf in self.GetxForm():
  696. ob = xf.bGetObject()
  697. d = ob.modifiers.new(mod_name, type='MESH_DEFORM')
  698. if d is None:
  699. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  700. self.bObject.append(d)
  701. self.get_target_and_subtarget(d, input_name="Object")
  702. props_sockets = self.gen_property_socket_map()
  703. evaluate_sockets(self, d, props_sockets)
  704. def bModifierApply(self, bContext=None):
  705. from bpy import ops
  706. standard_modifier_bind(self, bContext, ops.object.meshdeform_bind)
  707. class DeformerLatticeDeform(MantisDeformerNode):
  708. '''A node representing a lattice deform modifier'''
  709. __slots__ = ()
  710. def __init__(self, signature, base_tree):
  711. super().__init__(signature, base_tree, LatticeDeformSockets)
  712. # now set up the traverse target...
  713. self.init_parameters(additional_parameters={"Name":None})
  714. self.set_traverse([("Deformer", "Deformer")])
  715. self.prepared = True
  716. def GetxForm(self, socket="Deformer"):
  717. if socket == "Deformer":
  718. return super().GetxForm()
  719. else:
  720. trace_xForm_back(self, socket)
  721. def bRelationshipPass(self, bContext = None,):
  722. self.executed = True
  723. def bFinalize(self, bContext=None):
  724. prGreen("Executing Lattice Deform Node")
  725. mod_name = self.evaluate_input("Name")
  726. for xf in self.GetxForm():
  727. ob = xf.bGetObject()
  728. d = ob.modifiers.new(mod_name, type='LATTICE')
  729. if d is None:
  730. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  731. self.bObject.append(d)
  732. self.get_target_and_subtarget(d, input_name="Object")
  733. props_sockets = self.gen_property_socket_map()
  734. evaluate_sockets(self, d, props_sockets)
  735. class DeformerSmoothCorrectiveDeform(MantisDeformerNode):
  736. '''A node representing a corrective smooth deform modifier'''
  737. __slots__ = ()
  738. def __init__(self, signature, base_tree):
  739. super().__init__(signature, base_tree, SmoothDeformSockets)
  740. # now set up the traverse target...
  741. self.init_parameters(additional_parameters={"Name":None})
  742. self.set_traverse([("Deformer", "Deformer")])
  743. self.prepared = True
  744. def GetxForm(self, socket="Deformer"):
  745. if socket == "Deformer":
  746. return super().GetxForm()
  747. else:
  748. trace_xForm_back(self, socket)
  749. def bRelationshipPass(self, bContext = None,):
  750. self.executed = True
  751. def bFinalize(self, bContext=None):
  752. prGreen("Executing Smooth Deform Node")
  753. mod_name = self.evaluate_input("Name")
  754. for xf in self.GetxForm():
  755. ob = xf.bGetObject()
  756. d = ob.modifiers.new(mod_name, type='CORRECTIVE_SMOOTH')
  757. if d is None:
  758. raise RuntimeError(f"Modifier was not created in node {self} -- the object is invalid.")
  759. self.bObject.append(d)
  760. # self.get_target_and_subtarget(d, input_name="Object")
  761. props_sockets = self.gen_property_socket_map()
  762. evaluate_sockets(self, d, props_sockets)