Atualizar um script 2.7 que usa frame_current para funcionar com 2.8+

Oct 13 2020

Há um script que acho muito útil que funciona em 2.7x e não funciona mais em 2.8x, 2.9x. Eu quero atualizá-lo para funcionar com as versões atuais do Blender. O script pega um objeto e faz uma duplicata dele onde estaria em cada quadro, aplicando deformações de malha. Parece que parou de funcionar por causa dessas mudanças na API Python que vieram com o novo sistema de coleções.

O script que funciona em 2.7x foi criado por CodeManX :

import bpy

scene = bpy.context.scene
frame_current = scene.frame_current

r = intervalo (scene.frame_start, scene.frame_end + 1)
l = len (str (len (r)))
obs = []

para f em r:
    scene.frame_set (f)

    para ob em scene.objects:
        if ob.type == 'MESH' e ob.name.startswith ("modelo"):
            me = ob.to_mesh (cena, Verdadeiro, 'PREVIEW')
            new_ob = bpy.data.objects.new ("% s_frame% 0 * i"% (ob.name, l, f), me)
            new_ob.matrix_world = ob.matrix_world.copy ()
            obs.append (new_ob)

scene.frame_set (frame_current)
para ob em obs:
    scene.objects.link (ob)
scene.update ()

Mandei uma mensagem para o autor do código original na semana passada, mas parece que ele não está tão ativo no Blender SE atualmente, então não estou prendendo a respiração por uma resposta. Além disso, talvez no processo de tentar corrigir isso eu possa aprender mais sobre como a API funciona.

De acordo com as mudanças da API, substituí scene = bpy.context.scenepor layer = bpy.context.view_layere isso resolveu um erro. Mas agora estou tentando resolver este:

AttributeError: 'ViewLayer' object has no attribute 'frame_current'

Esta página do Manual do Blender ainda faz referências scene.frame_current. Esta página do manual está desatualizada? Ou estou entendendo mal e ainda podemos usar sceneem certos casos?

Este é meu script modificado de trabalho em andamento, parcialmente corrigido para 2.8+ :

import bpy

layer = bpy.context.view_layer
frame_current = layer.frame_current

r = intervalo (layer.frame_start, layer.frame_end + 1)
l = len (str (len (r)))
obs = []

para f em r:
    layer.frame_set (f)

    para ob em layer.objects:
        if ob.type == 'MESH' e ob.name.startswith ("modelo"):
            me = ob.to_mesh (camada, Verdadeiro, 'PREVIEW')
            new_ob = bpy.data.objects.new ("% s_frame% 0 * i"% (ob.name, l, f), me)
            new_ob.matrix_world = ob.matrix_world.copy ()
            obs.append (new_ob)

layer.frame_set (frame_current)
para ob em obs:
    layer.objects.link (ob)
layer.update ()

Qualquer ajuda seria muito apreciada. E se puder ser explicado de uma maneira geral que pode se aplicar a outras pessoas que estão tendo problemas para atualizar um script 2.7, ou especificamente aqueles que estão se perguntando sobre como frame_currentmudou, isso seria ótimo.

Finalmente, uma possível dica de nova sintaxe está nesta resposta, onde o autor riscou frame_current = 1e substituiu por frame_set(1)... infelizmente, minha lógica de tentar frame_get()não funcionou.

Respostas

4 batFINGER Oct 13 2020 at 15:44

Script atualizado.

Todas as mudanças aqui foram bem documentadas.

A obtenção da malha atualizada mudou.

Como faço para obter um bloco de dados de malha com modificadores e chaves de forma aplicadas no Blender 2.8?

A atualização da cena foi substituída.

Qual é a substituição de scene.update ()?

A configuração da moldura ainda é feita da mesma forma. ( frame_setnão é membro de ViewLayer.)

Vincular objeto a uma cena mudou.

vincular novo objeto à cena com python em 2.8

Os objetos da camada de visualização não têm método de link.

roteiro revisado.

import bpy
context = bpy.context
scene = context.scene
dg = context.evaluated_depsgraph_get()

frame_current = scene.frame_current

r = range(scene.frame_start, scene.frame_end + 1)
l = len(str(len(r)))
obs = []

for f in r:
    scene.frame_set(f)
    #dg = context.evaluated_depsgraph_get()
    for ob in scene.objects:
        if ob.type == 'MESH' and ob.name.startswith("Cube"):
            ev_ob = ob.evaluated_get(dg)
            me = ev_ob.data.copy()
            new_ob = bpy.data.objects.new("%s_frame%0*i" % (ob.name, l, f), me)
            new_ob.matrix_world = ob.matrix_world.copy()
            obs.append(new_ob)

scene.frame_set(frame_current)
for ob in obs:
    context.collection.objects.link(ob)
context.view_layer.update()

Observe que não testei isso completamente, com relação à frequência para avaliar o gráfico, descomente #dg = context.evalua....para ver se o resultado difere quando é avaliado por quadro.