2 puan yazan GN⁺ 2025-02-08 | 1 yorum | WhatsApp'ta paylaş
  • Arazinin kazılıp doldurulabildiği oyunlarda göllerin, nehirlerin ve su birikintilerinin yeni sınırlardan akıp gitmesi gerektiğinden hızlı ve kararlı ızgara tabanlı su simülasyonu gerekir
  • Hedef, yaklaşık 1 m ölçeğinde araziyle aynı ızgarayı kullanan; suyun korunması, kontrol edilebilir kararlılık ve doğrusal güncelleme maliyeti sağlayan 2B bir yükseklik alanı modelidir
  • Smoothed Particle Hydrodynamics ve Stable Fluids, sırasıyla yüksek çözünürlüklü parçacık akışkanlarına ve kapalı akışkan hacimlerine uygun olduğundan, arazi üzerindeki serbest yüzeyi hızlı işleme koşuluyla örtüşmez
  • Benimsenen virtual pipes yöntemi, staggered grid üzerinde su yüksekliğini ve hücreler arası akışı saklar; akış ivmelendirme, dışa akış ölçekleme ve su sütunu güncellemesini birkaç 2B dizi döngüsüyle işler
  • Uygun dt ve g değerlerinde su gibi görünen sonuçlar üretir, ancak eylemsizlik ve hız yayılımı olmadığından hızlı su akıntılarının bir gölün içine doğru ilerleyerek yayılmaması gibi bir sınır kalır

Arazi değiştirilebilen oyunlarda su neden zordur

  • Strateji oyunlarında ya da şehir/köy simülasyonlarında su; doğal sınırlar, denizcilik, balıkçılık, ticaret, deniz savaşları, içme suyu, taşımacılık ve görsellik gibi roller üstlenebilir
  • Arazinin doğrudan değiştirilebilmesi su işlemeyi çok daha zor hale getirir
    • Toprak, kum, kil gibi kaynaklar yerden çıkarıldığında arazinin de birlikte kaldırılması daha doğal görünür
    • Taş ve metal cevherleri de yüzeydeki nesneler olarak durmaktansa, toprağı kazarak çıkarılan kaynaklar olmaya daha uygundur
    • Eğimli yüzeylere bina yapılamıyorsa inşaattan önce arazinin düzleştirilmesi gerekir
    • Yaratıcı ifade aracı olarak arazi düzenleme başlı başına sunulabilir
  • Temel durum, bir gölün ya da su birikintisinin sınırı kazılıp bir su yolu açıldığında suyun nereye ve ne kadar akacağıdır

Basit çözümlerin yetersiz kaldığı noktalar

  • Olası geçici çözümler arasında suyu başlangıç konumunda sabitlemek, belirli bir yüksekliğin altındaki her şeyi su kabul etmek, çok derin kazmayı engellemek veya Minecraft/Dwarf Fortress tarzı basit akış modelleri kullanmak yer alır
  • Bu yöntemler alternatif olarak mümkün olsa da ana model olarak kullanılmak için fazla basit ya da fazla bloklu hisseder
  • Dwarf Fortress modeli diğer örneklere göre daha yakındır, ancak 3B varsayımıyla tasarlanmıştır; gereken problem ise ağırlıklı olarak 2B arazi üzerindeki sudur
  • Timberborn burada ele alınanla aynı modeli kullanır

İstenen simülasyon koşulları

  • Hedeflenen su modeli şu koşulları sağlamalıdır
    • Araziyle aynı ızgara üzerinde çalışması tercih edilir
    • Ortalama ölçek yaklaşık 1 m civarındadır; küçük su sıçramalarını simüle etmek gerekmez
    • Su, arazi üzerinde bir yükseklik alanı olarak görülür; dikey akışlar veya dikey kesitteki boşluklar dikkate alınmaz
    • Su akmalıdır ve simülasyon hataları nedeniyle yok olmamalıdır
    • Kararlılığı kontrol edilebilir olmalıdır
    • Bir adımın maliyeti simülasyon boyutuna göre doğrusal olmalı; ideal olarak birkaç döngüyle biten bir yapı olmalıdır

