Module kawa_scripts.modifiers

Expand source code
# Kawashirov's Scripts (c) 2021 by Sergey V. Kawashirov
#
# Kawashirov's Scripts is licensed under a
# Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
#
# You should have received a copy of the license along with this
# work.  If not, see <http://creativecommons.org/licenses/by-nc-sa/3.0/>.
#
#

import bpy as _bpy
from bpy import context as _C

from . import commons as _commons
from . import shapekeys as _shapekeys
from ._internals import log as _log
from ._internals import KawaOperator as _KawaOperator
from .reporter import LambdaReporter as _LambdaReporter

import typing as _typing

if _typing.TYPE_CHECKING:
        from typing import *
        from bpy.types import *
        from ._internals import *

MODIFIER_TYPES_DEFORM = {'ARMATURE', 'CAST', 'CURVE', 'DISPLACE', 'HOOK', 'LAPLACIANDEFORM', 'LATTICE', 'MESH_DEFORM', 'SHRINKWRAP',
        'SIMPLE_DEFORM', 'SMOOTH', 'CORRECTIVE_SMOOTH', 'LAPLACIANSMOOTH', 'SURFACE_DEFORM', 'WARP', 'WAVE'}


def is_deform_modifier(modifier: 'Modifier'):
        return modifier.type in MODIFIER_TYPES_DEFORM


def _get_modifier_index(obj: 'Object', modifier: 'Modifier') -> int:
        for idx in range(len(obj.modifiers)):
                if obj.modifiers[idx] == modifier:
                        return idx
        raise RuntimeError()


def _copy_modifier_and_move_up(ctx: 'ContextOverride', obj: 'Object', modifier_name: 'str', op: 'Operator' = None) -> 'Modifier':
        # Создаем копию арматуры
        modifier = obj.modifiers[modifier_name]
        modifier_i = _get_modifier_index(obj, modifier)
        if 'FINISHED' not in _bpy.ops.object.modifier_copy(ctx, modifier=modifier_name):
                _log.raise_error(RuntimeError, 'Huh? Can not copy modifier {0} on {1}!'.format(repr(modifier_name), repr(obj)), op=op)
        copy_modifier = obj.modifiers[modifier_i + 1]  # type: Modifier
        assert copy_modifier.type == modifier.type
        # Двигаем копию арматуры на верх
        while _get_modifier_index(obj, copy_modifier) > 0:
                if 'FINISHED' not in _bpy.ops.object.modifier_move_up(ctx, modifier=copy_modifier.name):
                        _log.raise_error(RuntimeError, 'Huh? Can not move up modifier {0} on {1}!'.format(repr(copy_modifier.name), repr(obj)), op=op)
        return copy_modifier


def modifier_apply_compat(obj: 'Object', apply_as: 'str', modifier: 'str', keep_modifier=False, op: 'Operator' = None):
        ctx = _C.copy()  # type: ContextOverride
        ctx['object'] = obj
        ctx['active_object'] = obj
        ctx['selected_objects'] = [obj]
        ctx['mode'] = 'OBJECT'
        ctx['edit_object'] = None
        if _bpy.app.version >= (2, 90, 0):
                # Blender 2.9x
                if apply_as == 'SHAPE':
                        return _bpy.ops.object.modifier_apply_as_shapekey(ctx, modifier=modifier, keep_modifier=keep_modifier)
                else:  # apply_as == 'DATA'
                        if keep_modifier:
                                copy_modifier = _copy_modifier_and_move_up(ctx, obj, modifier, op=op)
                                return _bpy.ops.object.modifier_apply(ctx, modifier=copy_modifier.name)
                        else:
                                return _bpy.ops.object.modifier_apply(ctx, modifier=modifier)
        else:
                # Blender 2.8x
                if keep_modifier:
                        copy_modifier = _copy_modifier_and_move_up(ctx, obj, modifier, op=op)
                        return _bpy.ops.object.modifier_apply(ctx, apply_as=apply_as, modifier=copy_modifier)
                else:
                        return _bpy.ops.object.modifier_apply(ctx, apply_as=apply_as, modifier=modifier)


def apply_all_modifiers(obj: 'Object', op: 'Operator' = None) -> 'int':
        # No context control
        _commons.ensure_deselect_all_objects()
        _commons.activate_object(obj)
        modifc = 0
        for mod_i, mod_name in list(enumerate(m.name for m in obj.modifiers)):
                if 'FINISHED' in _bpy.ops.object.modifier_apply(modifier=mod_name):
                        modifc += 1
                else:
                        _log.warning("Can not apply modifier #{0} {1} on {2}!".format(mod_i, repr(mod_name), repr(obj)), op=op)
                modifc += 1
        _commons.ensure_deselect_all_objects()
        return modifc


