CM3D2 Converter.misc_VIEW3D_PT_tools_weightpaint

  1# 「3Dビュー」エリア → 「ウェイトペイント」モード → ツールシェルフ → 「ウェイトツール」パネル
  2import bpy
  3import bmesh
  4import mathutils
  5from . import common
  6from . import compat
  7
  8
  9# メニュー等に項目追加
 10def menu_func(self, context):
 11    icon_id = common.kiss_icon()
 12    box = self.layout.box()
 13    column = box.column(align=False)
 14    column.prop(context.active_object.data, 'use_paint_mask_vertex', icon='VERTEXSEL', text="頂点選択モード")
 15    column.operator('mesh.selected_mesh_vertex_group_blur', text="選択部をぼかす", icon_value=icon_id)
 16    column.operator('mesh.selected_mesh_vertex_group_calculation', text="選択部に四則演算", icon_value=icon_id)
 17
 18
 19@compat.BlRegister()
 20class CNV_OT_selected_mesh_vertex_group_blur(bpy.types.Operator):
 21    bl_idname = 'mesh.selected_mesh_vertex_group_blur'
 22    bl_label = "選択部の頂点グループをぼかす"
 23    bl_description = "選択メッシュの頂点グループの割り当てをぼかします"
 24    bl_options = {'REGISTER', 'UNDO'}
 25
 26    items = [
 27        ('LINER', "リニア", "", 'LINCURVE', 1),
 28        ('TRIGONOMETRIC', "スムーズ", "", 'SMOOTHCURVE', 2),
 29    ]
 30    smooth_method = bpy.props.EnumProperty(items=items, name="減衰タイプ", default='TRIGONOMETRIC')
 31
 32    selection_blur_range_multi = bpy.props.FloatProperty(name="選択をぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
 33    selection_blur_accuracy = bpy.props.IntProperty(name="選択をぼかす分割精度", default=3, min=0, max=10, soft_min=1, soft_max=10)
 34
 35    items = [
 36        ('ALL', "全て", "", 'COLLAPSEMENU', 1),
 37        ('ACTIVE', "アクティブのみ", "", 'LAYER_ACTIVE', 2),
 38    ]
 39    target_vertex_group = bpy.props.EnumProperty(items=items, name="対象頂点グループ", default='ALL')
 40    items = [
 41        ('NORMAL', "通常・ぼかし", "", 'BRUSH_BLUR', 1),
 42        ('ADD', "増加・拡張", "", 'BRUSH_DARKEN', 2),
 43        ('SUB', "減少・縮小", "", 'BRUSH_LIGHTEN', 3),
 44    ]
 45    blur_mode = bpy.props.EnumProperty(items=items, name="ぼかしモード", default='NORMAL')
 46    blur_range_multi = bpy.props.FloatProperty(name="ウェイトをぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
 47    blur_count = bpy.props.IntProperty(name="ウェイトをぼかす回数", default=1, min=1, max=100, soft_min=1, soft_max=100)
 48    is_vertex_group_limit_total = bpy.props.BoolProperty(name="ウェイト数を4つに制限", default=True)
 49
 50    @classmethod
 51    def poll(cls, context):
 52        ob = context.active_object
 53        if ob.type == 'MESH':
 54            if len(ob.vertex_groups):
 55                return len(ob.data.vertices) and len(ob.data.edges)
 56        return False
 57
 58    def invoke(self, context, event):
 59        return context.window_manager.invoke_props_dialog(self)
 60
 61    def draw(self, context):
 62        self.layout.prop(self, 'smooth_method')
 63
 64        self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT')
 65        self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×")
 66        self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)")
 67
 68        self.layout.label(text="頂点グループをぼかす", icon='GROUP_VERTEX')
 69        self.layout.prop(self, 'target_vertex_group', text="対象グループ")
 70        self.layout.prop(self, 'blur_mode', text="モード")
 71        self.layout.prop(self, 'blur_range_multi', text="範囲 | 辺の長さの平均×")
 72        self.layout.prop(self, 'blur_count', text="実行回数")
 73        self.layout.prop(self, 'is_vertex_group_limit_total', icon='IMGDISPLAY')
 74
 75    def execute(self, context):
 76        class EmptyClass:
 77            pass
 78
 79        ob = context.active_object
 80        me = ob.data
 81
 82        pre_mode = ob.mode
 83        bpy.ops.object.mode_set(mode='OBJECT')
 84
 85        pre_selected_objects = context.selected_objects[:]
 86        for selected_object in pre_selected_objects:
 87            compat.set_select(selected_object, False)
 88        compat.set_select(ob, True)
 89
 90        bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
 91
 92        selection_ob = context.active_object
 93        selection_me = selection_ob.data
 94
 95        for v in selection_me.vertices:
 96            if v.hide:
 97                v.hide = False
 98                compat.set_select(v, False)
 99        for e in selection_me.edges:
100            if e.hide:
101                e.hide = False
102                compat.set_select(e, False)
103        for p in selection_me.polygons:
104            if p.hide:
105                p.hide = False
106                compat.set_select(p, False)
107
108        bpy.ops.object.mode_set(mode='EDIT')
109        bpy.ops.mesh.select_all(action='INVERT')
110        if context.tool_settings.mesh_select_mode[0]:
111            bpy.ops.mesh.delete(type='VERT')
112        elif context.tool_settings.mesh_select_mode[1]:
113            bpy.ops.mesh.delete(type='EDGE')
114        elif context.tool_settings.mesh_select_mode[2]:
115            bpy.ops.mesh.delete(type='FACE')
116        bpy.ops.mesh.select_all(action='SELECT')
117        if 1 <= self.selection_blur_accuracy:
118            # quadtriはデフォルトでFalseのため、省略(2.8では代わりにngon=Trueが追加)
119            bpy.ops.mesh.subdivide(
120                number_cuts=self.selection_blur_accuracy,
121                smoothness=0, quadcorner='INNERVERT',
122                fractal=0, fractal_along_normal=0, seed=0)
123        bpy.ops.object.mode_set(mode='OBJECT')
124
125        selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices))
126        for v in selection_me.vertices:
127            selection_kd.insert(v.co, v.index)
128        selection_kd.balance()
129        common.remove_data([selection_ob, selection_me])
130
131        compat.set_select(ob, True)
132        compat.set_active(context, ob)
133
134        bm = bmesh.new()
135        bm.from_mesh(me)
136        edge_lengths = [e.calc_length() for e in bm.edges]
137        bm.free()
138        edge_lengths.sort()
139        edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5)
140        average_edge_length = edge_lengths[edge_lengths_center_index]
141        selection_blur_range = average_edge_length * self.selection_blur_range_multi
142
143        vert_selection_values = [None for v in me.vertices]
144        for vert in me.vertices:
145            co, index, dist = selection_kd.find(vert.co)
146            if dist <= selection_blur_range + 0.00001:
147                if 0 < selection_blur_range:
148                    if self.smooth_method == 'TRIGONOMETRIC':
149                        value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range))
150                    else:
151                        value = 1.0 - (dist / selection_blur_range)
152                    vert_selection_values[vert.index] = value
153                else:
154                    vert_selection_values[vert.index] = 1.0
155
156        """
157        # 頂点カラーで選択状態を確認
158        preview_vertex_color = me.vertex_colors.new()
159        for loop in me.loops:
160            v = vert_selection_values[loop.vertex_index]
161            if v != None:
162                preview_vertex_color.data[loop.index].color = (v, v, v)
163            else:
164                preview_vertex_color.data[loop.index].color = (0, 0, 0)
165        """
166
167        kd = mathutils.kdtree.KDTree(len(me.vertices))
168        # [kd.insert(v.co, v.index) for v in me.vertices]
169        for v in me.vertices:
170            kd.insert(v.co, v.index)
171        kd.balance()
172
173        blur_range = average_edge_length * self.blur_range_multi
174
175        for i in range(self.blur_count):
176
177            pre_vert_weights = [[0.0 for vg in ob.vertex_groups] for v in me.vertices]
178            for vert in me.vertices:
179                for vge in vert.groups:
180                    pre_vert_weights[vert.index][vge.group] = vge.weight
181
182            for vert in me.vertices:
183                selection_value = vert_selection_values[vert.index]
184                if selection_value is None:
185                    continue
186
187                near_infos = []
188                total_effect = 0.0
189                for co, index, dist in kd.find_range(vert.co, blur_range):
190                    ec = EmptyClass()
191                    ec.index = index
192                    if 0 < blur_range:
193                        raw_effect = 1.0 - (dist / blur_range)
194                        if self.smooth_method == 'TRIGONOMETRIC':
195                            ec.effect = common.trigonometric_smooth(raw_effect)
196                        else:
197                            ec.effect = raw_effect
198                    else:
199                        ec.effect = 1.0
200                    total_effect += ec.effect
201                    near_infos.append(ec)
202
203                new_vert_weight = [0.0 for vg in ob.vertex_groups]
204                for ec in near_infos:
205                    pre_vert_weight = pre_vert_weights[ec.index]
206                    weight_multi = ec.effect / total_effect
207                    for vg_index, near_vert_pre_weight_value in enumerate(pre_vert_weight):
208                        current_vert_pre_weight_value = pre_vert_weights[vert.index][vg_index]
209
210                        if self.blur_mode == 'NORMAL':
211                            send_weight_value = near_vert_pre_weight_value
212                        elif self.blur_mode == 'ADD':
213                            if current_vert_pre_weight_value < near_vert_pre_weight_value:
214                                send_weight_value = near_vert_pre_weight_value
215                            else:
216                                send_weight_value = current_vert_pre_weight_value
217                        elif self.blur_mode == 'SUB':
218                            if near_vert_pre_weight_value < current_vert_pre_weight_value:
219                                send_weight_value = near_vert_pre_weight_value
220                            else:
221                                send_weight_value = current_vert_pre_weight_value
222
223                        new_vert_weight[vg_index] += send_weight_value * weight_multi
224
225                for vg in ob.vertex_groups:
226                    if self.target_vertex_group == 'ACTIVE' and ob.vertex_groups.active.name != vg.name: continue
227                    if vg.lock_weight:
228                        continue
229
230                    pre_weight = pre_vert_weights[vert.index][vg.index]
231                    new_weight = new_vert_weight[vg.index]
232                    result_weight = (pre_weight * (1.0 - selection_value)) + (new_weight * selection_value)
233
234                    if 0.0 < result_weight:
235                        vg.add([vert.index], result_weight, 'REPLACE')
236                    else:
237                        vg.remove([vert.index])
238
239        if self.is_vertex_group_limit_total:
240            bpy.ops.object.vertex_group_limit_total(group_select_mode='ALL', limit=4)
241
242        bpy.ops.object.mode_set(mode=pre_mode)
243        for selected_object in pre_selected_objects:
244            compat.set_select(selected_object, True)
245        return {'FINISHED'}
246
247
248@compat.BlRegister()
249class CNV_OT_selected_mesh_vertex_group_calculation(bpy.types.Operator):
250    bl_idname = 'mesh.selected_mesh_vertex_group_calculation'
251    bl_label = "選択部の頂点グループに四則演算"
252    bl_description = "選択メッシュの頂点グループの割り当てに四則演算を施します"
253    bl_options = {'REGISTER', 'UNDO'}
254
255    items = [
256        ('LINER', "リニア", "", 'LINCURVE', 1),
257        ('TRIGONOMETRIC', "スムーズ", "", 'SMOOTHCURVE', 2),
258    ]
259    smooth_method = bpy.props.EnumProperty(items=items, name="減衰タイプ", default='TRIGONOMETRIC')
260
261    selection_blur_range_multi = bpy.props.FloatProperty(name="選択をぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
262    selection_blur_accuracy = bpy.props.IntProperty(name="選択をぼかす分割精度", default=3, min=0, max=10, soft_min=1, soft_max=10)
263
264    items = [
265        ('ACTIVE', "アクティブのみ", "", 'LAYER_ACTIVE', 1),
266    ]
267    target_vertex_group = bpy.props.EnumProperty(items=items, name="対象頂点グループ", default='ACTIVE')
268    items = [
269        ('ADD', "加算", "", 'ZOOMIN', 1),
270        ('SUB', "減算", "", 'ZOOMOUT', 2),
271        ('MULTI', "乗算", "", 'X', 3),
272        ('DIV', "除算", "", 'FULLSCREEN_EXIT', 4),
273    ]
274    calculation_mode = bpy.props.EnumProperty(items=items, name="四則演算モード", default='ADD')
275    calculation_value = bpy.props.FloatProperty(name="値", default=1.0, min=-100.0, max=100.0, soft_min=-100.0, soft_max=100.0, step=10, precision=1)
276
277    @classmethod
278    def poll(cls, context):
279        ob = context.active_object
280        if ob.type == 'MESH':
281            return len(ob.vertex_groups) > 0
282        return False
283
284    def draw(self, context):
285        self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT')
286        self.layout.prop(self, 'smooth_method')
287        self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×")
288        self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)")
289
290        self.layout.label(text="四則演算", icon='BRUSH_ADD')
291        self.layout.prop(self, 'target_vertex_group', text="対象グループ")
292        self.layout.prop(self, 'calculation_mode', text="モード")
293        self.layout.prop(self, 'calculation_value', text="値")
294
295        calculation_text = "式: 元のウェイト "
296        if self.calculation_mode == 'ADD':
297            calculation_text += "+"
298        elif self.calculation_mode == 'SUB':
299            calculation_text += "-"
300        elif self.calculation_mode == 'MULTI':
301            calculation_text += "×"
302        elif self.calculation_mode == 'DIV':
303            calculation_text += "÷"
304        calculation_text += " " + str(round(self.calculation_value, 1))
305        self.layout.label(text=calculation_text)
306
307    def execute(self, context):
308        class EmptyClass:
309            pass
310
311        if self.calculation_mode == 'DIV' and self.calculation_value == 0.0:
312            self.report(type={'ERROR'}, message="0で除算することはできません、中止します")
313            return {'CANCELLED'}
314
315        ob = context.active_object
316        me = ob.data
317
318        pre_mode = ob.mode
319        bpy.ops.object.mode_set(mode='OBJECT')
320
321        pre_selected_objects = context.selected_objects[:]
322        for selected_object in pre_selected_objects:
323            compat.set_select(selected_object, False)
324        compat.set_select(ob, True)
325
326        bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
327
328        selection_ob = context.active_object
329        selection_me = selection_ob.data
330
331        for v in selection_me.vertices:
332            if v.hide:
333                v.hide = False
334                compat.set_select(v, False)
335        for e in selection_me.edges:
336            if e.hide:
337                e.hide = False
338                compat.set_select(e, False)
339        for p in selection_me.polygons:
340            if p.hide:
341                p.hide = False
342                compat.set_select(p, False)
343
344        bpy.ops.object.mode_set(mode='EDIT')
345        bpy.ops.mesh.select_all(action='INVERT')
346        if context.tool_settings.mesh_select_mode[0]:
347            bpy.ops.mesh.delete(type='VERT')
348        elif context.tool_settings.mesh_select_mode[1]:
349            bpy.ops.mesh.delete(type='EDGE')
350        elif context.tool_settings.mesh_select_mode[2]:
351            bpy.ops.mesh.delete(type='FACE')
352        bpy.ops.mesh.select_all(action='SELECT')
353        if 1 <= self.selection_blur_accuracy:
354            bpy.ops.mesh.subdivide(number_cuts=self.selection_blur_accuracy, smoothness=0, quadcorner='INNERVERT', fractal=0, fractal_along_normal=0, seed=0)
355        bpy.ops.object.mode_set(mode='OBJECT')
356
357        selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices))
358        [selection_kd.insert(v.co, v.index) for v in selection_me.vertices]
359        selection_kd.balance()
360        common.remove_data([selection_ob, selection_me])
361
362        compat.set_select(ob, True)
363        compat.set_active(context, ob)
364
365        bm = bmesh.new()
366        bm.from_mesh(me)
367        edge_lengths = [e.calc_length() for e in bm.edges]
368        bm.free()
369        edge_lengths.sort()
370        edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5)
371        average_edge_length = edge_lengths[edge_lengths_center_index]
372        selection_blur_range = average_edge_length * self.selection_blur_range_multi
373
374        vert_selection_values = [None for v in me.vertices]
375        for vert in me.vertices:
376            co, index, dist = selection_kd.find(vert.co)
377            if dist <= selection_blur_range + 0.00001:
378                if 0 < selection_blur_range:
379                    if self.smooth_method == 'TRIGONOMETRIC':
380                        value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range))
381                    else:
382                        value = 1.0 - (dist / selection_blur_range)
383                    vert_selection_values[vert.index] = value
384                else:
385                    vert_selection_values[vert.index] = 1.0
386
387        """
388        # 頂点カラーで選択状態を確認
389        preview_vertex_color = me.vertex_colors.new()
390        for loop in me.loops:
391            v = vert_selection_values[loop.vertex_index]
392            if v != None:
393                preview_vertex_color.data[loop.index].color = (v, v, v)
394            else:
395                preview_vertex_color.data[loop.index].color = (0, 0, 0)
396        """
397
398        for vert in me.vertices:
399            effect = vert_selection_values[vert.index]
400            if effect is None:
401                continue
402
403            pre_vert_weight = 0.0
404            for vge in vert.groups:
405                if ob.vertex_groups.active.index == vge.group:
406                    pre_vert_weight = vge.weight
407
408            if self.calculation_mode == 'ADD':
409                new_vert_weight = pre_vert_weight + self.calculation_value
410            elif self.calculation_mode == 'SUB':
411                new_vert_weight = pre_vert_weight - self.calculation_value
412            elif self.calculation_mode == 'MULTI':
413                new_vert_weight = pre_vert_weight * self.calculation_value
414            elif self.calculation_mode == 'DIV':
415                new_vert_weight = pre_vert_weight / self.calculation_value
416
417            if new_vert_weight < 0.0:
418                new_vert_weight = 0.0
419            elif 1.0 < new_vert_weight:
420                new_vert_weight = 1.0
421
422            new_vert_weight = (pre_vert_weight * (1.0 - effect)) + (new_vert_weight * effect)
423
424            if 0.0 < new_vert_weight:
425                ob.vertex_groups.active.add([vert.index], new_vert_weight, 'REPLACE')
426            else:
427                ob.vertex_groups.active.remove([vert.index])
428
429        bpy.ops.object.mode_set(mode=pre_mode)
430        for selected_object in pre_selected_objects:
431            compat.set_select(selected_object, True)
432        return {'FINISHED'}
@compat.BlRegister()
class CNV_OT_selected_mesh_vertex_group_blur(bpy_types.Operator):
 20@compat.BlRegister()
 21class CNV_OT_selected_mesh_vertex_group_blur(bpy.types.Operator):
 22    bl_idname = 'mesh.selected_mesh_vertex_group_blur'
 23    bl_label = "選択部の頂点グループをぼかす"
 24    bl_description = "選択メッシュの頂点グループの割り当てをぼかします"
 25    bl_options = {'REGISTER', 'UNDO'}
 26
 27    items = [
 28        ('LINER', "リニア", "", 'LINCURVE', 1),
 29        ('TRIGONOMETRIC', "スムーズ", "", 'SMOOTHCURVE', 2),
 30    ]
 31    smooth_method = bpy.props.EnumProperty(items=items, name="減衰タイプ", default='TRIGONOMETRIC')
 32
 33    selection_blur_range_multi = bpy.props.FloatProperty(name="選択をぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
 34    selection_blur_accuracy = bpy.props.IntProperty(name="選択をぼかす分割精度", default=3, min=0, max=10, soft_min=1, soft_max=10)
 35
 36    items = [
 37        ('ALL', "全て", "", 'COLLAPSEMENU', 1),
 38        ('ACTIVE', "アクティブのみ", "", 'LAYER_ACTIVE', 2),
 39    ]
 40    target_vertex_group = bpy.props.EnumProperty(items=items, name="対象頂点グループ", default='ALL')
 41    items = [
 42        ('NORMAL', "通常・ぼかし", "", 'BRUSH_BLUR', 1),
 43        ('ADD', "増加・拡張", "", 'BRUSH_DARKEN', 2),
 44        ('SUB', "減少・縮小", "", 'BRUSH_LIGHTEN', 3),
 45    ]
 46    blur_mode = bpy.props.EnumProperty(items=items, name="ぼかしモード", default='NORMAL')
 47    blur_range_multi = bpy.props.FloatProperty(name="ウェイトをぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
 48    blur_count = bpy.props.IntProperty(name="ウェイトをぼかす回数", default=1, min=1, max=100, soft_min=1, soft_max=100)
 49    is_vertex_group_limit_total = bpy.props.BoolProperty(name="ウェイト数を4つに制限", default=True)
 50
 51    @classmethod
 52    def poll(cls, context):
 53        ob = context.active_object
 54        if ob.type == 'MESH':
 55            if len(ob.vertex_groups):
 56                return len(ob.data.vertices) and len(ob.data.edges)
 57        return False
 58
 59    def invoke(self, context, event):
 60        return context.window_manager.invoke_props_dialog(self)
 61
 62    def draw(self, context):
 63        self.layout.prop(self, 'smooth_method')
 64
 65        self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT')
 66        self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×")
 67        self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)")
 68
 69        self.layout.label(text="頂点グループをぼかす", icon='GROUP_VERTEX')
 70        self.layout.prop(self, 'target_vertex_group', text="対象グループ")
 71        self.layout.prop(self, 'blur_mode', text="モード")
 72        self.layout.prop(self, 'blur_range_multi', text="範囲 | 辺の長さの平均×")
 73        self.layout.prop(self, 'blur_count', text="実行回数")
 74        self.layout.prop(self, 'is_vertex_group_limit_total', icon='IMGDISPLAY')
 75
 76    def execute(self, context):
 77        class EmptyClass:
 78            pass
 79
 80        ob = context.active_object
 81        me = ob.data
 82
 83        pre_mode = ob.mode
 84        bpy.ops.object.mode_set(mode='OBJECT')
 85
 86        pre_selected_objects = context.selected_objects[:]
 87        for selected_object in pre_selected_objects:
 88            compat.set_select(selected_object, False)
 89        compat.set_select(ob, True)
 90
 91        bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
 92
 93        selection_ob = context.active_object
 94        selection_me = selection_ob.data
 95
 96        for v in selection_me.vertices:
 97            if v.hide:
 98                v.hide = False
 99                compat.set_select(v, False)
100        for e in selection_me.edges:
101            if e.hide:
102                e.hide = False
103                compat.set_select(e, False)
104        for p in selection_me.polygons:
105            if p.hide:
106                p.hide = False
107                compat.set_select(p, False)
108
109        bpy.ops.object.mode_set(mode='EDIT')
110        bpy.ops.mesh.select_all(action='INVERT')
111        if context.tool_settings.mesh_select_mode[0]:
112            bpy.ops.mesh.delete(type='VERT')
113        elif context.tool_settings.mesh_select_mode[1]:
114            bpy.ops.mesh.delete(type='EDGE')
115        elif context.tool_settings.mesh_select_mode[2]:
116            bpy.ops.mesh.delete(type='FACE')
117        bpy.ops.mesh.select_all(action='SELECT')
118        if 1 <= self.selection_blur_accuracy:
119            # quadtriはデフォルトでFalseのため、省略(2.8では代わりにngon=Trueが追加)
120            bpy.ops.mesh.subdivide(
121                number_cuts=self.selection_blur_accuracy,
122                smoothness=0, quadcorner='INNERVERT',
123                fractal=0, fractal_along_normal=0, seed=0)
124        bpy.ops.object.mode_set(mode='OBJECT')
125
126        selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices))
127        for v in selection_me.vertices:
128            selection_kd.insert(v.co, v.index)
129        selection_kd.balance()
130        common.remove_data([selection_ob, selection_me])
131
132        compat.set_select(ob, True)
133        compat.set_active(context, ob)
134
135        bm = bmesh.new()
136        bm.from_mesh(me)
137        edge_lengths = [e.calc_length() for e in bm.edges]
138        bm.free()
139        edge_lengths.sort()
140        edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5)
141        average_edge_length = edge_lengths[edge_lengths_center_index]
142        selection_blur_range = average_edge_length * self.selection_blur_range_multi
143
144        vert_selection_values = [None for v in me.vertices]
145        for vert in me.vertices:
146            co, index, dist = selection_kd.find(vert.co)
147            if dist <= selection_blur_range + 0.00001:
148                if 0 < selection_blur_range:
149                    if self.smooth_method == 'TRIGONOMETRIC':
150                        value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range))
151                    else:
152                        value = 1.0 - (dist / selection_blur_range)
153                    vert_selection_values[vert.index] = value
154                else:
155                    vert_selection_values[vert.index] = 1.0
156
157        """
158        # 頂点カラーで選択状態を確認
159        preview_vertex_color = me.vertex_colors.new()
160        for loop in me.loops:
161            v = vert_selection_values[loop.vertex_index]
162            if v != None:
163                preview_vertex_color.data[loop.index].color = (v, v, v)
164            else:
165                preview_vertex_color.data[loop.index].color = (0, 0, 0)
166        """
167
168        kd = mathutils.kdtree.KDTree(len(me.vertices))
169        # [kd.insert(v.co, v.index) for v in me.vertices]
170        for v in me.vertices:
171            kd.insert(v.co, v.index)
172        kd.balance()
173
174        blur_range = average_edge_length * self.blur_range_multi
175
176        for i in range(self.blur_count):
177
178            pre_vert_weights = [[0.0 for vg in ob.vertex_groups] for v in me.vertices]
179            for vert in me.vertices:
180                for vge in vert.groups:
181                    pre_vert_weights[vert.index][vge.group] = vge.weight
182
183            for vert in me.vertices:
184                selection_value = vert_selection_values[vert.index]
185                if selection_value is None:
186                    continue
187
188                near_infos = []
189                total_effect = 0.0
190                for co, index, dist in kd.find_range(vert.co, blur_range):
191                    ec = EmptyClass()
192                    ec.index = index
193                    if 0 < blur_range:
194                        raw_effect = 1.0 - (dist / blur_range)
195                        if self.smooth_method == 'TRIGONOMETRIC':
196                            ec.effect = common.trigonometric_smooth(raw_effect)
197                        else:
198                            ec.effect = raw_effect
199                    else:
200                        ec.effect = 1.0
201                    total_effect += ec.effect
202                    near_infos.append(ec)
203
204                new_vert_weight = [0.0 for vg in ob.vertex_groups]
205                for ec in near_infos:
206                    pre_vert_weight = pre_vert_weights[ec.index]
207                    weight_multi = ec.effect / total_effect
208                    for vg_index, near_vert_pre_weight_value in enumerate(pre_vert_weight):
209                        current_vert_pre_weight_value = pre_vert_weights[vert.index][vg_index]
210
211                        if self.blur_mode == 'NORMAL':
212                            send_weight_value = near_vert_pre_weight_value
213                        elif self.blur_mode == 'ADD':
214                            if current_vert_pre_weight_value < near_vert_pre_weight_value:
215                                send_weight_value = near_vert_pre_weight_value
216                            else:
217                                send_weight_value = current_vert_pre_weight_value
218                        elif self.blur_mode == 'SUB':
219                            if near_vert_pre_weight_value < current_vert_pre_weight_value:
220                                send_weight_value = near_vert_pre_weight_value
221                            else:
222                                send_weight_value = current_vert_pre_weight_value
223
224                        new_vert_weight[vg_index] += send_weight_value * weight_multi
225
226                for vg in ob.vertex_groups:
227                    if self.target_vertex_group == 'ACTIVE' and ob.vertex_groups.active.name != vg.name: continue
228                    if vg.lock_weight:
229                        continue
230
231                    pre_weight = pre_vert_weights[vert.index][vg.index]
232                    new_weight = new_vert_weight[vg.index]
233                    result_weight = (pre_weight * (1.0 - selection_value)) + (new_weight * selection_value)
234
235                    if 0.0 < result_weight:
236                        vg.add([vert.index], result_weight, 'REPLACE')
237                    else:
238                        vg.remove([vert.index])
239
240        if self.is_vertex_group_limit_total:
241            bpy.ops.object.vertex_group_limit_total(group_select_mode='ALL', limit=4)
242
243        bpy.ops.object.mode_set(mode=pre_mode)
244        for selected_object in pre_selected_objects:
245            compat.set_select(selected_object, True)
246        return {'FINISHED'}
bl_idname = 'mesh.selected_mesh_vertex_group_blur'
bl_label = '選択部の頂点グループをぼかす'
bl_description = '選択メッシュの頂点グループの割り当てをぼかします'
bl_options = {'REGISTER', 'UNDO'}
items = [('NORMAL', '通常・ぼかし', '', 'BRUSH_BLUR', 1), ('ADD', '増加・拡張', '', 'BRUSH_DARKEN', 2), ('SUB', '減少・縮小', '', 'BRUSH_LIGHTEN', 3)]
smooth_method: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('LINER', 'リニア', '', 'LINCURVE', 1), ('TRIGONOMETRIC', 'スムーズ', '', 'SMOOTHCURVE', 2)], 'name': '減衰タイプ', 'default': 'TRIGONOMETRIC', 'attr': 'smooth_method'}> = <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('LINER', 'リニア', '', 'LINCURVE', 1), ('TRIGONOMETRIC', 'スムーズ', '', 'SMOOTHCURVE', 2)], 'name': '減衰タイプ', 'default': 'TRIGONOMETRIC', 'attr': 'smooth_method'}>
selection_blur_range_multi: <_PropertyDeferred, <built-in function FloatProperty>, {'name': '選択をぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'selection_blur_range_multi'}> = <_PropertyDeferred, <built-in function FloatProperty>, {'name': '選択をぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'selection_blur_range_multi'}>
selection_blur_accuracy: <_PropertyDeferred, <built-in function IntProperty>, {'name': '選択をぼかす分割精度', 'default': 3, 'min': 0, 'max': 10, 'soft_min': 1, 'soft_max': 10, 'attr': 'selection_blur_accuracy'}> = <_PropertyDeferred, <built-in function IntProperty>, {'name': '選択をぼかす分割精度', 'default': 3, 'min': 0, 'max': 10, 'soft_min': 1, 'soft_max': 10, 'attr': 'selection_blur_accuracy'}>
target_vertex_group: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ALL', '全て', '', 'COLLAPSEMENU', 1), ('ACTIVE', 'アクティブのみ', '', 'LAYER_ACTIVE', 2)], 'name': '対象頂点グループ', 'default': 'ALL', 'attr': 'target_vertex_group'}> = <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ALL', '全て', '', 'COLLAPSEMENU', 1), ('ACTIVE', 'アクティブのみ', '', 'LAYER_ACTIVE', 2)], 'name': '対象頂点グループ', 'default': 'ALL', 'attr': 'target_vertex_group'}>
blur_mode: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('NORMAL', '通常・ぼかし', '', 'BRUSH_BLUR', 1), ('ADD', '増加・拡張', '', 'BRUSH_DARKEN', 2), ('SUB', '減少・縮小', '', 'BRUSH_LIGHTEN', 3)], 'name': 'ぼかしモード', 'default': 'NORMAL', 'attr': 'blur_mode'}> = <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('NORMAL', '通常・ぼかし', '', 'BRUSH_BLUR', 1), ('ADD', '増加・拡張', '', 'BRUSH_DARKEN', 2), ('SUB', '減少・縮小', '', 'BRUSH_LIGHTEN', 3)], 'name': 'ぼかしモード', 'default': 'NORMAL', 'attr': 'blur_mode'}>
blur_range_multi: <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'ウェイトをぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'blur_range_multi'}> = <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'ウェイトをぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'blur_range_multi'}>
blur_count: <_PropertyDeferred, <built-in function IntProperty>, {'name': 'ウェイトをぼかす回数', 'default': 1, 'min': 1, 'max': 100, 'soft_min': 1, 'soft_max': 100, 'attr': 'blur_count'}> = <_PropertyDeferred, <built-in function IntProperty>, {'name': 'ウェイトをぼかす回数', 'default': 1, 'min': 1, 'max': 100, 'soft_min': 1, 'soft_max': 100, 'attr': 'blur_count'}>
is_vertex_group_limit_total: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'ウェイト数を4つに制限', 'default': True, 'attr': 'is_vertex_group_limit_total'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'ウェイト数を4つに制限', 'default': True, 'attr': 'is_vertex_group_limit_total'}>
@classmethod
def poll(cls, context):
51    @classmethod
52    def poll(cls, context):
53        ob = context.active_object
54        if ob.type == 'MESH':
55            if len(ob.vertex_groups):
56                return len(ob.data.vertices) and len(ob.data.edges)
57        return False
def invoke(self, context, event):
59    def invoke(self, context, event):
60        return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
62    def draw(self, context):
63        self.layout.prop(self, 'smooth_method')
64
65        self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT')
66        self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×")
67        self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)")
68
69        self.layout.label(text="頂点グループをぼかす", icon='GROUP_VERTEX')
70        self.layout.prop(self, 'target_vertex_group', text="対象グループ")
71        self.layout.prop(self, 'blur_mode', text="モード")
72        self.layout.prop(self, 'blur_range_multi', text="範囲 | 辺の長さの平均×")
73        self.layout.prop(self, 'blur_count', text="実行回数")
74        self.layout.prop(self, 'is_vertex_group_limit_total', icon='IMGDISPLAY')
def execute(self, context):
 76    def execute(self, context):
 77        class EmptyClass:
 78            pass
 79
 80        ob = context.active_object
 81        me = ob.data
 82
 83        pre_mode = ob.mode
 84        bpy.ops.object.mode_set(mode='OBJECT')
 85
 86        pre_selected_objects = context.selected_objects[:]
 87        for selected_object in pre_selected_objects:
 88            compat.set_select(selected_object, False)
 89        compat.set_select(ob, True)
 90
 91        bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
 92
 93        selection_ob = context.active_object
 94        selection_me = selection_ob.data
 95
 96        for v in selection_me.vertices:
 97            if v.hide:
 98                v.hide = False
 99                compat.set_select(v, False)
