Vẽ số lượng gạch khổng lồ trong Monogame (XNA) một cách hiệu quả


8

Tôi đang hỏi câu hỏi này vì tôi chưa tìm thấy câu trả lời dứt khoát cho nó.

Trước tiên, hãy để tôi nói một vài điều về trò chơi và những gì tôi đã làm. Trò chơi sẽ trở thành một RTS lấy bối cảnh trong một thế giới được tạo theo thủ tục bằng cách sử dụng tiếng ồn Simplex. Thế giới bao gồm các khối có kích thước 16 x 16 được tạo thành từ các sprite có kích thước 64 x 64. Tôi đã quản lý để tải và dỡ tải các khối một cách linh hoạt, hoạt động rất tốt. Thế giới sẽ trông hơi giống Rimworld, do đó, từ trên xuống với các lớp khác nhau (địa hình đầu tiên, họa tiết chuyển tiếp, cây cối, đề can, v.v.). Các thế giới mới được tạo ra có thể chứa các thực thể có thể ảnh hưởng đến môi trường (ví dụ: một ngôi làng đã trở thành một thị trấn) và do đó, chunk. Tôi chắc chắn rằng điều này có thể được tính bằng cách sử dụng một số loại chức năng, nhưng đó là điều cần lưu ý.

Các vấn đề chính tôi có là khi tôi phóng to ra, ngày càng nhiều gạch được rút ra mà ảnh hưởng nghiêm trọng đến hiệu suất. Với khoảng 30000 sprite, phần vẽ mất 8 ms, một nửa so với yêu cầu để chạy ở 60 FPS. Và đó chỉ là địa hình. Tôi đang sử dụng các bản đồ họa tiết để hạn chế số lần vẽ (30000 họa tiết được vẽ trong 6 số).

Các mục tiêu là để có thể thu nhỏ từ / làng / cấp thành phố thị trấn tất cả các cách để có thể nhìn thấy toàn bộ đất nước. Điều này phải được thực hiện một cách linh hoạt (ví dụ: không phải bằng cách nhấp vào biểu tượng bản đồ nhỏ, mà chỉ cần cuộn lại giống như trong Chỉ huy tối cao).

Tôi đã đọc nhiều bài viết về vấn đề này, nhưng tôi chưa tìm thấy hoặc thấy một ví dụ rõ ràng về nơi nó sẽ hoạt động. Dưới đây là danh sách các kỹ thuật tôi đã tìm thấy được cho là hoạt động:

  • Hình chữ nhật bẩn, như được mô tả ở đây , nơi bạn chỉ vẽ những thứ mới và giữ phần còn lại trong backbuffer. Điều này rất có ý nghĩa, nhưng tôi không biết làm thế nào để thực hiện điều này trong Monogame.
  • Lựa chọn ưu tiên của tôi: sử dụng rộng rãi các Mục tiêu kết xuất, như được mô tả ở đây , nơi bạn vẽ vào RenderTarget và sau đó lưu nó dưới dạng kết cấu. Trong trường hợp của tôi, một đoạn 16 x 16 bao gồm 64 x 64 sẽ tạo ra kết cấu 1024 x 1024. Tôi thực sự nghi ngờ điều này sẽ hoạt động về mặt hiệu suất, nhưng kết quả sẽ bao gồm các kết cấu rất chi tiết và cũng rất tuyệt khi sử dụng vì thực tế là phần lớn là tĩnh (địa hình / cây, v.v.) và không thay đổi nhiều. Nhưng điều này cũng có nghĩa là mỗi khi thay đổi được thực hiện thành một đoạn, thì Texture2D phải được thay đổi bằng SetData, từ những gì tôi đã trải nghiệm là khá tốn CPU. Tuy nhiên, nếu kết cấu là 16 x 16 thì nó thực sự có thể hoạt động và nó cũng sẽ cắt giảm việc sử dụng bộ nhớ và đĩa riêng.
  • Cho đến khi kết cấu bằng cách chỉ định SourceRonymous trong SpriteBatch. Đối với đồng cỏ / đại dương rộng lớn thì đây là một điểm cộng, vì chỉ có một sprite được rút ra. Tuy nhiên, đối với địa hình chi tiết với màu sắc khác nhau và các họa tiết khác nhau được trộn lẫn với nhau (bộ chuyển đổi sinh học và quần xã) tôi sợ rằng nó sẽ không tạo ra sự khác biệt lớn.
  • Giải pháp của riêng tôi, thỏa hiệp chi tiết, là sử dụng gạch 64 x 64 màu trắng tiêu chuẩn, cung cấp cho nó màu của 4 gạch xung quanh và sau đó chia tỷ lệ để nó bao phủ 4 gạch trước đó. Sự khác biệt ở đây (ngoài gạch có màu trơn) là cảnh quan thay đổi rõ rệt. Tôi cũng nên đề cập rằng các khu rừng vẫn phải được vẽ riêng vì chúng không hoàn toàn vuông.