def apply_deform_modifier_to_mesh_high_precision(mobj: 'Object', modifier: 'Modifier', keep_modifier=False, ignore_other_modifies=True,
                op: 'Operator' = None):
        if not is_deform_modifier(modifier):
                _log.raise_error(ValueError, "Modifier {0} on {1} has non-deform type {2}".format(
                        repr(modifier.name), repr(mobj), repr(modifier.type)), op=op)
        if mobj.data.shape_keys is None:
                # Простой режим применения, когда нет шейп-кеев на объекте
                return modifier_apply_compat(mobj, 'DATA', modifier.name, keep_modifier=True)
        #
        # Сложный режим применения, когда есть шейп кеи на объекте
        ctx = _C.copy()  # type: ContextOverride
        ctx['object'] = mobj
        ctx['active_object'] = mobj
        ctx['selected_objects'] = [mobj]
        ctx['mode'] = 'OBJECT'
        ctx['edit_object'] = None
        # Создание временной копии основного объекта
        # Новые объекты сохраняются в глобальный контекст, по этому нужно отлавливать их от туда
        cobj = None
        try:
                selset = set(_C.selected_objects)
                _bpy.ops.object.duplicate(ctx)
                selset = set(_C.selected_objects) - selset
                assert len(selset) == 1
                cobj = selset.pop()
                # Удаление всего лишнего с копии
                ctx['object'] = cobj
                ctx['active_object'] = cobj
                ctx['selected_objects'] = [cobj]
                ctx['mode'] = 'OBJECT'
                ctx['edit_object'] = None
                cobj.shape_key_clear()
                if ignore_other_modifies:
                        for cobj_modifier in list(m.name for m in cobj.modifiers if m.name != modifier.name):
                                _bpy.ops.object.modifier_remove(ctx, modifier=cobj_modifier)
                # Пересчет шейпкеев на копии
                mobj_mesh = mobj.data  # type: Mesh
                cobj_mesh = cobj.data  # type: Mesh
                for key in list(mobj.data.shape_keys.key_blocks):  # type: ShapeKey
                        if _log.is_debug():
                                _log.info("Transforming {0} on original {1} and copy {2}".format(key, mobj, cobj), op=op)
                        if not _shapekeys.ensure_len_match(mobj_mesh, key, op=op):
                                continue
                        if not _shapekeys.ensure_len_match(cobj_mesh, key, op=op):
                                continue
                        # Копирование данных шейпкея в копию
                        for i in range(len(key.data)):
                                cobj_mesh.vertices[i].co = key.data[i].co
                        # Деформирование копии
                        modifier_apply_compat(cobj, 'DATA', modifier.name, keep_modifier=True, op=op)
                        # Возврат данных из копии в шейпкей
                        for i in range(len(key.data)):
                                key.data[i].co = cobj_mesh.vertices[i].co
        finally:
                if cobj is not None:
                        ctx['object'] = cobj
                        ctx['active_object'] = cobj
                        ctx['selected_objects'] = [cobj]
                        ctx['mode'] = 'OBJECT'
                        ctx['edit_object'] = None
                        _bpy.ops.object.delete(ctx, use_global=True, confirm=False)
                        pass
        if not keep_modifier:
                ctx['object'] = mobj
                ctx['active_object'] = mobj
                ctx['selected_objects'] = [mobj]
                ctx['mode'] = 'OBJECT'
                ctx['edit_object'] = None
                _bpy.ops.object.modifier_remove(ctx, modifier=modifier.name)
        return {'FINISHED'}


class KawaApplyDeformModifierHighPrecision(_KawaOperator):
        bl_idname = "kawa.apply_deform_modifier_high_precision"
        bl_label = "Apply Deform Modifier (Shape Keys High Precision)"
        bl_description = "\n".join((
                "Apply active Deform-type Modifier of selected Mesh-object.",
                "Works on Meshes with Shape Keys with high precision.",
                "Shape Keys should not break."
        ))
        bl_options = {'REGISTER', 'UNDO'}
        
        @classmethod
        def poll(cls, context: 'Context'):
                if context.mode != 'OBJECT':
                        return False  # Требуется режим OBJECT
                obj = cls.get_active_obj(context)
                if obj.type != 'MESH':
                        return False  # Требуется тип объекта MESH
                modifier = obj.modifiers.active
                if modifier is None or not is_deform_modifier(modifier):
                        return False  # Требуется активный Deform Modifier
                return True
        
        def execute(self, context: 'Context'):
                obj = self.get_active_obj(context)
                apply_deform_modifier_to_mesh_high_precision(obj, obj.modifiers.active)
                return {'FINISHED'}
        
        def invoke(self, context: 'Context', event: 'Event'):
                return self.execute(context)


