Unterteilen Sie Objektflächen nach Flächen im Python-Skript

Sep 22 2020

Ich habe die folgende Szene mit mehreren Objekten:

Es handelt sich hauptsächlich um ein CAD-Modell, sodass einige der Gesichter einiger Objekte im Vergleich zu anderen Objekten größer sind. Was ich tun möchte, ist, zumindest die großen, wenn nicht alle, zu unterteilen (wenn man bedenkt, dass einige kleine, die die Flächenschwelle erfüllen würden, lang sind, müssen sie möglicherweise auch umstrukturiert werden), damit sie eine Flächenbeschränkung erfüllen. Außerdem möchte ich, dass die neuen unterteilten Objekte ihre Material- / Größen- / Namenseigenschaften nicht verlieren.

Wenn ich bedenke, dass ich das für eine Reihe von Szenen (im Umfang von ein paar Hundert) tun müsste, weiß ich nicht, ob es möglich wäre, die Aufgabe in einem GPU-Modus oder so zu erledigen (um ehrlich zu sein, seit ich habe es in der Praxis nicht ausprobiert, die CPU ist möglicherweise schnell genug).

Ich habe hier einen ähnlichen Thread gefunden, der alle Flächen unterteilt, deren Fläche größer als 1 mm ist, bis jede Fläche kleiner als 1 mm ist, aber die Lösung wird in der Benutzeroberfläche eher in einem Python-Skript beschrieben, das ich bevorzugen würde.


Aktualisieren:

Das Testen der folgenden Lösung von @batFINGER mit dem Operator remesh ergab nicht das gewünschte Ergebnis (ich habe es mit den Einstellungen 'SHARP' und getestet octree_depth=7-10, die für die Beibehaltung der ursprünglichen Geometrie am relevantesten zu sein schienen). Außerdem scheint es die UV-Texturabbildung zu zerstören, die ich wenn möglich nicht möchte. Ich habe Dyntopo über die Benutzeroberfläche ausprobiert, aber es scheint auch Probleme mit der Texturabbildung und der Beibehaltung der ursprünglichen Geometrie zu verursachen.

ZB Remesh-Operator mit 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()

Soweit ich verstanden habe, muss ich wirklich viele kleine Gesichter erstellen, die ich nicht wirklich will, wenn ich die Geometrie intakt halten möchte, und dennoch ist dies nicht garantiert. Für meinen Fall sollte die Größe der Gesichter, die die Möbel haben, auch für meine großen Flugzeugobjekte ausreichen, dh Decke, Boden, Wände usw.

Daher habe ich versucht, einigen der in den folgenden Links angegebenen Beispiele zu folgen:

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

und ich habe den folgenden Code geschrieben, in dem ich versuche, meine Objekte basierend auf der Kantenlänge zu unterteilen:

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)

Aber es scheint nicht wirklich zu funktionieren. Wenn andererseits alle Kanten mit einem festen Schnitt unterteilt werden, scheint dies zu funktionieren, aber auch hier werden alle Kanten auf ähnliche Weise geschnitten, was ich nicht möchte.

Dies ist beispielsweise die Ausgabe mit einem festen Schnitt von 5 in Wänden und Decke:

Die Ausgabe scheint in Ordnung zu sein, mit Ausnahme der Flächen in den Grenzen mit den langen Kanten, die unordentlich werden (dies ist auch etwas, das ich nach Möglichkeit finden muss, um sie anzusprechen).

Jede Idee, warum meine forSchleife zum Unterteilen der Kanten nach Schnitt nicht funktioniert. Jeder andere Vorschlag zur Lösung des Problems ist ebenfalls willkommen.

Antworten

2 batFINGER Sep 22 2020 at 16:09

Remesh-Modifikator.

Eine der Antworten verknüpft zu empfiehlt die Remesh Modifier, ohne in der Suche , was die richtigen Einstellungen wären, dh das ist der Code „do it“ , aber haben die Einstellungen nicht untersucht, und welche Werte zu setzen.

Schleife über die Objekte, füge einen Modifikator hinzu, erhalte das deformierte Netz, entferne das Modifikator-Aktualisierungsnetz.

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