CM3D2 Converter.misc_DATA_PT_modifiers

  1# 「プロパティ」エリア → 「モディファイア」タブ
  2import os
  3import re
  4import struct
  5import math
  6import unicodedata
  7import time
  8import bpy
  9import bmesh
 10import mathutils
 11from . import common
 12from . import compat
 13from .translations.pgettext_functions import *
 14
 15
 16# メニュー等に項目追加
 17def menu_func(self, context):
 18    ob = context.active_object
 19    if ob:
 20        if ob.type == 'MESH':
 21            me = ob.data
 22            if len(ob.modifiers):
 23                self.layout.operator('object.forced_modifier_apply', icon_value=common.kiss_icon())
 24
 25
 26@compat.BlRegister()
 27class CNV_UL_modifier_selector(common.CNV_UL_generic_selector):
 28    bl_label       = 'CNV_UL_modifier_selector'
 29    bl_options     = {'DEFAULT_CLOSED'}
 30    bl_region_type = 'WINDOW'
 31    bl_space_type  = 'PROPERTIES'
 32
 33    # Constants (flags)
 34    # Be careful not to shadow FILTER_ITEM!
 35    #bitflag_forced_true  = 1 << 0
 36    #bitflag_forced_false = 1 << 1
 37    #force_values = False
 38    #did_force_values = False
 39
 40    force_values = bpy.props.BoolProperty(
 41        name="force_values",
 42        default=False,
 43        options=set(),
 44    )
 45
 46    did_force_values = bpy.props.BoolProperty(
 47        name="force_values",
 48        default=False,
 49        options=set(),
 50    )
 51
 52    # This allows us to have mutually exclusive options, which are also all disable-able!
 53    def _gen_force_values(self, context):
 54        setattr(self, "force_values", True)
 55        setattr(self, "did_force_values", False)
 56        print("SET TRUE force_values =", self.force_values)
 57    
 58    def _gen_visible_update(name1, name2):
 59        def _u(self, context):
 60            self._gen_force_values(context)
 61            if (getattr(self, name1)):
 62                setattr(self, name2, False)
 63        return _u
 64    use_filter_viewport_visible = bpy.props.BoolProperty(
 65        name="Viewport",
 66        default=False,
 67        options=set(),
 68        description="Only enable modifiers visible in viewport",
 69        update=_gen_visible_update("use_filter_viewport_visible", "use_filter_renderer_visible"),
 70    )
 71    use_filter_renderer_visible = bpy.props.BoolProperty(
 72        name="Renderer",
 73        default=False,
 74        options=set(),
 75        description="Only enable modifiers visible in renderer",
 76        update=_gen_visible_update("use_filter_renderer_visible", "use_filter_viewport_visible"),
 77    )
 78    use_filter_reversed_visible = bpy.props.BoolProperty(
 79        name="Reverse Visible Filter",
 80        default=False,
 81        options=set(),
 82        description="Reverse the selected visible-in filter",
 83        update=_gen_force_values
 84    )
 85
 86
 87    use_filter_name_reverse = bpy.props.BoolProperty(
 88        name="Reverse Name",
 89        default=False,
 90        options=set(),
 91        description="Reverse name filtering",
 92    )
 93
 94    def _gen_order_update(name1, name2):
 95        def _u(self, ctxt):
 96            if (getattr(self, name1)):
 97                setattr(self, name2, False)
 98        return _u
 99    use_order_name = bpy.props.BoolProperty(
100        name="Name", default=False, options=set(),
101        description="Sort groups by their name (case-insensitive)",
102        update=_gen_order_update("use_order_name", "use_order_importance"),
103    )
104    use_filter_orderby_invert = bpy.props.BoolProperty(
105        name="Order by Invert",
106        default=False,
107        options=set(),
108        description="Invert the sort by order"
109    )
110
111
112    def draw_filter(self, context, layout):
113        row = layout.row()
114        row.label(text="Visible in:")
115        subrow = row.row(align=True)
116        subrow.prop(self, "use_filter_viewport_visible", toggle=True)
117        subrow.prop(self, "use_filter_renderer_visible", toggle=True)
118        icon = 'ZOOM_OUT' if self.use_filter_reversed_visible else 'ZOOM_IN'
119        icon = compat.icon(icon)
120        subrow.prop(self, "use_filter_reversed_visible", text="", icon=icon)
121
122        super(CNV_UL_modifier_selector, self).draw_filter(context, layout)
123
124    def filter_items(self, context, data, propname):
125        flt_flags, flt_neworder = super(CNV_UL_modifier_selector, self).filter_items(context, data, propname)
126        items = getattr(data, propname)
127
128        if getattr(self, 'did_force_values'):
129            setattr(self,'force_values', False)
130        setattr(self, 'did_force_values', getattr(self, 'force_values'))
131
132        print("CHECK force_values = ", getattr(self, 'force_values'))
133
134        if self.use_filter_viewport_visible or self.use_filter_renderer_visible or getattr(self, 'force_values'):
135
136            if not self.use_filter_reversed_visible:
137                in_flag  = self.bitflag_forced_true 
138                out_flag = ~(self.bitflag_forced_false | self.bitflag_soft_filter)
139            else:
140                in_flag  = self.bitflag_forced_false | self.bitflag_soft_filter
141                out_flag = ~self.bitflag_forced_true
142
143            for index, item in enumerate(items):
144                if getattr(self, 'force_values'):
145                    flt_flags[index] |= self.bitflag_forced_value
146
147                if self.use_filter_viewport_visible and item.filter0:
148                    flt_flags[index] |= in_flag
149                    flt_flags[index] &= out_flag
150                elif self.use_filter_renderer_visible and item.filter1:
151                    flt_flags[index] |= in_flag
152                    flt_flags[index] &= out_flag
153                elif not self.use_filter_viewport_visible and not self.use_filter_renderer_visible:
154                    pass
155                else:
156                    flt_flags[index] |= ~out_flag
157                    flt_flags[index] &= ~in_flag
158
159        return flt_flags, flt_neworder
160
161
162@compat.BlRegister()
163class CNV_OT_forced_modifier_apply(bpy.types.Operator):
164    bl_idname = 'object.forced_modifier_apply'
165    bl_label = "モディファイア強制適用"
166    bl_description = "シェイプキーのあるメッシュのモディファイアでも強制的に適用します"
167    bl_options = {'REGISTER', 'UNDO'}
168    
169    is_preserve_shape_key_values = bpy.props.BoolProperty(name="Preserve Shape Key Values", default=True , description="Ensure shape key values are not changed")
170
171    #is_applies = bpy.props.BoolVectorProperty(name="適用するモディファイア", size=32, options={'SKIP_SAVE'})
172    is_applies = bpy.props.CollectionProperty(type=common.CNV_SelectorItem)
173    active_modifier = bpy.props.IntProperty(name="Active Modifier")
174
175    apply_viewport_visible = bpy.props.BoolProperty(name="Apply Viewport-Visible Modifiers", default=False)
176    apply_renderer_visible = bpy.props.BoolProperty(name="Apply Renderer-Visible Modifiers", default=False)
177
178    initial_progress = bpy.props.FloatProperty(name="Progress", default=-1, options={'HIDDEN', 'SKIP_SAVE'})
179    
180    
181    @classmethod
182    def poll(cls, context):
183        ob = context.active_object
184        return len(ob.modifiers)
185
186    def invoke(self, context, event):
187        ob = context.active_object
188        if len(ob.modifiers) == 0:
189            return {'CANCELLED'}
190
191        for index, mod in enumerate(ob.modifiers):
192            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
193            #    self.report(type={'WARNING'}, message="Can only apply the first 32 modifiers at once.")
194            #    break
195            icon = 'MOD_%s' % mod.type.replace('DECIMATE','DECIM').replace('SOFT_BODY','SOFT').replace('PARTICLE_SYSTEM','PARTICLES').replace('_SPLIT','SPLIT').replace('_PROJECT','PROJECT').replace('_DEFORM','DEFORM').replace('_SIMULATION','SIM').replace('_EDIT','').replace('_MIX','').replace('_PROXIMITY','').replace('_PAINT','PAINT')
196            icon = compat.icon(icon)
197            
198            new_prop = None
199            if index < len(self.is_applies):
200                new_prop = self.is_applies[index]
201            else:
202                new_prop = self.is_applies.add()
203            
204            if new_prop.name == mod.name and new_prop.icon == icon:
205                # It's probably the same one, ignore it
206                pass
207            else:
208                new_prop.name      = mod.name
209                new_prop.index     = index
210                new_prop.value     = mod.show_viewport
211                new_prop.preferred = new_prop.value
212                new_prop.icon      = icon
213                new_prop.filter0   = mod.show_viewport
214                new_prop.filter1   = mod.show_render
215
216        while len(self.is_applies) > len(ob.modifiers):
217            self.is_applies.remove(len(self.is_applies)-1)
218
219        return context.window_manager.invoke_props_dialog(self)
220
221    def draw(self, context):
222        prefs = common.preferences()
223        if compat.IS_LEGACY:
224            self.layout.prop(prefs, 'custom_normal_blend'         , icon=compat.icon('SNAP_NORMAL'  ), slider=True)
225        self.layout.prop(self , 'is_preserve_shape_key_values', icon=compat.icon('SHAPEKEY_DATA'), slider=True)
226        self.layout.label(text="適用するモディファイア")
227        ob = context.active_object
228
229        #for index, mod in enumerate(ob.modifiers):
230        #    if index >= 32: # luvoid : can only apply 32 modifiers at once.
231        #        break
232        #    icon = 'MOD_%s' % mod.type.replace('DECIMATE','DECIM').replace('SOFT_BODY','SOFT').replace('PARTICLE_SYSTEM','PARTICLES').replace('_SPLIT','SPLIT').replace('_PROJECT','PROJECT').replace('_DEFORM','DEFORM').replace('_SIMULATION','SIM').replace('_EDIT','').replace('_MIX','').replace('_PROXIMITY','').replace('_PAINT','PAINT')
233        #    try:
234        #        self.layout.prop(self, 'is_applies', text=mod.name, index=index, icon=icon)
235        #    except:
236        #        self.layout.prop(self, 'is_applies', text=mod.name, index=index, icon='MODIFIER')
237        
238        self.layout.template_list("CNV_UL_modifier_selector", "", self, "is_applies", self, "active_modifier")
239        self.layout.label(text="Show filters", icon='FILE_PARENT')
240
241    def execute(self, context):
242        ob = context.object
243
244        did_start_progress = False
245        if self.initial_progress == -1:
246            progress_start = 0
247            context.window_manager.progress_begin(0, 1)
248            did_start_progress = True
249        else:
250            progress_start = self.initial_progress
251
252        if self.apply_viewport_visible or self.apply_renderer_visible:
253            for index, mod in enumerate(ob.modifiers):
254                new_prop = None
255                if index < len(self.is_applies):
256                    new_prop = self.is_applies[index]
257                else:
258                    new_prop = self.is_applies.add()
259                
260                new_prop.name      = mod.name
261                new_prop.index     = index
262                new_prop.value     = (self.apply_viewport_visible and mod.show_viewport) or (self.apply_renderer_visible and mod.show_render)
263
264        # 対象が一つも無い場合はキャンセル扱いとする
265        is_any = False
266        for item in self.is_applies:
267            if item.value:
268                is_any = True
269                break
270        if not is_any:
271            self.report(type={'INFO'}, message="適用対象のモディファイアがないため、キャンセルします")
272            context.window_manager.progress_update(progress_start + 1)
273            if did_start_progress:
274                context.window_manager.progress_end()
275            return {'CANCELLED'}
276
277        custom_normal_blend = common.preferences().custom_normal_blend
278        bpy.ops.object.mode_set(mode='OBJECT')
279
280        me = ob.data
281        is_shaped = bool(me.shape_keys)
282
283        pre_selected_objects = context.selected_objects[:]
284        pre_mode = ob.mode
285
286        arm_ob = None
287        if compat.IS_LEGACY:
288            for mod in ob.modifiers:
289                if mod.type == "ARMATURE":
290                    arm_ob = mod.object
291
292        progress = 0
293        progress_count = 1
294        progress_count += 2 if arm_ob else 0
295        progress_count += len(me.shape_keys.key_blocks) * 3 if is_shaped else 0
296
297        if is_shaped:
298            pre_active_shape_key_index = ob.active_shape_key_index
299            pre_relative_keys          = [None] * len(me.shape_keys.key_blocks)
300            pre_shape_key_values       = [0]    * len(me.shape_keys.key_blocks)
301            shape_names                = [""]   * len(me.shape_keys.key_blocks)
302            shape_deforms              = [None] * len(me.shape_keys.key_blocks)
303            for shape_index, shape in enumerate(me.shape_keys.key_blocks):
304                pre_relative_keys   [shape_index] = shape.relative_key.name
305                pre_shape_key_values[shape_index] = shape.value
306                shape_names         [shape_index] = shape.name
307                shape_deforms       [shape_index] = [shape.data[v.index].co.copy() for v in me.vertices]
308                
309                progress += 1
310                context.window_manager.progress_update(progress_start + progress / progress_count)
311
312            ob.active_shape_key_index = len(me.shape_keys.key_blocks) - 1
313            for i in me.shape_keys.key_blocks[:]:
314                ob.shape_key_remove(ob.active_shape_key)
315            
316            new_shape_deforms = []
317            for shape_index, deforms in enumerate(shape_deforms):
318                temp_ob = ob.copy()
319                temp_me = me.copy()
320                temp_ob.data = temp_me
321                compat.link(context.scene, temp_ob)
322                try:
323                    for vert in temp_me.vertices:
324                        vert.co = deforms[vert.index].copy()
325
326                    override = context.copy()
327                    override['object'] = temp_ob
328                    for index, mod in enumerate(temp_ob.modifiers):
329                        if self.is_applies[index].value:
330                            try:
331                                bpy.ops.object.modifier_apply(override, modifier=mod.name)
332                            except:
333                                temp_ob.modifiers.remove(mod)
334
335                    new_shape_deforms.append([v.co.copy() for v in temp_me.vertices])
336                except Exception as e:
337                    #ob.modifiers.remove(mod)
338                    self.report(type={'WARNING'}, message=f_tip_("Could not apply '{}' modifier \"{}\" to shapekey {}", mod.type, mod.name, shape_index))
339                    print(f_("Error applying '{type}' modifier \"{name}\":\n\t", type=mod.type, name=mod.name), e)
340                finally:
341                    common.remove_data(temp_ob)
342                    common.remove_data(temp_me)
343
344                    progress += 1
345                    context.window_manager.progress_update(progress_start + progress / progress_count)
346
347        if ob.active_shape_key_index != 0:
348            ob.active_shape_key_index = 0
349            me.update()
350
351        copy_modifiers = ob.modifiers[:]
352        mod_count = len(copy_modifiers)
353        mod_progress = 0
354        override = context.copy()
355        override['object'] = ob
356        for index, mod in enumerate(copy_modifiers):
357            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
358            #    break
359            if self.is_applies[index].value and (mod.type != 'ARMATURE' or not compat.IS_LEGACY):
360                if mod.type == 'MIRROR' and mod.use_mirror_vertex_groups:
361                    if bpy.ops.object.decode_cm3d2_vertex_group_names.poll():
362                        self.report(type={'WARNING'}, message="Vertex groups are not in blender naming style. Mirror modifier results may not be as expected")
363                    for vg in ob.vertex_groups[:]:
364                        replace_list = ((r'\.L$', ".R"), (r'\.R$', ".L"), (r'\.l$', ".r"), (r'\.r$', ".l"), (r'_L$', "_R"), (r'_R$', "_L"), (r'_l$', "_r"), (r'_r$', "_l"))
365                        for before, after in replace_list:
366                            mirrored_name = re.sub(before, after, vg.name)
367                            if mirrored_name not in ob.vertex_groups:
368                                ob.vertex_groups.new(override, name=mirrored_name)
369                try:
370                    bpy.ops.object.modifier_apply(override, modifier=mod.name)
371                except Exception as e:
372                    #ob.modifiers.remove(mod)
373                    self.report(type={'ERROR', 'WARNING'}, message=f_tip_("Could not apply '{type}' modifier \"{name}\"", type=mod.type, name=mod.name))
374                    print(f_("Error applying '{type}' modifier \"{name}\":\n\t", type=mod.type, name=mod.name), e)
375            
376            mod_progress += 1 if (mod.type != 'ARMATURE' or not compat.IS_LEGACY) else 0
377            context.window_manager.progress_update( progress_start + (progress + mod_progress / mod_count) / progress_count )
378
379        # Calculate custom normals for armature modifiers in legacy blender
380        if arm_ob:
381            bpy.ops.object.mode_set(mode='EDIT')
382            bpy.ops.object.mode_set(mode='OBJECT')
383
384            arm = arm_ob.data
385            arm_pose = arm_ob.pose
386
387            pose_quats = {}
388            for bone in arm.bones:
389                pose_bone = arm_pose.bones[bone.name]
390
391                bone_quat = bone.matrix_local.to_quaternion()
392                pose_quat = pose_bone.matrix.to_quaternion()
393                result_quat = compat.mul(pose_quat, bone_quat.inverted())
394
395                pose_quats[bone.name] = result_quat.copy()
396
397            custom_normals = []
398            for loop in me.loops:
399                vert = me.vertices[loop.vertex_index]
400                no = vert.normal.copy()
401
402                total_weight = 0.0
403                for vge in vert.groups:
404                    vg = ob.vertex_groups[vge.group]
405                    try:
406                        pose_quats[vg.name]
407                    except KeyError:
408                        continue
409                    total_weight += vge.weight
410
411                total_quat = mathutils.Quaternion()
412                if total_weight != 0.0:
413                    for vge in vert.groups:
414                        vg = ob.vertex_groups[vge.group]
415                        try:
416                            total_quat = total_quat.slerp(pose_quats[vg.name], vge.weight / total_weight)
417                        except KeyError:
418                            pass
419                
420                no.rotate(total_quat)
421                custom_normals.append(no)
422
423            progress += 1
424            context.window_manager.progress_update(progress_start + progress / progress_count)
425
426        override = context.copy()
427        override['object'] = ob
428        for index, mod in enumerate(copy_modifiers):
429            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
430            #    break
431            if self.is_applies[index].value and (mod.type == 'ARMATURE' and compat.IS_LEGACY):
432                try:
433                    bpy.ops.object.modifier_apply(override, modifier=mod.name)
434                except Exception as e:
435                    #ob.modifiers.remove(mod)
436                    self.report(type={'ERROR', 'WARNING'}, message=f_tip_("Could not apply '{mod_type}' modifier \"{mod_name}\"", mod_type=mod.type, mod_name=mod.name) )
437                    print(f_("Could not apply '{mod_type}' modifier \"{mod_name}\":\n\t", mod_type=mod.type, mod_name=mod.name), e)
438            
439            mod_progress += 1 if (mod.type == 'ARMATURE' and compat.IS_LEGACY) else 0
440            context.window_manager.progress_update( progress_start + (progress + mod_progress / mod_count) / progress_count )
441
442        progress += 1
443        context.window_manager.progress_update(progress_start + progress / progress_count)
444
445        compat.set_active(context, ob)
446
447        if is_shaped:
448            for deforms in new_shape_deforms:
449                if len(me.vertices) != len(deforms):
450                    self.report(type={'ERROR'}, message="ミラー等が原因で頂点数が変わっているためシェイプキーを格納できません、中止するのでCtrl+Z等で元に戻し修正してください。")
451                    context.window_manager.progress_update(progress_start + 1)
452                    if did_start_progress:
453                        context.window_manager.progress_end()
454                    return {'FINISHED', 'CANCELLED'}
455
456            for shape_index, deforms in enumerate(new_shape_deforms):
457                bpy.ops.object.shape_key_add(context.copy(), from_mix=False)
458                shape = ob.active_shape_key
459                shape.name = shape_names[shape_index]
460
461                for vert in me.vertices:
462                    shape.data[vert.index].co = deforms[vert.index].copy()
463
464                progress += 1
465                context.window_manager.progress_update(progress_start + progress / progress_count)
466
467            for shape_index, shape in enumerate(me.shape_keys.key_blocks):
468                shape.relative_key = me.shape_keys.key_blocks[pre_relative_keys[shape_index]]
469                if self.is_preserve_shape_key_values:
470                    shape.value = pre_shape_key_values[shape_index]
471
472            ob.active_shape_key_index = pre_active_shape_key_index
473
474        for temp_ob in pre_selected_objects:
475            compat.set_select(temp_ob, True)
476        bpy.ops.object.mode_set(mode=pre_mode)
477
478        if arm_ob:
479            for i, loop in enumerate(me.loops):
480                vert = me.vertices[loop.vertex_index]
481                no = vert.normal.copy()
482
483                try:
484                    custom_rot = mathutils.Vector((0.0, 0.0, 1.0)).rotation_difference(custom_normals[i])
485                except:
486                    continue
487                original_rot = mathutils.Vector((0.0, 0.0, 1.0)).rotation_difference(no)
488                output_rot = original_rot.slerp(custom_rot, custom_normal_blend)
489
490                output_no = mathutils.Vector((0.0, 0.0, 1.0))
491                output_no.rotate(output_rot)
492
493                custom_normals[i] = output_no
494            me.use_auto_smooth = True
495            me.normals_split_custom_set(custom_normals)
496
497            progress += 1
498            context.window_manager.progress_update(progress_start + progress / progress_count)
499
500        context.window_manager.progress_update(progress_start + 1)
501        if did_start_progress:
502            context.window_manager.progress_end()
503        return {'FINISHED'}
@compat.BlRegister()
class CNV_UL_modifier_selector(CM3D2 Converter.common.CNV_UL_generic_selector):
 27@compat.BlRegister()
 28class CNV_UL_modifier_selector(common.CNV_UL_generic_selector):
 29    bl_label       = 'CNV_UL_modifier_selector'
 30    bl_options     = {'DEFAULT_CLOSED'}
 31    bl_region_type = 'WINDOW'
 32    bl_space_type  = 'PROPERTIES'
 33
 34    # Constants (flags)
 35    # Be careful not to shadow FILTER_ITEM!
 36    #bitflag_forced_true  = 1 << 0
 37    #bitflag_forced_false = 1 << 1
 38    #force_values = False
 39    #did_force_values = False
 40
 41    force_values = bpy.props.BoolProperty(
 42        name="force_values",
 43        default=False,
 44        options=set(),
 45    )
 46
 47    did_force_values = bpy.props.BoolProperty(
 48        name="force_values",
 49        default=False,
 50        options=set(),
 51    )
 52
 53    # This allows us to have mutually exclusive options, which are also all disable-able!
 54    def _gen_force_values(self, context):
 55        setattr(self, "force_values", True)
 56        setattr(self, "did_force_values", False)
 57        print("SET TRUE force_values =", self.force_values)
 58    
 59    def _gen_visible_update(name1, name2):
 60        def _u(self, context):
 61            self._gen_force_values(context)
 62            if (getattr(self, name1)):
 63                setattr(self, name2, False)
 64        return _u
 65    use_filter_viewport_visible = bpy.props.BoolProperty(
 66        name="Viewport",
 67        default=False,
 68        options=set(),
 69        description="Only enable modifiers visible in viewport",
 70        update=_gen_visible_update("use_filter_viewport_visible", "use_filter_renderer_visible"),
 71    )
 72    use_filter_renderer_visible = bpy.props.BoolProperty(
 73        name="Renderer",
 74        default=False,
 75        options=set(),
 76        description="Only enable modifiers visible in renderer",
 77        update=_gen_visible_update("use_filter_renderer_visible", "use_filter_viewport_visible"),
 78    )
 79    use_filter_reversed_visible = bpy.props.BoolProperty(
 80        name="Reverse Visible Filter",
 81        default=False,
 82        options=set(),
 83        description="Reverse the selected visible-in filter",
 84        update=_gen_force_values
 85    )
 86
 87
 88    use_filter_name_reverse = bpy.props.BoolProperty(
 89        name="Reverse Name",
 90        default=False,
 91        options=set(),
 92        description="Reverse name filtering",
 93    )
 94
 95    def _gen_order_update(name1, name2):
 96        def _u(self, ctxt):
 97            if (getattr(self, name1)):
 98                setattr(self, name2, False)
 99        return _u