class KawaApplyAllModifiersHighPrecision(_KawaOperator):
        bl_idname = "kawa.apply_all_modifiers_high_precision"
        bl_label = "Apply All Modifiers (Shape Keys High Precision for Deform-Only)"
        bl_description = "\n".join((
                "Try to apply all Modifiers on all selected objects.",
                "For Deform-type modifiers works on Meshes with Shape Keys with high precision.",
                "Any non-Deform modifiers on Meshes with Shape Keys will be ignored with warning."
        ))
        bl_options = {'REGISTER', 'UNDO'}
        
        @classmethod
        def poll(cls, context: 'Context'):
                if len(cls.get_selected_objs(context)) < 1:
                        return False  # Должны быть выбраны какие-то объекты
                if context.mode != 'OBJECT':
                        return False  # Требуется режим OBJECT
                return True
        
        def _execute_obj(self, context: 'Context', obj) -> int:
                modifc = 0
                for mod_i, mod_name in list(enumerate(m.name for m in obj.modifiers)):
                        mod = obj.modifiers[mod_name]  # Численый индекс меняется при итерации
                        if is_deform_modifier(mod):
                                # Деформирующий модификатор - применим и не шейпкеии
                                result = apply_deform_modifier_to_mesh_high_precision(obj, mod, keep_modifier=False, op=self)
                                if 'FINISHED' in result:
                                        modifc += 1
                                else:
                                        self.warning("Can not apply modifier #{0} {1} on {2}: {3}!".format(
                                                mod_i, repr(mod_name), repr(obj), repr(result)))
                        elif obj.type == 'MESH' and obj.data.shape_keys is not None:
                                # не-деформирующий модификатор не применим на шейпкеи
                                self.warning("Can not apply non-deform-type modifier #{0} {1} on {2} with shape keys!".format(
                                        mod_i, repr(mod_name), repr(obj)))
                        else:
                                # Другое: либо это вообще не меш, либо это простая меш без шейпкеев
                                result = modifier_apply_compat(obj, 'DATA', mod, keep_modifier=False)
                                if 'FINISHED' in result:
                                        modifc += 1
                                else:
                                        self.warning("Can not apply modifier #{0} {1} on {2}: {3}!".format(
                                                mod_i, repr(mod_name), repr(obj), repr(result)))
                return modifc
        
        def execute(self, context: 'Context'):
                objs = list(self.get_selected_objs(context))
                counter_objs, counter_mods = 0, 0
                for obj in objs:
                        if len(obj.modifiers) < 1:
                                continue
                        self.info("Applying {0} modifiers on {1}...".format(len(obj.modifiers), repr(obj)))
                        modifc = self._execute_obj(context, obj)
                        counter_mods += modifc
                        counter_objs += 1 if modifc > 0 else 0
                self.info("Applied {0} modifiers on {1} objects!".format(counter_mods, counter_objs))
                return {'FINISHED'} if counter_mods > 0 else {'CANCELLED'}
        
        def invoke(self, context: 'Context', event: 'Event'):
                return self.execute(context)


class KawaApplyArmatureToMeshesHighPrecision(_KawaOperator):
        bl_idname = "kawa.apply_armature_to_meshes_high_precision"
        bl_label = "Apply Armature Poses to Meshes (Shape Keys High Precision)"
        bl_description = "\n".join((
                "Apply current poses of selected Armature-objects to selected Mesh-objects as Rest poses.",
                "Armatures and Meshes that is not selected are ignored.",
                "Works on Meshes with Shape Keys with high precision.",
                "Shape Keys should not break."
        ))
        bl_options = {'REGISTER', 'UNDO'}
        
        @classmethod
        def poll(cls, context: 'Context'):
                selected = cls.get_selected_objs(context)
                if len(selected) < 1:
                        return False  # Должны быть выбраны какие-то объекты
                if context.mode != 'OBJECT':
                        return False  # Требуется режим OBJECT
                if not any(obj for obj in selected if obj.type == 'ARMATURE'):
                        return False  # Требуется что бы была выбрана хотя бы одна арматура
                if not any(obj for obj in selected if obj.type == 'MESH'):
                        return False  # Требуется что бы была выбрана хотя бы одна меш
                return True
        
        def execute(self, context: 'Context'):
                selected = self.get_selected_objs(context)
                # Отбор арматур
                armatures = dict()  # type: Dict[Object, List[Tuple[Object, ArmatureModifier]]]
                for obj in selected:  # type: Object
                        if obj.type != 'ARMATURE':
                                continue
                        armatures[obj] = list()
                if len(armatures) < 1:
                        self.warning("No Armature-objects selected!")
                        return {'CANCELLED'}
                # Отбор модификатров
                modifc = 0
                for obj in selected:  # type: Object
                        if obj.type != 'MESH':
                                continue
                        for modifier in obj.modifiers:  # type: ArmatureModifier
                                if modifier.type != 'ARMATURE':
                                        continue
                                list_ = armatures.get(modifier.object)
                                if list_ is None:
                                        continue
                                list_.append((obj, modifier))
                                modifc += 1
                if modifc < 1:
                        self.warning("No Mesh-objects bound to given Armature-objects selected!")
                        return {'CANCELLED'}
                self.info("Applying poses from {0} armatures to {1} meshes...".format(len(armatures), modifc))

                aobjc, modifc = 0, 0
                for aobj, modifiers in armatures.items():  # type: Object
                        for mobj, modifier in modifiers:
                                if 'FINISHED' in apply_deform_modifier_to_mesh_high_precision(mobj, modifier, keep_modifier=True, op=self):
                                        modifc += 1
                        try:
                                # ctx = _C.copy()  # type: ContextOverride
                                # ctx['object'] = aobj
                                # ctx['active_object'] = aobj
                                # ctx['selected_objects'] = [aobj]
                                # ctx['edit_object'] = None
                                # FIXME контексты не работают
                                context.view_layer.objects.active = aobj
                                _bpy.ops.object.mode_set(mode='POSE', toggle=False)
                                _bpy.ops.pose.armature_apply(selected=False)
                        finally:
                                _bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
                        aobjc += 1
                self.info("Applied poses from {0} armatures to {1} meshes.".format(aobjc, modifc))
                return {'FINISHED'}
        
        def invoke(self, context: 'Context', event: 'Event'):
                return self.execute(context)


