Попробую написать аддон взрыва объектов.

Список разделов Blender 3D Плагины

Описание: Обсуждение расширений для Blender
Модератор: exooman

  • 2

Сообщение #1 denis8424 » 05.10.2016, 20:38

Точнее, автоматизировать предложенный Mihanik способ создания такого объекта - взрыва.
Спойлер
Вроде удалось реализовать в первом приближении основной функционал, выглядит так:

Код: Выделить всё

import bpy


def cloneMoveAndRename(object, name, index):

    status = bpy.ops.object.duplicate()
    obj = bpy.context.scene.objects.active
    obj.location[1] = obj.location[1] + (obj.dimensions[1] * index)
    obj.name = name + '_Explode_' + str(index)
    obj.data.name = name + '_Explode_' + str(index)
    print('cMAR', object.name)
    bpy.context.scene.frame_current = index
    bpy.ops.object.modifier_apply(modifier = 'Explode')
    bpy.ops.object.particle_system_remove()
    object.select = True
    bpy.ops.object.select_all(action = 'DESELECT')
   
    return obj.name
   
def objectToShape(objectExpl, listNames):
    for num in range(1, len(listNames)):
        currObj = bpy.context.scene.objects[listNames[num]]
        objectExpl.select = True
        bpy.context.scene.objects.active = objectExpl
        currObj.select = True
        bpy.ops.object.join_shapes()
        bpy.ops.object.select_all(action = 'DESELECT')
       
        currObj.select = True
        bpy.ops.object.delete()

def insertKeyToShape(shapeKeys, diff):
    for block in shapeKeys.key_blocks:
        if block.name == 'Basis':
            continue
        else:
            fr = int(block.name.split('_')[-1])
            frameList = [(0.0, fr-diff), (1.0, fr), (0.0, fr+diff)]
            for J in frameList:
                block.value = J[0]
                block.keyframe_insert("value", frame = J[1])   
   
   
def main():
    print('<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>')
    scene = bpy.context.scene
    object = bpy.context.object
    name = object.name
    listNames = []

    for i in range(1, 50):
        bpy.context.scene.frame_current = 0
        object.select = True
        bpy.context.scene.objects.active = object
           
        newName = cloneMoveAndRename(object, name, i)
        listNames.append(newName)
       
    print(listNames, len(listNames))
    objectExpl = bpy.context.scene.objects[listNames[0]]
   
    objectToShape(objectExpl, listNames)
           
    objectExpl.select = True
    bpy.context.scene.objects.active = objectExpl
    shapeKeys = objectExpl.data.shape_keys
    insertKeyToShape(shapeKeys, 1)       
   
    bpy.context.scene.frame_current = 0
   
if __name__ == '__main__':
    main()

Тут еще надо много кое-чего прикрутить, например модификатор Solidify, не говоря уже о UI. И повылавливать всякие ненужности. Повозится придется. Вопрос - где лучше разместить панельку с гуём, в Т-панели или где-нибудь во вкладке DATA?

Добавлено спустя 1 минуту 7 секунд:
P.S. Завтра буду вычитывать и дописывать.
denis8424
Аватара
Сообщения: 711

Сообщение #2 cdmax2002 » 05.10.2016, 21:39

В DATA
cdmax2002
Аватара
Сообщения: 156



Сообщение #3 Mihanik » 06.10.2016, 08:36

denis8424 писал(а):предложенный Mihanik
Ну ты его уже значительно улучшил предложив всё в одном файле делать. А так да, хорошо бы этот процесс автоматизировать, весьма полезно для игростроя. И так же полезно запекать в ключи форм действие других модификаторов не только основанных на частицах, ну скажем ткани, океана.
Mihanik M
Аватара
Сообщения: 1126

Сообщение #4 denis8424 » 07.10.2016, 17:50

Вылез косяк на стадии создания оператора, а именно, невозможно изменить "активность" объекта, оператор работает только на том объекте, который был в выбран при запуске, все остальные оно игнорирует, поэтому модификатор применяется только для одного объекта. А просто в скрипте всё работает.

Добавлено спустя 25 минут 1 секунду:
Или я что-то не так понял?
denis8424
Аватара
Сообщения: 711

Сообщение #5 denis8424 » 10.10.2016, 22:11

Выпотрошил пример Simple Operator из примеров блендера и заменил функционал. Замучился я с применением модификатора взрыва, никак не хотел он нормально применяться, пришлось каждый раз пересчитывать его данные, как итог, результат не похож на настроенный оригинал. Все остальное позже доделаю, а пока можно почитать, да и потестить:

Спойлер
Код: Выделить всё
import bpy

                                   
def main(context):
    """
    да, я знаю, что есть такая штука, как многострочные комментарии, но мне не
    нравится их цвет
    """

    print('<<<<<>>>>>') #debug
    # объект, который надо взорвать, он же изначальный, он же породитель
    object = bpy.context.object
    # имя этого объекта
    name = object.name
    # список имен будущих клонов объекта
    listName = []
    # эта переменная нужна для записи индекса клона в списке имен
    index = 0
    #смещение, плюс/минус сколько фреймов будет занимать ключ формы клона
    #оно же через сколько кадров будет создаваться клон
    diff = 5
    # кадры анимации, и так понятно ху из ху
    start_anim = 1
    end_anim = 26
   
    # Здесь мы будем создавать клоны изначального объекта
   
    for frame in range(start_anim, end_anim, diff):
        # выбираем и делаем активным объект, который надо взорвать
        object.select = True
        bpy.context.scene.objects.active = object
#        print(context.object.name) #debug
        # делаем его клон
        bpy.ops.object.duplicate()

        #Вот теперь есть нюанс, после применения оператора duplicate(), активным
        #и выбранным станет свежесозданный клон, c которыv мы и будем работать.
        #Если бы нам надо было работать с изначальным объектом, то пришлось бы
        #повторять его выбор и активизацию

        # собственно объект-клон
        newOb = bpy.context.scene.objects.active
        # переименовываем клон, его имя потом будет использоваться как имя
        # ключа формы
        newOb.name = name + 'Explode' + str(frame)
        # добавляем в список имен КОРТЕЖ, содержащий имя клона, кадр анимации,
        # и индекс кортежа в списке
        listName.append((newOb.name, frame, index))
        # изменяем переменную, что бы не оказалось, что у разных кортежей разный
        # индекс
        index = index + 1
#        print(context.object.name) #debug
        # снимаем выделение со всех объектов
        bpy.ops.object.select_all(action = 'DESELECT')
#        print(newOb.data.name) #debug
       
#    print('____') #debug
   
    # Здесь мы будем применять (Apply) модификатор взрыва и удалять клонам
    # систему частиц
       
    for name, frame, index in listName:
        # выковыриваем по имени нужный нам клон
        obj = bpy.context.scene.objects[name]
        #выбираем его и делаем его активным
        obj.select = True
        bpy.context.scene.objects.active = obj
        # выставляем текущий кадр сцены по упакованному в список имен
        bpy.context.scene.frame_current = frame
        # обновляем данные модификатор взрыва, к сожалению, без этого никак
        # нельзя обойтись, как следствие, результат будет отличаться от
        # настроенного на изначальном объекте.
        bpy.ops.object.explode_refresh(modifier = 'Explode')
