cách tốt nhất để tính các quy tắc đỉnh từ danh sách của Tam giác


8

xin chào, tôi là một người mới hoàn toàn trong lĩnh vực máy tính, rất xin lỗi nếu đó là một câu trả lời ngu ngốc. Tôi đang cố gắng tạo ra một công cụ 3d đơn giản từ đầu, nhiều hơn cho mục đích giáo dục hơn là sử dụng thực tế.

bây giờ tôi chỉ tính mặt bình thường. theo cách này:

tôi có một đối tượng Surface với trong danh sách của Triangle. tôi tính các quy tắc trong lớp Tam giác, theo cách này:

triangle.computeFaceNormals() {
    Vec3D u = v1.sub(v3)
    Vec3D v = v1.sub(v2)
    Vec3D normal = Vec3D.cross(u,v)
    normal.normalized()
    this.n1 = this.n2 = this.n3 = normal
}

và khi xây dựng bề mặt:

t = new Triangle(v1,v2,v3)
t.computeFaceNormals()
surface.addTriangle(t)

và tôi nghĩ rằng đây là cách tốt nhất để làm điều đó .. phải không?

Bây giờ .. điều này hoạt động, ok. nhưng ánh sáng nó không được làm mịn. Tôi đang cố gắng tính toán các tiêu chuẩn đỉnh. (Tôi đang thử nghiệm động cơ của mình với các bề mặt hình ống nên tôi có hầu hết các đỉnh được chia sẻ với nhiều hơn một hình tam giác)

Tôi đã tìm thấy thuật toán đơn giản này: đỉnh flipcode bình thường nhưng .. hei thuật toán này có .. độ phức tạp theo cấp số nhân? (nếu bộ nhớ của tôi không làm hỏng nền khoa học máy tính của tôi ..) (tạm thời .. nó có 3 vòng lặp lồng nhau .. tôi không nghĩ đó là cách tốt nhất để làm điều đó ..)

bất cứ đề nghị nào?


Ngôn ngữ này là gì? Dường như với tôi tlà kết quả của computeFaceNormals(không trả về gì), không phải là một hình tam giác.

đó là mã giả :) bạn đúng mã thực, tôi cũng đã "trả lại cái này", xin lỗi tôi đã chỉnh sửa!
nkint

Câu trả lời:


6

"Tốt nhất" là khá chủ quan - nó sẽ liên quan đến việc cân nhắc những gì bạn cần từ thuật toán so với đầu vào, độ phức tạp thời gian chạy và các thuộc tính khác.

Điều đó nói rằng, cả cách tiếp cận của bạn và cách tiếp cận FlipCode được liên kết đều hợp lý về mặt tạo ra kết quả có thể sử dụng (bạn hoàn toàn có thể sao chép 'quy tắc khuôn mặt' của mình sang từng đỉnh, nếu bạn không chia sẻ các trường hợp đỉnh thực tế giữa các tam giác, điều mà tôi không rõ trên từ mã của bạn). Các kỹ thuật khác bao gồm trọng số đóng góp của mỗi khuôn mặt bình thường bằng kích thước của góc được tạo với mỗi khuôn mặt được chia sẻ bởi đỉnh.

Bạn đúng ở chỗ cách tiếp cận FlipCode xuất hiện dưới mức tối ưu như được viết, nhưng nó có thể được chỉ định kém: không rõ liệu nó có ý định đề xuất vòng lặp thứ hai đi qua tất cả các mặt trong mô hình hay không, so với số ít các khuôn mặt có chung đỉnh trong câu hỏi. Nếu bạn có thông tin kề nhau để giảm không gian tìm kiếm của vòng lặp thứ hai, nó sẽ trở nên ít quan tâm hơn. Tất nhiên bạn có thể không có thông tin kề đó - đây là loại ý tôi muốn nói bằng cách xem xét những đầu vào nào bạn có sẵn cho thuật toán của mình.

Nếu bạn không chỉ muốn sao chép khuôn mặt bình thường vào các đỉnh hoặc bạn đang chia sẻ các đỉnh và không muốn chia chúng, bạn có thể:

foreach vertex:
   set vertex normal to (0,0,0)

foreach triangle:
   foreach vertex on that triangle:
      set vertex normal = normalize( vertex normal + face normal )

Điều này giả định rằng mỗi tam giác thực sự tham chiếu đến từng đỉnh thay vì lưu trữ một bản sao của nó - Tôi không biết bạn đang sử dụng ngôn ngữ nào nên tôi không biết liệu đó có phải là trường hợp hay không.


