Nội suy độ sâu cho bộ đệm z, với đường quét


10

Tôi phải viết phần mềm rasterizer 3d của riêng mình và cho đến nay tôi có thể chiếu mô hình 3d của mình làm bằng hình tam giác vào không gian 2d:

Tôi xoay, dịch và chiếu các điểm của mình để có được đại diện không gian 2d cho mỗi tam giác. Sau đó, tôi lấy 3 điểm tam giác và tôi thực hiện thuật toán quét (sử dụng phép nội suy tuyến tính) để tìm tất cả các điểm [x] [y] dọc theo các cạnh (trái và phải) của các tam giác, để tôi có thể quét tam giác theo chiều ngang, theo từng hàng và điền nó với pixel.

Những công việc này. Ngoại trừ tôi cũng phải thực hiện đệm z. Điều này có nghĩa là khi biết tọa độ z được xoay và dịch của 3 đỉnh của tam giác, tôi phải nội suy tọa độ z cho tất cả các điểm khác mà tôi tìm thấy bằng thuật toán scanline của mình.

Khái niệm này có vẻ đủ rõ ràng, trước tiên tôi tìm thấy Za và Zb với các tính toán sau:

var Z_Slope = (bottom_point_z - top_point_z) / (bottom_point_y - top_point_y);
var Za = top_point_z + ((current_point_y - top_point_y) * Z_Slope);

Sau đó, với mỗi Zp, tôi thực hiện phép nội suy tương tự theo chiều ngang:

var Z_Slope = (right_z - left_z) / (right_x - left_x);
var Zp = left_z + ((current_point_x - left_x) * Z_Slope);

nhập mô tả hình ảnh ở đây

Và nếu z hiện tại gần với người xem hơn z trước đó ở chỉ số đó thì hãy ghi màu vào bộ đệm màu VÀ ghi z mới vào bộ đệm z. (hệ tọa độ của tôi là x: left -> right; y: top -> bottom; z: khuôn mặt của bạn -> màn hình máy tính;)

Vấn đề là, nó đi haywire. Dự án ở đây và nếu bạn chọn nút radio "Bộ đệm Z", bạn sẽ thấy kết quả ... ( lưu ý rằng tôi sử dụng thuật toán của họa sĩ (-only- để vẽ khung dây) trong chế độ "Bộ đệm Z" cho mục đích gỡ lỗi )

PS: Tôi đã đọc ở đây rằng bạn phải biến z thành đối ứng của chúng (nghĩa là z = 1/z) trước khi bạn nội suy. Tôi đã thử điều đó, và dường như không có thay đổi. Tôi đang thiếu gì? (bất cứ ai cũng có thể làm rõ, chính xác nơi bạn phải biến z thành 1 / z và nơi (nếu) để biến nó trở lại?)

[EDIT] Đây là một số dữ liệu về giá trị z tối đa và tối thiểu tôi nhận được:

    max z: 1;                  min z: -1;                 //<-- obvious, original z of the vertices of the triangles
    max z: 7.197753398761272;  min z: 3.791703256899924;   //<-- z of the points that were drawn to screen (you know, after rotation, translation), by the scanline with zbuffer, gotten with interpolation but not 1/z.
    max z: 0.2649908532179404; min z: 0.13849507306889008;//<-- same as above except I interpolated 1/z instead of z.
//yes, I am aware that changing z to 1/z means flipping the comparison in the zBuffer check. otherwise nothing gets drawn.

Trước khi tôi đi vào việc sửa lỗi, ai đó có thể xác nhận rằng khái niệm của tôi cho đến nay là chính xác không?

[EDIT2]

Tôi đã giải quyết được bộ đệm z. Hóa ra, thứ tự vẽ không bị rối tung cả. Các tọa độ z đã được tính toán chính xác.

Vấn đề là, trong nỗ lực tăng tốc độ khung hình của tôi, tôi đã vẽ các hộp 4px / 4px, mỗi pixel thứ 4, thay vì các pixel thực trên màn hình. Vì vậy, tôi đã vẽ 16px cho mỗi pixel, nhưng chỉ kiểm tra bộ đệm z cho một trong số chúng. Tôi là một boob như vậy.

TL / DR: Câu hỏi vẫn đứng: Làm thế nào / tại sao / khi nào bạn phải sử dụng đối ứng của Z (như trong 1 / z) thay vì Z? Bởi vì ngay bây giờ, mọi thứ đều hoạt động. (không có sự khác biệt đáng chú ý).


Re: "Và tất nhiên tôi thêm vào zBuffer, nếu z hiện tại gần với người xem hơn giá trị trước đó tại chỉ mục đó." Tôi không rõ ràng với bạn rằng bạn đã nói rằng bạn muốn nói gì nhưng muốn chắc chắn rằng ý của bạn là "nếu z hiện tại gần với người xem hơn z trước đó ở chỉ số đó, hãy viết màu vào bộ đệm màu VÀ viết z mới vào bộ đệm z "Mục đích của bộ đệm z là chặn ghi màu nếu một màu tại pixel đó đã được ghi gần mắt máy ảnh hơn.
Alturis

Đúng rồi. Xin lỗi, đã muộn khi tôi nói câu hỏi của tôi. Tôi sẽ sửa lại.
Spectraljump

Câu trả lời:


