Subdiviser les faces des objets par zone dans le script python

Sep 22 2020

J'ai la scène suivante avec plusieurs objets:

Il s'agit principalement d'un modèle CAO, de sorte que vous pouvez voir que certaines des faces de certains objets sont plus grandes que d'autres. Ce que je voudrais faire, c’est subdiviser au moins les grands, sinon tous (étant donné que certains petits qui rempliraient le seuil de superficie sont longs, ils pourraient également devoir être restructurés) afin qu’ils remplissent une contrainte de superficie. Je voudrais également que les nouveaux objets subdivisés ne perdent pas leurs propriétés de matériau / taille / nom.

De plus, étant donné que j'aurais besoin de le faire pour un tas de scènes (jusqu'à quelques centaines), je ne sais pas s'il serait possible de traiter la tâche en mode GPU ou quelque chose (pour être honnête puisque je je ne l'ai pas essayé en pratique, le processeur pourrait être assez rapide)

J'ai trouvé un fil similaire ici pour subdiviser toutes les faces dont la zone est supérieure à 1 mm jusqu'à ce que chaque zone de face soit inférieure à 1 mm, mais la solution est décrite dans l'interface utilisateur plutôt dans un script python que je préférerais.


Mettre à jour:

Tester la solution ci-dessous à partir de @batFINGER avec l'opérateur remesh n'a pas donné le résultat souhaité (je l'ai testé avec les paramètres 'SHARP' et octree_depth=7-10, qui semblaient être les plus pertinents pour conserver la géométrie initiale intacte). De plus, cela semble détruire le mappage de texture UV dont je ne veux pas si possible. J'ai essayé dyntopo à partir de l'interface utilisateur, mais cela semble également créer des problèmes avec le mappage de texture et garder la géométrie initiale intacte.

Ex. Opérateur Remesh avec 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()

D'après ce que j'ai compris, si je veux garder la géométrie intacte, j'ai vraiment besoin de créer beaucoup de minuscules visages dont je ne veux pas vraiment et qui n'est toujours pas garanti. Pour mon cas, la taille des faces que les meubles ont devrait être suffisante également pour mes grands objets plans, c'est-à-dire le plafond, le sol, les murs, etc.

J'ai donc essayé de suivre certains des exemples donnés dans les liens suivants:

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

et j'ai écrit le code suivant dans lequel j'essaie de subdiviser mes objets en fonction de la longueur des bords:

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)

Mais cela ne semble pas vraiment fonctionner. Si par contre subdivisez tous les bords avec une coupe fixe, cela semble fonctionner mais encore une fois, tous les bords sont coupés de la même manière, ce qui n'est pas ce que je veux.

Par exemple, voici la sortie avec une coupe fixe de 5 dans les murs et le plafond:

La sortie semble correcte sauf les faces dans les limites avec les bords longs qui deviennent désordonnés (c'est aussi quelque chose que je dois trouver un moyen de résoudre si possible).

Toute idée de la raison forpour laquelle ma boucle de subdivision des bords par coupe ne fonctionne pas. Toute autre suggestion pour résoudre le problème est également la bienvenue.

Réponses

2 batFINGER Sep 22 2020 at 16:09

Modificateur Remesh.

L'une des réponses liées à recommande d'utiliser le modificateur remesh, sans examiner quels seraient les paramètres corrects, c'est -à- dire que c'est le code pour "le faire" mais n'a pas examiné les paramètres, et quelles valeurs définir.

Faites une boucle sur les objets, ajoutez un modificateur, récupérez le maillage déformé, supprimez les modificateurs de mise à jour du maillage.

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