classes = (
        KawaApplyDeformModifierHighPrecision,
        KawaApplyAllModifiersHighPrecision,
        KawaApplyArmatureToMeshesHighPrecision,
)

Functions

def apply_all_modifiers(obj: Object, op: Operator = None) ‑> int
Expand source code
def apply_all_modifiers(obj: 'Object', op: 'Operator' = None) -> 'int':
        # No context control
        _commons.ensure_deselect_all_objects()
        _commons.activate_object(obj)
        modifc = 0
        for mod_i, mod_name in list(enumerate(m.name for m in obj.modifiers)):
                if 'FINISHED' in _bpy.ops.object.modifier_apply(modifier=mod_name):
                        modifc += 1
                else:
                        _log.warning("Can not apply modifier #{0} {1} on {2}!".format(mod_i, repr(mod_name), repr(obj)), op=op)
                modifc += 1
        _commons.ensure_deselect_all_objects()
        return modifc
def apply_deform_modifier_to_mesh_high_precision(mobj: Object, modifier: Modifier, keep_modifier=False, ignore_other_modifies=True, op: Operator = None)
Expand source code
def apply_deform_modifier_to_mesh_high_precision(mobj: 'Object', modifier: 'Modifier', keep_modifier=False, ignore_other_modifies=True,
                op: 'Operator' = None):
        if not is_deform_modifier(modifier):
                _log.raise_error(ValueError, "Modifier {0} on {1} has non-deform type {2}".format(
                        repr(modifier.name), repr(mobj), repr(modifier.type)), op=op)
        if mobj.data.shape_keys is None:
                # Простой режим применения, когда нет шейп-кеев на объекте
                return modifier_apply_compat(mobj, 'DATA', modifier.name, keep_modifier=True)
        #
        # Сложный режим применения, когда есть шейп кеи на объекте
        ctx = _C.copy()  # type: ContextOverride
        ctx['object'] = mobj
        ctx['active_object'] = mobj
        ctx['selected_objects'] = [mobj]
        ctx['mode'] = 'OBJECT'
        ctx['edit_object'] = None
        # Создание временной копии основного объекта
        # Новые объекты сохраняются в глобальный контекст, по этому нужно отлавливать их от туда
        cobj = None
        try:
                selset = set(_C.selected_objects)
                _bpy.ops.object.duplicate(ctx)
                selset = set(_C.selected_objects) - selset
                assert len(selset) == 1
                cobj = selset.pop()
                # Удаление всего лишнего с копии
                ctx['object'] = cobj
                ctx['active_object'] = cobj
                ctx['selected_objects'] = [cobj]
                ctx['mode'] = 'OBJECT'
                ctx['edit_object'] = None
                cobj.shape_key_clear()
                if ignore_other_modifies:
                        for cobj_modifier in list(m.name for m in cobj.modifiers if m.name != modifier.name):
                                _bpy.ops.object.modifier_remove(ctx, modifier=cobj_modifier)
                # Пересчет шейпкеев на копии
                mobj_mesh = mobj.data  # type: Mesh
                cobj_mesh = cobj.data  # type: Mesh
                for key in list(mobj.data.shape_keys.key_blocks):  # type: ShapeKey
                        if _log.is_debug():
                                _log.info("Transforming {0} on original {1} and copy {2}".format(key, mobj, cobj), op=op)
                        if not _shapekeys.ensure_len_match(mobj_mesh, key, op=op):
                                continue
                        if not _shapekeys.ensure_len_match(cobj_mesh, key, op=op):
                                continue
                        # Копирование данных шейпкея в копию
                        for i in range(len(key.data)):
                                cobj_mesh.vertices[i].co = key.data[i].co
                        # Деформирование копии
                        modifier_apply_compat(cobj, 'DATA', modifier.name, keep_modifier=True, op=op)
                        # Возврат данных из копии в шейпкей
                        for i in range(len(key.data)):
                                key.data[i].co = cobj_mesh.vertices[i].co
        finally:
                if cobj is not None:
                        ctx['object'] = cobj
                        ctx['active_object'] = cobj
                        ctx['selected_objects'] = [cobj]
                        ctx['mode'] = 'OBJECT'
                        ctx['edit_object'] = None
                        _bpy.ops.object.delete(ctx, use_global=True, confirm=False)
                        pass
        if not keep_modifier:
                ctx['object'] = mobj
                ctx['active_object'] = mobj
                ctx['selected_objects'] = [mobj]
                ctx['mode'] = 'OBJECT'
                ctx['edit_object'] = None
                _bpy.ops.object.modifier_remove(ctx, modifier=modifier.name)
        return {'FINISHED'}
