1
$\begingroup$

I am trying to subdivide the following mesh which is split in 3 objects and each object is structured from quads:

enter image description here

I tried both the following two functions:

def subdivide_objects():    
    obs = [o for o in bpy.data.objects
        if o.type == 'MESH' and (o.name == "Wall" or o.name == "Ceiling" or o.name == "Floor")]
        
    for obj in obs:
        me = obj.data
        # New bmesh
        bm = bmesh.new()
        # load the mesh
        bm.from_mesh(me)            
        
        bmesh.ops.subdivide_edges(bm, edges=bm.edges, cuts=12, use_grid_fill=True)

        # Write back to the mesh
        bm.to_mesh(me)
        me.update()
        
def post_process_objects():
    bpy.ops.object.select_all(action='DESELECT') # Deselect all objects
    
    for o in ("Wall", "Ceiling", "Floor"):
       obj = bpy.context.scene.objects.get(o)
       bpy.context.view_layer.objects.active = obj
       if obj: 
           obj.select_set(True)
                  
           # Get into edit mode
           bpy.ops.object.mode_set(mode="EDIT")
            
           # Subdivide faces
           bpy.ops.mesh.subdivide(number_cuts=12)

           # Return back to object mode
           bpy.ops.object.mode_set(mode="OBJECT")
        
           bpy.ops.object.select_all(action='DESELECT') # Deselect all objects 

but for some reason both are not giving the desired result, but as you can see a faulty one:

enter image description here

Any idea what I am missing here (attached the .blend file)?


Update:

After applying @Lucca's solution, for some reason I am still facing the same problem on some specific parts of the plane as you can see in the following images:

enter image description here

enter image description here

It doesn't seem that I have duplicate vertices or something now thus ny idea why still the subdivide operator does not work properly.


Example for @batFINGER 's solution:

Still problematic:

enter image description here

$\endgroup$
3
$\begingroup$

Using same code from Add Cuboid.

enter image description here Test Run, first linked mesh in question, bisecting (2, 2, 2) 3x be same as running once with (8, 8, 8)

Another take on this is to use the same method as outlined in https://blender.stackexchange.com/a/102239/15543

Since all the edges are aligned in X, Y and Z can select on each and cut.

Note this is not joining the meshes, rather subdividing the axis aligned edges of each.

import bpy
import bmesh

from mathutils import Matrix

def subdivide(mesh, subs=(2, 2, 2)):
    bm = bmesh.new()
    bm.from_mesh(mesh)
        
    axes = [axis for axis in Matrix().to_3x3()]

    for cuts, axis in zip(subs, axes):
        def aligned(e):
            dir = (e.verts[1].co - e.verts[0].co).normalized()
            return abs(dir.dot(axis)) > 0.5
        if cuts == 1:
            continue
        bmesh.ops.subdivide_edges(bm,
            edges=[e for e in bm.edges if aligned(e)],
            use_grid_fill=True,
            cuts=cuts - 1)    
    bm.to_mesh(mesh)
    
for ob in bpy.context.selected_objects:
    if ob.type == 'MESH':
        subdivide(ob.data, (2, 2, 2))

By Edge Length, rather than cuts.

enter image description here Result on first linked mesh in question using method below

enter image description here Result on problematic mesh, converted to all quads. Notice thought that the walls are cut to not match ceiling so grids do not line up. They will (as shown above) if the wall edges match the corresponding roof / ceiling edge lengths.

Instead of cutting all edges the same, can instead keep to a minimal edge length, ie the longer the edge the more the cuts.

import bpy
import bmesh
from mathutils import Matrix, Vector
from collections import defaultdict
from math import ceil
     
