Làm cách nào tôi có thể tạo các trường khoảng cách đã ký (2D) trong thời gian thực, nhanh?


21

Trong một câu hỏi trước đây , có ý kiến ​​cho rằng các trường khoảng cách đã ký có thể được tính toán trước, được tải trong thời gian chạy và sau đó được sử dụng từ đó.

Vì lý do tôi sẽ giải thích ở cuối câu hỏi này (đối với những người quan tâm), tôi cần tạo các trường khoảng cách trong thời gian thực.

Có một số bài báo về các phương pháp khác nhau được cho là khả thi trong môi trường thời gian thực, chẳng hạn như các phương pháp cho biến đổi khoảng cách Chamfer và biến đổi dựa trên sơ đồ Voronoi (như được đề xuất trong bài trình bày này của anh chàng nhà phát triển Pixeljunk Shooter ), nhưng Tôi (và do đó có thể được giả định là rất nhiều người khác) có một thời gian rất khó thực sự đưa chúng vào sử dụng, vì chúng thường dài, phần lớn chứa đầy toán học và không được giải thích bằng thuật toán.

Thuật toán nào bạn muốn đề xuất để tạo các trường khoảng cách trong thời gian thực (thuận lợi trên GPU) đặc biệt là xem xét chất lượng kết quả của các trường khoảng cách?

Vì tôi đang tìm kiếm một lời giải thích / hướng dẫn thực tế trái ngược với một liên kết đến một tờ giấy hoặc slide khác, câu hỏi này sẽ nhận được tiền thưởng một khi nó đủ điều kiện cho một :-).

Đây là lý do tại sao tôi cần phải làm điều đó trong thời gian thực:

Nếu bạn phải tính toán trước các SDF này cho các môi trường 2D lớn (nghĩ về một bản đồ lớn giống như Terraria), điều này có nghĩa là bạn chấp nhận một chi phí khá lớn trong không gian lưu trữ (và thời gian tạo bản đồ) để thực hiện nhiều hơn thuật toán phức tạp đủ nhanh để tạo SDF thời gian thực.

Ví dụ: bản đồ tương đối nhỏ với 1000 * 256 (chiều rộng * chiều cao) với kích thước ô 10 * 10 pixel và do đó, tổng kích thước 10000 * 2560 pixel sẽ khiến bạn mất khoảng 2 megabyte, nếu bạn chọn kích thước tương đối nhỏ Độ phân giải SDF là 128x128, giả sử rằng bạn chỉ lưu trữ các giá trị khoảng cách từ 0 đến 255.

Rõ ràng, điều này có thể nhanh chóng trở nên quá nhiều và là một chi phí mà tôi không muốn có.

Có một cái gì đó khác:

SDF có thể được sử dụng cho nhiều thứ (như phát hiện va chạm) và một số ứng dụng hữu ích thậm chí chưa được phát hiện. Tôi nghĩ rằng rất nhiều người sẽ tìm kiếm những điều này trong tương lai, và nếu chúng ta nhận được câu trả lời toàn diện ở đây, tôi nghĩ chúng ta sẽ giúp được rất nhiều người.


Tôi đã hiểu "trường khoảng cách đã ký" là gì và lần đầu tiên là phiên bản GPU: http.developer.nvidia.com/GPUGems3/gpugems3_ch34.html Nó hơi cũ nhưng có thể giúp tìm kiếm thêm.
Patrick Hughes

1
Có thể tôi đang thiếu một cái gì đó, nhưng tôi hơi bối rối trước tuyên bố về lý do tại sao bạn cần phải làm điều đó trong thời gian thực (nhất là tại sao nó lại được gắn thẻ spoiler); Đầu tiên, bạn lấy con số 2MB cho SDF là 128x128 ở đâu? Thứ hai, tại sao bạn coi 2MB là việc sử dụng bộ nhớ đặc biệt nặng? Tôi đồng ý rằng nó không phải là không đáng kể, nhưng có vẻ như một phần nhỏ trong tổng thể sử dụng bộ nhớ bản đồ của bạn. Và thứ ba, làm thế nào để tạo trường trong thời gian thực sẽ lưu bộ nhớ đó? Bạn vẫn cần lưu trữ chính xác cùng một dữ liệu cho dù nó được tạo ra nhanh chóng hay được tính toán trước, phải không?
Steven Stadnicki

Nhìn rộng hơn, có thể dễ dàng rằng SDF không phải là kỹ thuật bạn cần. Thông tin thêm về tình huống cụ thể của bạn - đếm chướng ngại vật tĩnh, đếm chướng ngại vật động, v.v. - và chính xác hiệu quả mà bạn hy vọng đạt được sẽ hữu ích trong việc cố gắng xác định những gì có thể hữu ích cho bạn.
Steven Stadnicki

1
Nếu tôi tạo trường khoảng cách trong thời gian thực, tôi sẽ chỉ tạo 2 MB một lần cho mỗi khung hình (tổng chi phí bộ nhớ sẽ luôn là bộ nhớ cần thiết cho một trường khoảng cách, vì tôi chỉ cần một cho màn hình). Nếu tôi có một bản đồ lớn hơn ví dụ 1000x128 của tôi (tôi nghĩ rằng các bản đồ Terraria lớn vượt xa 10000) tôi cần một trong số 2mb cho mỗi 1000x128 bản đồ đó. Tại sao tôi cần SDF ở vị trí đầu tiên được mô tả trong câu hỏi đầu tiên mà tôi đã liên kết ở đầu câu hỏi này (đó là cho việc tạo bóng 2D cho GPU).
TravisG

