Eckpunkte ohne Schleifen
Ich arbeite an einem Python-Skript, um ein Netz zu exportieren. Ich muss Normalen exportieren, daher verwende ich diesen Code:
def get_custom_vertex_normals(mesh_obj):
mesh_obj.data.calc_normals_split()
nrm_avg_list = [None] * len(mesh_obj.data.vertices)
for loop in mesh_obj.data.loops:
nrm_avg_list[loop.vertex_index] = (loop.normal.x, loop.normal.y, loop.normal.z)
return nrm_avg_list
(Wie von @batFinger hervorgehoben, übernimmt diese Methode die Informationen aus der letzten Schleife, die denselben Scheitelpunkt aufweist. Dies ist für meinen eigenen Workflow in Ordnung, da ich vor dem Export Normalen zusammenführe, aber Leser dieser Frage sollten seine Methode verwenden, wenn Sie wollen durchschnittliche Normalen für einen Scheitelpunkt.
Das Problem ist nrm_avg_list, dass Elemente Nonedarauf sind. Haben einige Debugging und effektiv hatten diese Vertices keine Schleifen auf ihnen.
Ich habe versucht, mein Netz zu bereinigen (lose Geometrie zu löschen), aber diese Scheitelpunkte sind noch vorhanden (und ich kann sie im Ansichtsfenster nicht finden).
Wie soll ich diese Schurkenscheitelpunkte reinigen? Gibt es eine Möglichkeit, bpy.opsdiese Eckpunkte mithilfe der Python-API ( wenn möglich zu vermeiden ) einfach zu entfernen?
Antworten
Bmesh-Skript zum Entfernen von Verts, die nicht mit Gesichtern verknüpft sind
import bpy
import bmesh
from bpy import context
ob = context.object
me = ob.data
# clean all verts not connected to faces
bm = bmesh.new()
bm.from_mesh(me)
bmesh.ops.delete(
bm,
geom=[v for v in bm.verts if not v.link_faces],
context='VERTS', # default
)
bm.to_mesh(me)
Bezüglich Ihrer Fragemethode
Bei der Fragemethode geht es darum, dass derselbe Vert Mitglied vieler Schleifen sein kann. Nur der Scheitelpunkt in der letzten Schleife wird Ihrer Liste zugewiesen.
Suchen Sie mit einer bis vielen Beziehungen wie dieser, dass die defaultdictKlasse collectionsbeim Erstellen mit einem listSchlüssel einen Standardwert von hat list()oder an []den angehängt werden kann.
import bpy
from collections import defaultdict
def get_custom_vertex_normals(me):
me.calc_normals_split()
loop_norms = defaultdict(list)
for loop in me.loops:
loop_norms[loop.vertex_index].append(loop.normal)
return loop_norms
ob = bpy.context.object
loop_norms = get_custom_vertex_normals(ob.data)
for i, normals in loop_norms.items():
print(i, [tuple(round(x, 4) for x in v) for v in normals])
Bei Ausführung auf dem Standardwürfel werden folgende Ausgaben ausgeführt:
0 [(0.0, 0.0, -1.0), (1.0, -0.0, 0.0), (0.0, 1.0, 0.0)]
1 [(0.0, 0.0, -1.0), (1.0, -0.0, 0.0), (-0.0, -1.0, -0.0)]
2 [(0.0, 0.0, -1.0), (-0.0, -1.0, -0.0), (-1.0, 0.0, -0.0)]
3 [(0.0, 0.0, -1.0), (-1.0, 0.0, -0.0), (0.0, 1.0, 0.0)]
4 [(0.0, 0.0, 1.0), (1.0, -0.0, 0.0), (0.0, 1.0, 0.0)]
7 [(0.0, 0.0, 1.0), (-1.0, 0.0, -0.0), (0.0, 1.0, 0.0)]
6 [(0.0, 0.0, 1.0), (-0.0, -1.0, -0.0), (-1.0, 0.0, -0.0)]
5 [(0.0, 0.0, 1.0), (1.0, -0.0, 0.0), (-0.0, -1.0, -0.0)]
dh jeder Vert hat 3 Schleifen für jedes Gesicht, zu dem er gehört.
Die durchschnittliche Normalen könnten über berechnet werden
avge_normal = sum(normals, Vector()) / len(normals)
oder
avge_normal = sum(normals, Vector()).normalized()
um einen normalisierten Summenvektor zu erhalten. was, wenn auf Standardwürfel ausgeführt, in oben bearbeitet
for i, normals in loop_norms.items():
print(i, sum(normals, Vector()).normalized())
Ausgänge
0 <Vector (0.5774, 0.5774, -0.5774)>
1 <Vector (0.5774, -0.5774, -0.5774)>
2 <Vector (-0.5774, -0.5774, -0.5774)>
3 <Vector (-0.5774, 0.5774, -0.5774)>
4 <Vector (0.5774, 0.5774, 0.5774)>
7 <Vector (-0.5774, 0.5774, 0.5774)>
6 <Vector (-0.5774, -0.5774, 0.5774)>
5 <Vector (0.5774, -0.5774, 0.5774)>
Das könnte eher dem Ergebnis entsprechen, nach dem Sie suchen.
Um Scheitelpunkte mit Standard-API auszuwählen, müssen Sie die Auswahl aufheben und den Bearbeitungsmodus verlassen. Das Setzen von .select auf False funktioniert nicht. Mit diesem Ansatz wird nur das Setzen von True unterstützt.
import bpy
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
for v in bpy.context.object.data.vertices:
if v.co[1] > 0:
v.select = True
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.delete(type='VERT')