100    use_order_name = bpy.props.BoolProperty(
101        name="Name", default=False, options=set(),
102        description="Sort groups by their name (case-insensitive)",
103        update=_gen_order_update("use_order_name", "use_order_importance"),
104    )
105    use_filter_orderby_invert = bpy.props.BoolProperty(
106        name="Order by Invert",
107        default=False,
108        options=set(),
109        description="Invert the sort by order"
110    )
111
112
113    def draw_filter(self, context, layout):
114        row = layout.row()
115        row.label(text="Visible in:")
116        subrow = row.row(align=True)
117        subrow.prop(self, "use_filter_viewport_visible", toggle=True)
118        subrow.prop(self, "use_filter_renderer_visible", toggle=True)
119        icon = 'ZOOM_OUT' if self.use_filter_reversed_visible else 'ZOOM_IN'
120        icon = compat.icon(icon)
121        subrow.prop(self, "use_filter_reversed_visible", text="", icon=icon)
122
123        super(CNV_UL_modifier_selector, self).draw_filter(context, layout)
124
125    def filter_items(self, context, data, propname):
126        flt_flags, flt_neworder = super(CNV_UL_modifier_selector, self).filter_items(context, data, propname)
127        items = getattr(data, propname)
128
129        if getattr(self, 'did_force_values'):
130            setattr(self,'force_values', False)
131        setattr(self, 'did_force_values', getattr(self, 'force_values'))
132
133        print("CHECK force_values = ", getattr(self, 'force_values'))
134
135        if self.use_filter_viewport_visible or self.use_filter_renderer_visible or getattr(self, 'force_values'):
136
137            if not self.use_filter_reversed_visible:
138                in_flag  = self.bitflag_forced_true 
139                out_flag = ~(self.bitflag_forced_false | self.bitflag_soft_filter)
140            else:
141                in_flag  = self.bitflag_forced_false | self.bitflag_soft_filter
142                out_flag = ~self.bitflag_forced_true
143
144            for index, item in enumerate(items):
145                if getattr(self, 'force_values'):
146                    flt_flags[index] |= self.bitflag_forced_value
147
148                if self.use_filter_viewport_visible and item.filter0:
149                    flt_flags[index] |= in_flag
150                    flt_flags[index] &= out_flag
151                elif self.use_filter_renderer_visible and item.filter1:
152                    flt_flags[index] |= in_flag
153                    flt_flags[index] &= out_flag
154                elif not self.use_filter_viewport_visible and not self.use_filter_renderer_visible:
155                    pass
156                else:
157                    flt_flags[index] |= ~out_flag
158                    flt_flags[index] &= ~in_flag
159
160        return flt_flags, flt_neworder
bl_label = 'CNV_UL_modifier_selector'
bl_options = {'DEFAULT_CLOSED'}
bl_region_type = 'WINDOW'
bl_space_type = 'PROPERTIES'
force_values: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'force_values', 'default': False, 'options': set(), 'attr': 'force_values'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'force_values', 'default': False, 'options': set(), 'attr': 'force_values'}>
did_force_values: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'force_values', 'default': False, 'options': set(), 'attr': 'did_force_values'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'force_values', 'default': False, 'options': set(), 'attr': 'did_force_values'}>
use_filter_viewport_visible: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Viewport', 'default': False, 'options': set(), 'description': 'Only enable modifiers visible in viewport', 'update': <function CNV_UL_modifier_selector._gen_visible_update.<locals>._u at 0x7f6a0eb67e20>, 'attr': 'use_filter_viewport_visible'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Viewport', 'default': False, 'options': set(), 'description': 'Only enable modifiers visible in viewport', 'update': <function CNV_UL_modifier_selector._gen_visible_update.<locals>._u>, 'attr': 'use_filter_viewport_visible'}>
use_filter_renderer_visible: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Renderer', 'default': False, 'options': set(), 'description': 'Only enable modifiers visible in renderer', 'update': <function CNV_UL_modifier_selector._gen_visible_update.<locals>._u at 0x7f6a0eb67eb0>, 'attr': 'use_filter_renderer_visible'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Renderer', 'default': False, 'options': set(), 'description': 'Only enable modifiers visible in renderer', 'update': <function CNV_UL_modifier_selector._gen_visible_update.<locals>._u>, 'attr': 'use_filter_renderer_visible'}>
use_filter_reversed_visible: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Reverse Visible Filter', 'default': False, 'options': set(), 'description': 'Reverse the selected visible-in filter', 'update': <function CNV_UL_modifier_selector._gen_force_values at 0x7f6a0eb67d00>, 'attr': 'use_filter_reversed_visible'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Reverse Visible Filter', 'default': False, 'options': set(), 'description': 'Reverse the selected visible-in filter', 'update': <function CNV_UL_modifier_selector._gen_force_values>, 'attr': 'use_filter_reversed_visible'}>
use_filter_name_reverse: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Reverse Name', 'default': False, 'options': set(), 'description': 'Reverse name filtering', 'attr': 'use_filter_name_reverse'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Reverse Name', 'default': False, 'options': set(), 'description': 'Reverse name filtering', 'attr': 'use_filter_name_reverse'}>
use_order_name: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Name', 'default': False, 'options': set(), 'description': 'Sort groups by their name (case-insensitive)', 'update': <function CNV_UL_modifier_selector._gen_order_update.<locals>._u at 0x7f6a0eba4040>, 'attr': 'use_order_name'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Name', 'default': False, 'options': set(), 'description': 'Sort groups by their name (case-insensitive)', 'update': <function CNV_UL_modifier_selector._gen_order_update.<locals>._u>, 'attr': 'use_order_name'}>
use_filter_orderby_invert: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Order by Invert', 'default': False, 'options': set(), 'description': 'Invert the sort by order', 'attr': 'use_filter_orderby_invert'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Order by Invert', 'default': False, 'options': set(), 'description': 'Invert the sort by order', 'attr': 'use_filter_orderby_invert'}>
def draw_filter(self, context, layout):
113    def draw_filter(self, context, layout):
114        row = layout.row()
115        row.label(text="Visible in:")
116        subrow = row.row(align=True)
117        subrow.prop(self, "use_filter_viewport_visible", toggle=True)
118        subrow.prop(self, "use_filter_renderer_visible", toggle=True)
119        icon = 'ZOOM_OUT' if self.use_filter_reversed_visible else 'ZOOM_IN'
120        icon = compat.icon(icon)
121        subrow.prop(self, "use_filter_reversed_visible", text="", icon=icon)
122
123        super(CNV_UL_modifier_selector, self).draw_filter(context, layout)
def filter_items(self, context, data, propname):
125    def filter_items(self, context, data, propname):
126        flt_flags, flt_neworder = super(CNV_UL_modifier_selector, self).filter_items(context, data, propname)
127        items = getattr(data, propname)
128
129        if getattr(self, 'did_force_values'):
130            setattr(self,'force_values', False)
131        setattr(self, 'did_force_values', getattr(self, 'force_values'))
132
133        print("CHECK force_values = ", getattr(self, 'force_values'))
134
135        if self.use_filter_viewport_visible or self.use_filter_renderer_visible or getattr(self, 'force_values'):
136
137            if not self.use_filter_reversed_visible:
138                in_flag  = self.bitflag_forced_true 
139                out_flag = ~(self.bitflag_forced_false | self.bitflag_soft_filter)
140            else:
141                in_flag  = self.bitflag_forced_false | self.bitflag_soft_filter
142                out_flag = ~self.bitflag_forced_true
143
144            for index, item in enumerate(items):
145                if getattr(self, 'force_values'):
146                    flt_flags[index] |= self.bitflag_forced_value
147
148                if self.use_filter_viewport_visible and item.filter0:
149                    flt_flags[index] |= in_flag
150                    flt_flags[index] &= out_flag
151                elif self.use_filter_renderer_visible and item.filter1:
152                    flt_flags[index] |= in_flag
153                    flt_flags[index] &= out_flag
154                elif not self.use_filter_viewport_visible and not self.use_filter_renderer_visible:
155                    pass
156                else:
157                    flt_flags[index] |= ~out_flag
158                    flt_flags[index] &= ~in_flag
159
160        return flt_flags, flt_neworder
bl_rna = <bpy_struct, Struct("CNV_UL_modifier_selector")>
Inherited Members
CM3D2 Converter.common.CNV_UL_generic_selector
bitflag_soft_filter
bitflag_forced_value
bitflag_forced_true
bitflag_forced_false
cached_values
expanded_layout
draw_item
bpy_types._GenericUI
is_extended
append
prepend
remove
builtins.bpy_struct
keys
values
items
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_forced_modifier_apply(bpy_types.Operator):
163@compat.BlRegister()
164class CNV_OT_forced_modifier_apply(bpy.types.Operator):
165    bl_idname = 'object.forced_modifier_apply'
166    bl_label = "モディファイア強制適用"
167    bl_description = "シェイプキーのあるメッシュのモディファイアでも強制的に適用します"
168    bl_options = {'REGISTER', 'UNDO'}
169    
170    is_preserve_shape_key_values = bpy.props.BoolProperty(name="Preserve Shape Key Values", default=True , description="Ensure shape key values are not changed")
171
172    #is_applies = bpy.props.BoolVectorProperty(name="適用するモディファイア", size=32, options={'SKIP_SAVE'})
173    is_applies = bpy.props.CollectionProperty(type=common.CNV_SelectorItem)
174    active_modifier = bpy.props.IntProperty(name="Active Modifier")
175
176    apply_viewport_visible = bpy.props.BoolProperty(name="Apply Viewport-Visible Modifiers", default=False)
177    apply_renderer_visible = bpy.props.BoolProperty(name="Apply Renderer-Visible Modifiers", default=False)
178
179    initial_progress = bpy.props.FloatProperty(name="Progress", default=-1, options={'HIDDEN', 'SKIP_SAVE'})
180    
181    
182    @classmethod
183    def poll(cls, context):
184        ob = context.active_object
185        return len(ob.modifiers)
186
187    def invoke(self, context, event):
188        ob = context.active_object
189        if len(ob.modifiers) == 0:
190            return {'CANCELLED'}
191
192        for index, mod in enumerate(ob.modifiers):
193            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
194            #    self.report(type={'WARNING'}, message="Can only apply the first 32 modifiers at once.")
195            #    break
196            icon = 'MOD_%s' % mod.type.replace('DECIMATE','DECIM').replace('SOFT_BODY','SOFT').replace('PARTICLE_SYSTEM','PARTICLES').replace('_SPLIT','SPLIT').replace('_PROJECT','PROJECT').replace('_DEFORM','DEFORM').replace('_SIMULATION','SIM').replace('_EDIT','').replace('_MIX','').replace('_PROXIMITY','').replace('_PAINT','PAINT')
197            icon = compat.icon(icon)
198            
199            new_prop = None
200            if index < len(self.is_applies):
201                new_prop = self.is_applies[index]
202            else:
203                new_prop = self.is_applies.add()
204            
205            if new_prop.name == mod.name and new_prop.icon == icon:
206                # It's probably the same one, ignore it
207                pass
208            else:
209                new_prop.name      = mod.name
210                new_prop.index     = index
211                new_prop.value     = mod.show_viewport
212                new_prop.preferred = new_prop.value
213                new_prop.icon      = icon
214                new_prop.filter0   = mod.show_viewport
215                new_prop.filter1   = mod.show_render
216
217        while len(self.is_applies) > len(ob.modifiers):
218            self.is_applies.remove(len(self.is_applies)-1)
219
220        return context.window_manager.invoke_props_dialog(self)
221
222    def draw(self, context):
223        prefs = common.preferences()
224        if compat.IS_LEGACY:
225            self.layout.prop(prefs, 'custom_normal_blend'         , icon=compat.icon('SNAP_NORMAL'  ), slider=True)
226        self.layout.prop(self , 'is_preserve_shape_key_values', icon=compat.icon('SHAPEKEY_DATA'), slider=True)
227        self.layout.label(text="適用するモディファイア")
228        ob = context.active_object
229
230        #for index, mod in enumerate(ob.modifiers):
231        #    if index >= 32: # luvoid : can only apply 32 modifiers at once.
232        #        break
233        #    icon = 'MOD_%s' % mod.type.replace('DECIMATE','DECIM').replace('SOFT_BODY','SOFT').replace('PARTICLE_SYSTEM','PARTICLES').replace('_SPLIT','SPLIT').replace('_PROJECT','PROJECT').replace('_DEFORM','DEFORM').replace('_SIMULATION','SIM').replace('_EDIT','').replace('_MIX','').replace('_PROXIMITY','').replace('_PAINT','PAINT')
234        #    try:
235        #        self.layout.prop(self, 'is_applies', text=mod.name, index=index, icon=icon)
236        #    except:
237        #        self.layout.prop(self, 'is_applies', text=mod.name, index=index, icon='MODIFIER')
238        
239        self.layout.template_list("CNV_UL_modifier_selector", "", self, "is_applies", self, "active_modifier")
240        self.layout.label(text="Show filters", icon='FILE_PARENT')
241
242    def execute(self, context):
243        ob = context.object
244
245        did_start_progress = False
246        if self.initial_progress == -1:
247            progress_start = 0
248            context.window_manager.progress_begin(0, 1)
249            did_start_progress = True
250        else:
251            progress_start = self.initial_progress
252
253        if self.apply_viewport_visible or self.apply_renderer_visible:
254            for index, mod in enumerate(ob.modifiers):
255                new_prop = None
256                if index < len(self.is_applies):
257                    new_prop = self.is_applies[index]
258                else:
259                    new_prop = self.is_applies.add()
260                
261                new_prop.name      = mod.name
262                new_prop.index     = index
263                new_prop.value     = (self.apply_viewport_visible and mod.show_viewport) or (self.apply_renderer_visible and mod.show_render)
264
265        # 対象が一つも無い場合はキャンセル扱いとする
266        is_any = False
267        for item in self.is_applies:
268            if item.value:
269                is_any = True
270                break
271        if not is_any:
272            self.report(type={'INFO'}, message="適用対象のモディファイアがないため、キャンセルします")
273            context.window_manager.progress_update(progress_start + 1)
274            if did_start_progress:
275                context.window_manager.progress_end()
276            return {'CANCELLED'}
277
278        custom_normal_blend = common.preferences().custom_normal_blend
279        bpy.ops.object.mode_set(mode='OBJECT')
280
281        me = ob.data
282        is_shaped = bool(me.shape_keys)
283
284        pre_selected_objects = context.selected_objects[:]
285        pre_mode = ob.mode
286
287        arm_ob = None
288        if compat.IS_LEGACY:
289            for mod in ob.modifiers:
290                if mod.type == "ARMATURE":
291                    arm_ob = mod.object
292
293        progress = 0
294        progress_count = 1
295        progress_count += 2 if arm_ob else 0
296        progress_count += len(me.shape_keys.key_blocks) * 3 if is_shaped else 0
297
298        if is_shaped:
299            pre_active_shape_key_index = ob.active_shape_key_index
300            pre_relative_keys          = [None] * len(me.shape_keys.key_blocks)
301            pre_shape_key_values       = [0]    * len(me.shape_keys.key_blocks)
302            shape_names                = [""]   * len(me.shape_keys.key_blocks)
303            shape_deforms              = [None] * len(me.shape_keys.key_blocks)
304            for shape_index, shape in enumerate(me.shape_keys.key_blocks):
305                pre_relative_keys   [shape_index] = shape.relative_key.name
306                pre_shape_key_values[shape_index] = shape.value
307                shape_names         [shape_index] = shape.name
308                shape_deforms       [shape_index] = [shape.data[v.index].co.copy() for v in me.vertices]
309                
310                progress += 1
311                context.window_manager.progress_update(progress_start + progress / progress_count)
312
313            ob.active_shape_key_index = len(me.shape_keys.key_blocks) - 1
314            for i in me.shape_keys.key_blocks[:]:
315                ob.shape_key_remove(ob.active_shape_key)
316            
317            new_shape_deforms = []
318            for shape_index, deforms in enumerate(shape_deforms):
319                temp_ob = ob.copy()
320                temp_me = me.copy()
321                temp_ob.data = temp_me
322                compat.link(context.scene, temp_ob)
323                try:
324                    for vert in temp_me.vertices:
325                        vert.co = deforms[vert.index].copy()
326
327                    override = context.copy()
328                    override['object'] = temp_ob
329                    for index, mod in enumerate(temp_ob.modifiers):
330                        if self.is_applies[index].value:
331                            try:
332                                bpy.ops.object.modifier_apply(override, modifier=mod.name)
333                            except:
334                                temp_ob.modifiers.remove(mod)
335
336                    new_shape_deforms.append([v.co.copy() for v in temp_me.vertices])
337                except Exception as e:
338                    #ob.modifiers.remove(mod)
339                    self.report(type={'WARNING'}, message=f_tip_("Could not apply '{}' modifier \"{}\" to shapekey {}", mod.type, mod.name, shape_index))
340                    print(f_("Error applying '{type}' modifier \"{name}\":\n\t", type=mod.type, name=mod.name), e)
341                finally:
342                    common.remove_data(temp_ob)
343                    common.remove_data(temp_me)
344
345                    progress += 1
346                    context.window_manager.progress_update(progress_start + progress / progress_count)
347
348        if ob.active_shape_key_index != 0:
349            ob.active_shape_key_index = 0
350            me.update()
351
352        copy_modifiers = ob.modifiers[:]
353        mod_count = len(copy_modifiers)
354        mod_progress = 0
355        override = context.copy()
356        override['object'] = ob
357        for index, mod in enumerate(copy_modifiers):
358            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
359            #    break
360            if self.is_applies[index].value and (mod.type != 'ARMATURE' or not compat.IS_LEGACY):
361                if mod.type == 'MIRROR' and mod.use_mirror_vertex_groups:
362                    if bpy.ops.object.decode_cm3d2_vertex_group_names.poll():
363                        self.report(type={'WARNING'}, message="Vertex groups are not in blender naming style. Mirror modifier results may not be as expected")
364                    for vg in ob.vertex_groups[:]:
365                        replace_list = ((r'\.L$', ".R"), (r'\.R$', ".L"), (r'\.l$', ".r"), (r'\.r$', ".l"), (r'_L$', "_R"), (r'_R$', "_L"), (r'_l$', "_r"), (r'_r$', "_l"))
366                        for before, after in replace_list:
367                            mirrored_name = re.sub(before, after, vg.name)
368                            if mirrored_name not in ob.vertex_groups:
369                                ob.vertex_groups.new(override, name=mirrored_name)
370                try:
371                    bpy.ops.object.modifier_apply(override, modifier=mod.name)
372                except Exception as e:
373                    #ob.modifiers.remove(mod)
374                    self.report(type={'ERROR', 'WARNING'}, message=f_tip_("Could not apply '{type}' modifier \"{name}\"", type=mod.type, name=mod.name))
375                    print(f_("Error applying '{type}' modifier \"{name}\":\n\t", type=mod.type, name=mod.name), e)
376            
377            mod_progress += 1 if (mod.type != 'ARMATURE' or not compat.IS_LEGACY) else 0
378            context.window_manager.progress_update( progress_start + (progress + mod_progress / mod_count) / progress_count )
379
380        # Calculate custom normals for armature modifiers in legacy blender
381        if arm_ob:
382            bpy.ops.object.mode_set(mode='EDIT')
383            bpy.ops.object.mode_set(mode='OBJECT')
384
385            arm = arm_ob.data
386            arm_pose = arm_ob.pose
387
388            pose_quats = {}
389            for bone in arm.bones:
390                pose_bone = arm_pose.bones[bone.name]
391
392                bone_quat = bone.matrix_local.to_quaternion()
393                pose_quat = pose_bone.matrix.to_quaternion()
394                result_quat = compat.mul(pose_quat, bone_quat.inverted())
395
396                pose_quats[bone.name] = result_quat.copy()
397
398            custom_normals = []
399            for loop in me.loops:
400                vert = me.vertices[loop.vertex_index]
401                no = vert.normal.copy()
402
403                total_weight = 0.0
404                for vge in vert.groups:
405                    vg = ob.vertex_groups[vge.group]
406                    try:
407                        pose_quats[vg.name]
408                    except KeyError:
409                        continue
410                    total_weight += vge.weight
411
412                total_quat = mathutils.Quaternion()
413                if total_weight != 0.0:
414                    for vge in vert.groups:
415                        vg = ob.vertex_groups[vge.group]
416                        try:
417                            total_quat = total_quat.slerp(pose_quats[vg.name], vge.weight / total_weight)
418                        except KeyError:
419                            pass
420                
421                no.rotate(total_quat)
422                custom_normals.append(no)
423
424            progress += 1
425            context.window_manager.progress_update(progress_start + progress / progress_count)
426
427        override = context.copy()
428        override['object'] = ob
429        for index, mod in enumerate(copy_modifiers):
430            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
431            #    break
432            if self.is_applies[index].value and (mod.type == 'ARMATURE' and compat.IS_LEGACY):
433                try:
434                    bpy.ops.object.modifier_apply(override, modifier=mod.name)
435                except Exception as e:
436                    #ob.modifiers.remove(mod)
437                    self.report(type={'ERROR', 'WARNING'}, message=f_tip_("Could not apply '{mod_type}' modifier \"{mod_name}\"", mod_type=mod.type, mod_name=mod.name) )
438                    print(f_("Could not apply '{mod_type}' modifier \"{mod_name}\":\n\t", mod_type=mod.type, mod_name=mod.name), e)
439            
440            mod_progress += 1 if (mod.type == 'ARMATURE' and compat.IS_LEGACY) else 0
441            context.window_manager.progress_update( progress_start + (progress + mod_progress / mod_count) / progress_count )
442
443        progress += 1
444        context.window_manager.progress_update(progress_start + progress / progress_count)
445
446        compat.set_active(context, ob)
447
448        if is_shaped:
449            for deforms in new_shape_deforms:
450                if len(me.vertices) != len(deforms):
451                    self.report(type={'ERROR'}, message="ミラー等が原因で頂点数が変わっているためシェイプキーを格納できません、中止するのでCtrl+Z等で元に戻し修正してください。")
452                    context.window_manager.progress_update(progress_start + 1)
453                    if did_start_progress:
454                        context.window_manager.progress_end()
455                    return {'FINISHED', 'CANCELLED'}
456
457            for shape_index, deforms in enumerate(new_shape_deforms):
458                bpy.ops.object.shape_key_add(context.copy(), from_mix=False)
459                shape = ob.active_shape_key
460                shape.name = shape_names[shape_index]
461
462                for vert in me.vertices:
463                    shape.data[vert.index].co = deforms[vert.index].copy()
464
465                progress += 1
466                context.window_manager.progress_update(progress_start + progress / progress_count)
467
468            for shape_index, shape in enumerate(me.shape_keys.key_blocks):
469                shape.relative_key = me.shape_keys.key_blocks[pre_relative_keys[shape_index]]
470                if self.is_preserve_shape_key_values:
471                    shape.value = pre_shape_key_values[shape_index]
472
473            ob.active_shape_key_index = pre_active_shape_key_index
474
475        for temp_ob in pre_selected_objects:
476            compat.set_select(temp_ob, True)
477        bpy.ops.object.mode_set(mode=pre_mode)
478
479        if arm_ob:
480            for i, loop in enumerate(me.loops):
481                vert = me.vertices[loop.vertex_index]
482                no = vert.normal.copy()
483
484                try:
485                    custom_rot = mathutils.Vector((0.0, 0.0, 1.0)).rotation_difference(custom_normals[i])
486                except:
487                    continue
488                original_rot = mathutils.Vector((0.0, 0.0, 1.0)).rotation_difference(no)
489                output_rot = original_rot.slerp(custom_rot, custom_normal_blend)
490
491                output_no = mathutils.Vector((0.0, 0.0, 1.0))
492                output_no.rotate(output_rot)
493
494                custom_normals[i] = output_no
495            me.use_auto_smooth = True
496            me.normals_split_custom_set(custom_normals)
497
498            progress += 1
499            context.window_manager.progress_update(progress_start + progress / progress_count)
500
501        context.window_manager.progress_update(progress_start + 1)
502        if did_start_progress:
503            context.window_manager.progress_end()
504        return {'FINISHED'}
bl_idname = 'object.forced_modifier_apply'
bl_label = 'モディファイア強制適用'
bl_description = 'シェイプキーのあるメッシュのモディファイアでも強制的に適用します'
bl_options = {'REGISTER', 'UNDO'}
is_preserve_shape_key_values: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Preserve Shape Key Values', 'default': True, 'description': 'Ensure shape key values are not changed', 'attr': 'is_preserve_shape_key_values'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Preserve Shape Key Values', 'default': True, 'description': 'Ensure shape key values are not changed', 'attr': 'is_preserve_shape_key_values'}>
is_applies: <_PropertyDeferred, <built-in function CollectionProperty>, {'type': <class 'CM3D2 Converter.common.CNV_SelectorItem'>, 'attr': 'is_applies'}> = <_PropertyDeferred, <built-in function CollectionProperty>, {'type': <class 'CM3D2 Converter.common.CNV_SelectorItem'>, 'attr': 'is_applies'}>
active_modifier: <_PropertyDeferred, <built-in function IntProperty>, {'name': 'Active Modifier', 'attr': 'active_modifier'}> = <_PropertyDeferred, <built-in function IntProperty>, {'name': 'Active Modifier', 'attr': 'active_modifier'}>
apply_viewport_visible: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Apply Viewport-Visible Modifiers', 'default': False, 'attr': 'apply_viewport_visible'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Apply Viewport-Visible Modifiers', 'default': False, 'attr': 'apply_viewport_visible'}>
apply_renderer_visible: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Apply Renderer-Visible Modifiers', 'default': False, 'attr': 'apply_renderer_visible'}> = <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Apply Renderer-Visible Modifiers', 'default': False, 'attr': 'apply_renderer_visible'}>
initial_progress: <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'Progress', 'default': -1, 'options': {'HIDDEN', 'SKIP_SAVE'}, 'attr': 'initial_progress'}> = <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'Progress', 'default': -1, 'options': {'HIDDEN', 'SKIP_SAVE'}, 'attr': 'initial_progress'}>
@classmethod
def poll(cls, context):
182    @classmethod
183    def poll(cls, context):
184        ob = context.active_object
185        return len(ob.modifiers)
def invoke(self, context, event):
187    def invoke(self, context, event):
188        ob = context.active_object
189        if len(ob.modifiers) == 0:
190            return {'CANCELLED'}
191
192        for index, mod in enumerate(ob.modifiers):
193            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
194            #    self.report(type={'WARNING'}, message="Can only apply the first 32 modifiers at once.")
195            #    break
196            icon = 'MOD_%s' % mod.type.replace('DECIMATE','DECIM').replace('SOFT_BODY','SOFT').replace('PARTICLE_SYSTEM','PARTICLES').replace('_SPLIT','SPLIT').replace('_PROJECT','PROJECT').replace('_DEFORM','DEFORM').replace('_SIMULATION','SIM').replace('_EDIT','').replace('_MIX','').replace('_PROXIMITY','').replace('_PAINT','PAINT')
197            icon = compat.icon(icon)
198            
199            new_prop = None
200            if index < len(self.is_applies):
201                new_prop = self.is_applies[index]
202            else:
203                new_prop = self.is_applies.add()
204            
205            if new_prop.name == mod.name and new_prop.icon == icon:
206                # It's probably the same one, ignore it
207                pass
208            else:
209                new_prop.name      = mod.name
210                new_prop.index     = index
211                new_prop.value     = mod.show_viewport
212                new_prop.preferred = new_prop.value
213                new_prop.icon      = icon
214                new_prop.filter0   = mod.show_viewport
215                new_prop.filter1   = mod.show_render
216
217        while len(self.is_applies) > len(ob.modifiers):
218            self.is_applies.remove(len(self.is_applies)-1)
219
220        return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
222    def draw(self, context):
223        prefs = common.preferences()
224        if compat.IS_LEGACY:
225            self.layout.prop(prefs, 'custom_normal_blend'         , icon=compat.icon('SNAP_NORMAL'  ), slider=True)
226        self.layout.prop(self , 'is_preserve_shape_key_values', icon=compat.icon('SHAPEKEY_DATA'), slider=True)
227        self.layout.label(text="適用するモディファイア")
228        ob = context.active_object
229
230        #for index, mod in enumerate(ob.modifiers):
231        #    if index >= 32: # luvoid : can only apply 32 modifiers at once.
232        #        break
233        #    icon = 'MOD_%s' % mod.type.replace('DECIMATE','DECIM').replace('SOFT_BODY','SOFT').replace('PARTICLE_SYSTEM','PARTICLES').replace('_SPLIT','SPLIT').replace('_PROJECT','PROJECT').replace('_DEFORM','DEFORM').replace('_SIMULATION','SIM').replace('_EDIT','').replace('_MIX','').replace('_PROXIMITY','').replace('_PAINT','PAINT')
234        #    try:
235        #        self.layout.prop(self, 'is_applies', text=mod.name, index=index, icon=icon)
236        #    except:
237        #        self.layout.prop(self, 'is_applies', text=mod.name, index=index, icon='MODIFIER')
238        
239        self.layout.template_list("CNV_UL_modifier_selector", "", self, "is_applies", self, "active_modifier")
240        self.layout.label(text="Show filters", icon='FILE_PARENT')
def execute(self, context):
242    def execute(self, context):
243        ob = context.object
244
245        did_start_progress = False
246        if self.initial_progress == -1:
247            progress_start = 0
248            context.window_manager.progress_begin(0, 1)
249            did_start_progress = True
250        else:
251            progress_start = self.initial_progress
252
253        if self.apply_viewport_visible or self.apply_renderer_visible:
254            for index, mod in enumerate(ob.modifiers):
255                new_prop = None
256                if index < len(self.is_applies):
257                    new_prop = self.is_applies[index]
258                else:
259                    new_prop = self.is_applies.add()
260                
261                new_prop.name      = mod.name
262                new_prop.index     = index
263                new_prop.value     = (self.apply_viewport_visible and mod.show_viewport) or (self.apply_renderer_visible and mod.show_render)
264
265        # 対象が一つも無い場合はキャンセル扱いとする
266        is_any = False
267        for item in self.is_applies:
268            if item.value:
269                is_any = True
270                break
271        if not is_any:
272            self.report(type={'INFO'}, message="適用対象のモディファイアがないため、キャンセルします")
273            context.window_manager.progress_update(progress_start + 1)
274            if did_start_progress:
275                context.window_manager.progress_end()
276            return {'CANCELLED'}
277
278        custom_normal_blend = common.preferences().custom_normal_blend
279        bpy.ops.object.mode_set(mode='OBJECT')
280
281        me = ob.data
282        is_shaped = bool(me.shape_keys)
283
284        pre_selected_objects = context.selected_objects[:]
285        pre_mode = ob.mode
286
287        arm_ob = None
288        if compat.IS_LEGACY:
289            for mod in ob.modifiers:
290                if mod.type == "ARMATURE":
291                    arm_ob = mod.object
292
293        progress = 0
294        progress_count = 1
295        progress_count += 2 if arm_ob else 0
296        progress_count += len(me.shape_keys.key_blocks) * 3 if is_shaped else 0
297
298        if is_shaped:
299            pre_active_shape_key_index = ob.active_shape_key_index
300            pre_relative_keys          = [None] * len(me.shape_keys.key_blocks)
301            pre_shape_key_values       = [0]    * len(me.shape_keys.key_blocks)
302            shape_names                = [""]   * len(me.shape_keys.key_blocks)
303            shape_deforms              = [None] * len(me.shape_keys.key_blocks)
304            for shape_index, shape in enumerate(me.shape_keys.key_blocks):
305                pre_relative_keys   [shape_index] = shape.relative_key.name
306                pre_shape_key_values[shape_index] = shape.value
307                shape_names         [shape_index] = shape.name
308                shape_deforms       [shape_index] = [shape.data[v.index].co.copy() for v in me.vertices]
309                
310                progress += 1
311                context.window_manager.progress_update(progress_start + progress / progress_count)
312
313            ob.active_shape_key_index = len(me.shape_keys.key_blocks) - 1
314            for i in me.shape_keys.key_blocks[:]:
315                ob.shape_key_remove(ob.active_shape_key)
316            
317            new_shape_deforms = []
318            for shape_index, deforms in enumerate(shape_deforms):
319                temp_ob = ob.copy()
320                temp_me = me.copy()
321                temp_ob.data = temp_me
322                compat.link(context.scene, temp_ob)
323                try:
324                    for vert in temp_me.vertices:
325                        vert.co = deforms[vert.index].copy()
326
327                    override = context.copy()
328                    override['object'] = temp_ob
329                    for index, mod in enumerate(temp_ob.modifiers):
330                        if self.is_applies[index].value:
331                            try:
332                                bpy.ops.object.modifier_apply(override, modifier=mod.name)
333                            except:
334                                temp_ob.modifiers.remove(mod)
335
336                    new_shape_deforms.append([v.co.copy() for v in temp_me.vertices])
337                except Exception as e:
338                    #ob.modifiers.remove(mod)
339                    self.report(type={'WARNING'}, message=f_tip_("Could not apply '{}' modifier \"{}\" to shapekey {}", mod.type, mod.name, shape_index))
340                    print(f_("Error applying '{type}' modifier \"{name}\":\n\t", type=mod.type, name=mod.name), e)
341                finally:
342                    common.remove_data(temp_ob)
343                    common.remove_data(temp_me)
344
345                    progress += 1
346                    context.window_manager.progress_update(progress_start + progress / progress_count)
347
348        if ob.active_shape_key_index != 0:
349            ob.active_shape_key_index = 0
350            me.update()
351
352        copy_modifiers = ob.modifiers[:]
353        mod_count = len(copy_modifiers)
354        mod_progress = 0
355        override = context.copy()
356        override['object'] = ob
357        for index, mod in enumerate(copy_modifiers):
358            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
359            #    break
360            if self.is_applies[index].value and (mod.type != 'ARMATURE' or not compat.IS_LEGACY):
361                if mod.type == 'MIRROR' and mod.use_mirror_vertex_groups:
362                    if bpy.ops.object.decode_cm3d2_vertex_group_names.poll():
363                        self.report(type={'WARNING'}, message="Vertex groups are not in blender naming style. Mirror modifier results may not be as expected")
364                    for vg in ob.vertex_groups[:]:
365                        replace_list = ((r'\.L$', ".R"), (r'\.R$', ".L"), (r'\.l$', ".r"), (r'\.r$', ".l"), (r'_L$', "_R"), (r'_R$', "_L"), (r'_l$', "_r"), (r'_r$', "_l"))
366                        for before, after in replace_list:
367                            mirrored_name = re.sub(before, after, vg.name)
368                            if mirrored_name not in ob.vertex_groups:
369                                ob.vertex_groups.new(override, name=mirrored_name)
370                try:
371                    bpy.ops.object.modifier_apply(override, modifier=mod.name)
372                except Exception as e:
373                    #ob.modifiers.remove(mod)
374                    self.report(type={'ERROR', 'WARNING'}, message=f_tip_("Could not apply '{type}' modifier \"{name}\"", type=mod.type, name=mod.name))
375                    print(f_("Error applying '{type}' modifier \"{name}\":\n\t", type=mod.type, name=mod.name), e)
376            
377            mod_progress += 1 if (mod.type != 'ARMATURE' or not compat.IS_LEGACY) else 0
378            context.window_manager.progress_update( progress_start + (progress + mod_progress / mod_count) / progress_count )
379
380        # Calculate custom normals for armature modifiers in legacy blender
381        if arm_ob:
382            bpy.ops.object.mode_set(mode='EDIT')
383            bpy.ops.object.mode_set(mode='OBJECT')
384
385            arm = arm_ob.data
386            arm_pose = arm_ob.pose
387
388            pose_quats = {}
389            for bone in arm.bones:
390                pose_bone = arm_pose.bones[bone.name]
391
392                bone_quat = bone.matrix_local.to_quaternion()
393                pose_quat = pose_bone.matrix.to_quaternion()
394                result_quat = compat.mul(pose_quat, bone_quat.inverted())
395
396                pose_quats[bone.name] = result_quat.copy()
397
398            custom_normals = []
399            for loop in me.loops:
400                vert = me.vertices[loop.vertex_index]
401                no = vert.normal.copy()
402
403                total_weight = 0.0
404                for vge in vert.groups:
405                    vg = ob.vertex_groups[vge.group]
406                    try:
407                        pose_quats[vg.name]
408                    except KeyError:
409                        continue
410                    total_weight += vge.weight
411
412                total_quat = mathutils.Quaternion()
413                if total_weight != 0.0:
414                    for vge in vert.groups:
415                        vg = ob.vertex_groups[vge.group]
416                        try:
417                            total_quat = total_quat.slerp(pose_quats[vg.name], vge.weight / total_weight)
418                        except KeyError:
419                            pass
420                
421                no.rotate(total_quat)
422                custom_normals.append(no)
423
424            progress += 1
425            context.window_manager.progress_update(progress_start + progress / progress_count)
426
427        override = context.copy()
428        override['object'] = ob
429        for index, mod in enumerate(copy_modifiers):
430            #if index >= 32: # luvoid : can only apply 32 modifiers at once.
431            #    break
432            if self.is_applies[index].value and (mod.type == 'ARMATURE' and compat.IS_LEGACY):
433                try:
434                    bpy.ops.object.modifier_apply(override, modifier=mod.name)
435                except Exception as e:
436                    #ob.modifiers.remove(mod)
437                    self.report(type={'ERROR', 'WARNING'}, message=f_tip_("Could not apply '{mod_type}' modifier \"{mod_name}\"", mod_type=mod.type, mod_name=mod.name) )
438                    print(f_("Could not apply '{mod_type}' modifier \"{mod_name}\":\n\t", mod_type=mod.type, mod_name=mod.name), e)
439            
440            mod_progress += 1 if (mod.type == 'ARMATURE' and compat.IS_LEGACY) else 0
441            context.window_manager.progress_update( progress_start + (progress + mod_progress / mod_count) / progress_count )
442
443        progress += 1
444        context.window_manager.progress_update(progress_start + progress / progress_count)
445
446        compat.set_active(context, ob)
447
448        if is_shaped:
449            for deforms in new_shape_deforms:
450                if len(me.vertices) != len(deforms):
451                    self.report(type={'ERROR'}, message="ミラー等が原因で頂点数が変わっているためシェイプキーを格納できません、中止するのでCtrl+Z等で元に戻し修正してください。")
452                    context.window_manager.progress_update(progress_start + 1)
453                    if did_start_progress:
454                        context.window_manager.progress_end()
455                    return {'FINISHED', 'CANCELLED'}
456
457            for shape_index, deforms in enumerate(new_shape_deforms):
458                bpy.ops.object.shape_key_add(context.copy(), from_mix=False)
459                shape = ob.active_shape_key
460                shape.name = shape_names[shape_index]
461
462                for vert in me.vertices:
463                    shape.data[vert.index].co = deforms[vert.index].copy()
464
465                progress += 1
466                context.window_manager.progress_update(progress_start + progress / progress_count)
467
468            for shape_index, shape in enumerate(me.shape_keys.key_blocks):
469                shape.relative_key = me.shape_keys.key_blocks[pre_relative_keys[shape_index]]
470                if self.is_preserve_shape_key_values:
471                    shape.value = pre_shape_key_values[shape_index]
472
473            ob.active_shape_key_index = pre_active_shape_key_index
474
475        for temp_ob in pre_selected_objects:
476            compat.set_select(temp_ob, True)
477        bpy.ops.object.mode_set(mode=pre_mode)
478
479        if arm_ob:
480            for i, loop in enumerate(me.loops):
481                vert = me.vertices[loop.vertex_index]
482                no = vert.normal.copy()
483
484                try:
485                    custom_rot = mathutils.Vector((0.0, 0.0, 1.0)).rotation_difference(custom_normals[i])
486                except:
487                    continue
488                original_rot = mathutils.Vector((0.0, 0.0, 1.0)).rotation_difference(no)
489                output_rot = original_rot.slerp(custom_rot, custom_normal_blend)
490
491                output_no = mathutils.Vector((0.0, 0.0, 1.0))
492                output_no.rotate(output_rot)
493
494                custom_normals[i] = output_no
495            me.use_auto_smooth = True
496            me.normals_split_custom_set(custom_normals)
497
498            progress += 1
499            context.window_manager.progress_update(progress_start + progress / progress_count)
500
501        context.window_manager.progress_update(progress_start + 1)
502        if did_start_progress:
503            context.window_manager.progress_end()
504        return {'FINISHED'}
bl_rna = <bpy_struct, Struct("OBJECT_OT_forced_modifier_apply")>
Inherited Members
bpy_types.Operator
as_keywords
poll_message_set
builtins.bpy_struct
keys
values
items
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