Comment utiliser l'opération loopcut_slide sans aucune interface utilisateur?
J'ai donc besoin d'exécuter des opérateurs de coupe et de glissement de boucle de base sur un maillage. L'index de bord est connu et le montant de la diapositive est également fixe.
en utilisant la méthode de remplacement de Comment remplacer le contexte pour bpy.ops.mesh.loopcut? je suis capable d'effectuer la coupe avec succès dans l'éditeur de script de blender. mais lorsqu'il est exécuté sans l'interface utilisateur, le script donne une erreur.
Je voudrais également savoir s'il existe une autre méthode non basée sur l'interface utilisateur pour effectuer des coupes en boucle avec des mises à jour UV appropriées
voici une version d'exemple qui ajoute des coupes de boucle et un fonctionnement en douceur. testé sur l'éditeur de script 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()
```
Réponses
Subdiviser les boucles de bord est un bon ajustement pour la diapositive coupée en boucle.
La boucle couper et glisser est un opérateur avancé qui fait un peu derrière la scène. Peut sélectionner un seul bord et la coupe en boucle sélectionnera et coupera l'anneau de bord défini par le bord.
Opérateurs d'arête de subdivision Bmesh
Si une boucle d'arête est introduite dans l'opérateur bmesh subdivide arêtes avec l'utilisation de remplissage de grille, elle émule une boucle de base couper et glisser.
De plus, il y a l'opérateur de subdivision edge ring bmesh, qui générera une erreur si les arêtes soumises ne sont pas des anneaux de bord valides.
Il existe un certain nombre d'options disponibles pour les deux opérateurs, notamment la définition des espacements des coupes et le type de réduction lisse.
Parce que la coupe en boucle et le glissement subdivisent les bords, vous remarquerez un certain nombre d'options familières.
Consultez la documentation.
Voir Ajout d'un maillage cuboïde pour voir cela en fonctionnement pour créer un$i \times j \times k$ cuboïde.
Sélection des anneaux de bord.
Ont utilisé une méthode récursive similaire à celle illustrée ici.
Comment trouver des boucles et des anneaux en maille
N'ajoutez aucune vérification pour ne pas trouver un anneau de bord valide. (par exemple, les dernières arêtes trouvées voudraient être identiques ou une limite)
Tester le script, sélectionner l'arête en mode édition et exécuter le script. Utilise l'arête active pour sélectionner l'anneau d'arête.
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 ont utilisé un mode d'édition bmesh à titre d'exemple. Pour le script en mode objet, chargez le bmesh comme indiqué dans votre réponse . La bissectrice IMO ne donnera pas un bon résultat si les bords de la boucle de bord ne sont pas bien alignés.
Veuillez vous abstenir de publier le code de tous les objets dans les scripts de question lorsque cela n'est pas nécessaire.
bmesh bisect fait exactement cela ... mais ce n'est pas automatisé comme bpy loopcut, alors assurez-vous de sélectionner toutes les faces que vous devez couper et vous devrez fournir vous-même l'emplacement et la direction de la coupe.
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()
```