1
$\begingroup$

I have the following scene with multiple objects:

enter image description here

It is mainly a cad model so as you can see some of the faces on some of the objects are different larger in comparison to some others. What I would like to do is to subdivide at least the big ones if not all of them (considering that some small ones which would fulfill the area threshold are long they might also need to be restructured) so that they fulfill an area constraint. Also I would like the new subdivided objects not to lose their material/size/name properties.

Moreover, considering that I would need to do that for a bunch of scenes (to the extend of a couple of hundreds) I do not know whether it would be possible to address the task in a GPU mode or something (to be honest since I haven't tried it in practice, CPU might be fast enough).

I found a similar thread here subdivide all faces whose area is bigger than 1mm until each face area is smaller than 1mm but the solution is described in UI rather in a python script which I would prefer.


Update:

Testing the solution below from @batFINGER with the remesh operator did not give the desired result (I've tested it with the settings 'SHARP' and octree_depth=7-10, which they seemed to be the most relevant to keep the initial geometry intact). Moreover, it seems to destroy the UV texture mapping which I do not want if possible. I've tried dyntopo from the UI, but it also seems to create problems with the texture mapping and keeping the initial geometry intact.

E.g. Remesh operator with octree_depth=7:

bm = bmesh.new()
dg = context.evaluated_depsgraph_get()        
for o in obs:
    rm = o.modifiers.new("Remesh", type='REMESH')
    rm.mode = 'SHARP'
#    rm.sharpness = 100
    rm.octree_depth = 7
    #rm.scale = 0.2
    #rm.threshold = 0.5
    dg.update()
    bm.from_object(o,dg)
    o.modifiers.clear()
    bm.to_mesh(o.data)
    bm.clear()
bm.free()

enter image description here

From what I understood if I want to keep the geometry intact I really need to create a lot of tiny faces which I do not really want and still this is not warrantied. For my case the size of faces that the furniture have should be sufficient also for my big plane objects, i.e. ceiling, floor, walls, etc.

Thus I've tried to follow some of the examples given in the following links:

https://blender.stackexchange.com/a/93597/106722

https://blender.stackexchange.com/a/168193/106722

https://blender.stackexchange.com/a/120244/106722

https://blender.stackexchange.com/a/163936/106722

and I 've written the following code where I am trying to subdivide my objects based on the edges length:

import bpy
from mathutils import Vector
from bpy import context
import numpy as np
import bmesh

def subdivide_edge_cuts(obj, cuts=1):
    
    me = obj.data
    # New bmesh
    bm = bmesh.new()
    # load the mesh
    bm.from_mesh(me)
    
    ### collapse short edges
    edges_len_average = 0
    edges_count = 0
    shortest_edge = 10000
    for edge in bm.edges:
        if True:#edge.is_boundary:
            edges_count += 1
            length = edge.calc_length()
            edges_len_average += length
            if length < shortest_edge:
                shortest_edge = length
                
    edges_len_average = edges_len_average/edges_count
    
    print("Total edges: {}".format(len(bm.edges)))
    print("Shortest edge: {}".format(shortest_edge))
    print("Average edge: {}".format(edges_len_average))
 
    subdivide_edges = []
    for edge in bm.edges:
        cut_count = int(edge.calc_length()/shortest_edge)*cuts
        if cut_count <= 0:
            cut_count = 0

        subdivide_edges.append([edge,cut_count])

    print("Edges to subdivide: {}\n".format(len(subdivide_edges)))  

    # group edges by found cut
    grouped_edges = {}            
    for edge, cut in subdivide_edges:
        grouped_edges.setdefault(cut, []).append(edge)
        
    # This works
#    bmesh.ops.subdivide_edges(bm, edges=list(np.array(subdivide_edges)[:,0]), cuts=5, use_grid_fill=True)

    # This doesn't work
    for cut in grouped_edges:
        bmesh.ops.subdivide_edges(bm, edges=grouped_edges[cut], cuts=cut, use_grid_fill=True)

    # Write back to the mesh
    bm.to_mesh(me)
    me.update()

bpy.ops.object.select_all(action='SELECT')
obs = [o for o in context.selected_objects
        if o.type == 'MESH']

for ob in obs:
    subdivide_edge_cuts(ob)

But it doesn't really seem to work. If on the other hand subdivide all the edges with with a fixed cut then it seems to work but again all the edges are cut in a similar way which is not what I want.

For example this is the output with a fixed cut of 5 in the walls and ceiling:

enter image description here

The output seems fine except the faces in the boundaries with the long edges which are getting messy (this is also something that I need to find a way to address if possible).

Any idea why my for loop for subdividing the edges by cut does not work. Any other suggestion for addressing the problem is also welcome.

$\endgroup$

1 Answer 1

4
$\begingroup$

Remesh modifier.

One of the answers linked to recommends using the remesh modifier, without looking into what would be the correct settings, ie this is the code to "do it" but haven't investigated the settings, and what values to set.

Loop over the objects, add a modifier, get the deformed mesh, remove modifiers update mesh.

import bpy
import bmesh
from bpy import context

obs = [o for o in context.selected_objects
        if o.type == 'MESH']
bm = bmesh.new()
dg = context.evaluated_depsgraph_get()        
for o in obs:
    rm = o.modifiers.new("Remesh", type='REMESH')
    rm.mode = 'BLOCKS'
    #rm.scale = 0.2
    #rm.threshold = 0.5
    dg.update()
    bm.from_object(
            o,
            dg)
    o.modifiers.clear()
    bm.to_mesh(o.data)
    bm.clear()
bm.free()
$\endgroup$
2
  • $\begingroup$ Thanks @batFINGER, I will have a check on the Remesh settings and report back. $\endgroup$
    – ttsesm
    Sep 22, 2020 at 16:45
  • $\begingroup$ I've played a bit more with the remesh modifier with the settings from docs.blender.org/api/current/bpy.types.RemeshModifier.html but it didn't really work as expected, see my update in the initial post. $\endgroup$
    – ttsesm
    Sep 24, 2020 at 12:41

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.