Các công cụ và kỹ thuật ưa dùng cho phát triển game procedural
(cprimozic.net)- Khi các dự án scene·level 3D chạy trong trình duyệt ngày càng lớn hơn, các công cụ tái sử dụng áp dụng kỹ thuật procedural·generative cho những yếu tố cụ thể của level, thay vì tạo toàn bộ world, đã dần tích lũy lại
- Trọng tâm của công việc texture là Triplanar Mapping và Hex Tiling, được dùng để phủ texture không cần UV hoặc che giấu các mẫu lặp
- Cả hai kỹ thuật đều áp dụng
pow()lên trọng số nội suy để tăng tỷ lệ của trục hoặc kết quả tra cứu chiếm ưu thế, đồng thời giảm gánh nặng hiệu năng bằng cách bỏ qua một số lần tra cứu texture - Các fragment shader đắt đỏ có thể được giảm tải bằng Depth Pre-Pass; trong những scene có nhiều overdraw, hiệu năng có thể cải thiện hơn 30%
- Ở phía mesh·geometry, có một xu hướng mở rộng biểu hiện trang trí·bối cảnh·hư hại thông qua LoD terrain, pipeline xử lý mesh lúc runtime, và trong tương lai là Constructive Solid Geometry
Các công cụ procedural tích lũy trong scene 3D trên trình duyệt
- Trong vài năm qua, khi tạo 3D scenes and levels chạy trong trình duyệt, các demo độc lập xoay quanh custom shader đã dần phát triển thành những hình thức giống như game có kết nối với nhau
- Cách tiếp cận chung là áp dụng kỹ thuật procedural·generative vào những phần cụ thể của level, thay vì một thế giới được tạo procedural hoàn toàn
- Các công cụ và hiệu ứng procedural·bán procedural được tái sử dụng qua nhiều level đã tự nhiên tích lũy theo thời gian
Shader và texture
- Hầu hết texture là seamless texture có thể tile liền mạch theo hai trục, nhưng khi trải trên vùng rộng, các mẫu lặp có thể trở nên dễ nhận thấy
- Bằng cách mở rộng custom shader của Three.JS dựa trên
MeshPhysicalMaterial, nhiều tính năng đã được thêm vào để cải thiện hỗ trợ seamless texturing -
Triplanar Mapping
- Triplanar Mapping là công cụ cốt lõi cho texturing, được dùng trong gần như mọi level
- Nó cho phép phủ texture lên mesh bằng seamless texture mà không cần UV map được định nghĩa trước, nên rất hữu ích trong các trường hợp như terrain sinh procedural, nơi người làm model không có cơ hội định nghĩa UV mapping
- Kỹ thuật này hoạt động tốt với cả mesh được sinh ra lẫn mesh được model thủ công
- Cách triển khai nhẹ và đơn giản; có thể xem bản tham khảo tại triplanarMapping.ts
-
Cải tiến Triplanar Mapping
- Triplanar Mapping thông thường sẽ trộn tuyến tính các lần tra cứu texture theo ba trục dựa trên normal của fragment
- Ở những vùng mà normal không gần một trục đơn lẻ nào, texture có thể trông như bị xếp thành từng lớp
- Nếu áp dụng
pow()với số mũ lớn lên trọng số rồi chuẩn hóa lại, tỷ lệ của trục chiếm ưu thế sẽ tăng lên và vùng chuyển tiếp sẽ nhỏ lại - Sau phép biến đổi này, ở phần lớn mesh, trọng số của một trục sẽ gần 1, còn hai trục kia gần 0
- Bằng cách bỏ qua tra cứu texture cho các trọng số nhỏ hơn ngưỡng, chi phí hiệu năng của Triplanar Mapping có thể giảm xuống chỉ nhỉnh hơn đôi chút so với texturing dựa trên UV thông thường
- Việc xử lý normal map cần được cân nhắc riêng trong mã shader; ở đây dùng phương pháp GPU Gems
- Có thể xem chi tiết triển khai trong Normal Mapping for a Triplanar Shader
-
Hex Tiling
- Hex Tiling là một thuật toán dùng để che giấu hiện tượng tile và lặp dễ thấy của seamless texture
- Chỉ bằng cách thêm một tùy chọn cấu hình vào material, một scene có thể chuyển từ cảm giác như mockup hoàn thiện thấp sang gần với semi-realistic hơn
- Bản triển khai ban đầu dựa trên Shadertoy của Fabrice Neyret, sau đó được chuyển đổi cho phù hợp với hệ thống material của Three.JS và tích hợp vào shader material chính của dự án
- Về sau, với sự cho phép của tác giả, nó được port thành thư viện độc lập three-hex-tiling, cho phép thêm Hex Tiling vào built-in material của dự án Three.JS
- Khác với Triplanar Mapping, kỹ thuật này cần UV mapping được định nghĩa trước
- Nếu dùng cả hai kỹ thuật cùng lúc, số lần texture fetch tối đa trên mỗi fragment cho mỗi map có thể tăng đến 27, nên không thực tế
- Hex Tiling cũng nội suy tuyến tính ba kết quả tra cứu trên mỗi fragment, nên kỹ thuật trọng số
pow()dùng cho Triplanar Mapping cũng có thể cải thiện cả hiệu năng lẫn chất lượng kết quả ở đây
-
Depth Pre-Pass
- Các kỹ thuật texturing nâng cao có thể tạo ra fragment shader đắt đỏ trong những scene lớn
- Depth Pre-Pass là cách trước tiên render toàn bộ scene bằng một material rất đơn giản và rẻ để ghi lại depth của từng pixel
- Dù có overhead do phải render scene hai lần, trong các scene có nhiều overdraw thì lợi ích thường lớn hơn chi phí
- Khi overdraw nhiều, việc thêm Depth Pre-Pass có thể cải thiện hiệu năng hơn 30%
- Có thể thay đổi cấu hình pre-pass để chỉ render các fragment bị occlude, qua đó trực quan hóa những fragment vốn sẽ bị bỏ qua khi dùng pre-pass
- Có thể xem chi tiết cài đặt và cấu hình trong Three.JS tại dedicated article
-
Tổng hợp texture PBR dựa trên AI
- Texture do AI tạo ra được dùng trong gần như mọi scene
- Nếu dùng có chừng mực, kết quả có thể trông khá tốt; toàn bộ texture trong scene ví dụ đều là AI-generated
- Quy trình tạo texture, tạo PBR map và kết hợp thành seamless 4K texture mà không cần upscale được trình bày trong bài viết riêng
- Website được nhắc đến trong bài đó để tạo PBR map hiện không còn sử dụng được nữa
- Hiện tại, DeepBump được dùng để tạo normal map, và khi cần thì các công cụ không dùng AI như Materialize được dùng cho các map khác
-
Volumetric Fog/Clouds
- volumetric rendering là một lĩnh vực được quan tâm vì có thể mang lại hiệu ứng độc đáo cho scene
- Một shader tương đối tổng quát đã được tạo ra để có thể thêm cloud hoặc fog vào bất kỳ scene Three.JS nào
- Lấy cảm hứng từ Shadertoy của Inigo Quilez, một basic volumetric clouds shader dùng tra cứu noise LoD tương tự đã được tạo ra, rồi sau đó mở rộng thành dạng tổng quát và có thể cấu hình hơn
- Shader này hữu ích để lấp đầy khoảng trống trong các level thưa thớt, đồng thời thêm cảm giác động vào những level tĩnh bằng cloud hoặc fog chuyển động
- Một phần mã và cách tiếp cận do n8programs phát triển trong dự án
three-good-godrayscũng được sử dụng three-good-godrayscũng được dùng thường xuyên và mang lại bầu không khí rất đặc trưng cho level
Mesh và geometry
- Sinh mesh lúc runtime là lĩnh vực ngày càng được xử lý nhiều hơn
- Dù rất thích ý tưởng thế giới mọc lên từ một software seed, vẫn muốn tránh hiện tượng “vô hạn nhưng trống rỗng” của một số game đề cao procedural generation
- Vì vậy, thay vì tạo procedural toàn bộ trải nghiệm cốt lõi, trọng tâm chủ yếu là thêm trang trí, bối cảnh, procedural flourish vào level
-
LoD Terrain
- terrain generation là một lĩnh vực tiêu biểu của phát triển game procedural, và bản thân cách triển khai không có gì đặc biệt
- Giống như phần lớn phương pháp khác, terrain heightmap được tạo bằng noise function rồi được tessellate thành các triangle để render
- Triplanar Mapping hoặc Hex Tiling được dùng cho texturing
- Điểm cốt lõi là hệ thống LoD: terrain được tạo theo từng tile, và mỗi tile được sinh ở nhiều độ phân giải
- Các độ phân giải khác nhau được thay đổi động theo khoảng cách giữa tile và camera
- Hệ thống terrain generation này được tái sử dụng thường xuyên; nhờ tính linh hoạt và hiệu quả, nó có thể áp dụng cho nhiều level với ít công sức
-
Pipeline xử lý·biến đổi mesh procedural
- Phần được làm nhiều nhất gần đây là pipeline procedural mesh processing
- Mục tiêu ban đầu là subdivide và deform procedural các low-poly mesh, kể cả những mesh được tạo động
- Mục đích là khiến những mesh đơn giản như platform, boulder hay các cấu trúc lớn trông thực tế hoặc thú vị hơn khi được đặt vào level
- Công việc này dẫn đến một pipeline phần mềm trong runtime trình duyệt, nhận raw geometry data, chỉnh sửa tùy ý, rồi xuất lại sang định dạng có thể render được
- Quá trình này đòi hỏi những cân nhắc chi tiết, đặc biệt ở phần xử lý normal
- Có thể xem chi tiết triển khai trong bài subdividing meshes for displacement
Ứng viên thử nghiệm tiếp theo: Constructive Solid Geometry
- Hầu hết các công cụ được liệt kê ở đây ban đầu đều bắt đầu như những triển khai dùng một lần cho các trường hợp cụ thể, nhưng sau đó liên tục được tái sử dụng trong những level và ngữ cảnh khác
- Ý tưởng lớn tiếp theo muốn thử là Constructive Solid Geometry
- Constructive Solid Geometry là một hệ thống áp dụng boolean operator trong không gian 3D
- Có thể hợp nhất hai mesh bất kỳ
- Có thể cắt bỏ một chunk khỏi mesh
- Và có thể thực hiện các thao tác tương tự khác
- csg.js triển khai một toolkit CSG trong chỉ một file JavaScript có chú thích dài khoảng 500 LoC, bao gồm mesh primitive, boolean operator và API gọn gàng
- Có kế hoạch một ngày nào đó port thư viện này sang Rust để hiểu rõ hơn cách nó hoạt động
- Nếu dùng CSG cùng với mesh processing pipeline hiện có, khả năng tạo ra các kết quả thú vị là rất lớn
- Đặc biệt muốn thử khả năng damage mesh theo cách procedural
- Cắt bỏ các chunk khỏi building hoặc bridge để mô phỏng decay hay weathering
- Tạo crack trên wall hoặc road
1 bình luận
Ý kiến trên Hacker News
Trước đây tôi từng mày mò một chút với sinh thủ tục, đặc biệt là cố tạo ra những cái cây trông đẹp, nhưng mảnh ghép còn thiếu với tôi là cách nối hình học lại với nhau một cách dễ dàng
Tạo hai hình trụ thì dễ, nhưng ghép chúng lại sao cho tự nhiên thì rất khó
Về lý thuyết, CSG có thể lấp khoảng trống này, nhưng cách nghĩ vấn đề theo hướng đó không hề dễ. Vì không thể xem đơn giản như một vòng lặp thêm đỉnh, mà phải mô hình hóa mọi thứ thành hình khối 3D
Tôi cũng từng thử viết một routine nhận hai vòng đỉnh rồi dùng heuristic để thêm các mặt nối chúng lại, nhưng việc chọn đỉnh nào nối với đỉnh nào khó hơn dự kiến rất nhiều, và rất dễ tạo ra các mối nối xấu
Một ngày nào đó tôi muốn làm một game trong đó các hệ thống sinh thủ tục dạng module khác nhau có thể cộng tác mà vẫn giữ được tính ứng biến. Ví dụ như các hệ thống “chiếm” một phần của thế giới, rồi ủy thác phần đó cho hệ thống khác, hoặc nối nó một cách tự nhiên với các yếu tố xung quanh
Gần đây có một video [0] về tạo cây sinh tự động, và lời giải chỉ là để các hình trụ giao cắt nhau. Những cách hacky như vậy cũng có thể hoạt động tốt và cho kết quả ổn
Như đã nói, CSG cũng khả thi nhưng có thể quá phức tạp. Một cách khác là tạo khung xương của cây rồi loft, và nếu cần thì kết hợp với CSG để tạo thân và vỏ cây
Thư viện tốt sẽ mở ra nhiều khả năng. Nếu tìm được một thư viện hình học 3D hỗ trợ các phép toán boolean như hợp nhất hình trụ hoặc trừ hình học, bạn có thể thử rất nhiều ý tưởng mới. Tôi đã dùng thử vài cái, nhưng thứ duy nhất tương đối ưng ý là JSCAD [1]
[0] https://youtu.be/8zMbJmuwEUc?si=KQclrVPeSrIRmsbA
[1] https://github.com/jscad/OpenJSCAD.org
Cách này giống với việc mô tả và biến đổi hình khối 3D theo kiểu hàm
Nếu muốn xem trong demoscene người ta đã làm được gì với nó, tôi rất khuyến nghị tìm Mercury Delight trên YouTube. Trên Shadertoy cũng có nhiều ví dụ, và có rất nhiều thứ thật sự đáng kinh ngạc
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Condition...
Ví dụ dưới đây cũng đáng tham khảo
https://github.com/MaxBondABE/batteries/blob/master/src/geom...
Sinh địa hình tốt hoàn toàn không phải chuyện tầm thường, dù ở quy mô thế giới hay ở quy mô ngang tầm mắt
Cách tiếp cận đơn giản, như thấy trong bài, là tạo một heightmap gồ ghề, nhưng nó hầu như không giống địa hình ngoài đời và cũng không mấy thú vị để khám phá
Chẳng hạn, Dwarf Fortress bắt đầu từ midpoint displacement cơ bản, nhưng sau đó trải qua rất nhiều hậu xử lý tùy chỉnh
Trong những thứ được nêu trong bài này, không có gì dù chỉ mơ hồ là tầm thường cả. Riêng về render bằng shader GPU, tác giả rõ ràng gần với một lập trình viên 100x hơn so với hầu như mọi người trên Trái Đất
“Cách tiếp cận đơn giản” ư, thật sự đơn giản sao?
Trong 8 tỷ người, có bao nhiêu phần trăm có thể triển khai nổi dù chỉ bước “Hello World” cần thiết để bắt đầu bài này? Rồi có bao nhiêu người biết shader là gì? Việc làm OpenGL cũng đâu có nhiều đến thế. Tình huống kiểu “OpenGL là gì vậy, chúng tôi chỉ dùng Unity thôi” cũng rất phổ biến
Còn game thủ online thì sao? Vào lúc 1:22 chiều EST ngày 28/7/2024, trong số 1.021.282 người [1] đang online Counter Strike 2, có bao nhiêu phần trăm có thể triển khai dù chỉ bước đầu tiên của shader cần cho trò chơi họ đang chơi?
Có bao nhiêu phần trăm có thể biên dịch một chương trình C++ dòng lệnh đơn giản, hoặc viết một script JavaScript còn đơn giản hơn trong trình duyệt? Thật ra đây hơi giống câu hỏi bẫy, vì phần lớn mọi người còn chỉ vừa đủ dùng email
[1] https://steamdb.info/app/730/charts/
Cũng như AI, việc sinh nội dung thủ tục tốt nhất rốt cuộc cũng sẽ có hậu xử lý tùy chỉnh trong sản phẩm cuối
Đây là một bài tổng hợp rất tốt về nhiều kỹ thuật thủ tục dùng trên web, thật sự hữu ích
Nếu quan tâm đến trình biên tập màn chơi RPG thủ tục mà tôi đang làm, có thể xem https://github.com/gamedevgrunt/3D-Action-RPG-JavaScript
Trải nghiệm của tôi với depth pre-pass khá lẫn lộn
Sau vài lần thử, tôi không thấy cải thiện hiệu năng đáng kể trên GPU desktop tầm trung đến cao cấp
Tôi không biết chính xác lý do, nhưng có thể là vì early Z rejection đã giảm số lần gọi pixel shader. Thông thường mesh opaque được render theo thứ tự từ trước ra sau
Tuy nhiên, các thử nghiệm của tôi diễn ra trong bối cảnh ứng dụng CAD/CAM chứ không phải game. Cảnh cũng khá khác môi trường game thông thường: ít texture và hình học có số lượng polygon rất lớn
Depth pre-pass đôi khi cũng là bước đầu của occlusion culling, nhưng điều này cũng tùy tình huống. Nó có khả năng hữu ích hơn nhiều trong các cảnh đô thị phức tạp so với mô hình CAD
Nó hữu ích nhất khi độ phức tạp chiều sâu cao và fragment shader đắt. Công bằng mà nói thì phần lớn game thuộc trường hợp này
Trong deferred renderer thường không bắt buộc, nhưng với forward+ thì nhìn chung đem lại lợi ích khá đáng kể