Sử dụng độ phân giải đầy đủ của bộ đệm độ sâu để hiển thị 2D


9

Tôi đang làm việc trên một trình kết xuất từ ​​trước ra sau cho động cơ 2D bằng cách sử dụng phép chiếu chính tả. Tôi muốn sử dụng bộ đệm sâu để tránh rút tiền. Tôi có bộ đệm độ sâu 16 bit, camera ở Z = 100 nhìn vào Z = 0, zNear là 1 và zFar là 1000. Mỗi kết xuất sprite đặt tọa độ Z của nó thành các giá trị ngày càng xa, cho phép kiểm tra độ sâu bỏ qua kết xuất bất cứ điều gì bên dưới.

Tuy nhiên, tôi biết cách các vị trí Z kết thúc với các giá trị bộ đệm Z là phi tuyến tính. Tôi muốn sử dụng độ phân giải đầy đủ của bộ đệm độ sâu 16 bit, tức là cho phép 65536 giá trị duy nhất. Vì vậy, với mỗi sprite được hiển thị, tôi muốn tăng vị trí Z lên vị trí tiếp theo để tương quan với giá trị bộ đệm độ sâu duy nhất tiếp theo.

Nói cách khác, tôi muốn biến chỉ số tăng dần (0, 1, 2, 3 ...) của sprite được kéo vào vị trí Z thích hợp cho mỗi sprite để có giá trị bộ đệm độ sâu duy nhất. Tôi không chắc chắn về toán học đằng sau này. Tính toán để làm điều này là gì?

Lưu ý Tôi đang làm việc trong WebGL (về cơ bản là OpenGL ES 2) và tôi cần hỗ trợ nhiều loại phần cứng, vì vậy, trong khi các tiện ích mở rộng như gl_FragDepth có thể giúp việc này dễ dàng hơn, tôi không thể sử dụng nó vì lý do tương thích.


Tôi không thể tưởng tượng việc sử dụng bộ đệm z sẽ mang lại cho bạn nhiều hiệu suất tăng (nếu có) sau khi bạn đã thêm tất cả các cách viết, tính toán và so sánh so với sao chép họa tiết trở lại phía trước, không đề cập đến bất kỳ độ trong suốt / pha trộn alpha nào tai ương
Matt Esch

@MattEsch: Ý tưởng là tất cả những tính toán đó được thực hiện trong GPU với tốc độ cao, vì vậy thật có ý nghĩa khi làm điều đó.
Panda Pyjama

@MattEsch: FWIW này nhắm đến các GPU tích hợp của Intel, sử dụng bộ nhớ hệ thống thay vì bộ nhớ GPU chuyên dụng. Điều này làm cho chúng khá chậm và có khả năng đạt giới hạn tỷ lệ lấp đầy nếu rút quá nhiều họa tiết. Intel khuyến nghị cách tiếp cận này với tôi như một cách làm việc xung quanh nó. Có lẽ việc thực hiện kiểm tra độ sâu của họ được tối ưu hóa tốt và có thể tiết kiệm rất nhiều tỷ lệ lấp đầy. Nó vẫn còn để được nhìn thấy mặc dù, tôi chưa định hình nó!
AshleyBrain 22/05/2015

@PandaPajama khối sao chép bộ nhớ thực sự rất nhanh, vì vậy nếu bạn chỉ cần làm mờ họa tiết trên một bề mặt thì nó sẽ thực sự rất nhanh. Chi phí chính đầu tiên là lấy dữ liệu lên GPU ngay từ đầu, điều mà Ashley chỉ ra có thể tốn kém hơn trên các GPU tích hợp. Bạn thấy rằng thậm chí rất nhiều trò chơi 3d thực hiện một số lượng công việc không hề nhỏ trên CPU (như hoạt hình xương) vì tải lên dữ liệu cần thiết để thực hiện các tính toán ma trận ở vị trí đầu tiên là quá tốn kém.
Matt Esch

