1 điểm bởi GN⁺ 2024-09-29 | 1 bình luận | Chia sẻ qua WhatsApp
  • GodotOceanWaves là một thử nghiệm kết xuất trong Godot Engine nhằm tạo bề mặt biển khơi bằng phép biến đổi Fourier ngược của phổ sóng biển có hướng, đồng thời mô phỏng nhiều môi trường biển khác nhau bằng các tham số có thể điều chỉnh theo thời gian thực qua script
  • Gerstner waves phù hợp với chi tiết tần số thấp của mặt nước yên ả, nhưng có giới hạn với bề mặt biển khơi gồ ghề, nên dự án này sử dụng phổ dựa trên dữ liệu hải dương học thực nghiệm và FFT
  • Việc tạo sóng theo phương pháp Tessendorf: tạo trạng thái phổ ban đầu, lan truyền theo thời gian bằng quan hệ tán sắc, rồi áp dụng biến đổi Fourier ngược để tạo bản đồ độ dời, normal và foam
  • Phần kết xuất tuân theo BSDF trong bài trình bày Atlas GDC nhưng dùng phân bố GGX; foam được tích lũy và suy giảm ở các vùng có Jacobian của độ dời âm; sea spray được triển khai bằng GPUParticles3D của Godot và shader tùy chỉnh
  • Dự án xử lý vấn đề tiling và tải GPU bằng nhiều wave cascade, điều chỉnh chu kỳ cập nhật và phân tán tải theo từng cascade, nhưng các cascade phải dùng cùng độ phân giải texture phổ và cách làm sea spray bằng hạt có hiệu quả tăng mật độ thấp

GodotOceanWaves làm gì

  • GodotOceanWaves là một dự án thử nghiệm kết xuất biển khơi trong Godot Engine
  • Việc tạo sóng sử dụng biến đổi Fourier ngược của phổ sóng biển có hướng
  • Các tham số được công khai theo hướng gọn nhẹ và có thể sửa theo thời gian thực bằng script để mô phỏng nhiều môi trường sóng biển khác nhau
  • Có kèm các video demo ocean_demo.mp4environment_demo.mp4

Vì sao dùng sóng dựa trên Fourier thay vì Gerstner waves

  • Một cách phổ biến để tạo animation cho nước trong game là dịch chuyển vertex bằng Gerstner waves
  • Gerstner waves rất phù hợp để mô hình hóa chi tiết tần số thấp của mặt nước yên tĩnh, nhưng chưa đủ để biểu diễn chính xác bề mặt thô ráp của biển khơi
  • Khi dùng phổ sóng biển dựa trên dữ liệu thực nghiệm do các nhà hải dương học thu thập, có thể kiểm soát trực tiếp hơn việc cần thay đổi loại sóng và tham số nào để tạo ra một trạng thái biển cụ thể
  • FFT có độ phức tạp O(N log N) thấp hơn so với O(N^2) của biến đổi Fourier rời rạc cổ điển, và có thể mở rộng sang hệ thống song song nên phù hợp để chạy trên GPU
  • Với Gerstner waves, mỗi thread phải tính cho N sóng, còn với sóng dựa trên FFT, mỗi thread chỉ cần thực hiện lượng tính toán tương ứng log(N)

