1
$\begingroup$

When I subdivide edges of selected faces using the GUI, it ends up looking like this: enter image description here

On the other hand, using python, it looks like this, only generating vertices and not faces:

enter image description here

Here is the code - how can I get a similar result to the GUI, actually splitting faces up?

import bpy
import bl_operators
import bmesh
from math import ceil

obj = bpy.context.active_object

mat_zero = bpy.data.materials.new("mat_zero")
mat_zero.diffuse_color = (0, 0, 0, 1)
mat_one = bpy.data.materials.new("mat_one")
mat_one.diffuse_color = (1, 0, 0, 1)

obj.data.materials.append(mat_zero)
obj.data.materials.append(mat_one)

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


for edge in bm.edges:
    linked = edge.link_faces
    if(linked[0].smooth and linked[1].smooth):
        edge.seam = False

print(len(bm.faces))
bpy.ops.object.mode_set(mode="EDIT")

for face in bm.faces:
    if (face.smooth):
        face.material_index = 1
        area = face.calc_area()
        face.select = True
        for edge in face.edges:
            edge.select = True
        bmesh.ops.subdivide_edges(bm, edges=face.edges, cuts=1)


bm.normal_update()
me.update()

bpy.ops.object.mode_set(mode="OBJECT")


print(len(bm.faces))

bm.to_mesh(me)
print("done")
$\endgroup$
2
$\begingroup$

Processing edges twice.

The logic is wrong. If an edge is a boundary of two selected faces it gets subdivided twice (for each face). These are the edges to have seam set to false

To get all the edges of smooth faces. First will select smooth faces. Set the material on these faces. From these faces get the edges.

faces = [f for f in bm.faces if f.smooth]
edges = set(e for f in faces for e in f.edges)

by making edges a set it has only one of each unique member. Pass list(edges) to an operator.

Can use this narrowed down selection to do the seam setting.

Object mode test script. With object selected and active in OBJECT mode run the script below.

Set use_grid_fill=True in the bmesh subdivide operator if you wish to subdivide faces too.

import bpy
import bmesh

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

# object mode bmesh

bm = bmesh.new()
bm.from_mesh(me)

faces = [f for f in bm.faces if f.smooth]

for f in faces:
    f.material_index = 1

edges = set(e for f in faces for e in f.edges)

for e in edges:
    if all(f.smooth for f in e.link_faces):
        e.seam = False

bmesh.ops.subdivide_edges(bm,
        edges=list(edges),
        cuts=1,
        use_grid_fill=True,
        )
bm.to_mesh(me) 
me.update()

Recommend when using bmesh choosing which mode you wish script to run in. The toggle mode operator is not required in your question script.

If you wish to see live results as you are editing would go with an edit mode bmesh as below.

Here is a test file to run in EDIT mode. Can run this script against a "live" selection of edges.

import bpy
import bmesh

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

# edit mode bmesh

bm = bmesh.from_edit_mesh(me)

edges = [e for e in bm.edges if e.select]

bmesh.ops.subdivide_edges(bm,
        edges=edges,
        cuts=1,
        use_grid_fill=True,
        )
bmesh.update_edit_mesh(me)
me.update()
$\endgroup$
2
  • 1
    $\begingroup$ thanks so much!!! $\endgroup$
    – user89359
    Feb 27 '20 at 17:54
  • $\begingroup$ Pleasure. Good question btw. $\endgroup$
    – batFINGER
    Feb 27 '20 at 17:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.