Suddividi le facce degli oggetti per area nello script Python
Ho la seguente scena con più oggetti:
È principalmente un modello cad, quindi come puoi vedere alcune facce su alcuni oggetti sono diverse più grandi rispetto ad altri. Quello che vorrei fare è suddividere almeno quelli grandi se non tutti (considerando che alcuni piccoli che soddisfano la soglia di area sono lunghi potrebbero anche dover essere ristrutturati) in modo che soddisfino un vincolo di area. Inoltre vorrei che i nuovi oggetti suddivisi non perdessero le loro proprietà materiale / dimensione / nome.
Inoltre, considerando che avrei bisogno di farlo per un mucchio di scene (fino a un paio di centinaia) non so se sarebbe possibile affrontare l'attività in modalità GPU o qualcosa del genere (ad essere sincero dato che ho non l'ho provato in pratica, la CPU potrebbe essere abbastanza veloce).
Ho trovato un thread simile qui suddividere tutte le facce la cui area è maggiore di 1 mm fino a quando ciascuna area del viso è inferiore a 1 mm, ma la soluzione è descritta nell'interfaccia utente piuttosto in uno script Python che preferirei.
Aggiornare:
Testare la soluzione di seguito da @batFINGER con l'operatore remesh non ha dato il risultato desiderato (l'ho testato con le impostazioni 'SHARP' e octree_depth=7-10, che sembravano essere le più rilevanti per mantenere intatta la geometria iniziale). Inoltre, sembra distruggere la mappatura delle texture UV che non voglio se possibile. Ho provato dyntopo dall'interfaccia utente, ma sembra anche creare problemi con la mappatura delle texture e mantenere intatta la geometria iniziale.
Es. Operatore Remesh con 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()
Da quello che ho capito se voglio mantenere intatta la geometria ho davvero bisogno di creare un sacco di facce minuscole che non voglio davvero e ancora questo non è garantito. Nel mio caso la dimensione delle facce che hanno i mobili dovrebbe essere sufficiente anche per i miei grandi oggetti aerei, es. Soffitto, pavimento, pareti, ecc.
Quindi ho provato a seguire alcuni degli esempi forniti nei seguenti link:
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
e ho scritto il seguente codice in cui sto cercando di suddividere i miei oggetti in base alla lunghezza dei bordi:
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)
Ma non sembra funzionare davvero. Se invece suddivido tutti i bordi con un taglio fisso allora sembra funzionare ma ancora una volta tutti i bordi sono tagliati in modo simile che non è quello che voglio.
Ad esempio questa è l'uscita con un taglio fisso di 5 nelle pareti e nel soffitto:
L'output sembra a posto, tranne le facce nei bordi con i bordi lunghi che stanno diventando disordinati (anche questo è qualcosa che devo trovare un modo per risolvere se possibile).
Qualche idea sul perché il mio forciclo per suddividere i bordi per taglio non funziona. Ogni altro suggerimento per affrontare il problema è ben accetto.
Risposte
Modificatore di remesh.
Una delle risposte collegate a consiglia di utilizzare il modificatore remesh, senza guardare in quali sarebbero le impostazioni corrette, ovvero questo è il codice per "farlo" ma non ha indagato le impostazioni e quali valori impostare.
Esegui il loop sugli oggetti, aggiungi un modificatore, ottieni la mesh deformata, rimuovi i modificatori, aggiorna la 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()