#        print(frame, obj.name, bpy.context.selected_objects, context.object.name, bpy.context.scene.frame_current) #debug
        # применяем модификатор взрыва
        status = bpy.ops.object.modifier_apply(modifier = 'Explode')
#        print(status) #debug
        # удаляем систему частиц на клоне
        bpy.ops.object.particle_system_remove()
        # снимем выделение на клоне
        bpy.ops.object.select_all(action = 'DESELECT')
               
#        print('____________') #debug
       
#    print(listName) #debug
   
    # Здесь будем добавлять клонов как ключи формы, причем самому первому клону,
    # потому что нельзя добавит объект в ключи другому объекту, если у них
    # разное число вершин.
   
    for name, frame, index in listName:
        # пропускаем первого клона, на него будем писать ключи формы
        if index == 0:
            continue
        else:
            # понятно, выковыриваем клон(не первый) по имени, он пойдет в ключ формы
            currObj = bpy.context.scene.objects[name]
            # выбираем его
            currObj.select = True
            # получаем первого клона
            explObject = bpy.context.scene.objects[listName[0][0]]
            # выбираем его и делаем его активным
            explObject.select = True
            bpy.context.scene.objects.active = explObject
            # пишем текущий клон в ключ формы первого клона
            bpy.ops.object.join_shapes()
            # снимем выделение со всех объектов сцены
            bpy.ops.object.select_all(action = 'DESELECT')
            # снова выбираем текущего клона и в этот раз делаем его активным
            bpy.context.scene.objects.active = currObj
            currObj.select = True
            # удаляем текущий клон       
            bpy.ops.object.delete()
           
    # Здесь будем анимировать ключи формы
           
    # снимаем выделение со всех объектов, на всякий пожарный   
    bpy.ops.object.select_all(action = 'DESELECT')
    # выделям перый и теперь уже единственный клон
    objExpl = bpy.context.scene.objects[listName[0][0]]
    bpy.context.scene.objects.active = objExpl
    objExpl.select = True
    # получаем его список ключей форм
    shapeKeys = objExpl.data.shape_keys

    for name, frame, index in listName:
        # достаем ключ формы по имени, на всякий случай проверяя, есть ли такой
        if name in shapeKeys.key_blocks:
            # текущий ключ формы
            currBlock = shapeKeys.key_blocks[name]
            # генерируем список из кортежей "значение - кадр"
            frameList = [(0.0, frame-diff), (1.0, frame), (0.0, frame+diff)]
            # И по этому списку задаем ключи анимации ключам формы
            for J in frameList:
#                print(J) #debug
                currBlock.value = J[0]
                currBlock.keyframe_insert("value", frame = J[1])
#            print(currBlock.name) #debug


       