xin lỗi tiếng anh không phải là lang đầu tiên của tôi vì vậy mayebe tôi đã giải thích theo cách xấu những gì tôi muốn .. tôi chưa có quy tắc đỉnh! Tôi đã chỉnh sửa câu trả lời của mình một chút, hy vọng bây giờ tôi rõ ràng hơn
nkint

Không sao, tôi hiểu bạn không có quy tắc đỉnh. Mã giả mà tôi cung cấp sẽ tính toán chúng cho bạn bằng cách trước tiên đặt mức bình thường của mỗi đỉnh thành (0,0,0) và sau đó tổng hợp các quy tắc khuôn mặt cho mỗi mặt mà đỉnh chạm (dĩ nhiên là bình thường hóa lại).

5
Bạn không nên bình thường hóa thông thường theo cách này. Bạn nên bình thường hóa sau tất cả các tổng kết trong một foreach khác. Nếu có ví dụ 10 hình tam giác có cùng mức bình thường, nhưng cuối cùng là khác nhau (kết quả bình thường sẽ gần bằng với bình thường từ 10 hình tam giác), thì bạn sẽ có điều này, khi tính tổng cuối cùng: đặt đỉnh nromal = normalize (( 1,0,0) + (0,0,1)) và đó là (0,5,0,0,5), sai. Tôi hy vọng rằng tôi đã không nhầm lẫn bạn.
zacharmarz

7

Josh Petrie có quyền. Nếu bạn muốn tính toán các giá trị đỉnh, bạn nên cân trọng lượng tam giác theo góc. Nhưng bạn có thể sử dụng giải pháp ngây thơ và chỉ cần tổng hợp tất cả các quy tắc từ tất cả các mặt xung quanh đỉnh.

Vì vậy, bạn chỉ cần tính toán tất cả các quy tắc khuôn mặt và bình thường hóa chúng. Sau đó đặt tất cả các quy tắc đỉnh bằng không. Sau đó, cho mỗi mặt (tam giác) thêm bình thường của nó vào tất cả các đỉnh của nó. Sau đó bình thường hóa tất cả các quy tắc đỉnh. Và thế là xong.

Nó không quá chính xác nhưng nó có thể là đủ.

Và khuôn mặt của bạn tính toán bình thường ở trên - nó đúng nhưng bạn nên biết, bên nào bình thường. Nó có thể đi lên hoặc xuống. Nó phụ thuộc vào sản phẩm chéo - AxB không giống với BxA - nó cung cấp cho bạn vectơ đối diện.


Điểm tốt liên quan đến các sản phẩm chéo.

2

Chúng ta hãy giả sử rằng chúng ta có một khối lập phương được làm từ 6 hình chữ nhật. Chúng ta đã biết rằng đỉnh bình thường cho một khối không phải là tổng bình thường của các mặt kết nối vì cạnh sắc nét. Nếu bạn xây dựng một bản đồ giá trị đỉnh và đó là các quy tắc đỉnh khác nhau cho một khối, bạn kết thúc với 3 quy tắc cho mỗi đỉnh.

Hãy ghi nhớ điểm trên đây là cách tôi tính các quy tắc đỉnh (tôi đã kiểm tra và đang sử dụng nó).

class Face{
    uint vert_indices[3];
    vec3 surface_normal;
    vec3 vertex_normal[3];
}

Mỗi mặt theo dõi các quy tắc đỉnh để sử dụng vì hai mặt có thể chia sẻ một đỉnh không có nghĩa là đỉnh bình thường sẽ giống nhau cho mỗi mặt.

Chúng ta hãy giả sử chúng ta đang cố gắng để tính toán đỉnh bình thường đối với vert khi vẽ face2 .

vert được chia sẻ bởi face0 , face1 , face2 , face3face4 . Tất cả các mặt trên là hàng xóm theo thứ tự và face0face4 kết nối để tạo thành một vòng lặp.

Đỉnh bình thường đối với vert là tổng của tất cả các chuỗi hàng xóm kết nối với face2 bình thường. Chuỗi dừng lại nếu góc giữa hai mặt lân cận lớn hơn 0,8 radian (angle == arccos (crossSản phẩm (faceA.surface_n normal, faceB.surface_n normal)).

nếu góc giữa face0face1 là hơn 0,8 radian và góc giữa face3face4 là hơn 0,8 radian hơn đỉnh bình thường đối với vert khi vẽ face2bình thường hóa ( surfnormal1 + surfnormal2 + surfnormal3 ).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.