# Subdivide in GUI vs Subdivide in Python

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

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

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:
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")


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()

• thanks so much!!! Feb 27 '20 at 17:54
• Pleasure. Good question btw. Feb 27 '20 at 17:58