Đồ họa 2D - tại sao sử dụng spritesheets?


62

Tôi đã thấy nhiều ví dụ về cách kết xuất các sprite từ một spritesheet nhưng tôi không hiểu tại sao đó là cách phổ biến nhất để xử lý các sprite trong các trò chơi 2d.

Tôi đã bắt đầu với kết xuất sprite 2d trong một vài ứng dụng demo mà tôi đã tạo bằng cách xử lý từng khung hình động cho bất kỳ loại sprite nào dưới dạng kết cấu của chính nó - và bộ sưu tập họa tiết này được lưu trữ trong từ điển. Điều này có vẻ phù hợp với tôi và phù hợp với quy trình làm việc của tôi khá tốt, vì tôi có xu hướng tạo hoạt hình của mình dưới dạng tệp gif / mng và sau đó trích xuất các khung thành từng pngs.

Có một lợi thế hiệu suất đáng chú ý để kết xuất từ ​​một trang duy nhất chứ không phải từ các kết cấu riêng lẻ? Với phần cứng hiện đại có khả năng vẽ hàng triệu đa giác lên màn hình một trăm lần một giây, điều đó có quan trọng đối với các trò chơi 2d của tôi chỉ với vài chục hình chữ nhật 50x100px không?

Các chi tiết triển khai tải một kết cấu vào bộ nhớ đồ họa và hiển thị nó trong XNA có vẻ khá trừu tượng. Tất cả những gì tôi biết là kết cấu bị ràng buộc với thiết bị đồ họa khi chúng được tải, sau đó trong vòng lặp trò chơi, kết cấu sẽ được hiển thị theo lô. Vì vậy, tôi không rõ liệu lựa chọn của mình có ảnh hưởng đến hiệu suất hay không.

Tôi nghi ngờ rằng có một số lý do rất chính đáng mà hầu hết các nhà phát triển trò chơi 2d dường như đang sử dụng chúng, tôi chỉ không hiểu tại sao.


Không, nó không thực sự quá quan trọng đối với 50 sprite lẻ của bạn. Nhưng mất gì?
Vịt Cộng sản

Câu trả lời:


69

Một lập luận mạnh mẽ cho việc sử dụng spritesheets là số lượng họa tiết có sẵn trên thẻ đồ họa có thể bị hạn chế. Do đó, thư viện đồ họa của bạn sẽ liên tục phải xóa kết cấu và phân bổ lại họa tiết trên GPU. Sẽ hiệu quả hơn nhiều khi chỉ phân bổ một kết cấu lớn một lần.

Ngoài ra, hãy xem xét rằng kích thước kết cấu thường có sức mạnh bằng 2. Vì vậy, nếu bạn có Sprite 50x100px, bạn sẽ phân bổ họa tiết với kích thước 64x128px hoặc trong trường hợp xấu hơn là 128x128px. Điều đó chỉ làm lãng phí bộ nhớ đồ họa. Tốt hơn nên đóng gói tất cả các họa tiết vào kết cấu 1024x1024px, điều này sẽ cho phép các họa tiết 20x10 và bạn sẽ chỉ mất 24 pixel theo chiều ngang và chiều dọc. Đôi khi, thậm chí các sprite có kích thước khác nhau được kết hợp thành một tấm sprite lớn để sử dụng kết cấu hiệu quả nhất có thể.

Phụ lục: Một lý do rất quan trọng để sử dụng sprite-sheet là để giảm số lượng cuộc gọi rút thăm trên GPU của bạn, điều này có thể có tác động đáng chú ý đến hiệu suất. Điều này đã được nêu trong các câu trả lời khác và tôi thêm điều này vì mục đích hoàn chỉnh để điều này được hiển thị nhiều hơn.


1
Cảm ơn, tôi đã không xem xét một trong những điểm đó - Bạn có biết đại khái về giới hạn số lượng họa tiết có sẵn không? Tôi chưa bao giờ thấy chỉ số này được đề cập về thông số kỹ thuật đồ họa - về cơ bản giới hạn có bằng với dung lượng RAM đồ họa không?
Columbo

Thông thường giới hạn sẽ là bộ nhớ GPU, vâng. Tôi nghĩ rằng có một số hạn chế về số lượng kết cấu trên thẻ cũ nhưng tôi dường như không thể tìm thấy một tài liệu tham khảo chứng minh điểm đó.
bummzack

12
Ngay cả khi không có giới hạn về số lượng, lưu lượng xe buýt để di chuyển nhiều hình ảnh nhỏ cũng không hiệu quả bằng một (hoặc một vài) lần chuyển lớn.
Mordachai

