Como adicionar um modificador de espelho a todos os objetos de uma determinada coleção?

Nov 29 2020

Eu gostaria de adicionar um modificador de espelho para cada objeto de uma certa coleção.

O problema é que o modificador só será adicionado ao último objeto que recebe o mesmo modificador várias vezes e não sei por quê:

 def add_empty_collection(self):
    for obj in bpy.data.collections['my_collection'].all_objects:
        print("obj_: ", obj)
        bpy.ops.object.select_all(action='DESELECT') # Deselecting all
        obj.select_set(True)
        bpy.ops.object.modifier_add(type='MIRROR')
        bpy.context.object.modifiers["Mirror"].use_axis[0] = False
        bpy.context.object.modifiers["Mirror"].use_axis[1] = True
        bpy.context.object.modifiers["Mirror"].use_axis[2] = False
        bpy.context.object.modifiers["Mirror"].mirror_object = bpy.data.objects["target"]

P: Como adicionar um modificador de espelho a todos os objetos de uma determinada coleção?

Respostas

3 Psyonic Nov 29 2020 at 10:25

É melhor você usar bpy.data.objectspara manipulá-los. Desta forma, você não precisa depender do que está selecionado, tudo o que você precisa é o nome do objeto.

import bpy

mod_name = 'My-Mirror-Modifier'

for obj in bpy.data.collections["My-Collection"].all_objects:
    if obj.type == 'MESH':
        mod = obj.modifiers.new(mod_name, 'MIRROR')
        mod.use_axis[0] = False
        mod.use_axis[1] = True
        mod.use_axis[2] = False
        mod.mirror_object = bpy.data.objects["Light"]
2 batFINGER Nov 30 2020 at 12:47

Para os operadores, use o contexto.

Dado o selfno código da pergunta, supondo que você está escrevendo um operador

Seguindo a resposta de @RoufirHassan à guisa de explicação, fazer um loop nos objetos da coleção, desmarcando e selecionando um único, não estava mudando o objeto ativo. Adicionar context.objectà declaração de impressão confirmaria isso.

O objeto ativo e o objeto selecionado zero são sempre os mesmos?

para corrigir defina o objeto ativo para o objeto de loop antes de chamar o operador.

context.view_layer.objects.active = obj

API do Blender 2.8, python, definir objeto ativo

No entanto, um problema aqui seria que os scripts tendem a ficar terrivelmente lentos se estiverem executando um loop em muitos operadores. A contagem de corridas do operador usando o código de pergunta corrigido seria 2 x número de objetos na coleção.

Operador de adição de modificador adiciona ao final da pilha de modificadores

se estiver usando o operador de adição de modificadores, o modificador recém-adicionado será

context.object.modifiers[-1]

ou seja, o último. Mais uma vez no blender usar o nome pode ser duvidoso, assim como com objetos adicionar outro com o mesmo nome não terá o mesmo nome.

Candidato principal para KeyError

Nunca use a bpy.data.whatevers["Foo"]menos que você tenha certeza de que "Foo" existe. Onde pode ter valor, Nonetambém recomendo o uso de objetos de cena, como se o objeto em bpy.data.objectsnão estiver vinculado à cena, provavelmente não funcionará como esperado.

target = context.scene.objects.get("Foo")

ou use o contexto. Neste caso, por exemplo, a coleção pode ser uma coleção de contexto (selecionada por último em outliner) e o alvo do modificador pode sercontext.object

Substituindo o contexto

Pode passar um dicionário de contexto para os operadores. Abaixo está o método explicado por @RoufirHassan usando override. Nota: isso adicionará todos os modificadores do primeiro objeto de malha na coleção (incluindo o espelho recém-adicionado) a todos os outros objetos de malha na coleção, exceto para o alvo do espelho se for um objeto de malha na mesma coleção

Isso executará apenas 2 operadores, não importa quantos objetos estejam na coleção.

import bpy

context = bpy.context

coll = context.collection
ob = context.object

mesh_obs = [o for o in coll.all_objects 
        if o.type == 'MESH'
        and o is not ob]


if mesh_obs:
    ao = mesh_obs.pop(0)
    bpy.ops.object.modifier_add(
            {"object" : ao},
            type='MIRROR'
            )
    mod = ao.modifiers[-1]
    mod.use_axis = (True, False, True)
    mod.mirror_object = ob
    bpy.ops.object.make_links_data(
            {"object" : ao,
             "selected_editable_objects": mesh_obs
             },
             type='MODIFIERS',
             )

Métodos API.

Finalmente, eu recomendaria usar o método API conforme sugerido na resposta de @Pysonic , exceto usar o contexto para definir a coleção e o destino do modificador.

1 RoufirHasan Nov 29 2020 at 09:50

Selecione todas as malhas em sua coleção e adicione um modificador de espelho.

Mas, como você disse, ele apenas espelhará o objeto ativo (objeto ativo = último objeto selecionado com contorno de cor diferente). Portanto, para espelhar cada objeto, basta digitar ( Ctrl+ L) > modificadores . Ele irá vincular todos os objetos com o mesmo modificador.

Você pode usá-lo para quaisquer outros modificadores.