Chuyển Đổi Shader Của Effekseer
Dự án chuyển đổi shader của Effekseer
Ban đầu, engine game của chúng tôi sử dụng hệ thống particle tự phát triển. Khi hoàn thành xong phần cốt lõi, trong giai đoạn xây dựng công cụ biên tập đi kèm, một đồng nghiệp phụ trách phát triển công cụ đã đề xuất chuyển sang hệ thống mã nguồn mở trưởng thành khác để giảm gánh nặng bảo trì.
Đồng nghiệp đó giới thiệu Effekseer và đã hoàn thành việc tích hợp Effekseer vào engine của chúng tôi.
Gần đây, tôi tình cờ thấy một lập trình viên trên Twitter đang tìm kiếm giải pháp particle system cho bgfx. Anh ấy muốn một hệ thống hoàn thiện hơn demo particle mặc định của bgfx, đồng thời phàn nàn rằng tích hợp Popcorn quá phức tạp. Tôi đã giới thiệu Effekseer cho anh ấy.
Việc tích hợp Effekseer bao gồm hai khía cạnh: kết nối với API đồ họa, và tích hợp với engine. Phần thứ hai liên quan đến quản lý tài nguyên như texture, shader và module. Vì bgfx chỉ là lớp trừu tượng hóa API đồ họa (tương đương OpenGL/DirectX/Metal), việc chỉ viết renderer cho bgfx chưa đủ. Nếu không tích hợp quản lý tài nguyên, hệ thống particle sẽ tồn tại hai bản quản lý tài nguyên riêng biệt - một ở engine và một ở particle system, điều này rõ ràng không hợp lý.
Năm ngoái khi tích hợp, chúng tôi làm khá đơn giản khi trộn lẫn hai phần này. Điều này khiến việc tái sử dụng cho dự án khác dùng bgfx trở nên khó khăn. Qua tìm hiểu, tôi biết lập trình viên trên Twitter từng là Principal R&D Programmer tại Crytek, có kinh nghiệm dày dặn với game AAA. Tôi khuyên anh ấy tự tích hợp Effekseer cho dự án của mình, nhưng anh ấy sẵn sàng trả phí để tham khảo mã nguồn của chúng tôi.
Sau khi cân nhắc, tôi quyết định thiết kế lại lớp trừu tượng hóa, tách phần liên quan đến bgfx khỏi engine để tạo ra renderer Effekseer cho bgfx độc lập, sau đó open-source. Anh lập trình viên kia rất ủng hộ ý tưởng cùng bảo trì. Dự án hiện đã bắt đầu và có thể theo dõi tại:
Hiện tại tôi đang tập trung vào phần chuyển đổi shader - công việc khiến tôi có nhiều điều muốn chia sẻ.
Effekseer có 6 loại vật liệu tích hợp, dùng để render particle sprite (quad) hoặc model 3D. Sprite và model dùng vertex shader khác nhau nhưng chia sẻ fragment shader, tổng cộng 18 shader.
Shader của bgfx có định dạng đặc biệt nên không thể dùng trực tiếp shader từ Effekseer. Năm ngoái đồng nghiệp đã thủ công chuyển đổi vài shader từ phiên bản OpenGL, nhưng chỉ làm một phần và phiên bản Effekseer hiện tại đã có nhiều thay đổi.
Tôi nghiên cứu sâu và phát hiện Effekseer hỗ trợ đa dạng API từ DirectX9 đến 12, OpenGL 2/3 ES, Vulkan, Metal… Tất cả shader này đều được sinh tự động từ phiên bản DirectX11 thông qua công cụ dựa trên glslang.
Lý tưởng nhất là mở rộng công cụ này để sinh shader cho bgfx, nhưng việc fork và sửa mã nguồn sẽ phát sinh chi phí bảo trì lâu dài. Tôi chọn giải pháp khác: viết công cụ chuyển đổi riêng bằng Lua.
Vì bgfx dùng cú pháp GLSL nên tôi chọn chuyển đổi từ phiên bản Vulkan (được sinh tự động nên cấu trúc rất chuẩn). Chỉ dùng thư viện string cơ bản của Lua, tôi hoàn thành công cụ trong 4 tiếng với 100 dòng code.
Tại sao công cụ đơn giản này lại đủ dùng? Vì chúng tôi chỉ cần xử lý ~15 file shader, không cần tính toàn diện. Công cụ chỉ cần chạy khi có cập nhật từ upstream, kết quả chuyển đổi sẽ được commit trực tiếp vào repo. Công cụ có thể thêm cơ chế kiểm tra để báo lỗi khi gặp đoạn mã không hiểu, thay vì cố gắng xử lý mù quáng.
Trong tương lai khi nâng cấp phiên bản, quá trình chuyển đổi sẽ tự động nhưng có giám sát. Nếu công cụ không còn phù hợp, việc cải tiến cũng không tốn nhiều công sức. Công cụ chuyên dụng này còn có thể kiểm tra thêm: tên Uniform, định dạng Vertex Layout có khớp với renderer không - giúp đơn giản hóa việc phát triển renderer mà không cần sinh code C++.
Hiện tại, dự án đang trong quá trình phát triển, tôi sẽ tiếp tục chia sẻ các trải nghiệm chi tiết trong thời gian tới.