5

Trả lời nhanh: Z không phải là hàm tuyến tính của (X ', Y'), nhưng 1 / Z là. Vì bạn nội suy tuyến tính, bạn nhận được kết quả chính xác cho 1 / Z, nhưng không cho Z.

Bạn không để ý vì miễn là so sánh giữa Z1 và Z2 là chính xác, zbuffer sẽ làm đúng, ngay cả khi cả hai giá trị đều sai. Bạn chắc chắn sẽ nhận thấy khi bạn thêm ánh xạ kết cấu (và để trả lời câu hỏi bạn sẽ có sau đó: nội suy 1 / Z, U / Z và V / Z, và xây dựng lại U và V từ các giá trị này: U = (U / Z) / (1 / Z), V = (V / Z) / (1 / Z). Bạn sẽ cảm ơn tôi sau)

Một ví dụ. Lấy một tờ giấy. Chế độ xem từ trên xuống, vì vậy hãy quên tọa độ Y. X là trục hoành, Z là trục tung, camera nằm ở (0, 0), mặt phẳng chiếu là z = 1.

Xét các điểm A (-2, 2) và B (2, 4). Điểm giữa M của đoạn AB là (0, 3). Càng xa càng tốt.

Bạn chiếu A vào A ': X' = X / Z = -1, vì vậy A 'là (-1, 1). Tương tự, B 'là (0,5, 1). Nhưng lưu ý rằng hình chiếu của M là (0, 1), KHÔNG phải là trung điểm của A'B '. Tại sao? Bởi vì nửa bên phải của phân khúc nằm xa máy ảnh hơn nửa bên trái, nên nó trông nhỏ hơn.

Vậy chuyện gì xảy ra nếu bạn cố tính Z của M 'bằng phép nội suy tuyến tính? dx = (0,5 - -1) = 1,5, dz = (4 - 2) = 2, vì vậy với M 'trong đó X' = 0, Z nội suy tuyến tính là zA + (dz / dx) (x - xA) = 2 + (2 / 1,5) (0 - -1) = 2 + 1.333 = 3.3333 - KHÔNG phải 3!

Tại sao? Bởi vì với mỗi bước theo hướng X ', bạn không di chuyển cùng một lượng theo hướng Z (hay nói cách khác, Z không phải là hàm tuyến tính của X'). Tại sao? Bởi vì bạn càng đi đúng, phân khúc càng xa máy ảnh, do đó, một pixel thể hiện khoảng cách xa hơn trong không gian.

Cuối cùng, điều gì xảy ra nếu bạn nội suy 1 / Z thay thế? Đầu tiên bạn tính 1 / Z tại A và B: 0,5 và 0,25 tương ứng. Sau đó, bạn nội suy: dx = (0,5 - -1) = 1,5, dz = (0,25 - 0,5) = -0,25, vì vậy tại X '= 0 bạn tính 1 / Z = 0,5 + (-0,25 / 1,5) * (0 - -1) = 0,3333. Nhưng đó là 1 / Z, vì vậy giá trị của Z là ... chính xác, 3. Như vậy.

Vâng, toán học là tuyệt vời.


1
Ồ, và liên quan đến "khi": tính các giá trị 1 / Z trước khi bắt đầu raster hóa tam giác (ví dụ ngay trước vòng lặp dọc), do đó bạn sẽ được nội suy 1 / Z ở bên trái và bên phải của đường quét. Nội suy các tuyến tính này (KHÔNG thực hiện lại 1 / Z - các giá trị được nội suy đã là 1 / Z!) Và hoàn tác biến đổi ngay trước khi kiểm tra zbuffer.
ggambett

1
Và cuối cùng, tại sao. Một mặt phẳng (trong đó tam giác được nhúng) là Ax + By + Cz + D = 0. z là hàm tuyến tính rõ ràng của (x, y). Bạn chiếu sao cho x '= x / z và y' = y / z. Từ đó, x = x'z và y = y'z. Nếu bạn thay thế chúng trong phương trình ban đầu, bạn sẽ nhận được Ax'z + By'x + Cz + D = 0. Bây giờ z = -D / (Ax '+ By' + C), trong đó rõ ràng z không phải là hàm tuyến tính của (x ', y'). Nhưng 1 / z do đó (Ax '+ By' + C) / -D, là hàm tuyến tính của (x ', y').
ggambett

1
Bạn biết đấy, tôi đã đọc khá nhiều bài báo và khóa học, và không ai trong số chúng khá rõ ràng như câu trả lời của bạn. Đối với hậu thế, tôi cũng sẽ lưu ý rằng "Các chữ cái" U "và" V "biểu thị các trục của kết cấu 2D vì" X "," Y "và" Z "đã được sử dụng để biểu thị các trục của đối tượng 3D trong mô hình không gian. Kết cấu UV cho phép đa giác tạo nên một vật thể 3D được vẽ bằng màu từ hình ảnh. " - Wikipedia - UV Mapping
Spectraljump

Vui mừng khi nghe điều đó. Trên thực tế, tôi đã dạy Đồ họa máy tính ở kiếp trước :)
ggambett

Cảm ơn rất nhiều - tôi đã luôn tò mò về điều này - và tôi không biết liệu mình có tìm được câu trả lời hay hơn không! +1
Codemith 18/2/13
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.