Shading, foam và sea spray

  • Mô hình chiếu sáng mặt biển nhìn chung theo BSDF của bài trình bày Atlas GDC
  • Phân bố microfacet dùng GGX thay vì Beckmann
    • Lý do là highlight phẳng và mượt hơn của GGX mang lại vẻ ngoài đồng đều hơn trong nhiều môi trường sóng biển đã thử nghiệm
  • Bản đồ normal/foam được lấy mẫu bằng cách trộn lọc bicubic và bilinear theo mật độ pixel trong không gian thế giới
    • Cách này giảm artifact aliasing của texture ở bề mặt có độ phân giải thấp, đồng thời giữ chi tiết ở bề mặt có độ phân giải cao
  • Sea foam được xác định vị trí tạo theo phương pháp Tessendorf, tại nơi đỉnh sóng cuộn vào trong, tức là nơi Jacobian của độ dời mang giá trị âm
    • Foam được tích lũy tuyến tính vào texture qua nhiều lần cập nhật sóng
    • Các tham số "foam grow rate""foam decay rate" lần lượt điều khiển tích lũy và suy giảm theo hàm mũ
  • Sea spray được triển khai bằng node GPUParticles3D của Godot và shader hạt tùy chỉnh
    • Các hạt được phân bố đều trên một mặt phẳng bên trong bounding box của GPUParticles3D
    • Chúng bị culling theo lượng foam tại vị trí đó, và các hạt không bị culling sẽ bắt đầu vòng đời từ một offset ngẫu nhiên
    • Mỗi hạt dùng billboard sprite với một texture tĩnh
    • Trong suốt vòng đời, scale và displacement được thay đổi để mô phỏng hình dạng splash, còn hiệu ứng dissolve trong mesh shader tạo cảm giác tia nước bị atomize khi bay trong không khí
  • Nhược điểm lớn của cách làm sea spray này là dù tăng mạnh số lượng hạt thì mật độ tăng thêm vẫn rất ít
    • Nguyên nhân là các hạt phân bố đều trong bounding box nên phần lớn hạt thêm vào vẫn bị culling

Pipeline mô phỏng sóng

  • Cách tạo sóng bề mặt bám rất sát phương pháp của Tessendorf
  • Trạng thái biển phổ ban đầu được tạo bằng cách nhân hàm phổ sóng biển có hướng với các số ngẫu nhiên phân bố Gaussian
  • Trạng thái ban đầu được lan truyền theo thời gian bằng quan hệ tán sắc liên kết tần số sóng với tốc độ truyền
  • Áp dụng biến đổi Fourier ngược cho trạng thái đã lan truyền để tạo bản đồ độ dời và bản đồ normal
  • Phần triển khai được xây dựng thành pipeline compute shader sử dụng lớp trừu tượng RenderingDevice của Godot

Cấu hình phổ sóng biển

  • Hàm phổ sóng biển có hướng S(ω, θ) trả về năng lượng của sóng khi biết tần số ω và hướng θ
  • Hàm này được cấu thành từ hàm phổ không hướng S(ω) và hàm khuếch tán có hướng D(ω, θ), và hai lựa chọn này độc lập với nhau
  • Với phổ không hướng, dự án dùng phổ Texel-Marsen-Arsloe(TMA) được Horvath mô tả
    • TMA sử dụng tốc độ gió U, độ sâu nước D và fetch length F
    • TMA kết hợp phổ JONSWAP trước đó với một hàm suy giảm theo độ sâu
  • Với hàm khuếch tán có hướng, dự án dùng cách trộn giữa khuếch tán có hướng flatHasselmann của Horvath bằng tham số spread μ
    • Cũng bao gồm tham số swell ξ do Horvath đề xuất để mô hình hóa độ kéo dài của sóng biển
    • Khuếch tán có hướng Hasselmann được chọn vì nó cung cấp nghiệm giải tích gần đúng cho hệ số chuẩn hóa Q(σ)
  • Theo đề xuất của Tessendorf, hàm phổ kết quả còn được nhân thêm với một hạng tử triệt tiêu sóng nhỏ
    • Hạng tử này sử dụng độ lớn vector số sóng k và tham số detail δ
  • Phổ sóng biển có hướng cuối cùng là sự kết hợp của TMA, directional spread trộn và triệt tiêu sóng nhỏ

Triển khai GPU FFT

  • FFT sử dụng triển khai GPU tùy chỉnh được viết bằng compute shader
  • Dự án dùng thuật toán Stockham FFT thay vì Cooley-Tukey để tránh hoán vị bit-reversal ban đầu
  • Theo Flügge, một texture "butterfly" mã hóa luồng dữ liệu của FFT được tính toán
    • Texture này chỉ cần tính lại một lần mỗi khi độ phân giải texture phổ thay đổi
  • FFT 2D trước tiên áp dụng kernel FFT theo chiều hàng của texture phổ
  • Sau đó texture được transpose bằng compute shader để tái sử dụng cùng kernel FFT theo chiều hàng như thể đó là FFT theo chiều cột
  • Việc transpose không chỉ cho phép tái sử dụng pipeline mà còn cải thiện mô hình truy cập bộ nhớ

