การเรนเดอร์คลื่นทะเลแบบ FFT ที่นำไปใช้งานใน Godot
(github.com/2Retr0)GodotOceanWaves
เป็นการทดลองเรนเดอร์ทะเลเปิดด้วย Godot Engine โดยสร้างคลื่นจากการแปลงฟูริเยร์ผกผันของสเปกตรัมคลื่นทะเลแบบมีทิศทาง มีพารามิเตอร์แบบเรียบง่ายที่สามารถปรับคุณสมบัติของคลื่นได้แบบเรียลไทม์ผ่านสคริปต์ เพื่อจำลองสภาพแวดล้อมคลื่นทะเลได้หลากหลายรูปแบบ
บทนำ
ทำไมต้องใช้การแปลงฟูริเยร์?
- วิธีทั่วไปในการทำแอนิเมชันน้ำในวิดีโอเกมคือการใช้ Gerstner waves อย่างไรก็ตาม วิธีนี้เหมาะกับการจำลองรายละเอียดความถี่ต่ำของผิวน้ำที่สงบ แต่ยังไม่เพียงพอสำหรับการแสดงพื้นผิวทะเลเปิดที่ขรุขระได้อย่างแม่นยำ
- เพื่อแก้ปัญหานี้ จึงจำลองคลื่นด้วย การแปลงฟูริเยร์ผกผัน ของสเปกตรัมคลื่นทะเลที่อิงจากข้อมูลเชิงประจักษ์ซึ่งนักสมุทรศาสตร์เก็บรวบรวมไว้
- ข้อดีของการทำงานในโดเมนความถี่คือสามารถปรับคุณสมบัติของทะเลได้ง่าย เมื่อใช้ Gerstner waves จะไม่ชัดเจนว่าต้องปรับคลื่นและพารามิเตอร์อย่างไรเพื่อเลียนแบบสภาวะทะเลแบบใดแบบหนึ่ง
- ใช้อัลกอริทึม Fast Fourier Transform (FFT) ในการคำนวณการแปลงฟูริเยร์ ซึ่งมีความซับซ้อนในการคำนวณต่ำกว่าอัลกอริทึมการแปลงฟูริเยร์แบบไม่ต่อเนื่องแบบดั้งเดิม และเหมาะกับการรันบน GPU
ผลลัพธ์
การเชดคลื่น
โมเดลแสง
- โมเดลแสงของทะเลยึดตาม BSDF ที่อธิบายไว้ใน GDC talk ของ 'Atlas' เป็นหลัก แต่ใช้การกระจายแบบ GGX แทนการกระจายแบบ Beckmann สำหรับการกระจายของผิวจุลภาค
- มีการสุ่มตัวอย่าง normal/form map โดยผสมการกรองแบบ bicubic และ bilinear ตามความหนาแน่นพิกเซลใน world space
ฟองทะเล
- Tessendorf เสนอวิธีสร้างฟองเมื่อยอดคลื่นม้วนกลับเข้าหาตัวเอง
- ฟองจะสะสมแบบเชิงเส้นและสลายแบบเอ็กซ์โปเนนเชียล โดยควบคุมด้วยพารามิเตอร์ "อัตราการเติบโตของฟอง" และ "อัตราการสลายของฟอง"
ละอองน้ำทะเล
- ละอองน้ำทะเลถูกจำลองเป็นอนุภาคโดยใช้โหนด GPUParticles3D ของ Godot
- อนุภาคถูกกระจายอย่างสม่ำเสมอภายใน bounding box ของโหนด GPUParticles3D
- อนุภาคละอองน้ำทะเลแต่ละตัวใช้ billboard sprite ที่มีเท็กซ์เจอร์คงที่เพียงหนึ่งภาพ
การจำลองคลื่น
- วิธีสร้างคลื่นผิวน้ำเป็นไปตามแนวทางของ Tessendorf
- ฟังก์ชันสเปกตรัมคลื่นทะเลแบบมีทิศทางจะคืนค่าพลังงานของคลื่นตามความถี่และทิศทาง
สเปกตรัมคลื่นทะเล
- เลือกใช้สเปกตรัม Texel-Marsen-Arsloe (TMA) เป็นฟังก์ชันสเปกตรัมแบบไม่มีทิศทาง
- ใช้การผสมระหว่างฟังก์ชันการกระจายทิศทางแบบ flat และ Hasselmann
Fast Fourier Transform
- เขียน FFT implementation แบบปรับแต่งเองสำหรับ GPU
- ใช้อัลกอริทึม Stockham FFT เพื่อหลีกเลี่ยงการเรียงสับเปลี่ยนแบบ bit-reversal ในขั้นต้น
คลื่นแบบคาสเคด
- เมื่ออยู่ในระยะไกล อาการ tile artifact จะเห็นได้ชัดมาก
- ระบบสร้างคลื่นสามารถซ้อนหลาย wave cascade พร้อมกันได้
การกระจายภาระงาน
- การเคลื่อนไหวของคลื่นยังสามารถดูนุ่มนวลได้แม้ไม่อัปเดต displacement ทุกเฟรม
- มีการเพิ่มพารามิเตอร์ "อัตราการอัปเดต" เพื่อควบคุมความถี่ต่อวินาทีที่ wave cascade จะถูกอัปเดต
เอกสารอ้างอิง
- Flügge, Fynn-Jorin. Realtime GPGPU FFT Ocean Water Simulation. Hamburg University of Technology. (2017).
- Gunnell, Garrett. I Tried Simulating The Entire Ocean. (2023).
- Horvath, Christopher J. Empirical Directional Wave Spectra for Computer Graphics. DigiPro. (2015).
- Tessendorf, Jerry. Simulating Ocean Water. SIGGRAPH. (2004).
- Matusiak, Robert. Implementing Fast Fourier Transform Algorithms of Real-Valued Sequences. Texas Instruments. (2001).
- Mihelich, Mark. Wakes, Explosions and Lighting: Interactive Water Simulation in 'Atlas'. GDC. (2019).
- Pensionerov, Ivan. FFT-Ocean. GitHub. (2020).
การแสดงลิขสิทธิ์
- Evening Road 01 (Pure Sky) by Jarod Guest is used under the CC0 1.0 license.
- OTFFT DIT Stockham Algorithm by Takuya Okahisa is used and modified under the MIT license.
สรุปโดย GN⁺
- GodotOceanWaves เป็นการทดลองเรนเดอร์ทะเลเปิดด้วย Godot Engine โดยสร้างคลื่นจากการแปลงฟูริเยร์ผกผันของสเปกตรัมคลื่นทะเลแบบมีทิศทาง
- ใช้ Fast Fourier Transform (FFT) เพื่อให้ทำงานได้อย่างมีประสิทธิภาพบน GPU และสามารถจำลองสภาพแวดล้อมคลื่นทะเลได้หลากหลายรูปแบบ
- ครอบคลุมองค์ประกอบหลายด้าน เช่น การเชดคลื่น ฟองทะเล ละอองน้ำทะเล และการจำลองคลื่น เพื่อจำลองพื้นผิวทะเลที่สมจริง
- โปรเจ็กต์นี้อาจเป็นประโยชน์ต่อการสร้างการเรนเดอร์ทะเลที่สมจริงในวิดีโอเกมและงานจำลองต่างๆ
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ที่เก็บข้อมูล Godot อีกสองอันของคนนี้ก็น่าสนใจมากเช่นกัน
เมื่อ 20 ปีก่อน ต่อให้ใช้เวลาหลายเดือนไปกับการเรนเดอร์พื้นผิวทะเล ก็ยังไปไม่ถึงระดับนี้
คลิปเดโมให้ความรู้สึกโอเวอร์ไปนิดหน่อย
คาดว่าการเรนเดอร์ใน Godot นี้ทำงานแบบเรียลไทม์
ของแบบนี้นี่แหละที่ทำให้เริ่มสนใจคอมพิวเตอร์ แต่ระหว่างทางก็หมดไฟเพราะต้องเจอกับไลบรารี, endpoint และงานบริษัท
ถ้าสนใจการจำลองคลื่น/ทะเล Acerola เคยลงวิดีโอเจ๋ง ๆ เกี่ยวกับหัวข้อนี้ไว้
น่าสนใจว่าปัญหานี้มันยากขนาดไหน
เคยอาศัยอยู่ริมชายหาดมาหลายปี
วิธีนี้มีข้อจำกัดอยู่บ้างเมื่อเป็นคลื่นลูกใหญ่มาก
ใน Shadertoy ก็มีตัวอย่างเจ๋ง ๆ เหมือนกัน
Fourier คิดค้นการแปลงความถี่ของคลื่นขึ้นมาจากการวัดคลื่นน้ำขึ้นน้ำลง
น่าประทับใจมาก แต่ยังมีปัญหาเล็กน้อยเรื่องความนุ่มของคลื่น