5
Điểm tốt, nhưng khía cạnh quan trọng nhất để giảm thiểu các quầy hàng đường ống bằng cách giảm số lần gọi rút thăm. GPU thích một lượng nhỏ các công việc lớn, hơn là một số lượng lớn các công việc nhỏ. Đặt tất cả các họa tiết của bạn vào một loạt các tờ lớn có nghĩa là bạn có thể thiết lập giai đoạn văn bản lên một lần và rút ra rất nhiều phép thuật cùng một lúc trong một đợt. Spritebatch làm điều này cho bạn. Nếu bạn có nhiều hơn một spritesheet, hãy đảm bảo yêu cầu spritebatch sắp xếp theo kết cấu
Cubed2D

Thêm nén kết cấu sẽ biến bất kỳ không gian chùng nào thành một lượng rất nhỏ trên đầu, trên hết tất cả
Joe Plante

36

Tôi muốn nói rằng tranh luận để sử dụng sẽ là khả năng kết xuất nhiều thứ trong một cuộc gọi rút thăm. Lấy ví dụ kết xuất phông chữ, không có spritesheet, bạn cần kết xuất mỗi ký tự bằng một hoán đổi kết cấu riêng biệt theo sau là một lệnh gọi. Ném chúng vào một spritesheet và bạn có thể kết xuất toàn bộ câu chỉ bằng một lệnh gọi (các ký tự khác nhau trong phông chữ được chọn bằng cách chỉ định các UV khác nhau cho các góc). Đây là một cách hiển thị hiệu quả hơn nhiều khi một công cụ kết xuất rất thực tế trên nhiều nền tảng đang thực hiện quá nhiều lệnh gọi API.

Nó cũng có thể giúp tiết kiệm không gian, nhưng nó phụ thuộc vào việc đóng gói của bạn vào spritesheet ở nơi đầu tiên.


2
+1 Chạm vào khi thực hiện cuộc gọi. (điều mà tôi không thấy trong câu trả lời được chấp nhận)
Michael Coleman

11

Mỗi cuộc gọi rút thăm có một số tiền nhất định. Bằng cách sử dụng các tấm sprite, bạn có thể bó bản vẽ của những thứ không sử dụng cùng một khung hình của một hình ảnh động (hay nói chung hơn, mọi thứ trên cùng một vật liệu) giúp tăng hiệu suất rất nhiều. Điều này có thể không quá quan trọng đối với các PC hiện đại tùy thuộc vào trò chơi của bạn, nhưng nó chắc chắn là vấn đề đối với iPhone.


2
Nó chắc chắn vẫn còn vấn đề. Phần cứng đồ họa đã được tối ưu hóa theo hướng đẩy hàng tấn đa giác cho một số lượng nhỏ các mô hình chi tiết (ví dụ: ký tự) vì hầu hết các trò chơi có xu hướng theo hướng đó. Kết quả là bạn cần phải đẩy càng nhiều đa giác càng tốt trong mỗi vài chục cuộc gọi rút thăm. Các công cụ trò chơi kết xuất các cảnh lớn như thành phố thường kết hợp nhiều kết cấu thành một để nhanh chóng giảm các cuộc gọi.
jhocking

Tôi chắc chắn tự hỏi nếu kết cấu u, v ánh xạ trong rất nhiều phần cứng 3D, cộng với các hoạt động xóa bit có lợi từ bảng sprite.
Joe Plante

7

Ngoài việc xem xét hiệu suất, các tấm sprite có thể tiện dụng khi tạo ra nghệ thuật; mỗi nhân vật có thể ở trong trang tính của riêng mình và bạn có thể thấy tất cả các khung hình chỉ bằng cách cuộn xung quanh. Nó giúp tôi giữ một cái nhìn nhất quán trên tất cả các khung.

Ngoài ra, tôi mã trong AS3 và mỗi tệp hình ảnh yêu cầu một hướng dẫn nhúng riêng. Tôi muốn có một lần nhúng toàn bộ một spritesheet hơn 24 lần nhúng cho tất cả các khung, ngay cả khi tôi đang sử dụng một lớp tài nguyên riêng biệt.


1
+1. Mặc dù OP không sử dụng Flash, nhưng việc nhúng hoặc tải cũng là một điểm có lợi cho spritesheets. Nó cũng có liên quan khi tài sản được tải từ Máy chủ web trong đó 1 yêu cầu được ưu tiên hơn hàng trăm yêu cầu (cho mỗi "khung").
bummzack

