Como usar a operação loopcut_slide sem nenhuma IU?

Oct 01 2020

Portanto, preciso executar alguns operadores básicos de corte e deslizamento de loop em uma malha. O índice de borda é conhecido e o valor do slide também é fixo.

usando o método de substituição de Como faço para substituir o contexto de bpy.ops.mesh.loopcut? sou capaz de executar o corte com sucesso dentro do editor de script do blender. mas quando executado sem a IU, o script fornece um erro.

Eu também gostaria de saber se há métodos alternativos não baseados na IU para realizar cortes de loop com atualizações de UV adequadas

aqui está uma versão de exemplo que adiciona cortes em loop e operação suave. testado no editor de script do Blender 2.83

import bpy

bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)

bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 0))
bpy.ops.object.editmode_toggle()


win      = bpy.context.window
scr      = win.screen
areas3d  = [area for area in scr.areas if area.type == 'VIEW_3D']
region   = [region for region in areas3d[0].regions if region.type == 'WINDOW']

override = {'window':win,
            'screen':scr,
            'area'  :areas3d[0],
            'region':region[0],
            'scene' :bpy.context.scene,
            }


bpy.ops.mesh.loopcut_slide(override, 
MESH_OT_loopcut={
"number_cuts":5, 
"smoothness":1, 
"falloff":'INVERSE_SQUARE', 
"object_index":0, 
"edge_index":4, 
"mesh_select_mode_init":(False, True, False)
}, 
TRANSFORM_OT_edge_slide={
"value":0,
"single_side":False,
"use_even":False,
"flipped":False,
"use_clamp":True,
"mirror":True,
"snap":False,
"snap_target":'CLOSEST',
"snap_point":(0, 0, 0),
"snap_align":False,
"snap_normal":(0, 0, 0),
"correct_uv":False,
"release_confirm":False,
"use_accurate":False})

bpy.ops.object.editmode_toggle()

```

Respostas

1 batFINGER Oct 11 2020 at 22:15

Subdivide edge loops é um bom ajuste para slides com loop cut.

O loop cut and slide é um operador avançado que está fazendo um pouco dos bastidores. Pode selecionar uma única aresta e o corte em loop selecionará e cortará o anel de aresta definido pela aresta.

Bmesh subdividir operadores de borda

Se um loop de borda é alimentado no operador bmesh subdivide edge com usar preenchimento de grade, ele emula um corte e slide de loop básico.

Também existe o operador subdivide edge ring bmesh, que lançará um erro se as arestas enviadas não forem anéis de aresta válidos.

Anéis de borda submersa. Perfil quadrado inverso, fator 0,5

Existem várias opções disponíveis para ambos os operadores, incluindo a configuração dos espaçamentos dos cortes e o tipo de declínio suave.

Como o loop cut e o slide estão subdividindo as bordas, você perceberá uma série de opções familiares.

Consulte a docs ..

Consulte Adicionando uma malha cubóide para ver isso em operação para criar um$i \times j \times k$ cubóide.

Selecionando os anéis de aresta.

Usei um método recursivo semelhante ao mostrado aqui.

Como encontrar loops e anéis de malha

Não adicionei nenhuma verificação para não encontrar um anel de borda válido. (por exemplo, as últimas arestas encontradas devem ser iguais ou limites)

Teste o script, selecione a borda no modo de edição e execute o script. Usa a aresta ativa para selecionar o anel da aresta.

import bpy
import bmesh

cuts = 4

context = bpy.context
ob = context.object
me = ob.data

bm = bmesh.from_edit_mesh(me)
edge = bm.select_history.active
def edge_loops(edge):
    def walk(edge):
        yield edge
        edge.tag = True
        for l in edge.link_loops:
            loop = l.link_loop_radial_next.link_loop_next.link_loop_next
            if not (len(loop.face.verts) != 4 or loop.edge.tag):
                yield from walk(loop.edge)
    for e in bm.edges:
        e.tag = False
    return list(walk(edge))
        
if isinstance(edge, bmesh.types.BMEdge): 
    ''' 
    bmesh.ops.subdivide_edges(
        bm,
        edges=edge_loops(edge),
        cuts=cuts,
        smooth_falloff='INVERSE_SQUARE',
        use_grid_fill=True,
        )
    '''
    bmesh.ops.subdivide_edgering(
        bm,
        edges=edge_loops(edge),
        cuts=cuts,
        profile_shape='INVERSE_SQUARE',
        profile_shape_factor=0.0,
        )    
    bmesh.update_edit_mesh(me)

Note ter usado um modo de edição bmesh a título de exemplo. Para o script de modo de objeto, carregue o bmesh conforme mostrado em sua resposta . O bisect IMO não vai dar um bom resultado se as bordas do loop de borda não estiverem bem alinhadas.

Evite postar, exclua todos os códigos de objetos em scripts de pergunta quando não for necessário.

1 Prime007 Oct 11 2020 at 14:26

bmesh bisect faz exatamente isso ... mas não é automatizado como o bpy loopcut, então certifique-se de selecionar todas as faces que você precisa para cortar e você mesmo precisará fornecer o local e a direção do corte.

import bpy
import bmesh
import math
import mathutils

bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
bpy.ops.mesh.primitive_plane_add(enter_editmode=False, align='WORLD', location=(0, 0, 0))

def bmesh_loopcut(bm,face_list,direction_axis,center='auto'):
    for f in bm.faces:
        f.select = False
    bm.faces.ensure_lookup_table()  
    for f in face_list:
        bm.faces[f].select = True

    edges = [e for e in bm.edges if e.select == True]
    faces = [f for f in bm.faces if f.select == True]
    
    if center=='auto':    
        weights = [f.calc_area() for f in faces]
        weighted_centres = [f.calc_area() * f.calc_center_median() for f in faces]
        cutting_point = sum(weighted_centres, mathutils.Vector()) / sum(weights)
    else:
        cutting_point = bpy.context.scene.cursor.location
    geom = []
    geom.extend(edges)
    geom.extend(faces) 

    result = bmesh.ops.bisect_plane(bm,dist=0.01,geom=geom,plane_co=cutting_point,plane_no=direction_axis)



# Make a new BMesh
bm = bmesh.new()

obj = bpy.context.object

ob = obj
me = ob.data 
bm = bmesh.new() 
bm.from_mesh(me)


face_cut=([0])
bmesh_loopcut(bm,face_cut,[1,0,0])
    
bm.to_mesh(me)
bm.free()
me.update()

```