1
@heishe bạn đang cố tạo 2Mb dữ liệu một lần trên mỗi khung? Nghiêm túc?
kaoD

Câu trả lời:


9

Catalin Zima giải thích cách đạt được bóng 2D động trong bài viết của mình - và anh ta sử dụng trường khoảng cách đã ký (từ những gì tôi có thể nói đó chỉ là một cái tên ưa thích cho bộ đệm bóng trong ngữ cảnh này). Phương pháp của anh ta cần GPU, và việc triển khai của anh ta không phải là tốt nhất (anh ta giảm xuống dưới 60Hz ở khoảng 20 đèn trên máy của tôi, tôi có khoảng 500 đèn); đó là điều được mong đợi vì ông đã ủng hộ sự rõ ràng của mã về tốc độ.

Thực hiện

Chính xác như được thực hiện bởi anh ta:

  1. Kết xuất tất cả các bóng đổ thành một kết cấu.
  2. Tính khoảng cách đến tâm của ánh sáng cho mỗi pixel và gán giá trị đó cho RGB của các pixel mờ.
  3. Làm biến dạng hình ảnh để nó thể hiện cách một camera 3D sẽ nhìn thấy các pixel đó.
  4. Ép hình ảnh thành hình ảnh có kích thước 2xN bằng cách sử dụng thay đổi kích thước bất thường được mô tả trong bài viết của anh ấy (thay đổi kích thước đơn giản sẽ không hoạt động).
  5. Hình ảnh 2xN hiện là trường khoảng cách đã ký của bạn cho cả bốn góc phần tư ánh sáng (hãy nhớ rằng một góc phần tư về cơ bản là một camera đơn ở 90 độ).
  6. Kết xuất ánh sáng.
  7. Làm mờ ánh sáng (dựa trên khoảng cách từ ánh sáng) để bạn có được bóng mềm.

Việc thực hiện cuối cùng của tôi là (mỗi bước là một shader duy nhất):

  1. Làm (1).
  2. Làm (2) và (3) .
  3. Làm (4). Việc triển khai của anh ta rất chậm: nếu bạn có thể thử và sử dụng GPGPU cho việc này. Tôi không thể sử dụng GPGPU (XNA) vì vậy những gì tôi đã làm là:
    • Thiết lập một lưới trong đó các cột N / 2 đầu tiên được biểu thị bằng các góc N / 2 với cùng một vị trí CHÍNH XÁC (bao gồm cột đầu tiên của bộ đệm cuối cùng) nhưng khác nhau về tọa độ kết cấu (điều tương tự cho các cột N / 2 thứ hai)
    • Tắt kiểm tra độ sâu trên GPU.
    • Sử dụng chức năng trộn MIN pixel.
  4. Làm (6) và (7).

Nó khá tài tình: về cơ bản nó là một bản dịch trực tiếp về cách xử lý bóng trong 3D thành 2D.

Cạm bẫy

Cạm bẫy chính là một số đối tượng không nên bị che khuất: trong ví dụ của tôi, tôi đã viết một bản sao Liero (giun thời gian thực) và do đó, không muốn, ví dụ, sâu của người chơi bị che khuất (ít nhất là một con sâu trên màn hình của mỗi người chơi). Tất cả những gì tôi đã làm cho những đối tượng 'đặc biệt' này là vẽ lại chúng như bước cuối cùng. Điều trớ trêu là hầu hết các vật thể không bị che khuất (sâu, tiền cảnh) nên có vấn đề rút tiền ở đây.


Điều chỉnh của bạn đối với phương pháp thay đổi kích thước có phải là điều duy nhất để tăng tốc độ để xử lý 500 đèn trên 60fps không?
TravisG

OK, tôi sẽ chấp nhận câu trả lời vì nó giải quyết vấn đề ban đầu của tôi, nhưng nó không thực sự trả lời những gì tôi đã đưa tiền thưởng cho. Tôi sẽ đợi và có lẽ ai đó sẽ mất nhiều thời gian để giải thích một trong một số phương pháp O (N) cho việc tạo trường khoảng cách đã ký xung quanh.
TravisG

@heishe về câu hỏi đầu tiên của bạn: không chắc chắn. Tôi đã thực hiện tất cả các tối ưu hóa trong một lần - tôi nghĩ rằng tôi nhớ tắt nó đi và xem tốc độ khung hình giảm đáng kể. Tất cả trong tất cả 6 cuộc gọi rút thăm mỗi ánh sáng sẽ giết chết tốc độ khung hình của bạn. Như tôi đã nói, từ những gì tôi có thể nói, bạn có 4 trường khoảng cách được ký ở bước (5) - nhưng ai đó biết nhiều hơn về chúng sẽ cần phải xác nhận điều đó.
Jonathan Dickinson

Vâng, đó là một trường hợp rất đặc biệt của một trường khoảng cách đã ký. Trong trường khoảng cách được ký bình thường, mọi pixel chứa khoảng cách đến chướng ngại vật gần nhất. Trong thuật toán này, trường khoảng cách chỉ chứa một chướng ngại vật và chướng ngại vật chỉ có 1 pixel trong toàn bộ hình ảnh (nguồn sáng), đó là lý do tại sao trường khoảng cách này có thể được tạo trong O (N).
TravisG

1
@heishe đây là shader của tôi: gist.github.com/2384073 . Biến dạng là 2 + 3.
Jonathan Dickinson
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.