def subdivide(mesh, subs=(1, 1, 1)):
    bm = bmesh.new()
    bm.from_mesh(mesh)
        
    axes = [axis for axis in Matrix().to_3x3()]

    for min_length, axis in zip(subs, axes):
        def aligned(e):
            dir = (e.verts[1].co - e.verts[0].co).normalized()
            return abs(dir.dot(axis)) > 0.5
        edges=[e for e in bm.edges if aligned(e)]
        pool_edges = defaultdict(list)
        for e in edges:
            l = e.calc_length()
            cuts = ceil(l / min_length)
            pool_edges[cuts].append(e) 
        for cuts, edges in pool_edges.items():
            if cuts == 1:
                continue
            bmesh.ops.subdivide_edges(bm,
                edges=edges,
                use_grid_fill=True,
                cuts=cuts - 1)    
    bm.to_mesh(mesh)

for ob in bpy.context.selected_objects:
    if ob.type == 'MESH':
        subdivide(ob.data, (0.5, 0.5, 0.5))

EDIT.

Re problematic mesh in question

enter image description here The face from ceiling not subdividing is a 7 edge ngon.

Having followed the progression of this there is an expectation that there are no doubles, and no ngons in the mesh. The "problematic" roof mesh shown in question has both. The floor has similar issues.

could clean by removing doubles, and removing inline verts, however this should be done prior when generating the initial floor-plan.

    bmesh.ops.remove_doubles(
            bm,
            verts=bm.verts,
            dist=1e-4,
            )
    bmesh.ops.dissolve_verts(
            bm,
            verts=[
                v for v in bm.verts
                if len(v.link_edges) == 2 and
                    abs((v.link_edges[0].other_vert(v).co - v.co).angle(
                     v.co - v.link_edges[1].other_vert(v).co)) <= 1e-4
                     ]
            )
$\endgroup$
8
  • $\begingroup$ thanks for the response. As usual a nice answer, however testing your code sometimes I am still getting not a correct subdivision. Check on the updated example I've added based on your solution in my initial post. $\endgroup$
    – ttsesm
    Feb 9 at 13:01
  • 1
    $\begingroup$ Edited re it being a problematic mesh. $\endgroup$
    – batFINGER
    Feb 9 at 14:12
  • $\begingroup$ Thanks a lot :-). $\endgroup$
    – ttsesm
    Feb 9 at 14:16
  • 1
    $\begingroup$ @ttsesm cheers. Have added re sub'd longer edges more than shorter. $\endgroup$
    – batFINGER
    Feb 9 at 15:31
  • $\begingroup$ That's neat, many thanks for your time. $\endgroup$
    – ttsesm
    Feb 10 at 21:28
4
$\begingroup$

It's not a problem with your code, but rather with your base objects. You have several overlapping vertices and edges in there. Take a look at this screenshot: A screenshot of two overlapping vertices

See how there is no orange line indicating connected edges to the left? If I pull the vertex point to the right, this happens: A screenshot of the overlapping vertices separated

This kind of 'malformed' model will play havoc with expected outputs.

There are quite a few vertices like that in your model. Fixing them by hand can be tedious, so it's a good idea to start with using Blender's 'Merge vertices by distance' functionality. In newer versions of Blender (I'm using 2.91, don't have a 2.8 install to check right now), this can be accessed by selecting two ore more vertices (using A to select all will do in your case), then pressing M -> By Distance: A screenshot of the 'Merge Vertices' functionality

Just repeat this for each object, then run your script again: A screenshot of the subdivided object

I assume that looks like what you expected.

I've attached a .blend file with the fix I did:

$\endgroup$
2
  • $\begingroup$ Thanks a lot, indeed the issue was the duplicate vertices. For completeness, in python if someone wants to achieve the same result he can use bpy.ops.mesh.remove_doubles(threshold = 0.05) in edit mode. $\endgroup$
    – ttsesm
    Jan 18 at 10:57
  • $\begingroup$ The problem with the subdivision is still chasing me finally. Check on my update in the initial post. It doesn't seem that I have any duplicate vertices or something now but for some reason parts of the plane are not subdivided. $\endgroup$
    – ttsesm
    Feb 9 at 10:42

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.