def is_deform_modifier(modifier: Modifier)
Expand source code
def is_deform_modifier(modifier: 'Modifier'):
        return modifier.type in MODIFIER_TYPES_DEFORM
def modifier_apply_compat(obj: Object, apply_as: str, modifier: str, keep_modifier=False, op: Operator = None)
Expand source code
def modifier_apply_compat(obj: 'Object', apply_as: 'str', modifier: 'str', keep_modifier=False, op: 'Operator' = None):
        ctx = _C.copy()  # type: ContextOverride
        ctx['object'] = obj
        ctx['active_object'] = obj
        ctx['selected_objects'] = [obj]
        ctx['mode'] = 'OBJECT'
        ctx['edit_object'] = None
        if _bpy.app.version >= (2, 90, 0):
                # Blender 2.9x
                if apply_as == 'SHAPE':
                        return _bpy.ops.object.modifier_apply_as_shapekey(ctx, modifier=modifier, keep_modifier=keep_modifier)
                else:  # apply_as == 'DATA'
                        if keep_modifier:
                                copy_modifier = _copy_modifier_and_move_up(ctx, obj, modifier, op=op)
                                return _bpy.ops.object.modifier_apply(ctx, modifier=copy_modifier.name)
                        else:
                                return _bpy.ops.object.modifier_apply(ctx, modifier=modifier)
        else:
                # Blender 2.8x
                if keep_modifier:
                        copy_modifier = _copy_modifier_and_move_up(ctx, obj, modifier, op=op)
                        return _bpy.ops.object.modifier_apply(ctx, apply_as=apply_as, modifier=copy_modifier)
                else:
                        return _bpy.ops.object.modifier_apply(ctx, apply_as=apply_as, modifier=modifier)

Classes

class KawaApplyAllModifiersHighPrecision

Storage of an operator being executed, or registered after execution

Expand source code
class KawaApplyAllModifiersHighPrecision(_KawaOperator):
        bl_idname = "kawa.apply_all_modifiers_high_precision"
        bl_label = "Apply All Modifiers (Shape Keys High Precision for Deform-Only)"
        bl_description = "\n".join((
                "Try to apply all Modifiers on all selected objects.",
                "For Deform-type modifiers works on Meshes with Shape Keys with high precision.",
                "Any non-Deform modifiers on Meshes with Shape Keys will be ignored with warning."
        ))
        bl_options = {'REGISTER', 'UNDO'}
        
        @classmethod
        def poll(cls, context: 'Context'):
                if len(cls.get_selected_objs(context)) < 1:
                        return False  # Должны быть выбраны какие-то объекты
                if context.mode != 'OBJECT':
                        return False  # Требуется режим OBJECT
                return True
        
        def _execute_obj(self, context: 'Context', obj) -> int:
                modifc = 0
                for mod_i, mod_name in list(enumerate(m.name for m in obj.modifiers)):
                        mod = obj.modifiers[mod_name]  # Численый индекс меняется при итерации
                        if is_deform_modifier(mod):
                                # Деформирующий модификатор - применим и не шейпкеии
                                result = apply_deform_modifier_to_mesh_high_precision(obj, mod, keep_modifier=False, op=self)
                                if 'FINISHED' in result:
                                        modifc += 1
                                else:
                                        self.warning("Can not apply modifier #{0} {1} on {2}: {3}!".format(
                                                mod_i, repr(mod_name), repr(obj), repr(result)))
                        elif obj.type == 'MESH' and obj.data.shape_keys is not None:
                                # не-деформирующий модификатор не применим на шейпкеи
                                self.warning("Can not apply non-deform-type modifier #{0} {1} on {2} with shape keys!".format(
                                        mod_i, repr(mod_name), repr(obj)))
                        else:
                                # Другое: либо это вообще не меш, либо это простая меш без шейпкеев
                                result = modifier_apply_compat(obj, 'DATA', mod, keep_modifier=False)
                                if 'FINISHED' in result:
                                        modifc += 1
                                else:
                                        self.warning("Can not apply modifier #{0} {1} on {2}: {3}!".format(
                                                mod_i, repr(mod_name), repr(obj), repr(result)))
                return modifc
        
        def execute(self, context: 'Context'):
                objs = list(self.get_selected_objs(context))
                counter_objs, counter_mods = 0, 0
                for obj in objs:
                        if len(obj.modifiers) < 1:
                                continue
                        self.info("Applying {0} modifiers on {1}...".format(len(obj.modifiers), repr(obj)))
                        modifc = self._execute_obj(context, obj)
                        counter_mods += modifc
                        counter_objs += 1 if modifc > 0 else 0
                self.info("Applied {0} modifiers on {1} objects!".format(counter_mods, counter_objs))
                return {'FINISHED'} if counter_mods > 0 else {'CANCELLED'}
        
        def invoke(self, context: 'Context', event: 'Event'):
                return self.execute(context)