Wave cascade và xử lý tiling

  • Ở khoảng cách xa, đặc biệt khi có sea foam, artifact tiling trở nên rất rõ rệt
  • Hệ thống tạo sóng xử lý vấn đề này bằng cách cho phép chồng nhiều wave cascade cùng lúc
  • Mỗi cascade có kích thước tiling và bộ tham số riêng
  • Các cascade có thể được thêm hoặc xóa động theo thời gian thực
  • Vì mọi cascade đều dùng cùng một compute pipeline, chúng phải có cùng độ phân giải texture phổ
  • Một lựa chọn khác là trộn độ dời và normal của sóng với noise để giảm artifact tiling với chi phí hiệu năng thấp hơn
  • Để tránh giao thoa sóng khi chồng các cascade, cần chọn cẩn thận tham số và kích thước của từng cascade
  • Phase sóng của các cascade cũng cần được offset để không giao thoa với nhau
    • Hệ thống tự động thử làm điều này bằng cách offset khác nhau thời điểm bắt đầu của từng cascade
    • Tuy vậy, tài liệu cũng lưu ý chưa chắc cách này thực sự hiệu quả

Phân tán tải cập nhật

  • Vì chuyển động sóng vốn bất quy tắc nên ngay cả khi không cập nhật độ dời mỗi frame, cảm nhận thị giác vẫn có thể đủ mượt
  • Tham số "update rate" điều khiển tần suất cập nhật mỗi giây của wave cascade
  • Bỏ qua frame giúp giảm thời gian GPU dành cho FFT, nhưng ở những frame có chạy pipeline tạo sóng vẫn xảy ra hiện tượng khựng
  • Thử nghiệm tính toán bất đồng bộ cập nhật cascade bằng local RenderingDevice của Godot đã tạo ra overhead hiệu năng lớn do truyền texture giữa CPU và GPU
  • Thay vào đó, hệ thống thử phân tán tải cho các cascade
    • Nếu thời gian frame ngắn hơn update rate thì mỗi frame chỉ cập nhật một cascade
    • Cách này giảm khựng hình trong khi vẫn giữ lợi ích giảm tải GPU từ việc bỏ qua frame

Tài liệu tham khảo