Mevcut akışkan simülasyonlarıyla uyumsuzluk

  • Smoothed Particle Hydrodynamics etkileyici yüksek çözünürlüklü akışkan sonuçları üretir, ancak burada gereken problemden farklıdır
    • 1 m boyutundaki su parçacıkları su balonu gibi görünebilir
    • Parçacıklar küçültülürse performans maliyeti artar
    • Hedef yüksek çözünürlüklü gerçekçilik değil, hızlı ve makul görünen bir modeldir
  • Jos Stam’in Stable Fluids yaklaşımı, kapalı bir tank gibi akışkanla dolu hacimleri ele alan modele daha yakındır
    • Arazi üzerindeki serbest yüzeyi doğrudan ele alma probleminden farklıdır
    • Bazı adımlarda seyrek doğrusal sistemleri yinelemeli olarak çözmek gerektiğinden maliyetlidir
    • Tüm Navier-Stokes denklemlerini çözmeye yönelik bir yaklaşımdır; burada gereken ise shallow water equations’tır

Shallow water equations ve ızgara seçimi

  • Shallow water equations, arazi üzerindeki su katmanını dikey yönde ortalayıp 2B denklemlerle ele alan bir yaklaşımdır
  • “Shallow”, su sütununun dikey boyutunun ilgilenilen yatay ölçekten çok daha küçük olduğu varsayımını ifade eder
    • Nehir derinliğinin birkaç metreden onlarca metreye, ilgi mesafesinin ise kilometre ölçeğine çıktığı durumlarda geçerli olabilir
  • Yaygın collocated grid, su yüksekliğini ve hızı aynı hücrede saklar; ancak akışkan dinamiğinde sorun çıkarabilir
    • Birinci türev safça ayrıklaştırılırsa yön yanlılığı veya kararsızlık oluşabilir
    • Soldan ve sağdan giren, yukarıdan ve aşağıdan çıkan akışların aynı hücrede bulunması, toplam hızın 0 gibi görünmesi çelişkisini yaratır
  • Staggered grid, su yüksekliği ve yoğunluk gibi değerleri hücrelerde, hız veya akış değerlerini ise hücreler arasındaki kenarlarda saklar
    • N x N su yüksekliği dizisi
    • (N+1) x N X yönü akış dizisi
    • N x (N+1) Y yönü akış dizisi

Virtual pipes yöntemi

  • Virtual pipes, su hücrelerinin sanal borularla birbirine bağlı olduğunu varsayıp akışı hesaplayan bir yöntemdir
  • Başvurulan makalelerden biri çok seviyeli su sütunlarını ve dikey bağlantıları da ele alır; diğeri ağırlıklı olarak hidrolik erozyonu konu alır, ancak burada bu hedef dışarıda bırakılmıştır
  • Saklanan değer sayısı 3’tür
    • water: her hücrenin su sütunu yüksekliği
    • flowX: yatay komşu hücreler arasındaki toplam su akışı
    • flowY: dikey komşu hücreler arasındaki toplam su akışı
  • Hız yerine akış (flow, flux) saklanır
    • Akış, birim zamanda geçen su hacmi olarak görülebilir
    • Boş hücreler arasındaki akış doğal olarak 0 diye tanımlanır
    • Hız, akışın kesit alanına bölünmüş halidir; su neredeyse yokken 0/0 veya eşik değeri sorunları doğurabilir