Ancestors

  • kawa_scripts._internals.KawaOperator
  • bpy.types.Operator
  • bpy.types.bpy_struct

Class variables

var bl_description : str
var bl_idname : str
var bl_label : str
var bl_options : Union[Set[str], Set[int]]
var bl_property : str
var bl_translation_context : str
var bl_undo_group : str
var has_reports : bool
var layout : bpy.types.UILayout
var macros : Union[Dict[str, bpy.types.Macro], List[bpy.types.Macro], bpy.types.bpy_prop_collection]
var name : str
var options : bpy.types.OperatorOptions
var properties : bpy.types.OperatorProperties

Static methods

def poll(context: Context)

Test if the operator can be called or not

:param context: :type context: 'Context'

Expand source code
@classmethod
def poll(cls, context: 'Context'):
        if len(cls.get_selected_objs(context)) < 1:
                return False  # Должны быть выбраны какие-то объекты
        if context.mode != 'OBJECT':
                return False  # Требуется режим OBJECT
        return True

Methods

def execute(self, context: Context)

Execute the operator

:param context: :type context: 'Context' :rtype: typing.Union[typing.Set[str], typing.Set[int]] :return: result * RUNNING_MODAL Running Modal, Keep the operator running with blender. * CANCELLED Cancelled, The operator exited without doing anything, so no undo entry should be pushed. * FINISHED Finished, The operator exited after completing its action. * PASS_THROUGH Pass Through, Do nothing and pass the event on. * INTERFACE Interface, Handled but not executed (popup menus).

Expand source code
def execute(self, context: 'Context'):
        objs = list(self.get_selected_objs(context))
        counter_objs, counter_mods = 0, 0
        for obj in objs:
                if len(obj.modifiers) < 1:
                        continue
                self.info("Applying {0} modifiers on {1}...".format(len(obj.modifiers), repr(obj)))
                modifc = self._execute_obj(context, obj)
                counter_mods += modifc
                counter_objs += 1 if modifc > 0 else 0
        self.info("Applied {0} modifiers on {1} objects!".format(counter_mods, counter_objs))
        return {'FINISHED'} if counter_mods > 0 else {'CANCELLED'}
def invoke(self, context: Context, event: Event)

Invoke the operator

:param context: :type context: 'Context' :param event: :type event: 'Event' :rtype: typing.Union[typing.Set[str], typing.Set[int]] :return: result * RUNNING_MODAL Running Modal, Keep the operator running with blender. * CANCELLED Cancelled, The operator exited without doing anything, so no undo entry should be pushed. * FINISHED Finished, The operator exited after completing its action. * PASS_THROUGH Pass Through, Do nothing and pass the event on. * INTERFACE Interface, Handled but not executed (popup menus).

Expand source code
def invoke(self, context: 'Context', event: 'Event'):
        return self.execute(context)
class KawaApplyArmatureToMeshesHighPrecision

Storage of an operator being executed, or registered after execution

Expand source code
class KawaApplyArmatureToMeshesHighPrecision(_KawaOperator):
        bl_idname = "kawa.apply_armature_to_meshes_high_precision"
        bl_label = "Apply Armature Poses to Meshes (Shape Keys High Precision)"
        bl_description = "\n".join((
                "Apply current poses of selected Armature-objects to selected Mesh-objects as Rest poses.",
                "Armatures and Meshes that is not selected are ignored.",
                "Works on Meshes with Shape Keys with high precision.",
                "Shape Keys should not break."
        ))
        bl_options = {'REGISTER', 'UNDO'}
        
        @classmethod
        def poll(cls, context: 'Context'):
                selected = cls.get_selected_objs(context)
                if len(selected) < 1:
                        return False  # Должны быть выбраны какие-то объекты
                if context.mode != 'OBJECT':
                        return False  # Требуется режим OBJECT
                if not any(obj for obj in selected if obj.type == 'ARMATURE'):
                        return False  # Требуется что бы была выбрана хотя бы одна арматура
                if not any(obj for obj in selected if obj.type == 'MESH'):
                        return False  # Требуется что бы была выбрана хотя бы одна меш
                return True
        
        def execute(self, context: 'Context'):
                selected = self.get_selected_objs(context)
                # Отбор арматур
                armatures = dict()  # type: Dict[Object, List[Tuple[Object, ArmatureModifier]]]
                for obj in selected:  # type: Object
                        if obj.type != 'ARMATURE':
                                continue
                        armatures[obj] = list()
                if len(armatures) < 1:
                        self.warning("No Armature-objects selected!")
                        return {'CANCELLED'}
                # Отбор модификатров
                modifc = 0
                for obj in selected:  # type: Object
                        if obj.type != 'MESH':
                                continue
                        for modifier in obj.modifiers:  # type: ArmatureModifier
                                if modifier.type != 'ARMATURE':
                                        continue
                                list_ = armatures.get(modifier.object)
                                if list_ is None:
                                        continue
                                list_.append((obj, modifier))
                                modifc += 1
                if modifc < 1:
                        self.warning("No Mesh-objects bound to given Armature-objects selected!")
                        return {'CANCELLED'}
                self.info("Applying poses from {0} armatures to {1} meshes...".format(len(armatures), modifc))

                aobjc, modifc = 0, 0
                for aobj, modifiers in armatures.items():  # type: Object
                        for mobj, modifier in modifiers:
                                if 'FINISHED' in apply_deform_modifier_to_mesh_high_precision(mobj, modifier, keep_modifier=True, op=self):
                                        modifc += 1
                        try:
                                # ctx = _C.copy()  # type: ContextOverride
                                # ctx['object'] = aobj
                                # ctx['active_object'] = aobj
                                # ctx['selected_objects'] = [aobj]
                                # ctx['edit_object'] = None
                                # FIXME контексты не работают
                                context.view_layer.objects.active = aobj
                                _bpy.ops.object.mode_set(mode='POSE', toggle=False)
                                _bpy.ops.pose.armature_apply(selected=False)
                        finally:
                                _bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
                        aobjc += 1
                self.info("Applied poses from {0} armatures to {1} meshes.".format(aobjc, modifc))
                return {'FINISHED'}
        
        def invoke(self, context: 'Context', event: 'Event'):
                return self.execute(context)