1 bình luận

 
GN⁺ 2024-09-29
Các ý kiến trên Hacker News
  • Hai kho Godot khác do người này tạo cũng rất thú vị. Tôi thích việc họ đưa nhiều chi tiết khi mô tả kho, và kho này đặc biệt nổi bật: https://github.com/2Retr0/GodotGaussianSplatting
    Không biết có phải sinh viên không. Họ thường xuyên trích dẫn các công trình khác và có vẻ hiểu khá rõ các tài liệu mới công bố gần đây

    • Có vẻ có khả năng là sinh viên. Tiêu đề và mô tả của một kho là ENGR96A-coursework, Relevant coursework for ENGR 96A Introduction to Engineering Design F23, và nhìn vào ngày commit thì F23 có vẻ nghĩa là học kỳ mùa thu năm 2023
      Tất nhiên, các lớp UCLA được nhắc tới trong kho có thể được mở cho tất cả mọi người, nên có thể không nhất thiết phải là sinh viên ghi danh tại UCLA theo nghĩa truyền thống mới học được
  • 20 năm trước, có lẽ dù chỉnh mặt biển trong phần render hàng tháng trời cũng không thể đến gần mức này. Kết quả làm ra thật sự rất tốt
    Tuy nhiên video demo trông hơi phóng đại. Với tư cách người có nhật ký hàng hải hơn 50.000 hải lý đi biển khơi, nếu sóng sắc và cao như vậy thì gió phải thổi mạnh hơn rất nhiều. Dù vậy có lẽ chỉ cần chỉnh tham số là được
    Nếu làm bằng Godot thì có thể xem là render thời gian thực không? Tôi cũng tò mò liệu có cần GPU quái vật không

    • Đây không phải phê phán mà là quan sát: nếu tưởng tượng một biển siro ngô nóng được nhuộm màu xanh, có lẽ nó sẽ trông như thế này. Độ nhớt có vẻ đúng, nhưng sức căng bề mặt có thể khác nước biển thật. Nước biển thật là H2O mặn cùng với vật chất sinh học dạng keo, một thứ rất phổ biến ngoài đời nhưng khá bẩn thỉu đối với động lực học chất lưu tính toán
      Ngoài ra, bọt nước biển ở đây trông như một hiệu ứng hậu kỳ, trong khi ngoài biển thật, bọt nước làm cùn độ sắc của sóng và điều đó cũng lờ mờ hiện ra về mặt thị giác
      Dĩ nhiên mô hình thanh nhã, đơn giản và hiệu quả này hầu như không có vật lý, nên mong hãy xem những điều này như vài gợi ý để thử chọc vào và thử nghiệm, hơn là kiểu khoanh tay phê bình
    • Ngày nay có nhiều video nói về những thứ này nên toàn bộ quy trình đã dễ tiếp cận hơn phần nào, nhưng vẫn còn rất nhiều cạm bẫy
      Một trong các video tôi thích về chủ đề này: https://m.youtube.com/watch?v=yPfagLeUa7k
      Cái này cũng ổn: https://m.youtube.com/watch?v=kGEqaX4Y4bQ
    • Tôi có một dự án game, nhưng cứ thấy công nghệ game hay ho là lại bị nerd sniping và muốn tự triển khai. Nếu dùng hoặc mua asset có sẵn thì tiến độ tôi làm đến giờ chắc cũng có thể làm được trong một game jam 48 giờ
      Thay vào đó, cuối tuần nào tôi cũng nghịch water shader cho đến khi có được diện mạo mong muốn. Nhưng game của tôi là game giải đố nên chẳng cần nước. Giờ tôi chỉ có thêm một màn hình bắt đầu thật ngầu mà thôi
    • Khi tôi tốt nghiệp, làm những thứ như particle engine hay marching cubes đã là dự án luận văn tốt nghiệp rồi
      Giờ chúng chỉ là một ô checkbox trong game engine, và còn vô số tính năng như thế. Mọi người khó hình dung môi trường hiện nay tốt đến mức nào nhờ các engine hiện đại
      Tôi không có ý hạ thấp giá trị của công trình này; đây thật sự là một thành tựu tuyệt vời và xin tán dương tác giả. Tôi chỉ muốn nói rằng chúng ta đang sống trong một thời kỳ tốt đẹp đến mức nào
    • Tôi đồng ý rằng chỉ nhìn video thì nó có vẻ hơi ngẫu nhiên
      Dù vậy trông rất tốt, và trong phạm vi tôi tìm hiểu sơ gần đây thì có lẽ thuộc hàng tốt nhất trong những thứ khả thi
      Cá nhân tôi muốn thấy sóng ngoài khơi thường có nhịp điệu hơn. Tôi tò mò liệu mô phỏng gió 15 knot thổi trên mặt nước dài 1 km trong vài giờ có khớp với những gì quan sát thực tế không, tức là các đợt vỡ sóng tương đối có trật tự hình thành rồi tan ra
  • Những thứ như thế này đã kéo tôi vào thế giới máy tính, vậy mà lúc nào không hay tôi lại sa vào cuộc sống dễ dàng và nhàm chán của việc nối các thư viện, endpoint và những thứ nhảm nhí kiểu doanh nghiệp với nhau, dẫn tới burnout
    Hy vọng một ngày nào đó tôi có thể quay lại

    • Tôi nghĩ cứ dịch chuyển từng chút một là được. Hãy tìm lĩnh vực ban đầu khiến bạn hứng thú, muốn học thêm và cuối cùng muốn làm thử; đào sâu vài giờ mỗi tuần rồi tăng dần, đồng thời rời xa công việc hiện tại
      Mong bạn thử. Mọi người đều đang cổ vũ bạn
    • Tôi thấy nhiều bạn bè kiếm nhiều tiền hơn tôi nhờ làm những việc như vậy, nhưng tôi đã đi theo mối quan tâm của mình và chuyển sang robotics ngay cơ hội đầu tiên, và không hối hận. Ít nhất với tôi, không gì bằng cảm giác nhìn code của mình tương tác với thế giới thực
  • Cách tiếp cận thì khác, nhưng nếu quan tâm đến mô phỏng sóng/đại dương, Acerola đã làm một video tuyệt vời như thường lệ về chủ đề này. https://youtu.be/PH9q0HNBjT4https://youtu.be/yPfagLeUa7k
    Sửa: một cái đã được liên kết trong phần tài liệu tham khảo, nhưng vì dùng tên thật thay vì nickname nên giờ tôi mới nhận ra

  • Thật thú vị là vấn đề này khó đến mức nào. Đã cố gắng suốt hàng chục năm mà vẫn còn nằm trong thung lũng kỳ dị
    Nếu tạm dừng cảnh này lại, những con sóng nhô lên trông như núi phủ tuyết. Để nước có hình dạng sắc như vậy thì gió phải khá mạnh, nhưng gió không thể thổi thẳng lên trên, nên cảm giác không thực tế. Những đặc điểm sắc nhọn như thế phải có tính định hướng
    Dù vậy, tính chất của sóng lừng được nắm bắt khá tốt. Chuyển động lên xuống lớn hơn chuyển động ngang, đúng với những gì có thể mong đợi ở biển khơi

    • Tôi đã chơi Nightingale, và nước biển trong đó thật sự đặc biệt. Nói rõ hơn, có vẻ họ giữ sóng ở mức êm để không phải xử lý các vấn đề như bọt nước, rồi tập trung vào những phần khác
      Tôi không biết họ mô phỏng truyền sáng như thế nào, nhưng nó hoạt động tốt. Ánh sáng xuyên qua giữa các con sóng lúc bình minh hoặc hoàng hôn rất tuyệt, khiến hiệu ứng thật sự thuyết phục
      Có thể nói là hơi thiên về hội họa, nhưng không trông sai
  • Tôi đã sống ở bãi biển vài năm. Khi sống ở bãi biển, biển mê hoặc và dễ chịu về mặt cảm giác đến mức bạn có thể nhìn hàng giờ. Nhìn thứ này, có lẽ tôi sẽ không nghĩ dù chỉ một khoảnh khắc rằng đây là render

    • Hiện tôi sống ở bãi biển và còn có tầm nhìn từ độ cao khoảng tầng 14 so với mặt nước, nhưng kỳ lạ là tôi thấy rõ đây là giả. Không có những mảng tối do gió giật tạo ra, và các phần trắng đi thẳng lên chứ không cuộn vào dù chỉ một chút. Ngoài những điểm đó thì khá giống thật
    • Bạn đã từng thật sự nhìn sóng và chuyển động của chúng chưa? Nếu đã sống ở bãi biển vài năm, bạn sẽ nhận ra ngay rằng sự hình thành bọt và chuyển động của sóng không tự nhiên
  • Trên Shadertoy cũng có ví dụ khá ổn: https://www.shadertoy.com/view/Ms2SD1

  • Fourier đã nghĩ ra phép biến đổi tần số sóng khi đo sóng thủy triều, nên theo một nghĩa nào đó thì gần như đã đi trọn một vòng
    Rất ấn tượng

  • Tuy tuyệt vời, nhưng cách tiếp cận này sẽ phần nào sụp đổ với các con sóng thật lớn do tính phi tuyến. Gợn nước không phải sóng sin, nhưng với sóng nhỏ và sóng cao trung bình thì đủ giống để phương pháp này hoạt động rất tốt
    Sóng cực lớn không chỉ lệch xa sóng sin hơn nhiều, mà các con sóng còn bắt đầu tương tác phi tuyến với nhau, điều mà phương pháp chồng chập tuyến tính dùng ở đây không thể nắm bắt
    Vì vậy với hầu hết trạng thái biển, nó rất tuyệt. Nhưng nếu muốn tạo sóng kiểu “The Perfect Storm” một cách thực tế thì cần cách tiếp cận khác

  • Rất ấn tượng và tốt hơn những gì tôi từng thấy, nhưng sóng lừng có cảm giác hơi lệch. Nếu phải giải thích thì tôi nghĩ sóng tần số cao không di chuyển cưỡi lên trên sóng tần số thấp như trong video