Chắc chắn bạn muốn giảm yêu cầu máy chủ cho một trò chơi trực tuyến. Chúng tôi đã cân nhắc xem nên đưa hình ảnh vào .swf hay spritesheet vì cả hai đều hoàn thành mục tiêu chính này (cuối cùng chúng tôi quyết định spritesheets ít tốn công sức hơn cho các nghệ sĩ của chúng tôi).
jhocking

7

Một lý do khác để sử dụng spritesheets với XNA là vì với sự phát triển của Xbox360, có một vấn đề được biết đến với thời gian triển khai / tải chậm liên quan đến số lượng tệp bạn có trong dự án của mình. Vì vậy, kết hợp nhiều tệp hình ảnh nhỏ vào một tệp hình ảnh sẽ giúp chống lại vấn đề đó.


5

Tôi sẽ không đề cập đến bộ nhớ / GPU ở đây, vì có đủ câu trả lời như thế.

Thay vào đó, nó có thể làm sáng tỏ nghệ thuật của bạn khi bạn làm việc trên nó - và sau đó. Thay vì phải lướt qua 10 hình ảnh để xem chu kỳ đi bộ, bạn có thể thấy tất cả các khung hình trong một lần. Nếu bạn muốn phân phối cái này, bạn chỉ có 1 tệp để xử lý thay vì 10.

Và sau đó, nó cũng sạch hơn (từ quan điểm tổ chức) để có character.png và địch.png qua characterwalk01 cho đến characterwalk10, sau đó characterattack01 đến characterattack05, và nó tiếp tục.


4

Bộ nhớ đồ họa không có quản lý bộ nhớ phình to như hệ thống tệp trên đĩa; đối diện là trường hợp: nó được giữ đơn giản và nhanh chóng .

Một cách quản lý bộ nhớ đơn giản và nhanh như vậy có thể giống như chỉ có một sprite khổng lồ 4096x4096 duy nhất được cắt thành nhiều nhánh nhỏ hơn bằng cách giảm một nửa chiều rộng và / hoặc chiều cao của nó. (Tồn tại một kỹ thuật quản lý bộ nhớ 1 chiều tương tự, nhưng tôi quên tên.) Cuối cùng, Phân mảnh phải được thực hiện.

Để bỏ qua việc quản lý bộ nhớ như vậy trong thời gian chạy , các nhà phát triển sẽ tự động điền vào các họa tiết lớn với nhiều họa tiết nhỏ hơn trong thời gian biên dịch hoặc ngay cả trong quá trình xử lý đồ họa.


3

Cũng đừng quên các thao tác I / O nó có thể giúp bạn tiết kiệm trong quá trình khởi tạo. Nếu bạn đang tải từ ổ đĩa CD, mỗi tệp là một cuộc gọi I / O bổ sung và có thể mất một chút thời gian để tìm kiếm (ổ cứng hiện đại khoảng 15 ms mỗi tệp, CD có thể 50-100ms?). Điều này có thể giúp bạn tiết kiệm rất nhiều thời gian khởi tạo vì chỉ có một tệp phải được tìm nạp. Nó cũng cho phép hệ điều hành của bạn lưu trữ các hoạt động I / O này, trong trường hợp ứng dụng của bạn đang làm một việc khác (như chờ GPU).


1
Ở đầu bên kia, nếu bạn muốn giải quyết vấn đề tìm kiếm tệp, bạn có thể có tất cả các họa tiết của mình được đóng gói trong một tệp, sử dụng định dạng tùy chỉnh. Hầu hết các trò chơi làm điều đó.
tigrou

0

Khác với hiệu suất hiệu quả hơn, tôi thấy nó đơn giản dễ dàng hơn. Nó đòi hỏi một chút công việc để đảm bảo hình ảnh của bạn luôn nằm trong giới hạn của chúng khi tạo ra nghệ thuật, nhưng việc xem tất cả các hình ảnh bạn đang xử lý vào lúc này sẽ dễ dàng hơn rất nhiều.

Theo tôi, nó cũng dễ viết mã hơn. Tôi chỉ đơn giản là có một loạt các đối tượng như:

sheet = {
    img: (the actual image),
    rects: [
        {x:0, y:0, w:32, h:32},
        {x:32, y:0, w:32, h:32},
        {x:64, y:0, w:32, h:32}
    ]
};

sheets.push(sheet);

Sau đó, cho mỗi mục tôi cung cấp cho nó hai giá trị, tờ và chỉnh lưu. Trang tính sẽ là chỉ mục trong mảng các đối tượng và trực tràng sẽ là chỉ mục trong mảng rects của trang tính đó.

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.