Ancestors

  • kawa_scripts._internals.KawaOperator
  • bpy.types.Operator
  • bpy.types.bpy_struct

Class variables

var bl_description : str
var bl_idname : str
var bl_label : str
var bl_options : Union[Set[str], Set[int]]
var bl_property : str
var bl_translation_context : str
var bl_undo_group : str
var has_reports : bool
var layout : bpy.types.UILayout
var macros : Union[Dict[str, bpy.types.Macro], List[bpy.types.Macro], bpy.types.bpy_prop_collection]
var name : str
var options : bpy.types.OperatorOptions
var properties : bpy.types.OperatorProperties

Static methods

def poll(context: Context)

Test if the operator can be called or not

:param context: :type context: 'Context'

Expand source code
@classmethod
def poll(cls, context: 'Context'):
        selected = cls.get_selected_objs(context)
        if len(selected) < 1:
                return False  # Должны быть выбраны какие-то объекты
        if context.mode != 'OBJECT':
                return False  # Требуется режим OBJECT
        if not any(obj for obj in selected if obj.type == 'ARMATURE'):
                return False  # Требуется что бы была выбрана хотя бы одна арматура
        if not any(obj for obj in selected if obj.type == 'MESH'):
                return False  # Требуется что бы была выбрана хотя бы одна меш
        return True

Methods

def execute(self, context: Context)

Execute the operator

:param context: :type context: 'Context' :rtype: typing.Union[typing.Set[str], typing.Set[int]] :return: result * RUNNING_MODAL Running Modal, Keep the operator running with blender. * CANCELLED Cancelled, The operator exited without doing anything, so no undo entry should be pushed. * FINISHED Finished, The operator exited after completing its action. * PASS_THROUGH Pass Through, Do nothing and pass the event on. * INTERFACE Interface, Handled but not executed (popup menus).

Expand source code
def execute(self, context: 'Context'):
        selected = self.get_selected_objs(context)
        # Отбор арматур
        armatures = dict()  # type: Dict[Object, List[Tuple[Object, ArmatureModifier]]]
        for obj in selected:  # type: Object
                if obj.type != 'ARMATURE':
                        continue
                armatures[obj] = list()
        if len(armatures) < 1:
                self.warning("No Armature-objects selected!")
                return {'CANCELLED'}
        # Отбор модификатров
        modifc = 0
        for obj in selected:  # type: Object
                if obj.type != 'MESH':
                        continue
                for modifier in obj.modifiers:  # type: ArmatureModifier
                        if modifier.type != 'ARMATURE':
                                continue
                        list_ = armatures.get(modifier.object)
                        if list_ is None:
                                continue
                        list_.append((obj, modifier))
                        modifc += 1
        if modifc < 1:
                self.warning("No Mesh-objects bound to given Armature-objects selected!")
                return {'CANCELLED'}
        self.info("Applying poses from {0} armatures to {1} meshes...".format(len(armatures), modifc))

        aobjc, modifc = 0, 0
        for aobj, modifiers in armatures.items():  # type: Object
                for mobj, modifier in modifiers:
                        if 'FINISHED' in apply_deform_modifier_to_mesh_high_precision(mobj, modifier, keep_modifier=True, op=self):
                                modifc += 1
                try:
                        # ctx = _C.copy()  # type: ContextOverride
                        # ctx['object'] = aobj
                        # ctx['active_object'] = aobj
                        # ctx['selected_objects'] = [aobj]
                        # ctx['edit_object'] = None
                        # FIXME контексты не работают
                        context.view_layer.objects.active = aobj
                        _bpy.ops.object.mode_set(mode='POSE', toggle=False)
                        _bpy.ops.pose.armature_apply(selected=False)
                finally:
                        _bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
                aobjc += 1
        self.info("Applied poses from {0} armatures to {1} meshes.".format(aobjc, modifc))
        return {'FINISHED'}