class explodeToShape(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.explode_to_shape"
    bl_label = "Explode To Shape"

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        main(context)
        return {'FINISHED'}


def register():
    bpy.utils.register_class(explodeToShape)


def unregister():
    bpy.utils.unregister_class(explodeToShape)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.object.explode_to_shape()

denis8424
Аватара
Сообщения: 711

Сообщение #6 denis8424 » 10.11.2016, 19:42

Картинка
Изображение

Текущее состояние кода:

Код: Выделить всё
bl_info = {
    "name" : "ExplodeToShape",
    "author" : "denis8424",
    "category" : "Game Engine",
    "version" : (0, 5),
    }

import bpy

def main(animationProps, solidifyProps, dead_Explode, particleProps):
    ########################
    # VAR
    ########################
    stepA = animationProps[0]
    start_Fr = animationProps[1]
    end_Fr = animationProps[2]
    useSolidify = solidifyProps[0]
    thickness = solidifyProps[1]
    count = particleProps[0]
    lifetime = particleProps[1]
    factor_random = particleProps[2]
    factor_normal = particleProps[3]
    object_align_factor_X = particleProps[4]
    object_align_factor_Y = particleProps[5]
    object_align_factor_Z = particleProps[6]

   
   
    print('<<<<<<<>>>>>>>')
   
    object = bpy.context.object
   
    name = object.name
   
    listName = []
   
    index = 0
   
    for frame in range(start_Fr, end_Fr, stepA):
        bpy.context.scene.frame_current = 1
        object.select = True
        bpy.context.scene.objects.active = object
        bpy.ops.object.duplicate()
        bpy.ops.object.select_all(action = 'DESELECT')
        newOb = bpy.context.scene.objects.active
        newOb.name = name + 'Explode' + str(frame)
        listName.append((newOb.name, frame, index))
        index = index + 1
        newOb.location[1] = index * newOb.dimensions[1]
        bpy.ops.object.modifier_add(type = 'PARTICLE_SYSTEM')
        #part_S = newOb.particle_systems[-1]
        #print(newOb.name, newOb.particle_systems)
        newOb.select = True
        bpy.context.scene.objects.active = bpy.data.objects[newOb.name]
        #print(bpy.context.object.name, bpy.context.scene.objects.active.name)
       
        part_S = newOb.particle_systems['ParticleSystem']
        part_S.settings.frame_start = start_Fr
        part_S.settings.frame_end = start_Fr
        part_S.settings.count = count
        part_S.settings.lifetime = lifetime
        part_S.settings.object_align_factor[0] = object_align_factor_X
        part_S.settings.object_align_factor[1] = object_align_factor_Y
        part_S.settings.object_align_factor[2] = object_align_factor_Z
        part_S.settings.factor_random = factor_random
        part_S.settings.normal_factor = factor_normal
        part_S.settings.integrator = 'EULER'
       
        bpy.ops.object.modifier_add(type = 'EXPLODE')
        newOb.modifiers['Explode'].show_dead = dead_Explode
        bpy.context.scene.frame_current = frame
        bpy.ops.object.modifier_apply(modifier = 'Explode')
        bpy.ops.object.particle_system_remove()
        if useSolidify == True:
            bpy.ops.object.modifier_add(type = 'SOLIDIFY')
            newOb.modifiers['Solidify'].thickness = thickness
            bpy.ops.object.modifier_apply(modifier = 'Solidify')
        #print(newOb.modifiers)
        bpy.ops.object.select_all(action = 'DESELECT')
    #print(listName)
    # Здесь будем добавлять клонов как ключи формы, причем самому первому клону,
    # потому что нельзя добавит объект в ключи другому объекту, если у них
    # разное число вершин.
   
    for name, frame, index in listName:
        #print(name)
        # пропускаем первого клона, на него будем писать ключи формы
        if index == 0:
            continue
        else:
            # понятно, выковыриваем клон(не первый) по имени, он пойдет в ключ формы
            currObj = bpy.context.scene.objects[name]
            # выбираем его
            currObj.select = True
            # получаем первого клона
            explObject = bpy.context.scene.objects[listName[0][0]]
            # выбираем его и делаем его активным
            explObject.select = True
            bpy.context.scene.objects.active = explObject
            # пишем текущий клон в ключ формы первого клона
            bpy.ops.object.join_shapes()
            # снимем выделение со всех объектов сцены
            bpy.ops.object.select_all(action = 'DESELECT')
            # снова выбираем текущего клона и в этот раз делаем его активным
            bpy.context.scene.objects.active = currObj
            currObj.select = True
            # удаляем текущий клон       
            bpy.ops.object.delete()
           
    # Здесь будем анимировать ключи формы
           
    # снимаем выделение со всех объектов, на всякий пожарный   
    bpy.ops.object.select_all(action = 'DESELECT')
    # выделям перый и теперь уже единственный клон
    objExpl = bpy.context.scene.objects[listName[0][0]]
    bpy.context.scene.objects.active = objExpl
    objExpl.select = True
    # получаем его список ключей форм
    shapeKeys = objExpl.data.shape_keys

    for name, frame, index in listName:
        # достаем ключ формы по имени, на всякий случай проверяя, есть ли такой
        if name in shapeKeys.key_blocks:
            # текущий ключ формы
            currBlock = shapeKeys.key_blocks[name]
            # генерируем список из кортежей "значение - кадр"
            frameList = [(0.0, frame-stepA), (1.0, frame), (0.0, frame+stepA)]
            # И по этому списку задаем ключи анимации ключам формы
            for J in frameList:
#                print(J) #debug
                currBlock.value = J[0]
                currBlock.keyframe_insert("value", frame = J[1])

    bpy.context.scene.frame_current = 1

class ExplodeOperator(bpy.types.Operator):
    """Explode object"""
    bl_idname = "object.explode_operator"
    bl_label = "Explode Object Operator"
    bl_options = {'REGISTER', 'UNDO'}
   
    stepA = bpy.props.IntProperty(
        name = "stepA",
        default = 1,
        min = 1,
        max = 8,
        step = 1,
        description = "differential"
        )
       
    start_Fr = bpy.props.IntProperty(
        name = "start frame",
        default = 1,
        min = 1,
        max = 255,
        step = 1,
        description = "start frame"
        )
   
    end_Fr = bpy.props.IntProperty(
        name = "end_frame",
        default = 8,
        min = 1,
        max = 255,
        step = 1,
        description = "end frame"
        )

       
    thickness_Solidify = bpy.props.FloatProperty(
        name = "thickness_Solidify",
        default = 0.05,
        min = 0.01,
        max = 1.0,
        step = 1,
        description = "Solidify thickness"
        )
       
    use_Solidify = bpy.props.BoolProperty(
        name = 'use_Solidify',
        default = False,
        description = 'Solidify usy or not'
        )
       
    dead_Explode = bpy.props.BoolProperty(
        name = 'Explode Dead',
        default = False,
        description = 'dead_Explode'
        )
       
    count = bpy.props.IntProperty(
        name = "count",
        default = 32,
        min = 1,
        max = 255,
        step = 1,
        description = "Particle Count"
        )
               
    lifetime = bpy.props.IntProperty(
        name = "lifetime",
        default = 50,
        min = 1,
        max = 255,
        step = 1,
        description = "Particle lifetime"
        )
       
    factor_random = bpy.props.FloatProperty(
        name = "factor_random",
        default = 0.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle random factor"
        )
       
    factor_normal = bpy.props.FloatProperty(
        name = "factor_normal",
        default = 0.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle normal factor"
        )
     
    object_align_factor_X = bpy.props.FloatProperty(
        name = "object_align_factor_X",
        default = 0.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
    object_align_factor_Y = bpy.props.FloatProperty(
        name = "object_align_factor_Y",
        default = 0.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
    object_align_factor_Z = bpy.props.FloatProperty(
        name = "object_align_factor_Z",
        default = 0.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
       
    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        animationProps = [
            self.stepA,
            self.start_Fr,
            self.end_Fr
            ]   
        solidifyProps = [
            self.use_Solidify,
            self.thickness_Solidify
            ]
        particleProps = [
            self.count,
            self.lifetime,
            self.factor_random,
            self.factor_normal,
            self.object_align_factor_X,
            self.object_align_factor_Y,
            self.object_align_factor_Z
            ]
       
        main(
        animationProps,
        solidifyProps,
        self.dead_Explode,
        particleProps
        )
        return {'FINISHED'}
   
    def draw(self, context):
        layout = self.layout
       
        layout.label(text = 'Animation:')
        box = layout.box()
        box.prop(self, 'stepA')
        row = box.row(align = True)
        row.prop(self, 'start_Fr')
        row.prop(self, 'end_Fr')
       
        layout.label(text = 'Solidify Modifier:')
        box = layout.box()
        row = box.row(align = True)
        #row.label(text = 'Solidify:')
        row.prop(self, 'use_Solidify')
        if self.use_Solidify == True:
            box.prop(self, 'thickness_Solidify')
       
#        layout.label(text = 'Explode Modifier:')   
#        box = layout.box()
#        box.prop(self, 'dead_Explode')
       
        layout.label(text = 'Particle System:')   
        box = layout.box()
        box.prop(self, 'count')
        box.prop(self, 'lifetime')
        box.prop(self, 'factor_random')
        box.prop(self, 'factor_normal')
        col = box.column(align = True)
        col.prop(self, 'object_align_factor_X')
        col.prop(self, 'object_align_factor_Y')
        col.prop(self, 'object_align_factor_Z')
       


def add_object_menu(self, context):
    self.layout.separator()
    self.layout.operator(
        ExplodeOperator.bl_idname,
        text = ExplodeOperator.__doc__)
    self.layout.label(text = 'EXPLODEEEEE!!!!')
    self.layout.separator()
   
def register():
    bpy.utils.register_class(ExplodeOperator)
    bpy.types.VIEW3D_MT_object.append(add_object_menu)
   
def unregister():
    bpy.utils.unregister_class(ExplodeOperator)
    bpy.types.VIEW3D_MT_object.remove(add_object_menu)


   
if __name__ == '__main__':
    register()
denis8424
Аватара
Сообщения: 711

  • 3

Сообщение #7 denis8424 » 10.12.2016, 18:22

Вполне функциональная версия, считайте, что Бета.
Что есть на данный момент:
    Нормальный вызов оператора из меню 3D - вида -> Object или по имени
    Собранные до кучи для удобства настройки модификаторов и системы частиц
    Работоспособный код, который автоматизирует создание "взрывающегося клона"
Что было сделано в этой версии:
    Изменена логика добавления модификаторов и системы частиц на объекты. Теперь настройки системы частиц едины для всех клонов, то есть это один particle settings - меньше мусора.
    Переименованы некоторые переменные, их имена стали более осмыслены.
    Создаваемые ключи анимации теперь имеют тип Linear, а не Bezier
    Система частиц стала реагировать на гравитацию - исправлена логическая ошибка.
    Аддон переехал из Game Engin в Animation - так правильнее.
Что еще надо сделать, и тут понадобится ваша помощь:
    Придумать вменяемое название для аддона, нынешнее не информативно.
    Накатать описание аддона, желательно на английском.
    Переименовать переменные и подсказки к ним, тут нужен свободно владеющий английским языком человек, который понимает, что пишет.
    Изменить диапазон изменения некоторых переменных, про некоторые вещи и так понятно, что надо менять, но некоторые лучше увидит человек со стороны.
    Выкинуть ненужные переменные, или добавить новые.
    Добавить нужные параметры в интерфейс настройки, если надо.
    Тестировать, в том числе производительность результата в BGE.

код на данный момент:
Код: Выделить всё
bl_info = {
    "name" : "ExplodeToShape",
    "author" : "denis8424",
    "category" : "Animation",
    "version" : (0, 7),
    }

import bpy

def main(animationProps, solidifyProps, dead_Explode, particleProps):
   
    print('<<<<<<<>>>>>>>') # это чтобы в консоли отличать сообщения между
                            # разными запусками оператора
   
    ########################
    # VAR
    ########################
   
    # выковыриваем из списков переменные. Списки, чтобы вызов функции
    # был короче, оно в принципе не обязательно, просто я лентяй
   
    # количество кадров, приходящееся на один ключ
    frameWithAKey = animationProps[0]
    # стартовый кадр анимации
    startFr = animationProps[1]
    # конечный кадр анимации
    end_Fr = animationProps[2]
    # использовать ли модификатор Твердости
    useSolidify = solidifyProps[0]
    # параметр толщины вышеупомянутого модификатора Твердости
    thickness = solidifyProps[1]
   
    # Теперь пошли настроики системы частиц
   
    # количество "кусков"
    count = particleProps[0]
    # время жизни частиц
    lifetime = particleProps[1]
    # Эти два параметра управляют индивидуальной скоростью разлета осколков   
    # направление задается случайным образом
    factor_random = particleProps[2]
    # направление задается от нормали
    factor_normal = particleProps[3]
   
    # А эти три - задают общий для всех обломков вектор полета
    object_align_factor_X = particleProps[4]
    object_align_factor_Y = particleProps[5]
    object_align_factor_Z = particleProps[6]
                               
    # выковыриваем из контекста нужные данные
   
    # текущая сцена
    scene = bpy.context.scene
    # объект, для которого вызывается оператор
    object = bpy.context.object
    # имя объекта, нужно для задания имен ключам
    name = object.name
   
    # создаем список имен используемых объектов
    # формат - [имя, соответствующий кадр анимации, индекс в списке]
   
    listNames = []
    # сразу создаем переменную индекса, надо будет посмотреть, может её выкинуть
    index = 0
   
    # Вот теперь пошла работа
   
    # Создаем клон нашего объекта
    bpy.ops.object.duplicate()
    # Получаем его, он будет клонироваться, на нем висят все модификаторы и он
    # же отвечает за форму базового ключа
    basisOb = scene.objects.active
    # переименовываем нашу основу
    basisOb.name = name + ' BasisExplode' 
    # добавляем модификатор системы частиц     
    bpy.ops.object.modifier_add(type = 'PARTICLE_SYSTEM')
    # получаем добавленную систему частиц
    part_S = basisOb.particle_systems['ParticleSystem']
    # и настраиваем её, переменные мы знаем
    # начало и конец испускания частиц должны быть одинаковы!
    part_S.settings.frame_start = startFr
    part_S.settings.frame_end = startFr   
    part_S.settings.count = count
    part_S.settings.lifetime = lifetime
    part_S.settings.factor_random = factor_random
    part_S.settings.normal_factor = factor_normal
    part_S.settings.object_align_factor[0] = object_align_factor_X
    part_S.settings.object_align_factor[1] = object_align_factor_Y
    part_S.settings.object_align_factor[2] = object_align_factor_Z
    part_S.settings.integrator = 'EULER'
    part_S.settings.use_modifier_stack = True
    # Надо наверное сделать возможность типа физики частиц
    part_S.settings.physics_type = 'NEWTON'
   
    # Теперь добавляем модификатор взрыва   
    bpy.ops.object.modifier_add(type = 'EXPLODE')
   
    # И модификатор "Твердости", если таковая галочка установлена
    if useSolidify == True:
        bpy.ops.object.modifier_add(type = 'SOLIDIFY')
        basisOb.modifiers['Solidify'].thickness = 0.1
    # добавляем базовый объект в список имен
    listNames.append((basisOb.name, startFr, index))
   
    # Теперь будем клонировать некоторое количество раз наш базовый объект           
    for frame in range(startFr + frameWithAKey, end_Fr + frameWithAKey, frameWithAKey):
        # в процессе рассчитываем ключевые кадры
        # поскольку это цикл, то после копирования активным станет новый клон,
        # поэтому снова делаем активным базовый объект
        scene.objects.active = basisOb
        # выбираем базовый объект
        basisOb.select = True
        # клонируем его
        bpy.ops.object.duplicate()
        # получаем новую копию
        newOb = scene.objects.active
        # и переименовываем
        newOb.name = name + ' Explode' + str(frame)
        # увеличиваем индекс на 1
        index = index + 1
        # добавляем имя клона, кадр анимации и индекс в список имен
        listNames.append((newOb.name, frame, index)) 
        # снимаем выбор со всех объектов         
        bpy.ops.object.select_all(action = 'DESELECT')
               
    # Теперь достаем из списка имя клона и связанный с ним номер кадра   
    for name, frame, index in listNames:
        # устанавливаем текущий кадр в сцене
        scene.frame_set(frame, 0.0)
        # получаем текущий объект из сцены по имени
        currOb = scene.objects[name]
        # делаем его активным и выбираем
        scene.objects.active = currOb
        currOb.select = True
        # а теперь применяем модификаторы
        # сначала модификатор взрыва
        bpy.ops.object.modifier_apply(modifier = 'Explode', apply_as = 'DATA')
        # потом удаляем ситсему частиц
        bpy.ops.object.particle_system_remove()
        # и если мы выбрали "твердость" обломков
        if useSolidify == True:
            # то применяем и этот модификатор
            bpy.ops.object.modifier_apply(modifier = 'Solidify')
        # снимаем выделение   
        bpy.ops.object.select_all(action = 'DESELECT')

   
   
    #print(listNames)
    # Здесь будем добавлять клонов как ключи формы, причем самому первому клону,
    # потому что нельзя добавить объект в ключи другому объекту, если у них
    # разное число вершин.
   
    for name, frame, index in listNames:
        #print(name)
        # пропускаем первого клона, он же базовый, на него будем писать ключи
        # формы
        if index == 0:
            continue
        else:
            # понятно, выковыриваем клон(не первый) по имени, он пойдет
            # в ключ формы
            currObj = bpy.context.scene.objects[name]
            # выбираем его
            currObj.select = True
            # получаем первого клона
            explObject = bpy.context.scene.objects[listNames[0][0]]
            # выбираем его и делаем его активным
            explObject.select = True
            bpy.context.scene.objects.active = explObject
            # пишем текущий клон в ключ формы первого клона
            bpy.ops.object.join_shapes()
            # снимем выделение со всех объектов сцены
            bpy.ops.object.select_all(action = 'DESELECT')
            # снова выбираем текущего клона и в этот раз делаем его активным
            bpy.context.scene.objects.active = currObj
            currObj.select = True
            # удаляем текущий клон       
            bpy.ops.object.delete()
           
    # Здесь будем анимировать ключи формы
           
    # снимаем выделение со всех объектов, на всякий пожарный   
    bpy.ops.object.select_all(action = 'DESELECT')
    # выделям первый и теперь уже единственный клон, он же наш базовый
    objExpl = bpy.context.scene.objects[listNames[0][0]]
    bpy.context.scene.objects.active = objExpl
    objExpl.select = True
    # получаем его список ключей форм
    shapeKeys = objExpl.data.shape_keys

    for name, frame, index in listNames:
        # достаем ключ формы по имени, на всякий случай проверяя, есть ли такой
        if name in shapeKeys.key_blocks:
            # текущий ключ формы
            currBlock = shapeKeys.key_blocks[name]
            # генерируем список из кортежей "значение - кадр"
            frameList = [(0.0, frame-frameWithAKey),
                        (1.0, frame),
                        (0.0, frame+frameWithAKey)]
            # И по этому списку задаем ключи анимации ключам формы
            for J in frameList:
#                print(J) #debug
                currBlock.value = J[0]
                currBlock.interpolation = 'KEY_LINEAR'
                currBlock.keyframe_insert("value", frame = J[1])
   
    # изменяем тип ключевых точек для кривых анимации
   
    # выковыриваем циклом по одной ФКурву из списка данных анимации   
    for f_curve in shapeKeys.animation_data.action.fcurves:
        # из ФКурвы достаем список ключевых точек и проходим по одной
        for key_point in f_curve.keyframe_points:
            #изменяем тип
            key_point.interpolation = 'LINEAR'

    # возвращаем сцену в первый кадр   
    bpy.context.scene.frame_set(1, 0.0)

class ExplodeOperator(bpy.types.Operator):
    """Explode object"""
    bl_idname = "object.explode_operator"
    bl_label = "Explode Object Operator"
    bl_options = {'REGISTER', 'UNDO'}
   
    frameWithAKey = bpy.props.IntProperty(
        name = "frameWithAKey",
        default = 1,
        min = 1,
        max = 8,
        step = 1,
        description = "animation frame with a shape key"
        )
       
    startFr = bpy.props.IntProperty(
        name = "start frame",
        default = 1,
        min = 1,
        max = 255,
        step = 1,
        description = "start animation frame"
        )
   
    end_Fr = bpy.props.IntProperty(
        name = "end_frame",
        default = 8,
        min = 1,
        max = 255,
        step = 1,
        description = "end animation frame"
        )

       
    thickness_Solidify = bpy.props.FloatProperty(
        name = "thickness_Solidify",
        default = 0.05,
        min = 0.01,
        max = 1.0,
        step = 1,
        description = "Solidify thickness"
        )
       
    use_Solidify = bpy.props.BoolProperty(
        name = 'use_Solidify',
        default = False,
        description = 'Solidify usy or not'
        )
   
    # а вот это не сделанная настороика модификатора взрыва   
    dead_Explode = bpy.props.BoolProperty(
        name = 'Explode Dead',
        default = False,
        description = 'dead_Explode'
        )
       
    count = bpy.props.IntProperty(
        name = "count",
        default = 32,
        min = 1,
        max = 255,
        step = 1,
        description = "Particle Count"
        )
               
    lifetime = bpy.props.IntProperty(
        name = "lifetime",
        default = 50,
        min = 1,
        max = 255,
        step = 1,
        description = "Particle lifetime"
        )
       
    factor_random = bpy.props.FloatProperty(
        name = "factor_random",
        default = 1.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle random factor"
        )
       
    factor_normal = bpy.props.FloatProperty(
        name = "factor_normal",
        default = 1.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle normal factor"
        )
     
    object_align_factor_X = bpy.props.FloatProperty(
        name = "object_align_factor_X",
        default = 0.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
    object_align_factor_Y = bpy.props.FloatProperty(
        name = "object_align_factor_Y",
        default = 0.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
    object_align_factor_Z = bpy.props.FloatProperty(
        name = "object_align_factor_Z",
        default = 0.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
       
    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        animationProps = [
            self.frameWithAKey,
            self.startFr,
            self.end_Fr
            ]   
        solidifyProps = [
            self.use_Solidify,
            self.thickness_Solidify
            ]
        particleProps = [
            self.count,
            self.lifetime,
            self.factor_random,
            self.factor_normal,
            self.object_align_factor_X,
            self.object_align_factor_Y,
            self.object_align_factor_Z
            ]
       
        main(
        animationProps,
        solidifyProps,
        self.dead_Explode,
        particleProps
        )
        return {'FINISHED'}
   
    def draw(self, context):
        layout = self.layout
       
        layout.label(text = 'Animation:')
        box = layout.box()
        box.prop(self, 'frameWithAKey')
        row = box.row(align = True)
        row.prop(self, 'startFr')
        row.prop(self, 'end_Fr')
       
        layout.label(text = 'Solidify Modifier:')
        box = layout.box()
        row = box.row(align = True)
        #row.label(text = 'Solidify:')
        row.prop(self, 'use_Solidify')
        if self.use_Solidify == True:
            box.prop(self, 'thickness_Solidify')
       
#        layout.label(text = 'Explode Modifier:')   
#        box = layout.box()
#        box.prop(self, 'dead_Explode')
       
        layout.label(text = 'Particle System:')   
        box = layout.box()
        box.prop(self, 'count')
        box.prop(self, 'lifetime')
        box.prop(self, 'factor_random')
        box.prop(self, 'factor_normal')
        col = box.column(align = True)
        col.prop(self, 'object_align_factor_X')
        col.prop(self, 'object_align_factor_Y')
        col.prop(self, 'object_align_factor_Z')
       


def add_object_menu(self, context):
    self.layout.separator()
    self.layout.operator(
        ExplodeOperator.bl_idname,
        text = ExplodeOperator.__doc__)
    self.layout.separator()
   
def register():
    bpy.utils.register_class(ExplodeOperator)
    bpy.types.VIEW3D_MT_object.append(add_object_menu)
   
def unregister():
    bpy.utils.unregister_class(ExplodeOperator)
    bpy.types.VIEW3D_MT_object.remove(add_object_menu)


   
if __name__ == '__main__':
    register()

Добавлено спустя 2 часа 14 минут:
P.S. файл аддона как он есть.
Вложения
explodeToShape.py.7z
(4.16 КБ) Скачиваний: 25
denis8424
Аватара
Сообщения: 711

  • 1

Сообщение #8 denis8424 » 13.12.2016, 22:05

Код: Выделить всё
# И модификатор "Твердости", если таковая галочка установлена
    if useSolidify == True:
        bpy.ops.object.modifier_add(type = 'SOLIDIFY')
        basisOb.modifiers['Solidify'].thickness = 0.1
:facepalm: :suicid:
Создал переменную, а использовать-то забыл!
Код: Выделить всё
# И модификатор "Твердости", если таковая галочка установлена
    if useSolidify == True:
        bpy.ops.object.modifier_add(type = 'SOLIDIFY')
        basisOb.modifiers['Solidify'].thickness = thickness
denis8424
Аватара
Сообщения: 711

  • 2

Оно опять переехало.

Сообщение #9 denis8424 » 17.12.2016, 21:50

:-D Теперь уже в Object. Всё же создается новый объект.
Немножечко изменил алгоритм работы, теперь можно посмотреть на трассы разлета осколков, настроить всё как надо. а только потом запекать в ключи формы.
Добавил возможность отключения влияния гравитации на траекторию полета осколков.

Картинка
Изображение

Состояние кода на данный момент:
Код: Выделить всё
bl_info = {
    "name" : "ExplodeToShape",
    "author" : "denis8424",
    "category" : "Object",
    "version" : (0, 8),
    }

import bpy

def createClones(animationProps, solidifyProps, particleProps):
   
    print('<<<<<<<>>>>>>>') # это чтобы в консоли отличать сообщения между
                            # разными запусками оператора
   
    ########################
    # VAR
    ########################
   
    # выковыриваем из списков переменные. Списки, чтобы вызов функции
    # был короче, оно в принципе не обязательно, просто я лентяй
   
    # количество кадров, приходящееся на один ключ
    frameWithAKey = animationProps[0]
    # стартовый кадр анимации
    startFr = animationProps[1]
    # конечный кадр анимации
    end_Fr = animationProps[2]
    # использовать ли модификатор Твердости
    useSolidify = solidifyProps[0]
    # параметр толщины вышеупомянутого модификатора Твердости
    thickness = solidifyProps[1]
   
    # Теперь пошли настройки системы частиц
   
    # количество "кусков"
    count = particleProps[0]
    # время жизни частиц
    lifetime = particleProps[1]
    # использовать ли силу гравитации для рассчета траектории частиц
    use_Gravity = particleProps[2]
    # Эти два параметра управляют индивидуальной скоростью разлета осколков   
    # направление задается случайным образом
    factor_random = particleProps[3]
    # направление задается от нормали
    factor_normal = particleProps[4]
   
    # А эти три - задают общий для всех обломков вектор полета
    object_align_factor_X = particleProps[5]
    object_align_factor_Y = particleProps[6]
    object_align_factor_Z = particleProps[7]
                               
    # выковыриваем из контекста нужные данные
   
    # текущая сцена
    scene = bpy.context.scene
    # объект, для которого вызывается оператор
    object = bpy.context.object
    # имя объекта, нужно для задания имен ключам
    name = object.name
   
    # создаем список имен используемых объектов
    # формат - [имя, соответствующий кадр анимации, индекс в списке]
   
    listNames = []
    # сразу создаем переменную индекса, надо будет посмотреть, может её выкинуть
    index = 0
   
    # Вот теперь пошла работа
   
    # Создаем клон нашего объекта
    bpy.ops.object.duplicate()
    # Получаем его, он будет клонироваться, на нем висят все модификаторы и он
    # же отвечает за форму базового ключа
    basisOb = scene.objects.active
    # переименовываем нашу основу
    basisOb.name = name + ' BasisExplode' 
    # добавляем модификатор системы частиц     
    bpy.ops.object.modifier_add(type = 'PARTICLE_SYSTEM')
    # получаем добавленную систему частиц
    part_S = basisOb.particle_systems['ParticleSystem']
    # и настраиваем её, переменные мы знаем
    # начало и конец испускания частиц должны быть одинаковы!
    part_S.settings.frame_start = startFr
    part_S.settings.frame_end = startFr   
    part_S.settings.count = count
    part_S.settings.lifetime = lifetime
    part_S.settings.factor_random = factor_random
    part_S.settings.normal_factor = factor_normal
    part_S.settings.object_align_factor[0] = object_align_factor_X
    part_S.settings.object_align_factor[1] = object_align_factor_Y
    part_S.settings.object_align_factor[2] = object_align_factor_Z
    part_S.settings.integrator = 'EULER'
    part_S.settings.use_modifier_stack = True
    # Использовать ли гравитацию при расчете физики частиц
    part_S.settings.physics_type = 'NEWTON'
    if use_Gravity == True:
        part_S.settings.effector_weights.gravity = 1.0
    else:
        part_S.settings.effector_weights.gravity = 0.0
   
    # Теперь добавляем модификатор взрыва   
    bpy.ops.object.modifier_add(type = 'EXPLODE')
   
    # И модификатор "Твердости", если таковая галочка установлена
    if useSolidify == True:
        bpy.ops.object.modifier_add(type = 'SOLIDIFY')
        basisOb.modifiers['Solidify'].thickness = thickness
    # добавляем базовый объект в список имен
    listNames.append((basisOb.name, startFr, index))
   
    # Теперь будем клонировать некоторое количество раз наш базовый объект           
    for frame in range(startFr + frameWithAKey, end_Fr + frameWithAKey, frameWithAKey):
        # в процессе рассчитываем ключевые кадры
        # поскольку это цикл, то после копирования активным станет новый клон,
        # поэтому снова делаем активным базовый объект
        scene.objects.active = basisOb
        # выбираем базовый объект
        basisOb.select = True
        # клонируем его
        bpy.ops.object.duplicate()
        # получаем новую копию
        newOb = scene.objects.active
        # и переименовываем
        newOb.name = name + ' Explode' + str(frame)
        # увеличиваем индекс на 1
        index = index + 1
        # добавляем имя клона, кадр анимации и индекс в список имен
        listNames.append((newOb.name, frame, index)) 
        # снимаем выбор со всех объектов         
        bpy.ops.object.select_all(action = 'DESELECT')
               
    # Теперь достаем из списка имя клона и связанный с ним номер кадра   
    for name, frame, index in listNames:
        # устанавливаем текущий кадр в сцене
        scene.frame_set(frame, 0.0)
        # получаем текущий объект из сцены по имени
        currOb = scene.objects[name]
        # делаем его активным и выбираем
        scene.objects.active = currOb
        currOb.select = True
        # а теперь применяем модификаторы
       
        #bpy.ops.object.particle_system_remove()
        # сначала модификатор взрыва
        bpy.ops.object.modifier_apply(modifier = 'Explode', apply_as = 'DATA')
        # потом удаляем сиcтсему частиц
        bpy.ops.object.particle_system_remove()
        # и если мы выбрали "твердость" обломков
        if useSolidify == True:
            # то применяем и этот модификатор
            bpy.ops.object.modifier_apply(modifier = 'Solidify')
        # снимаем выделение   
        bpy.ops.object.select_all(action = 'DESELECT')
    # ну и чтобы во время работы не терялась панель настроики делаем активным и
    # выбранным наш базовый объект еще раз  )))   
    basisOb.select = True
    scene.objects.active = basisOb

    return listNames
   
def bakeShapeKeys(listNames, frameWithAKey, context):
   
    #print(listNames)
    # Здесь будем добавлять клонов как ключи формы, причем самому первому клону,
    # потому что нельзя добавить объект в ключи другому объекту, если у них
    # разное число вершин.
   
    for name, frame, index in listNames:
        #print(name)
        # пропускаем первого клона, он же базовый, на него будем писать ключи
        # формы
        if index == 0:
            continue
        else:
            # понятно, выковыриваем клон(не первый) по имени, он пойдет
            # в ключ формы
            currObj = bpy.context.scene.objects[name]
            # выбираем его
            currObj.select = True
            # получаем первого клона
            explObject = bpy.context.scene.objects[listNames[0][0]]
            # выбираем его и делаем его активным
            explObject.select = True
            bpy.context.scene.objects.active = explObject
            # пишем текущий клон в ключ формы первого клона
            bpy.ops.object.join_shapes()
            # снимем выделение со всех объектов сцены
            bpy.ops.object.select_all(action = 'DESELECT')
            # снова выбираем текущего клона и в этот раз делаем его активным
            bpy.context.scene.objects.active = currObj
            currObj.select = True
            # удаляем текущий клон       
            bpy.ops.object.delete()
           
    # Здесь будем анимировать ключи формы
           
    # снимаем выделение со всех объектов, на всякий пожарный   
    bpy.ops.object.select_all(action = 'DESELECT')
    # выделям первый и теперь уже единственный клон, он же наш базовый
    objExpl = bpy.context.scene.objects[listNames[0][0]]
    bpy.context.scene.objects.active = objExpl
    objExpl.select = True
    # получаем его список ключей форм
    shapeKeys = objExpl.data.shape_keys

    for name, frame, index in listNames:
        # достаем ключ формы по имени, на всякий случай проверяя, есть ли такой
        if name in shapeKeys.key_blocks:
            # текущий ключ формы
            currBlock = shapeKeys.key_blocks[name]
            # генерируем список из кортежей "значение - кадр"
            frameList = [(0.0, frame-frameWithAKey),
                        (1.0, frame),
                        (0.0, frame+frameWithAKey)]
            # И по этому списку задаем ключи анимации ключам формы
            for J in frameList:
#                print(J) #debug
                currBlock.value = J[0]
                currBlock.interpolation = 'KEY_LINEAR'
                currBlock.keyframe_insert("value", frame = J[1])
   
    # изменяем тип ключевых точек для кривых анимации
   
    # выковыриваем циклом по одной ФКурву из списка данных анимации   
    for f_curve in shapeKeys.animation_data.action.fcurves:
        # из ФКурвы достаем список ключевых точек и проходим по одной
        for key_point in f_curve.keyframe_points:
            #изменяем тип
            key_point.interpolation = 'LINEAR'

    # возвращаем сцену в первый кадр   
    bpy.context.scene.frame_set(1, 0.0)
   
    return listNames

class bakeShapeOperator(bpy.types.Operator):
    """Return the readiness status"""
    bl_idname = "object.explode_to_shape_button_operator"
    bl_label = "Bake Explode Operator"
    bl_options = {'REGISTER', 'UNDO'}
   
    def execute(self, context):
        # print("operator_two") #debug       
        bpy.types.Scene.tresult = True
       
        return {'FINISHED'}
   
    def draw(self, context):
        layout = self.layout
        layout.label(text = 'Bake Explode Operator:')

class ExplodeOperator(bpy.types.Operator):
    """Explode object"""
    bl_idname = "object.explode_operator"
    bl_label = "Explode Object Operator"
    bl_options = {'REGISTER', 'UNDO'}
   
    #  Эта переменная задает через какое количество кадров будет создан
    #клон объекта и соответственно ключ формы
    frameWithAKey = bpy.props.IntProperty(
        name = "frameWithAKey",
        default = 1,
        min = 1,
        max = 8,
        step = 1,
        description = "animation frame with a shape key"
        )
    #  Эта переменная задает желаемый начальный кадр анимации взрыва   
    startFr = bpy.props.IntProperty(
        name = "start frame",
        default = 1,
        min = 1,
        max = 255,
        step = 1,
        description = "start animation frame"
        )
    #  Эта перерменная задает конец анимации
    # Но на самом деле это немного не так. Скорее эта переменная гарантирует,
    #что в этом кадре анимация взрыва еще будет работать нормально.
    end_Fr = bpy.props.IntProperty(
        name = "end_frame",
        default = 8,
        min = 1,
        max = 255,
        step = 1,
        description = "end animation frame"
        )
    #  Использовать ли модификатор "толщины"
    use_Solidify = bpy.props.BoolProperty(
        name = 'use_Solidify',
        default = False,
        description = 'Solidify usy or not'
        )
    #  Если использовать, то указываем какой толщины   
    thickness_Solidify = bpy.props.FloatProperty(
        name = "thickness_Solidify",
        default = 0.05,
        min = 0.01,
        max = 5.0,
        step = 0.1,
        description = "Solidify thickness"
        )
       
       
    #  Количество кусков в настройках системы частиц   
    count = bpy.props.IntProperty(
        name = "count",
        default = 32,
        min = 1,
        max = 255,
        step = 1,
        description = "Particle Count"
        )
    #  Время жизни частиц           
    lifetime = bpy.props.IntProperty(
        name = "lifetime",
        default = 50,
        min = 1,
        max = 255,
        step = 1,
        description = "Particle lifetime"
        )
       
    #  Использовать ли силу гравитации для рассчета траектории частиц
    use_Gravity = bpy.props.BoolProperty(
        name = 'use_Gravity',
        default = False,
        description = 'use gravity to calculate the trajectory of the particles'
        )
       
    #  Эта переменная имеет отношение к заданию начальной скорости частицы.
    # Скорость и направление полета частицы задается случайным образом.     
    factor_random = bpy.props.FloatProperty(
        name = "factor_random",
        default = 1.0,
        min = 0.0,
        max = 255.0,
        step = 1.0,
        description = "Particle random factor"
        )
    #  Задает скорость частицы, с направлением вдоль по нормали испустившего
    #элемента.   
    factor_normal = bpy.props.FloatProperty(
        name = "factor_normal",
        default = 1.0,
        min = -255,
        max = 255.0,
        step = 1.0,
        description = "Particle normal factor"
        )
    #  Эти три переменные задают вектор начальной скорости, каждая задает
    #величину по своей оси
    object_align_factor_X = bpy.props.FloatProperty(
        name = "object_align_factor_X",
        default = 0.0,
        min = -255.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
    object_align_factor_Y = bpy.props.FloatProperty(
        name = "object_align_factor_Y",
        default = 0.0,
        min = -255.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
    object_align_factor_Z = bpy.props.FloatProperty(
        name = "object_align_factor_Z",
        default = 0.0,
        min = -255.0,
        max = 255.0,
        step = 1.0,
        description = "Particle speed factor"
        )
       
    status = bpy.props.BoolProperty(
        name = 'status',
        default = False,
        description = 'tresult'
        )
       
    @classmethod
    # Проверяем вначале, есть ли вообще объект и можно ли его взорвать
    def poll(cls, context):
        if context.object is not None and \
        context.active_object.select == True and\
        context.active_object.type == 'MESH':
            return context.active_object
        else:
            return None

    def execute(self, context):
        animationProps = [
            self.frameWithAKey,
            self.startFr,
            self.end_Fr
            ]   
        solidifyProps = [
            self.use_Solidify,
            self.thickness_Solidify
            ]
        particleProps = [
            self.count,
            self.lifetime,
            self.use_Gravity,
            self.factor_random,
            self.factor_normal,
            self.object_align_factor_X,
            self.object_align_factor_Y,
            self.object_align_factor_Z
            ]
       
        try:
            self.status = bpy.types.Scene.tresult
        except:
            print('except')
            self.status = bpy.types.Scene.tresult = False
            print('except', bpy.types.Scene.tresult)
           
        if self.status == True:
            print('Done', bpy.types.Scene.tresult)
            bpy.types.Scene.tresult = None
            print('Done /', bpy.types.Scene.tresult)
            self.listNames = createClones(animationProps,
                                            solidifyProps,
                                            particleProps)
            bakeShapeKeys(self.listNames, self.frameWithAKey, context)

                       
            return  {'FINISHED'}
        else:
            print('not')
            self.listNames = createClones(animationProps,
                                            solidifyProps,
                                            particleProps)
            #bakeShapeKeys(self.listNames, self.frameWithAKey, context)
           
            return {'FINISHED'}

   
    def draw(self, context):
        layout = self.layout       
        layout.label(text = 'Animation:')
        box = layout.box()
        box.prop(self, 'frameWithAKey')
        row = box.row(align = True)
        row.prop(self, 'startFr')
        row.prop(self, 'end_Fr')
       
        layout.label(text = 'Solidify Modifier:')
        box = layout.box()
        row = box.row(align = True)
        #row.label(text = 'Solidify:')
        row.prop(self, 'use_Solidify')
        if self.use_Solidify == True:
            box.prop(self, 'thickness_Solidify')           
        layout.label(text = 'Particle System:')   
        box = layout.box()
        box.prop(self, 'count')
        box.prop(self, 'lifetime')
        box.prop(self, 'factor_random')
        box.prop(self, 'factor_normal')
        box.prop(self, 'use_Gravity')
        col = box.column(align = True)
        col.prop(self, 'object_align_factor_X')
        col.prop(self, 'object_align_factor_Y')
        col.prop(self, 'object_align_factor_Z')
        box = layout.box()
        box.operator('object.explode_to_shape_button_operator')

       
       

def add_object_menu(self, context):
    self.layout.separator()
    self.layout.operator(
        ExplodeOperator.bl_idname,
        text = ExplodeOperator.__doc__)
    self.layout.separator()
   
def register():
    bpy.utils.register_class(bakeShapeOperator)
    bpy.utils.register_class(ExplodeOperator)
    bpy.types.VIEW3D_MT_object.append(add_object_menu)
   
def unregister():
    bpy.utils.unregister_class(bakeShapeOperator)
    bpy.utils.unregister_class(ExplodeOperator)
    bpy.types.VIEW3D_MT_object.remove(add_object_menu)

if __name__ == '__main__':
    register()
           

Добавлено спустя 16 часов 52 минуты:
RC1
Как пользоваться:
Выбираем объект, переходим в меню 3D вида "Object", там должно быть яркое "Explode object", кликаем мышкой. В T-панели, там где находятся обычно настройки операторов вылезет панель. Параметры:
frame with a key - количество кадров, приходящееся на один ключ анимации
start frame - стартовый кадр анимации
end frame - конечный кадр анимации, хотя анимация продолжается несколько дольше
use Solidify - использовать ли этот модификатор
thickness Solidify - если использовать, то какую толщину задать
count - количество "кусков"
lifetime - время жизни частиц
factor random - вектор разлета частиц задается случайным образом, вносится случайность
factor normal - вектор задается направлением нормали
use Gravity - использовать ли силу тяжести при расчете траектории
object align factor X
object align factor Y
object align factor Z - начальная скорость частиц, как если бы объект перед взрывом двигался
Bake Explode Operator - запечь результат в ключи формы и удалить ненужные клоны.
Если обьект будет неподходящего типа, или у него уже будут ключи формы, или система частиц, то "Explode Object" будет тусклым и ничего не получится.
Вложения
explodeToShape.py.7z
(5.44 КБ) Скачиваний: 23
denis8424
Аватара
Сообщения: 711

Сообщение #10 Mihanik » 18.12.2016, 16:49

denis8424, Круто конечно, но у меня простой объект взорвал всё правильно, а по сложнее почему то начали ключи теряться.
Спойлер
Изображение
Mihanik M
Аватара
Сообщения: 1126

Сообщение #11 denis8424 » 18.12.2016, 16:54

А в консоль что пишет?
denis8424
Аватара
Сообщения: 711

Сообщение #12 Mihanik » 18.12.2016, 17:14

denis8424 писал(а):А в консоль что пишет?
Кракозяблики, не знаю мож это кирилица мозг парит.
Изображение
По позже от кирилицы избавлюсь, проверю.
Mihanik M
Аватара
Сообщения: 1126

Сообщение #13 denis8424 » 18.12.2016, 17:23

Ось какая? Я тут по-быстрому склепал "Здание", так и назвал кириллицей, на сорок кило поликов, запекает без проблем, но ме-е-едленно. Сунул результат (106 с копейками кило)в BGE, просел до 21 фпс.

Добавлено спустя 2 минуты 40 секунд:
По большей части в консоли будет предупреждение блендера, вроде как не отвечает за результат:
"Информация: Примененый модификатор был не первым в списке, поэтому результат может отличаться от ожидаемого"

Добавлено спустя 1 минуту 58 секунд:
P.S. Вижу, что за ось.

Добавлено спустя 2 минуты 58 секунд:
P.P.S. Подразделил здание, полмиллиона полигонов. Блендер тормозит, БГЕ вылетел.
denis8424
Аватара
Сообщения: 711

Сообщение #14 Mihanik » 18.12.2016, 20:23

В общем не понял в чём косяк был. Это давнишний файл, и это здание я уже ломал штатным взрывом блендера, но удалил все модефикаторы, и частицы. Если чё вот он.
https://yadi.sk/d/V2mmcrNL33xyZx
Потом уже удалил и материал циклов, что там был и UV, и вот уже который раз нормально взрывается. А тот который по ссылке продолжает терять ключи.
Mihanik M
Аватара
Сообщения: 1126

Сообщение #15 denis8424 » 18.12.2016, 21:06

Скачал, но ключи оно терять пока не хочет.

Добавлено спустя 13 минут 44 секунды:
P.S. Удалось повторить ошибку, на максимальном числе частиц. Пишет, что для успешного добавления в ключи формы сетка должна содержать одинаковое количество частиц.
denis8424
Аватара
Сообщения: 711

Сообщение #16 Mihanik » 18.12.2016, 21:28

У меня продолжает терять, и даже на вновь созданном объекте, не всегда. А как с краказябликами в консоли бороться? Так хоть прочитал чего пишет. Ось Вида семерка 64-разрядная
Mihanik M
Аватара
Сообщения: 1126

Сообщение #17 denis8424 » 18.12.2016, 21:32

Винду надо русифицировать. Как - без понятия, у меня линь.
denis8424
Аватара
Сообщения: 711

Сообщение #18 Mihanik » 18.12.2016, 21:34

denis8424 писал(а):Пишет, что для успешного добавления в ключи формы сетка должна содержать одинаковое количество частиц.
каким то чудом создаются частицы лишние? Я так понимаю, они все должны быть созданы на первом кадре.
Mihanik M
Аватара
Сообщения: 1126

Сообщение #19 denis8424 » 18.12.2016, 21:38

Или слипаются старые.
denis8424
Аватара
Сообщения: 711

Сообщение #20 denis8424 » 19.12.2016, 21:17

Любопытно. Сперва грешил на то, что объект здания сделан в старом файле. Саппендил его в новый файл, всё нормально взрывается. Решил проверить заодно на своем старом меше и бленде(драконе, если кому интересно), однако тоже всё прошло нормально. Блендер тормозит, аж звук в аудиоплейере линя заикается, вылетает то и дело, но считает как надо. Ладно, лезу обратно в скачанный файл, и обращаю внимание на плоскость, на которой здание стоит и по которой куски здания так ползают. Тут мне приходит в голову, а чего это собственно эти самые куски не проваливаются? Полез в настроики физики земли-матушки, и узрел включенную коллизию. Отключил и с воплем "Аллах акбар!", начал взрывать здание раз за разом. Всё считается нормально. Включил физику поверхности и молча начал взрывать, и сразу же пошел облом. Тут одно из двух - либо Аллах действительно велик, либо алгоритм рассчета столкновения что-то с частицами делает нехорошее.
denis8424
Аватара
Сообщения: 711

След.

Вернуться в Плагины

Кто сейчас на форуме (по активности за 5 минут)

Сейчас этот раздел просматривают: 1 гость