I have the following scene with multiple objects:
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()
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:
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.