def invoke(self, context: Context, event: Event)

Invoke the operator

:param context: :type context: 'Context' :param event: :type event: 'Event' :rtype: typing.Union[typing.Set[str], typing.Set[int]] :return: result * RUNNING_MODAL Running Modal, Keep the operator running with blender. * CANCELLED Cancelled, The operator exited without doing anything, so no undo entry should be pushed. * FINISHED Finished, The operator exited after completing its action. * PASS_THROUGH Pass Through, Do nothing and pass the event on. * INTERFACE Interface, Handled but not executed (popup menus).

Expand source code
def invoke(self, context: 'Context', event: 'Event'):
        return self.execute(context)
class KawaApplyDeformModifierHighPrecision

Storage of an operator being executed, or registered after execution

Expand source code
class KawaApplyDeformModifierHighPrecision(_KawaOperator):
        bl_idname = "kawa.apply_deform_modifier_high_precision"
        bl_label = "Apply Deform Modifier (Shape Keys High Precision)"
        bl_description = "\n".join((
                "Apply active Deform-type Modifier of selected Mesh-object.",
                "Works on Meshes with Shape Keys with high precision.",
                "Shape Keys should not break."
        ))
        bl_options = {'REGISTER', 'UNDO'}
        
        @classmethod
        def poll(cls, context: 'Context'):
                if context.mode != 'OBJECT':
                        return False  # Требуется режим OBJECT
                obj = cls.get_active_obj(context)
                if obj.type != 'MESH':
                        return False  # Требуется тип объекта MESH
                modifier = obj.modifiers.active
                if modifier is None or not is_deform_modifier(modifier):
                        return False  # Требуется активный Deform Modifier
                return True
        
        def execute(self, context: 'Context'):
                obj = self.get_active_obj(context)
                apply_deform_modifier_to_mesh_high_precision(obj, obj.modifiers.active)
                return {'FINISHED'}
        
        def invoke(self, context: 'Context', event: 'Event'):
                return self.execute(context)

Ancestors

  • kawa_scripts._internals.KawaOperator
  • bpy.types.Operator
  • bpy.types.bpy_struct

Class variables

var bl_description : str
var bl_idname : str
var bl_label : str
var bl_options : Union[Set[str], Set[int]]
var bl_property : str
var bl_translation_context : str
var bl_undo_group : str
var has_reports : bool
var layout : bpy.types.UILayout
var macros : Union[Dict[str, bpy.types.Macro], List[bpy.types.Macro], bpy.types.bpy_prop_collection]
var name : str
var options : bpy.types.OperatorOptions
var properties : bpy.types.OperatorProperties

Static methods

def poll(context: Context)

Test if the operator can be called or not

:param context: :type context: 'Context'

Expand source code
@classmethod
def poll(cls, context: 'Context'):
        if context.mode != 'OBJECT':
                return False  # Требуется режим OBJECT
        obj = cls.get_active_obj(context)
        if obj.type != 'MESH':
                return False  # Требуется тип объекта MESH
        modifier = obj.modifiers.active
        if modifier is None or not is_deform_modifier(modifier):
                return False  # Требуется активный Deform Modifier
        return True

Methods

def execute(self, context: Context)

Execute the operator

:param context: :type context: 'Context' :rtype: typing.Union[typing.Set[str], typing.Set[int]] :return: result * RUNNING_MODAL Running Modal, Keep the operator running with blender. * CANCELLED Cancelled, The operator exited without doing anything, so no undo entry should be pushed. * FINISHED Finished, The operator exited after completing its action. * PASS_THROUGH Pass Through, Do nothing and pass the event on. * INTERFACE Interface, Handled but not executed (popup menus).

Expand source code
def execute(self, context: 'Context'):
        obj = self.get_active_obj(context)
        apply_deform_modifier_to_mesh_high_precision(obj, obj.modifiers.active)
        return {'FINISHED'}
def invoke(self, context: Context, event: Event)

Invoke the operator

:param context: :type context: 'Context' :param event: :type event: 'Event' :rtype: typing.Union[typing.Set[str], typing.Set[int]] :return: result * RUNNING_MODAL Running Modal, Keep the operator running with blender. * CANCELLED Cancelled, The operator exited without doing anything, so no undo entry should be pushed. * FINISHED Finished, The operator exited after completing its action. * PASS_THROUGH Pass Through, Do nothing and pass the event on. * INTERFACE Interface, Handled but not executed (popup menus).

Expand source code
def invoke(self, context: 'Context', event: 'Event'):
        return self.execute(context)