@MattEsch: Chỉ có rất nhiều thứ bạn có thể làm chỉ với việc làm mờ. Xoay, chia tỷ lệ và biến dạng xuất hiện trong tâm trí, nhưng cũng vì bạn có các pixel shader / đỉnh, giới hạn của những gì bạn có thể làm với phần cứng cao hơn nhiều so với những gì bạn có thể làm chỉ với việc làm mờ.
Panda Pyjama

Câu trả lời:


5

Thật vậy, các giá trị được lưu trữ trong bộ đệm z không phải là tuyến tính với tọa độ z thực tế của các đối tượng của bạn, mà là đối ứng của chúng, để mang lại độ phân giải nhiều hơn cho những gì ở gần mắt hơn so với những gì ở gần mặt phẳng phía sau.

Những gì bạn làm là bạn ánh xạ của bạn zNearđể 0và bạn zFarđến 1. Đối với zNear=1zFar=2, nó sẽ trông như thế này

Zbuffer

Cách tính toán này được xác định bởi:

z_buffer_value = k * (a + (b / z))

Ở đâu

 k = (1 << N), maximum value the Z buffer can store
 N = number of bits of Z precision
 a = zFar / ( zFar - zNear )
 b = zFar * zNear / ( zNear - zFar )
 z = distance from the eye to the object

... và z_buffer_value là một số nguyên.

Phương trình trên được mang đến cho bạn nhờ sự giúp đỡ của trang tuyệt vời này , giải thích bộ đệm z theo cách thực sự tốt.

Vì vậy, để tìm thấy sự cần thiết zcho một cái nhất định z_buffer_value, chúng tôi chỉ cần xóa z:

z = (k * b) / (z_buffer_value - (k * a))

Cảm ơn câu trả lời! Tôi hơi bối rối làm thế nào bạn có công thức cuối cùng của bạn mặc dù. Nếu tôi thực hiện z_buffer_value = k * (a + (b / z))và chỉ đơn giản là sắp xếp lại để giải quyết z, thì tôi nhận được: z = b / ((z_buffer_value / k) - a)- làm thế nào bạn đến được công thức cuối cùng khác nhau?
AshleyBrain

@AshleyBrain: bạn lấy mẫu số (v / k) - a => (v - k * a) / kvà thu gọn lại (k * b) / (v - (k * a)). Đó là kết quả tương tự.
Panda Pyjama

Ah tôi thấy. Cảm ơn câu trả lời, nó hoạt động tốt!
AshleyBrain

0

Có lẽ bạn nên thay đổi cách tiếp cận của bạn với một cái gì đó đơn giản hơn. Tôi sẽ làm gì; Giữ điều sâu Z của bạn, nhưng giữ một danh sách những gì bạn kết xuất. Sắp xếp danh sách đó dựa trên giá trị Độ sâu z và hiển thị các đối tượng theo thứ tự của danh sách.

Hy vọng điều này có thể giúp đỡ. Mọi người luôn nói với tôi để giữ cho mọi thứ đơn giản.


1
Xin lỗi, điều đó không giúp được gì nhiều. Tôi đã làm điều đó. Câu hỏi là về những vị trí Z để lựa chọn.
AshleyBrain

0

Vì bạn đã có một danh sách sắp xếp các thứ cần kết xuất (từ trước ra sau), bạn có thực sự cần tăng chỉ số Z không? Bạn không thể sử dụng "ít hơn hoặc bằng" cho "chức năng kiểm tra"? Bằng cách này, nó thực sự sẽ kiểm tra xem một pixel cụ thể đã được vẽ hay chưa.


"Ít hơn hoặc bằng" vẫn sẽ khiến mọi thứ bị rút hoàn toàn, vì mọi thứ sẽ luôn có chỉ số Z bằng nhau và do đó vượt qua bài kiểm tra độ sâu.
AshleyBrain
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.