Bir adımı oluşturan 3 aşama

  • Bir simülasyon adımı üç aşamaya ayrılır
    • Akış ivmelendirme: Komşu hücrelerin su yüzeyi yükseklik farkına göre hücreler arası akışı artırır
    • Dışa akış ölçekleme: Bir hücreden çıkan su, hücrenin gerçekten sahip olduğundan fazlaysa dışa akışları azaltır
    • Su sütunu güncellemesi: Komşu akışlara göre her hücrenin su yüksekliğini artırır veya azaltır
  • Akış ivmelendirme

    • Komşu iki hücrenin su yükseklikleri farklıysa akış yüksek taraftan alçak tarafa doğru ivmelenir
    • X ve Y yönlerindeki iç kenarlar için akış güncellenir; g, dt, dx, dy kullanılır
    • Sanal boru kesit alanı A yalnızca g ile çarpım olarak kullanıldığından basit kullanımlarda g içine katılmış gibi ele alınabilir
    • Sürtünme, her adımda akışı azaltacak şekilde eklenir
    • Makale pow(friction, dt) katsayısını önerir
    • Daha sezgisel değerlerle kullanmak için pow(1-friction, dt) tercih edilebilir
    • friction=0, önceki akışı tamamen yok eden maksimum sürtünme; friction=1 ise sürtünme yok şeklinde görülebilir
    • dt büyüdükçe simülasyon hızlanır ancak kararsızlaşabilir
    • Akışkan simülasyonlarında Courant-Friedrichs-Lewy condition önemlidir
    • Pratikte dt kararlı olana kadar küçültülmelidir; kullanılan değerler kabaca 0.001 ile 0.01 arasındadır
  • Su sütunu güncellemesi

    • Her hücre komşu dört akışa bakarak su ekler veya çıkarır
    • Soldan ve alttan gelen flowX(x,y), flowY(x,y) eklenir
    • Sağa ve yukarı çıkan flowX(x+1,y), flowY(x,y+1) çıkarılır
    • Hesaplanan akışlara göre suyun hücreler arasında gerçekten taşındığı aşamadır
  • Dışa akış ölçekleme

    • Akış çok büyükse güncellemeden sonra bazı hücrelerin su yüksekliği negatif olabilir
    • Her hücre için yalnızca çıkan akışlar toplanır ve bir adımda kaldırılacak suyun gerçek su miktarını aşıp aşmadığı kontrol edilir
    • Kaldırılacak miktar çok büyükse çıkan akışlar aynı oranda azaltılarak su yüksekliğinin 0 veya üzerinde kalması sağlanır
    • Bu aşama, negatif su miktarını engelleyen temel kararlılık mekanizmasıdır

Arazi, sınır koşulları ve viskozite işleme

  • Arazi, akış ivmelendirme aşamasında su sütunu yüksekliği yerine su yüzeyi yüksekliği kullanılarak yansıtılır
    • Su yüzeyi yüksekliği = terrain(x,y) + water(x,y)
    • Arazisi yüksek olan hücre, aynı su sütunu yüksekliğine sahip olsa bile yüzeyi daha yüksek olduğundan suyu hareket ettirebilir
  • Sınır koşulları sınır akış değerleriyle örtük olarak belirlenir
    • flowX(0,y), flowX(N,y), flowY(x,0), flowY(x,N) sınıra karşılık gelir
    • 0 bırakılırsa duvar gibi çalışır
    • Giriş değerleri su ekler, çıkış değerleri suyu kaldırır
    • Arazi üzerindeki suda, harita kenarındaki suyun kaybolduğu dışa akış sınırı doğal olabilir
    • Bir nehrin sınırı geçtiği kısımlar giriş sınırı yapılarak nehir suyunun akması sağlanabilir
  • Sınır akışları her simülasyon adımının başında yeniden ayarlanmalıdır
    • Çünkü dışa akış ölçeklemesi sınır akışlarını değiştirerek dışa akış sınırını duvar gibi davranır hale getirebilir
  • Makalede su yüksekliğine göre akışı azaltan bir viskozite terimi de vardır
    • Fikir, ince su katmanlarının iç kuvvetler nedeniyle zor hareket ettiği; kalın su katmanlarının ise daha özgürce hareket ettiğidir
    • Magma akışı gibi yerlerde yararlı olabilir
    • Suda kullanılmamıştır ve büyük arazi ölçeğinde viskozite etkisi neredeyse yoktur

Uygulama akışı ve performans biçimi

  • Kodun tamamı şu sırayla yapılandırılmıştır
    • Sınır akışlarını başlatma
    • pow(1-friction, dt) sürtünme katsayısını önceden hesaplama
    • X akışını ivmelendirme
    • Y akışını ivmelendirme
    • Negatif su miktarını önlemek için dışa akış ölçekleme
    • Su sütununu güncelleme
  • Simülasyonun büyük kısmı birkaç 2B diziyi dolaşan 4 döngü ve basit formüllerle tamamlanır
  • C++ güncelleme kodunun tamamı water_2d.cpp içinde görülebilir
  • Video örneği birkaç gün önce yayımlanan WebGPU water simulator projesinden alınmıştır; videodaki parçacıklar görselleştirme içindir ve simülasyona katılmaz
  • Uygun dt ve g değerleri bulunduğunda kararlı görünür, gereksinimleri karşılar ve su gibi görünen sonuçlar üretir