100        for e in selection_me.edges:
101            if e.hide:
102                e.hide = False
103                compat.set_select(e, False)
104        for p in selection_me.polygons:
105            if p.hide:
106                p.hide = False
107                compat.set_select(p, False)
108
109        bpy.ops.object.mode_set(mode='EDIT')
110        bpy.ops.mesh.select_all(action='INVERT')
111        if context.tool_settings.mesh_select_mode[0]:
112            bpy.ops.mesh.delete(type='VERT')
113        elif context.tool_settings.mesh_select_mode[1]:
114            bpy.ops.mesh.delete(type='EDGE')
115        elif context.tool_settings.mesh_select_mode[2]:
116            bpy.ops.mesh.delete(type='FACE')
117        bpy.ops.mesh.select_all(action='SELECT')
118        if 1 <= self.selection_blur_accuracy:
119            # quadtriはデフォルトでFalseのため、省略(2.8では代わりにngon=Trueが追加)
120            bpy.ops.mesh.subdivide(
121                number_cuts=self.selection_blur_accuracy,
122                smoothness=0, quadcorner='INNERVERT',
123                fractal=0, fractal_along_normal=0, seed=0)
124        bpy.ops.object.mode_set(mode='OBJECT')
125
126        selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices))
127        for v in selection_me.vertices:
128            selection_kd.insert(v.co, v.index)
129        selection_kd.balance()
130        common.remove_data([selection_ob, selection_me])
131
132        compat.set_select(ob, True)
133        compat.set_active(context, ob)
134
135        bm = bmesh.new()
136        bm.from_mesh(me)
137        edge_lengths = [e.calc_length() for e in bm.edges]
138        bm.free()
139        edge_lengths.sort()
140        edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5)
141        average_edge_length = edge_lengths[edge_lengths_center_index]
142        selection_blur_range = average_edge_length * self.selection_blur_range_multi
143
144        vert_selection_values = [None for v in me.vertices]
145        for vert in me.vertices:
146            co, index, dist = selection_kd.find(vert.co)
147            if dist <= selection_blur_range + 0.00001:
148                if 0 < selection_blur_range:
149                    if self.smooth_method == 'TRIGONOMETRIC':
150                        value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range))
151                    else:
152                        value = 1.0 - (dist / selection_blur_range)
153                    vert_selection_values[vert.index] = value
154                else:
155                    vert_selection_values[vert.index] = 1.0
156
157        """
158        # 頂点カラーで選択状態を確認
159        preview_vertex_color = me.vertex_colors.new()
160        for loop in me.loops:
161            v = vert_selection_values[loop.vertex_index]
162            if v != None:
163                preview_vertex_color.data[loop.index].color = (v, v, v)
164            else:
165                preview_vertex_color.data[loop.index].color = (0, 0, 0)
166        """
167
168        kd = mathutils.kdtree.KDTree(len(me.vertices))
169        # [kd.insert(v.co, v.index) for v in me.vertices]
170        for v in me.vertices:
171            kd.insert(v.co, v.index)
172        kd.balance()
173
174        blur_range = average_edge_length * self.blur_range_multi
175
176        for i in range(self.blur_count):
177
178            pre_vert_weights = [[0.0 for vg in ob.vertex_groups] for v in me.vertices]
179            for vert in me.vertices:
180                for vge in vert.groups:
181                    pre_vert_weights[vert.index][vge.group] = vge.weight
182
183            for vert in me.vertices:
184                selection_value = vert_selection_values[vert.index]
185                if selection_value is None:
186                    continue
187
188                near_infos = []
189                total_effect = 0.0
190                for co, index, dist in kd.find_range(vert.co, blur_range):
191                    ec = EmptyClass()
192                    ec.index = index
193                    if 0 < blur_range:
194                        raw_effect = 1.0 - (dist / blur_range)
195                        if self.smooth_method == 'TRIGONOMETRIC':
196                            ec.effect = common.trigonometric_smooth(raw_effect)
197                        else:
198                            ec.effect = raw_effect
199                    else:
200                        ec.effect = 1.0
201                    total_effect += ec.effect
202                    near_infos.append(ec)
203
204                new_vert_weight = [0.0 for vg in ob.vertex_groups]
205                for ec in near_infos:
206                    pre_vert_weight = pre_vert_weights[ec.index]
207                    weight_multi = ec.effect / total_effect
208                    for vg_index, near_vert_pre_weight_value in enumerate(pre_vert_weight):
209                        current_vert_pre_weight_value = pre_vert_weights[vert.index][vg_index]
210
211                        if self.blur_mode == 'NORMAL':
212                            send_weight_value = near_vert_pre_weight_value
213                        elif self.blur_mode == 'ADD':
214                            if current_vert_pre_weight_value < near_vert_pre_weight_value:
215                                send_weight_value = near_vert_pre_weight_value
216                            else:
217                                send_weight_value = current_vert_pre_weight_value
218                        elif self.blur_mode == 'SUB':
219                            if near_vert_pre_weight_value < current_vert_pre_weight_value:
220                                send_weight_value = near_vert_pre_weight_value
221                            else:
222                                send_weight_value = current_vert_pre_weight_value
223
224                        new_vert_weight[vg_index] += send_weight_value * weight_multi
225
226                for vg in ob.vertex_groups:
227                    if self.target_vertex_group == 'ACTIVE' and ob.vertex_groups.active.name != vg.name: continue
228                    if vg.lock_weight:
229                        continue
230
231                    pre_weight = pre_vert_weights[vert.index][vg.index]
232                    new_weight = new_vert_weight[vg.index]
233                    result_weight = (pre_weight * (1.0 - selection_value)) + (new_weight * selection_value)
234
235                    if 0.0 < result_weight:
236                        vg.add([vert.index], result_weight, 'REPLACE')
237                    else:
238                        vg.remove([vert.index])
239
240        if self.is_vertex_group_limit_total:
241            bpy.ops.object.vertex_group_limit_total(group_select_mode='ALL', limit=4)
242
243        bpy.ops.object.mode_set(mode=pre_mode)
244        for selected_object in pre_selected_objects:
245            compat.set_select(selected_object, True)
246        return {'FINISHED'}
bl_rna = <bpy_struct, Struct("MESH_OT_selected_mesh_vertex_group_blur")>
Inherited Members
bpy_types.Operator
as_keywords
poll_message_set
builtins.bpy_struct
keys
values
get
pop
as_pointer
keyframe_insert
keyframe_delete
driver_add
driver_remove
is_property_set
property_unset
is_property_hidden
is_property_readonly
is_property_overridable_library
property_overridable_library_set
path_resolve
path_from_id
type_recast
bl_rna_get_subclass_py
bl_rna_get_subclass
id_properties_ensure
id_properties_clear
id_properties_ui
id_data
@compat.BlRegister()
class CNV_OT_selected_mesh_vertex_group_calculation(bpy_types.Operator):
249@compat.BlRegister()
250class CNV_OT_selected_mesh_vertex_group_calculation(bpy.types.Operator):
251    bl_idname = 'mesh.selected_mesh_vertex_group_calculation'
252    bl_label = "選択部の頂点グループに四則演算"
253    bl_description = "選択メッシュの頂点グループの割り当てに四則演算を施します"
254    bl_options = {'REGISTER', 'UNDO'}
255
256    items = [
257        ('LINER', "リニア", "", 'LINCURVE', 1),
258        ('TRIGONOMETRIC', "スムーズ", "", 'SMOOTHCURVE', 2),
259    ]
260    smooth_method = bpy.props.EnumProperty(items=items, name="減衰タイプ", default='TRIGONOMETRIC')
261
262    selection_blur_range_multi = bpy.props.FloatProperty(name="選択をぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1)
263    selection_blur_accuracy = bpy.props.IntProperty(name="選択をぼかす分割精度", default=3, min=0, max=10, soft_min=1, soft_max=10)
264
265    items = [
266        ('ACTIVE', "アクティブのみ", "", 'LAYER_ACTIVE', 1),
267    ]
268    target_vertex_group = bpy.props.EnumProperty(items=items, name="対象頂点グループ", default='ACTIVE')
269    items = [
270        ('ADD', "加算", "", 'ZOOMIN', 1),
271        ('SUB', "減算", "", 'ZOOMOUT', 2),
272        ('MULTI', "乗算", "", 'X', 3),
273        ('DIV', "除算", "", 'FULLSCREEN_EXIT', 4),
274    ]
275    calculation_mode = bpy.props.EnumProperty(items=items, name="四則演算モード", default='ADD')
276    calculation_value = bpy.props.FloatProperty(name="値", default=1.0, min=-100.0, max=100.0, soft_min=-100.0, soft_max=100.0, step=10, precision=1)
277
278    @classmethod
279    def poll(cls, context):
280        ob = context.active_object
281        if ob.type == 'MESH':
282            return len(ob.vertex_groups) > 0
283        return False
284
285    def draw(self, context):
286        self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT')
287        self.layout.prop(self, 'smooth_method')
288        self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×")
289        self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)")
290
291        self.layout.label(text="四則演算", icon='BRUSH_ADD')
292        self.layout.prop(self, 'target_vertex_group', text="対象グループ")
293        self.layout.prop(self, 'calculation_mode', text="モード")
294        self.layout.prop(self, 'calculation_value', text="値")
295
296        calculation_text = "式: 元のウェイト "
297        if self.calculation_mode == 'ADD':
298            calculation_text += "+"
299        elif self.calculation_mode == 'SUB':
300            calculation_text += "-"
301        elif self.calculation_mode == 'MULTI':
302            calculation_text += "×"
303        elif self.calculation_mode == 'DIV':
304            calculation_text += "÷"
305        calculation_text += " " + str(round(self.calculation_value, 1))
306        self.layout.label(text=calculation_text)
307
308    def execute(self, context):
309        class EmptyClass:
310            pass
311
312        if self.calculation_mode == 'DIV' and self.calculation_value == 0.0:
313            self.report(type={'ERROR'}, message="0で除算することはできません、中止します")
314            return {'CANCELLED'}
315
316        ob = context.active_object
317        me = ob.data
318
319        pre_mode = ob.mode
320        bpy.ops.object.mode_set(mode='OBJECT')
321
322        pre_selected_objects = context.selected_objects[:]
323        for selected_object in pre_selected_objects:
324            compat.set_select(selected_object, False)
325        compat.set_select(ob, True)
326
327        bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
328
329        selection_ob = context.active_object
330        selection_me = selection_ob.data
331
332        for v in selection_me.vertices:
333            if v.hide:
334                v.hide = False
335                compat.set_select(v, False)
336        for e in selection_me.edges:
337            if e.hide:
338                e.hide = False
339                compat.set_select(e, False)
340        for p in selection_me.polygons:
341            if p.hide:
342                p.hide = False
343                compat.set_select(p, False)
344
345        bpy.ops.object.mode_set(mode='EDIT')
346        bpy.ops.mesh.select_all(action='INVERT')
347        if context.tool_settings.mesh_select_mode[0]:
348            bpy.ops.mesh.delete(type='VERT')
349        elif context.tool_settings.mesh_select_mode[1]:
350            bpy.ops.mesh.delete(type='EDGE')
351        elif context.tool_settings.mesh_select_mode[2]:
352            bpy.ops.mesh.delete(type='FACE')
353        bpy.ops.mesh.select_all(action='SELECT')
354        if 1 <= self.selection_blur_accuracy:
355            bpy.ops.mesh.subdivide(number_cuts=self.selection_blur_accuracy, smoothness=0, quadcorner='INNERVERT', fractal=0, fractal_along_normal=0, seed=0)
356        bpy.ops.object.mode_set(mode='OBJECT')
357
358        selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices))
359        [selection_kd.insert(v.co, v.index) for v in selection_me.vertices]
360        selection_kd.balance()
361        common.remove_data([selection_ob, selection_me])
362
363        compat.set_select(ob, True)
364        compat.set_active(context, ob)
365
366        bm = bmesh.new()
367        bm.from_mesh(me)
368        edge_lengths = [e.calc_length() for e in bm.edges]
369        bm.free()
370        edge_lengths.sort()
371        edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5)
372        average_edge_length = edge_lengths[edge_lengths_center_index]
373        selection_blur_range = average_edge_length * self.selection_blur_range_multi
374
375        vert_selection_values = [None for v in me.vertices]
376        for vert in me.vertices:
377            co, index, dist = selection_kd.find(vert.co)
378            if dist <= selection_blur_range + 0.00001:
379                if 0 < selection_blur_range:
380                    if self.smooth_method == 'TRIGONOMETRIC':
381                        value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range))
382                    else:
383                        value = 1.0 - (dist / selection_blur_range)
384                    vert_selection_values[vert.index] = value
385                else:
386                    vert_selection_values[vert.index] = 1.0
387
388        """
389        # 頂点カラーで選択状態を確認
390        preview_vertex_color = me.vertex_colors.new()
391        for loop in me.loops:
392            v = vert_selection_values[loop.vertex_index]
393            if v != None:
394                preview_vertex_color.data[loop.index].color = (v, v, v)
395            else:
396                preview_vertex_color.data[loop.index].color = (0, 0, 0)
397        """
398
399        for vert in me.vertices:
400            effect = vert_selection_values[vert.index]
401            if effect is None:
402                continue
403
404            pre_vert_weight = 0.0
405            for vge in vert.groups:
406                if ob.vertex_groups.active.index == vge.group:
407                    pre_vert_weight = vge.weight
408
409            if self.calculation_mode == 'ADD':
410                new_vert_weight = pre_vert_weight + self.calculation_value
411            elif self.calculation_mode == 'SUB':
412                new_vert_weight = pre_vert_weight - self.calculation_value
413            elif self.calculation_mode == 'MULTI':
414                new_vert_weight = pre_vert_weight * self.calculation_value
415            elif self.calculation_mode == 'DIV':
416                new_vert_weight = pre_vert_weight / self.calculation_value
417
418            if new_vert_weight < 0.0:
419                new_vert_weight = 0.0
420            elif 1.0 < new_vert_weight:
421                new_vert_weight = 1.0
422
423            new_vert_weight = (pre_vert_weight * (1.0 - effect)) + (new_vert_weight * effect)
424
425            if 0.0 < new_vert_weight:
426                ob.vertex_groups.active.add([vert.index], new_vert_weight, 'REPLACE')
427            else:
428                ob.vertex_groups.active.remove([vert.index])
429
430        bpy.ops.object.mode_set(mode=pre_mode)
431        for selected_object in pre_selected_objects:
432            compat.set_select(selected_object, True)
433        return {'FINISHED'}
bl_idname = 'mesh.selected_mesh_vertex_group_calculation'
bl_label = '選択部の頂点グループに四則演算'
bl_description = '選択メッシュの頂点グループの割り当てに四則演算を施します'
bl_options = {'REGISTER', 'UNDO'}
items = [('ADD', '加算', '', 'ZOOMIN', 1), ('SUB', '減算', '', 'ZOOMOUT', 2), ('MULTI', '乗算', '', 'X', 3), ('DIV', '除算', '', 'FULLSCREEN_EXIT', 4)]
smooth_method: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('LINER', 'リニア', '', 'LINCURVE', 1), ('TRIGONOMETRIC', 'スムーズ', '', 'SMOOTHCURVE', 2)], 'name': '減衰タイプ', 'default': 'TRIGONOMETRIC', 'attr': 'smooth_method'}> = <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('LINER', 'リニア', '', 'LINCURVE', 1), ('TRIGONOMETRIC', 'スムーズ', '', 'SMOOTHCURVE', 2)], 'name': '減衰タイプ', 'default': 'TRIGONOMETRIC', 'attr': 'smooth_method'}>
selection_blur_range_multi: <_PropertyDeferred, <built-in function FloatProperty>, {'name': '選択をぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'selection_blur_range_multi'}> = <_PropertyDeferred, <built-in function FloatProperty>, {'name': '選択をぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'selection_blur_range_multi'}>
selection_blur_accuracy: <_PropertyDeferred, <built-in function IntProperty>, {'name': '選択をぼかす分割精度', 'default': 3, 'min': 0, 'max': 10, 'soft_min': 1, 'soft_max': 10, 'attr': 'selection_blur_accuracy'}> = <_PropertyDeferred, <built-in function IntProperty>, {'name': '選択をぼかす分割精度', 'default': 3, 'min': 0, 'max': 10, 'soft_min': 1, 'soft_max': 10, 'attr': 'selection_blur_accuracy'}>
target_vertex_group: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ACTIVE', 'アクティブのみ', '', 'LAYER_ACTIVE', 1)], 'name': '対象頂点グループ', 'default': 'ACTIVE', 'attr': 'target_vertex_group'}> = <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ACTIVE', 'アクティブのみ', '', 'LAYER_ACTIVE', 1)], 'name': '対象頂点グループ', 'default': 'ACTIVE', 'attr': 'target_vertex_group'}>
calculation_mode: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ADD', '加算', '', 'ZOOMIN', 1), ('SUB', '減算', '', 'ZOOMOUT', 2), ('MULTI', '乗算', '', 'X', 3), ('DIV', '除算', '', 'FULLSCREEN_EXIT', 4)], 'name': '四則演算モード', 'default': 'ADD', 'attr': 'calculation_mode'}> = <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ADD', '加算', '', 'ZOOMIN', 1), ('SUB', '減算', '', 'ZOOMOUT', 2), ('MULTI', '乗算', '', 'X', 3), ('DIV', '除算', '', 'FULLSCREEN_EXIT', 4)], 'name': '四則演算モード', 'default': 'ADD', 'attr': 'calculation_mode'}>
calculation_value: <_PropertyDeferred, <built-in function FloatProperty>, {'name': '値', 'default': 1.0, 'min': -100.0, 'max': 100.0, 'soft_min': -100.0, 'soft_max': 100.0, 'step': 10, 'precision': 1, 'attr': 'calculation_value'}> = <_PropertyDeferred, <built-in function FloatProperty>, {'name': '値', 'default': 1.0, 'min': -100.0, 'max': 100.0, 'soft_min': -100.0, 'soft_max': 100.0, 'step': 10, 'precision': 1, 'attr': 'calculation_value'}>
@classmethod
def poll(cls, context):
278    @classmethod
279    def poll(cls, context):
280        ob = context.active_object
281        if ob.type == 'MESH':
282            return len(ob.vertex_groups) > 0
283        return False
def draw(self, context):
285    def draw(self, context):
286        self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT')
287        self.layout.prop(self, 'smooth_method')
288        self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×")
289        self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)")
290
291        self.layout.label(text="四則演算", icon='BRUSH_ADD')
292        self.layout.prop(self, 'target_vertex_group', text="対象グループ")
293        self.layout.prop(self, 'calculation_mode', text="モード")
294        self.layout.prop(self, 'calculation_value', text="値")
295
296        calculation_text = "式: 元のウェイト "
297        if self.calculation_mode == 'ADD':
298            calculation_text += "+"
299        elif self.calculation_mode == 'SUB':
300            calculation_text += "-"
301        elif self.calculation_mode == 'MULTI':
302            calculation_text += "×"
303        elif self.calculation_mode == 'DIV':
304            calculation_text += "÷"
305        calculation_text += " " + str(round(self.calculation_value, 1))
306        self.layout.label(text=calculation_text)
def execute(self, context):
308    def execute(self, context):
309        class EmptyClass:
310            pass
311
312        if self.calculation_mode == 'DIV' and self.calculation_value == 0.0:
313            self.report(type={'ERROR'}, message="0で除算することはできません、中止します")
314            return {'CANCELLED'}
315
316        ob = context.active_object
317        me = ob.data
318
319        pre_mode = ob.mode
320        bpy.ops.object.mode_set(mode='OBJECT')
321
322        pre_selected_objects = context.selected_objects[:]
323        for selected_object in pre_selected_objects:
324            compat.set_select(selected_object, False)
325        compat.set_select(ob, True)
326
327        bpy.ops.object.duplicate(linked=False, mode='TRANSLATION')
328
329        selection_ob = context.active_object
330        selection_me = selection_ob.data
331
332        for v in selection_me.vertices:
333            if v.hide:
334                v.hide = False
335                compat.set_select(v, False)
336        for e in selection_me.edges:
337            if e.hide:
338                e.hide = False
339                compat.set_select(e, False)
340        for p in selection_me.polygons:
341            if p.hide:
342                p.hide = False
343                compat.set_select(p, False)
344
345        bpy.ops.object.mode_set(mode='EDIT')
346        bpy.ops.mesh.select_all(action='INVERT')
347        if context.tool_settings.mesh_select_mode[0]:
348            bpy.ops.mesh.delete(type='VERT')
349        elif context.tool_settings.mesh_select_mode[1]:
350            bpy.ops.mesh.delete(type='EDGE')
351        elif context.tool_settings.mesh_select_mode[2]:
352            bpy.ops.mesh.delete(type='FACE')
353        bpy.ops.mesh.select_all(action='SELECT')
354        if 1 <= self.selection_blur_accuracy:
355            bpy.ops.mesh.subdivide(number_cuts=self.selection_blur_accuracy, smoothness=0, quadcorner='INNERVERT', fractal=0, fractal_along_normal=0, seed=0)
356        bpy.ops.object.mode_set(mode='OBJECT')
357
358        selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices))
359        [selection_kd.insert(v.co, v.index) for v in selection_me.vertices]
360        selection_kd.balance()
361        common.remove_data([selection_ob, selection_me])
362
363        compat.set_select(ob, True)
364        compat.set_active(context, ob)
365
366        bm = bmesh.new()
367        bm.from_mesh(me)
368        edge_lengths = [e.calc_length() for e in bm.edges]
369        bm.free()
370        edge_lengths.sort()
371        edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5)
372        average_edge_length = edge_lengths[edge_lengths_center_index]
373        selection_blur_range = average_edge_length * self.selection_blur_range_multi
374
375        vert_selection_values = [None for v in me.vertices]
376        for vert in me.vertices:
377            co, index, dist = selection_kd.find(vert.co)
378            if dist <= selection_blur_range + 0.00001:
379                if 0 < selection_blur_range:
380                    if self.smooth_method == 'TRIGONOMETRIC':
381                        value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range))
382                    else:
383                        value = 1.0 - (dist / selection_blur_range)
384                    vert_selection_values[vert.index] = value
385                else:
386                    vert_selection_values[vert.index] = 1.0
387
388        """
389        # 頂点カラーで選択状態を確認
390        preview_vertex_color = me.vertex_colors.new()
391        for loop in me.loops:
392            v = vert_selection_values[loop.vertex_index]
393            if v != None:
394                preview_vertex_color.data[loop.index].color = (v, v, v)
395            else:
396                preview_vertex_color.data[loop.index].color = (0, 0, 0)
397        """
398
399        for vert in me.vertices:
400            effect = vert_selection_values[vert.index]
401            if effect is None:
402                continue
403
404            pre_vert_weight = 0.0
405            for vge in vert.groups:
406                if ob.vertex_groups.active.index == vge.group:
407                    pre_vert_weight = vge.weight
408
409            if self.calculation_mode == 'ADD':
410                new_vert_weight = pre_vert_weight + self.calculation_value
411            elif self.calculation_mode == 'SUB':
412                new_vert_weight = pre_vert_weight - self.calculation_value
413            elif self.calculation_mode == 'MULTI':
414                new_vert_weight = pre_vert_weight * self.calculation_value
415            elif self.calculation_mode == 'DIV':
416                new_vert_weight = pre_vert_weight / self.calculation_value
417
418            if new_vert_weight < 0.0:
419                new_vert_weight = 0.0
420            elif 1.0 < new_vert_weight:
421                new_vert_weight = 1.0
422
423            new_vert_weight = (pre_vert_weight * (1.0 - effect)) + (new_vert_weight * effect)
424
425            if 0.0 < new_vert_weight:
426                ob.vertex_groups.active.add([vert.index], new_vert_weight, 'REPLACE')
427            else:
428                ob.vertex_groups.active.remove([vert.index])
429
430        bpy.ops.object.mode_set(mode=pre_mode)
431        for selected_object in pre_selected_objects:
432            compat.set_select(selected_object, True)
433        return {'FINISHED'}
bl_rna = <bpy_struct, Struct("MESH_OT_selected_mesh_vertex_group_calculation")>
Inherited Members
bpy_types.Operator
as_keywords
poll_message_set
builtins.bpy_struct
keys
values
get
pop
as_pointer
keyframe_insert
keyframe_delete
driver_add
driver_remove
is_property_set
property_unset
is_property_hidden
is_property_readonly
is_property_overridable_library
property_overridable_library_set
path_resolve
path_from_id
type_recast
bl_rna_get_subclass_py
bl_rna_get_subclass
id_properties_ensure
id_properties_clear
id_properties_ui
id_data