-
Notifications
You must be signed in to change notification settings - Fork 235
/
Copy pathinstancer_mk2.py
188 lines (140 loc) · 5.77 KB
/
instancer_mk2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# This file is part of project Sverchok. It's copyrighted by the contributors
# recorded in the version control history of the file, available from
# its original location https://github.com/nortikin/sverchok/commit/master
#
# SPDX-License-Identifier: GPL3
# License-Filename: LICENSE
import itertools
import bpy
from bpy.props import BoolProperty, StringProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import dataCorrect, updateNode
def make_or_update_instance(node, obj_name, matrix, blueprint_obj):
context = bpy.context
scene = context.scene
objects = bpy.data.objects
# WHAT ABOUT MODIFIERS ON THESE OBJECTS?
collections = bpy.data.collections
collection = collections.get(node.basedata_name)
if obj_name in objects:
sv_object = objects[obj_name]
if sv_object.data != blueprint_obj.data:
sv_object.data = blueprint_obj.data
else:
data = blueprint_obj.data # data_kind.get(data_name)
if node.full_copy:
sv_object = blueprint_obj.copy()
sv_object.name = obj_name
else:
sv_object = objects.new(obj_name, blueprint_obj.data)
collection.objects.link(sv_object)
# if the object is selected in the scene, this node can keep the instance unselected
sv_object.select_set(0)
# apply matrices
if matrix:
sv_object.matrix_local = list(zip(*matrix))
if sv_object.data:
if hasattr(sv_object.data, "update"):
sv_object.data.update() # for some reason this _is_ necessary.
return sv_object
class SvInstancerNodeMK2(SverchCustomTreeNode, bpy.types.Node):
''' Copy by mesh data from object input '''
bl_idname = 'SvInstancerNodeMK2'
bl_label = 'Obj instancer MK2'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_INSTANCER'
@property
def replacement_nodes(self):
return [('SvInstancerNodeMK3', None, None)]
def updateNode_copy(self, context):
# this means we should empty the collection, and let process repopulate
objects = bpy.data.collections[self.basedata_name].objects
for obj in objects:
bpy.data.objects.remove(obj)
updateNode(self, context)
activate: BoolProperty(
default=True,
name='Show', description='Activate node?',
update=updateNode)
full_copy: BoolProperty(name="Full Copy", update=updateNode_copy)
delete_source: BoolProperty(
default=False,
name='Delete Source', description='Delete Source Objects',
update=updateNode)
basedata_name: StringProperty(
default='Alpha',
description='stores the mesh name found in the object, this mesh is instanced',
update=updateNode)
has_instance: BoolProperty(default=False)
def sv_init(self, context):
self.inputs.new('SvObjectSocket', 'objects')
self.inputs.new('SvMatrixSocket', 'matrix')
self.outputs.new('SvObjectSocket', 'objects')
def draw_buttons(self, context, layout):
row = layout.row(align=True)
row.prop(self, "activate", text="Update")
row = layout.row(align=True)
row.prop(self, "delete_source", text="RM Source", toggle=True)
row.prop(self, "full_copy", text="full copy", toggle=True)
layout.label(text="Object base name")
col = layout.column(align=True)
row = col.row(align=True)
row.prop(self, "basedata_name", text="", icon='FILE_CACHE')
def get_matrices(self):
if self.inputs['matrix'].is_linked:
return dataCorrect(self.inputs['matrix'].sv_get())
return []
def process(self):
if not self.activate:
return
matrices = self.get_matrices()
if not matrices:
return
objects = self.inputs['objects'].sv_get()
if not objects:
return
new_objects = []
self.ensure_collection()
combinations = zip(itertools.cycle(objects), matrices)
for obj_index, (obj, matrix) in enumerate(combinations):
obj_name = f'{self.basedata_name}.{obj_index:04d}'
new_objects.append(make_or_update_instance(self, obj_name, matrix, obj))
num_objects = len(matrices)
if self.delete_source:
for obj in objects:
bpy.data.objects.remove(obj)
self.remove_non_updated_objects(num_objects)
self.outputs['objects'].sv_set(new_objects)
def ensure_collection(self):
collections = bpy.data.collections
if not collections.get(self.basedata_name):
collection = collections.new(self.basedata_name)
bpy.context.scene.collection.children.link(collection)
def remove_non_updated_objects(self, num_objects):
meshes = bpy.data.meshes
objects = bpy.data.objects
collections = bpy.data.collections
# use collections to gather objects.
objs = collections.get(self.basedata_name)
if not objs:
return
objs = [obj.name for obj in objs.objects if int(obj.name.split(".")[-1]) >= num_objects]
if not objs:
return
# select and finally remove all excess objects
collections = bpy.data.collections
collection = collections.get(self.basedata_name)
for object_name in objs:
obj = objects[object_name]
obj.hide_select = False
collection.objects.unlink(obj)
objects.remove(obj)
# def sv_free(self):
# # self.remove_non_updated_objects(-1)
# # or remove content of associated collection...undecided, lets see what
# # people expect...
# pass
def register():
bpy.utils.register_class(SvInstancerNodeMK2)
def unregister():
bpy.utils.unregister_class(SvInstancerNodeMK2)