Kalan sınırlamalar

  • Bu modelde eylemsizlik ve hız yayılımı yoktur
    • Hızlı bir su akıntısı göle girse bile gölün içine doğru yayılmayı sürdürmez, her yöne dağılır
    • Su yüksekliği aynıysa ters yönlerdeki paralel iki su akıntısı birbirleriyle etkileşmeden var olabilir
  • Su bir bölgeye ilk girdiğinde dalgalar oluşur ve bu biraz tuhaf görünebilir

Altıgen ve üçgen ızgaralara genişletme

  • Hedef oyun kare ızgara değil, düzenli bir üçgen ızgara kullanır
  • Üçgen ızgara, altıgen ızgaranın dual’i olarak görülebilir
    • Komşu altıgen merkezleri çizgilerle birleştirildiğinde düzenli bir üçgen ızgara oluşur
    • Red Blob Games’in hexagonal grids yazısında axial coordinate system’ın pointy-top hex yönünün dual ızgarasında kullanılmasına benzer
  • Üçgen ızgara da hafif eğik genel bir 2B dizide saklanabilir
  • Su sütunu yüksekliği, su yüzeyi render’ını kolaylaştırmak için ızgara köşelerinde saklanır
  • Akış üç yöne ayrılır
    • X yönü akışı
    • Y yönü akışı
    • Z yönü akışı
  • N x N köşe ızgarasında şu diziler kullanılır
    • (N+1) x N X akış dizisi
    • N x (N+1) Y akış dizisi
    • (N+1) x (N+1) Z akış dizisi; ancak bottom-left ve top-right değerleri kullanılmaz
  • Kare ızgarayla karşılaştırıldığında sınır koşullarına, ivmelendirmeye, dışa akış ölçeklemeye ve su güncellemesine Z akışını eklemek yeterlidir
  • En zor kısım indekslemeyi yanlış yapmamaktır
  • Üçgen/altıgen ızgaralar için C++ kodu water_2d_hex.cpp içinde görülebilir
  • Bu yöntem kare ızgaraya göre biraz daha izotropik olabilir