Nếu bất cứ ai có bất kỳ ý tưởng nào về cách giải quyết vấn đề này, ngay cả khi nó có nghĩa là thỏa hiệp một số điều (chẳng hạn như chi tiết, hoặc sử dụng 16 x 16 sprite), tôi rất thích nghe nó.


Đừng để người dùng thu nhỏ quá nhiều
Bálint

Tôi cũng đã gặp vấn đề về hiệu suất với dự án MonoGame được tạo theo thủ tục của mình. Giải pháp của tôi là giới hạn những gì được hiển thị (giới hạn phạm vi thu nhỏ và chỉ vẽ những gì trên màn hình). Có vẻ như MonoGame được thiết kế với một câu thần chú "vẽ mọi khung hình", nhưng tôi hy vọng ai đó có kinh nghiệm hơn với MonoGame sẽ sửa lỗi cho tôi.
Ngụy biện hợp lý

Làm thế nào để bạn làm cho gạch? Cụ thể hơn - bạn có sử dụng SpriteBatch không và bạn sử dụng nó như thế nào?
loodakrawa

Câu trả lời:


3

Card đồ họa được tối ưu hóa để vẽ một vài thứ nhiều lần thay vì ngược lại.

Trong trường hợp của bạn, bạn có rất nhiều thứ (kết cấu khác nhau) mà bạn muốn vẽ rất nhiều lần (số lượng gạch).

IMO, tối ưu hóa đơn giản nhất bạn có thể làm để đạt được hiệu suất đáng kể là:

  1. Kết hợp kết cấu của bạn thành atlours. Điều này sẽ tăng tốc đáng kể mọi thứ vì card đồ họa của bạn bây giờ chỉ vẽ một (hoặc một vài) họa tiết thay vì nhiều họa tiết nhỏ.
  2. Batch gạch của bạn với SpriteBatch trong chế độ SpriteSortMode.Texture. Điều này sẽ sắp xếp các họa tiết của bạn theo kết cấu và giảm thiểu số lượng chuyển đổi kết cấu thành số lượng kết cấu thực tế khác nhau. Nhược điểm của phương pháp này là các họa tiết của bạn sẽ không được sắp xếp theo độ sâu. Điều này có lẽ là tốt vì gạch của bạn đều ở cùng độ sâu. Tôi giả sử bạn cũng có những thứ khác vì vậy sẽ rất hợp lý khi tách SpriteBatch cho các ô và một thứ khác cho mọi thứ khác (được đặt thành SpriteSortMode.BackToFront).

Tôi sẽ khuyên bạn nên làm cả hai điều. Chúc may mắn.


2

Tôi phát hiện ra rằng SpriteBatch không phù hợp để vẽ gạch. Một lý do là các sprite có nghĩa là cho các đối tượng động và được sử dụng cho nhiều mục đích. Một lý do khác là nó cực kỳ bị ràng buộc bởi CPU , vd. như được giải thích trong bản mô tả vẽ 30.000 đối tượng có giá 8 ms (trong khi chipset của tôi đạt tối đa 30%). Ngoài ra, có thể rút tối đa 3000 họa tiết trước khi thực hiện cuộc gọi rút thăm mới đối với GPU (theo đợt và tất cả).

Giải pháp là vẽ gạch của riêng tôi bằng cách sử dụng các hình tứ giác . Điều này kết hợp với VertexBuffer cho phép tôi vẽ tới 500.000 ô kết cấu trong một cuộc gọi rút thăm trong đó phương thức vẽ tiêu thụ khoảng 1/20 của một phần nghìn giây. Tất nhiên tôi có lẽ sẽ không phải vẽ nhiều như vậy, nhưng dù sao thì cuối cùng tôi cũng có được GPU của mình để có khối lượng công việc 75% với tốc độ 60 khung hình / giây ổn định.


Nghe có vẻ tốt đấy. Tôi muốn tìm hiểu thêm về điều đó - bạn đã làm theo bất kỳ hướng dẫn nào hoặc bạn có bất kỳ liên kết với một mô tả chi tiết hơn về quá trình này?
loodakrawa

2
Tôi đã học được hầu hết về mọi nơi có đề cập đến XNA / Monogame và kết cấu tứ giác. Tuy nhiên, riemers.net đã giúp tôi rất nhiều vì nó nhắm vào những người chỉ muốn thiết lập một cái gì đó nhanh chóng mà hiệu quả. Bạn sẽ muốn đặc biệt làm theo hướng dẫn địa hình 3D của mình vì nó cũng bao gồm VertexBuffers và IndexBuffers. Biến nó thành một loại địa hình ngói không nên là một vấn đề.
Guguhl Pluhs

Nếu đó là câu trả lời cho câu hỏi của bạn nhiều nhất, bạn rất sẵn lòng đánh dấu nó là được chấp nhận :)
Vaillancourt

@GuguhlPluhs Tôi biết điều này là muộn, nhưng bạn vẫn có thêm một số thông tin về chủ đề này? Tôi đang đối mặt với cùng một vấn đề.
Jelle
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.