Dọc không có vòng

Sep 23 2020

Tôi đang làm việc trên một tập lệnh Python để xuất một lưới. Tôi cần xuất định mức, vì vậy tôi sử dụng mã này:

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

(Như đã chỉ ra bởi @batFinger, phương pháp này sẽ lấy thông tin từ vòng lặp cuối cùng có cùng đỉnh. Điều này tốt cho quy trình làm việc của riêng tôi vì tôi đang hợp nhất các chuẩn trước khi xuất, nhưng người đọc câu hỏi này nên sử dụng phương pháp của anh ấy nếu họ muốn định mức trung bình cho một đỉnh).

Vấn đề là nrm_avg_listcuối cùng có các yếu tố Nonetrên đó. Đã thực hiện một số gỡ lỗi và hiệu quả các đỉnh này không có vòng lặp trên chúng.

Đã cố gắng làm sạch lưới của tôi (xóa hình học lỏng lẻo) nhưng các đỉnh này vẫn còn (và tôi không thể tìm thấy chúng trong khung nhìn).

Tôi nên làm thế nào để làm sạch các đỉnh bất hảo này? Có cách nào, sử dụng API Python (tránh bpy.opsnếu có thể) để loại bỏ các đỉnh này một cách đơn giản không?

Trả lời

2 batFINGER Sep 23 2020 at 11:35

Tập lệnh Bmesh để loại bỏ các chuyển từ không được liên kết với bất kỳ khuôn mặt nào

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)

Re phương pháp câu hỏi của bạn

Vấn đề với phương pháp câu hỏi là cùng một vert có thể là thành viên của nhiều vòng lặp. Chỉ đỉnh trong vòng lặp cuối cùng mới được gán cho danh sách của bạn.

Tìm với một đến nhiều mối quan hệ như thế này mà defaultdictlớp từ collectionskhi được tạo bằng một listcung cấp cho bất kỳ khóa nào một giá trị mặc định list()hoặc []có thể được nối vào.

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

khi chạy trên khối mặc định, kết quả đầu ra:

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

tức là mỗi vert có 3 vòng lặp cho mỗi mặt mà nó thuộc về.

Mức bình thường trung bình có thể được tính bằng

avge_normal = sum(normals, Vector()) / len(normals)

hoặc là

avge_normal = sum(normals, Vector()).normalized()

để có được một vectơ tổng chuẩn hóa. mà khi chạy trên khối mặc định được chỉnh sửa ở trên

for i, normals in loop_norms.items():
    print(i, sum(normals, Vector()).normalized())

đầu ra

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

có thể giống như kết quả mà bạn đang có.

Y-King Sep 23 2020 at 09:43

để chọn các đỉnh với API tiêu chuẩn, bạn cần bỏ chọn mọi thứ và để lại chế độ chỉnh sửa. Đặt .select thành False không hoạt động, chỉ hỗ trợ đặt thành True bằng cách sử dụng phương pháp này.

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