1 yorum

 
GN⁺ 2025-02-08
Hacker News yorumları
  • Akışkan simülasyonuna dair farklı bir yaklaşım olarak Coding Adventure videoları var
    Rendering Fluids: https://www.youtube.com/watch?v=kOkfC5fLfgE
    I Tried Putting my Fluid Simulation on a Planet: https://www.youtube.com/watch?v=8nIB7e_eds4&t=817s
    GitHub: https://github.com/SebLague/Fluid-Sim?tab=readme-ov-file

  • Prosedürel üretimli oyunlarda hidrolojik simülasyonun zor olmasının nedenlerinden biri, su biriktiğinde çevredeki hücreleri etkilemesi ve bu etkinin de diğer komşu hücrelere yayılmaya devam etmesi
    Prosedürel üretim çoğu zaman paralelleştirmeye uygundur, ama tam da paralelleştirmenin en çok gerekli göründüğü sonsuz alanlarda bu hesaplamaları düzgün biçimde paralelleştirmek zordur
    Bu konunun çok fazla araştırıldığını görmedim; bu alanda çalışanlar arasında https://nickmcd.me sitesini özellikle beğeniyorum. Şimdiye kadar gördüğüm en iyi prosedürel arazilerden bazıları orada
    Ancak o çalışmada da simülasyonun tasarımı nedeniyle alan sınırlı. Olası bir çözüm olarak, kırılamayan havza sınırlarını prosedürel olarak üretip sonra tüm havzayı tek seferde paralel simüle etmek en iyi yaklaşım gibi görünüyor
    Çok ilginç bir problem ama bilgi alanımın dışında olduğu için daha çok gözlemci konumundayım

    • Merak ediyorsanız, kısmi diferansiyel denklemleri çözen alanda geçen “etki alanı” ve “bağımlılık alanı” kavramlarına bakabilirsiniz
      Bunlar, belirli bir noktadaki değeri etkileyebilecek alan ile o noktanın değerinin etkileyebileceği alanı ifade eder; yani yukarıda söylenenlerle doğrudan bağlantılıdır. Bazı durumlarda bu alanlar önceden bilinebilir
    • İçtenlikle söylüyorum, https://nickmcd.me sitesine mutlaka bakın. Gerçekten etkileyici
    • İlginç bir soru. Muhtemelen her bölgenin çevresine sınır koyup, etkinin yayılabileceği azami hız, yani nedensellik varsayımıyla bu yapılabilir
      Örneğin 10 saatlik adımı simüle etmek için 10 ızgara hücresi kalınlığında bir sınır koyarsınız. Her bölgede 10 adımı hesapladıktan sonra, paralel hesaplanan diğer sınır simülasyonlarıyla sınır durumunu senkronize eder ve bunu tekrarlarsınız
    • Nick'in daha 25 yaşında olduğunu öğrenince şaşırdım
  • Biraz konu dışı ama, yazıda kaynak toplamak için araziyi değiştirmenin gerekli olduğundan bahsedilen kısım aklıma takıldı
    Animal Crossing'in bunu arazi deformasyonu olmadan da oldukça akıllıca ve verimli şekilde çözdüğünü hep düşünmüşümdür. Ağaç kestiğinizde kütük çıkıyor ama yalnızca belli miktarda; yani fiilen bir bekleme süresi oluşuyor
    Pahalı arazi deformasyonu olmadan da geri bildirim ve sınırlı kaynak hissi verebilirsiniz. Elbette her oyuna uymaz ve küçük haritalarda daha iyi çalışır, ama düşünmeye değer. Oyunun gerçekten ihtiyacı yoksa arazi deformasyonu yapmamak çoğu zaman daha iyidir

    • Yazıda da yakındaki altın cevheri kayaları biçiminde böyle bir stratejiden söz ediliyordu
      Kaynak dağıtma yöntemi olarak standart bir yaklaşım, ama bekleme süresi sonsuz kaynak sorununu çözmüyor; yalnızca yavaşlatıyor. Ayrıca biraz sıkıcı ve etkisi zayıf
  • Bu konuyu tertemiz ele alan bir yazı ve Timberborn'a değinmesine sevindim
    Bu aralar oyuna tamamen sardım; hâlâ denemediyseniz kesinlikle tavsiye ederim. Fizik tabanlı su akışı oyundaki başka bir karakter gibi ve suyu tutup motorlarda kullanmanın ve tarlalara ulaştırmanın yolunu bulmak temel oyun döngüsünü oluşturuyor

  • Eğlenceli ve uygulaması da gerçekten çok iyi olmuş. Böyle şeyler geliştirirken en büyük risk, güzel sonuçlara bakıp parametrelerle oynayarak saatleri harcamak
    2011'de bir makale çalışması için bizzat GPU tabanlı akışkanlar dinamiği uyguladığımı hatırladım. Yüzey, yani doku üzerinde akan bir akışkan olarak kanı ele almıştım; 2D'de simüle edip ardından yerçekimi ve yüzey eğimini dikkate alarak mesh üzerine projekte etmiştim
    Kısa bir videoyu da YouTube'a yüklemiştim: https://youtu.be/4vGrNc-GGW8

  • Gerçekten harika
    Yakın zamanda o3-mini-high yardımıyla benzer bir fikri denedim. Algoritma fikrini anlattım; o da manuel müdahale olmadan bunu 3D olarak uygulayıp render etti. Yine de prompt'u birkaç kez vermem gerekti
    https://3d-water-sim.netlify.app/
    Henüz kusursuz değil ama bunun sebebi kurcalamayı bırakmış olmam; her yinelemede oldukça belirgin biçimde iyileşiyordu. İlginç olan, arazi üretimi için bir yerlerden CDN benzeri bir şey çekmek yerine, Perlin gürültüsünün çalışan bir sürümünü sıfırdan düzgün biçimde uygulamış olması

    • Böyle deneylerde amacın eğlence mi yoksa öğrenme mi olduğunu merak ediyorum. Eğer amaç öğrenmekse, kendin uygulamamış olsan bile bu yazıyı okumanın hâlâ değerli olup olmadığını da merak ediyorum
      Bu, yolculuk ile varış noktası arasındaki farka dair bir soru
  • Yazıdaki “Bu modelde atalet ve hız yayılımı yok. Hızlı bir su akışı göle girse bile gölün içine doğru daha fazla yayılmaz ve birikmiş ataleti yok sayarak her yöne dağılır. Su seviyesi aynıysa, ters yönlerde akan iki paralel su akışı da birbiriyle etkileşmeyebilir” denen kısım, aynı yöndeki çevredeki 6 akış oku ile ortalama alınarak çözülebilir gibi görünüyor
    Bunun için öndeki ve arkadaki oklara büyük ağırlık, yanlardaki oklara ise küçük ağırlık verilir. Örneğin böyle oklar olduğunda
    -a-> -b->
    -c-> -d-> -e->
    -f-> -g->
    New_d = d * (1 - 2*.1 - 4*.01) + (c+e).1 + (a+b+f+b).01
    Buradaki .1 ve .01 rastgele seçilmiş ağırlıklar olduğu için ayarlanması gerekir; titreşimi azaltmak için kullanıldığı gibi üsler de eklenebilir. O katsayı da dahil edilirse şöyle olabilir
    New_d = d * (1 - 2*.1 - 4*.01 - .001) + (c+e).1 + (a+b+f+b).01

    • Doğru çözüme daha yakın yaklaşım, özgün ızgarayla eşleşen bir 2. türev ızgarası daha eklemek gibi görünüyor
      grid 0: her hücrenin su yüksekliği
      grid 1: her kenardaki su akışı, yani 1. türev
      grid 2: her hücrenin su ivmesi, yani 2. türev
      Her ızgara bir önceki ızgaranın düal ızgarası ve onun türev değerini depolayan bir yapı. Aslında kenar verisini özel ele almaya gerek kalmadan yalnızca köşe verisi tutup tamamen düal ızgara olarak işlemek de mümkün gibi görünüyor. Kenar akışı, o kenarın iki ucundaki köşe akışlarının toplamından türetilebilir
      Buna göre akışla akışkan yüksekliği güncellenir, hangi hızla ne kadar akışkan kütlesinin hücreye girdiğine göre ivme güncellenir, ardından ivme ve mevcut akışkan yüksekliğiyle akış güncellenir. Akışkanlar dinamiğini çok iyi bilmiyorum ama sayısal simülasyon açısından doğru görünüyor ve çapraz akış da mümkün hale geliyor
    • Bu yöntem momentumun korunumu ilkesini bozar. Gerçekçi akış elde etmek için süreklilik denklemini kullanarak akışın enerjisini korumak ve kaymanın girdaplara dağılıp yayılmasını sağlamak gerekir
      Yazıda da dendiği gibi hesaplama maliyeti çok daha fazla olacağı için, bu kadar gerçekçiliğin pratik kullanım senaryosu için gerçekten gerekli olup olmadığına önce bakmak gerekir
  • Bunu birkaç yıl önce meraktan yaptığım kaba bir çalışma: https://aperocky.com/hydrosim/
    Bu kişisel proje soğuk depolama rafına kaldırılmadan önce erozyonu nasıl ele alacağımı çözememiştim. Yazarın bu kısma değinip denklemleri de eklemesini beğendim

  • Yakın zamanda benzer bir şeyi yayımladım. İçinde rastgele heightfield üretimi, tortu taşınımı ve erozyon da var: https://github.com/Ono-Sendai/terraingen

  • Şirketimizdeki harika bir geliştiricinin araştırma projesinin parçası olarak yaptığı eğitsel bir sel simülasyonunu doğrudan deneyebilirsiniz
    https://flood.concord.org/
    Belirgin bir etki görmek için alttaki araç çubuğunda model değerlerini değiştirmeniz gerekir
    Bu, WebGL'de komşu hücreleri temel alarak hücre değerlerini hesaplayan hücre tabanlı bir simülasyon. Bu hesabı yapan shader burada
    https://github.com/concord-consortium/flooding-model/blob/ma...