
2026/03/31 17:41
**高速で美しい侵食フィルタ**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
要約
ブログでは、水の流れをシミュレートせずにリアルな谷とリッジを生成するGPUフレンドリーな地形侵食法を紹介しています。開発には 8か月 が要しました。この手法は、Clay John の 2018 年「Eroded Terrain Noise」と Felix Westin/Fewes の 2023 年の改良に基づき、表面勾配と整列したストライプパターンを追加するノイズ関数を使用しています。
回転しやすい単一のピボットでストライプが歪むことを避けるため、パターンはセルに分割され、それぞれにランダムなピボットがあります。隣接セルのストライプは滑らかにブレンドされます。ピークと谷では、ストライプ頻度やフェードが極端になりアーティファクトが発生するため、以下の2つの解決策を導入しています:
- 周波数アプローチ – ストライプ幅を傾斜に比例させる(完全適用時に谷の膨らみが生じます)。
- フェードアプローチ – ストライプ幅は一定ですが、急峻度に応じて白/黒へフェードし、イーズアウト形状関数でV字型谷を保ちます。
著者はさらに3つの技術を紹介して視覚品質を向上させています:
- スタックフェード – オクターブごとにマスクとフェードターゲットを反復適用。
- 正規化された谷 – 閾値以上でサイン/コサインペアを正規化し、ループアーティファクトを回避。
- ストレート谷 – サイン波の符号を傾斜として使用し、直線的な谷の縁を強制。
実装では高さマップと解析微分の両方を出力します。微分は出力時にフェード(ゼロへ)し、内部利用時にはフェードせず、木被覆などの機能が可能です。オプションパラメータで谷の重み、侵食強度、リッジ/クレースの丸め、およびオクターブごとのエッジ丸めを制御できます。
リッジマップ(フェードターゲットから派生し、特定機能を除く)は山側にデンドリック排水ストリークを描画するために使用できます。最終イテレーションは Mozilla Public License v2 の下で公開され、中間版「Clean Terrain Erosion Filter」と高度版「Advanced Terrain Erosion Filter」、および「Mouse‑Paint Eroded Mountains」の Shadertoy リンクが提供されています。
今後の作業として、特定の侵食地形タイプをエミュレートし、パラメータをさらに調整し、オープンエンドな手法によりコミュニティからの貢献を歓迎する計画です。また、Shadertoy Exporter バリアントなどの実用的なエクスポートツールを共有し、Cloudflare 認証や iframe 制限が動画制作に与える課題についても議論しています。
この手法はゲーム開発者とプロシージャルアーティストがGPU上で高速に高品質な侵食効果を生成できるようにし、シミュレーション時間を短縮するとともに、大規模または詳細な世界のサポートを可能にします。
本文
このブログ記事と付随する動画は、過去8か月間にわたって取り組んできた侵食技術について解説しています。
動画では詳細なアニメーションを用いながら、発見・改良・進化のプロセスに焦点を当てています。一方この記事は最終バージョンで実装した具体的な手順やパラメータの詳細を紹介します。
まず動画をご覧いただくことをおすすめしますが、必須ではありません。必要ならば最後のリンクへ直接飛んでください。
実際の侵食と仮想ランドスケープ
自然界では雨水が山側に集まり、小川となって谷間を切り開きます。
これらの小川はさらに大きな流れに合流し、互いにぶつかることで鋭い隆起(リッジ)を残します。
数え切れない水滴をシミュレートすると処理が遅く、チャンク単位で扱うのも難しいため、実際に侵食をシミュレートすることなく「侵食されたような見た目」を作り出す手法が必要です。この記事ではそのような技術を紹介します。
高度な地形侵食フィルタ
Advanced Terrain Erosion Filter のスクリーンショット(自分の作品)
これは、枝分かれした谷間とリッジを生成する特殊ノイズであり、各点を独立して評価できるため高速、GPU フレンドリー、チャンク対応が可能です。
全地形を定義する代わりに、高さ関数上のフィルタとして適用できます。
背景
- Shadertoy:シェーダー(GPU プログラム)を共有するサイト。表面外観やエフェクトを決めます。
- Clay John (Bluesky) は 2018 年に Eroded Terrain Noise を投稿しました。
シミュレーションなしで一回通過だけで動く侵食ノイズを目指していました。 - Fewes / Felix Westin が 2023 年に改良し、洗練されたバージョンを公開しました。
私自身は 2025–26 年に独自実装を行い、オリジナルの欠点を改善した版と、よりシャープな谷間を生成できるパラメータ豊富な版を作成しています。まず基礎概念をレビューし、その後差異について掘り下げます。
基本アイデア
- 高さ関数(その勾配―最大上昇方向と急峻度も提供)から開始します。
水はこの勾配の反対方向に流れます(負勾配矢印を想像)。 - 傾斜方向に沿って「ストライプ」を追加し、傾斜がある面上で交互に谷間とリッジを生成します。
- 繰り返し:新しい傾斜に合わせてさらに小さなストライプを追加。これが枝分かれパターンを生み出します。各反復は オクターブ と呼ばれます。
問題点
非均一な高さ関数に適用すると、単一オクターブの結果は不規則になります。ストライプパターンを回転させると、中心ピボットから遠くなるほど出力が歪みます。
ストライプ生成
- パターンをセルに分割し、各セルごとにランダムなピボット(Worley ノイズのよう)を持たせます。
これで歪みはセル内に限定されます。 - 隣接セルのストライプをブレンドして断続性を回避します:2つのサイン波を混ぜると、振幅が減少した別のサイン波になります。
セルサイズが重要:
- 大きいセル → ピボット1個分の歪みに近くなる。
- 小さいセル → 粒状ノイズになり、すべて白(リッジのみ)になる。各セルのストライプが中央に白帯を持つためです。
ピークの保持
単純な手法では、傾斜がゼロになる峰や谷で折れ曲がりが発生し、勾配方向が急激に変わります。対処法は2種類あります。
1. 周波数アプローチ
ストライプの周波数を傾斜に比例させます:平坦な地形 → 厚いストライプ。峰・谷(ゼロ傾斜)は無限に厚いリッジになります。山岳には有効ですが、侵食強度が高度とともに減衰しないと谷の膨らみを引き起こします。
2. フェードアプローチ
ストライプ幅は一定に保ちつつ、傾斜がゼロになるにつれてターゲット値へフェードさせます。
- 白 にフェード → ピークを保持できるが谷の膨らみも残る。
- 黒 にフェード → 谷の膨らみは除去されるがピークに折れ線が生じる。
- 高度依存のフェードターゲット(例:谷から峰へ黒→白)を使えば、ピークと谷の両方を同時にシャープにできます。
フェードアプローチは次のように表せます:
float inverse_lerp(float a, float b, float v) { return (v - a) / (b - a); } float fadeTarget = inverse_lerp(valleyAlt, peakAlt, h) * 2.0 - 1.0;
不連続性の処理:勾配にイージング関数を適用します。
float ease_out(float t) { float v = 1.0 - saturate(t); return 1.0 - v * v; // sqrt 曲線の鏡像 }
谷間をシャープにし、枝分かれさせる
以下は3つの補完的手法です。
1. スタッキングフェード
各オクターブが原始的な谷間を現在のフェードターゲットへ向けてフェードさせます。その後、急峻な斜面で以降の影響をブロックするマスクを更新します。マスクは任意のディテールパラメータと乗算して結合されます。
float pow_inv(float t, float power) { return 1.0 - pow(1.0 - saturate(t), power); } combiMask = pow_inv(combiMask, detail) * newMask;
2. 正規化谷間
各ストライプのコサイン/サインペアは単位円上の点として解釈できます。これらを補間すると半径が縮む可能性があります。正規化して長さを1に戻します。スパイキーなノイズを避けるため、長さ > 0.5 の値だけを正規化し、
k = 2 を掛けてスケール調整します。
3. ストレート谷間
外挿されたサイン波はリッジや谷底に勾配がないため、小さな谷間は大きなものと平行になり、枝分かれが不自然になります。各谷間ごとに「仮想的な傾斜」を設定し、サイン成分の符号(-1 または 1)を用いて固定勾配を与えます。
// サインの符号で -1 または 1 を決定
これにより枝分かれ角がクリーンになります。
微分情報
フィルタは高さと解析的微分(勾配)を出力しますが、実際にはあまり正確ではありません。内部では2種類の微分版を保持しています:
:ゼロへフェードさせたもの(最終出力に使用)。heightAndSlope
:フェードしないバージョン(内部計算に使用)。gullySlope
この二重アプローチで滑らかさを保ちつつ、内部論理は簡潔にできます。
追加の微調整
頭が尖った峰
正規化した谷間は山頂を柔らかくします。
gullyWeight (0 < gw ≤ 1) を減らし、侵食強度を 1/gw に増やすことで峰を鋭利に保ちつつ、谷の形状を変えません。
リッジとクレーズの丸み
マスクの斜面に可変サイズのイージングを適用し、フェードターゲットに応じてリッジとクレーズ別々に丸み値をブレンドします。オクターブごとにラプランシティで調整可能です。
水の排水(樹状ストリーク)
最終フェードターゲットはリッジ/クレーズマップに近いものです。特定機能を除いた並列コピーを保持すれば、白=リッジ、黒=クレーズを強調した「リッジマップ」を生成できます。谷底に薄い線を重ねることでリアルな排水パターンが得られます。
今後の展望
最新の Shadertoy(Advanced Terrain Erosion Filter と Mouse‑Paint Eroded Mountains)では、手法全体の可能性を示しています。モジュール化されているため、他者は様々な侵食地形をエミュレートしたり、新しいパラメータで実験することが容易です。
コードは MPL v2 で公開しており、さらなる改善にご協力いただけます。
リンク
YouTube 動画
- Fast & Gorgeous Erosion Filter Explained – 詳細なビジュアライゼーションとプロセス解説。
- Better Mountain Generators That Aren’t Perlin Noise or Erosion – シミュレーション不要技術の洗練された動画(自分の動画で参照)。
Shadertoys
| タイトル | 説明 |
|---|---|
| Eroded Terrain Noise by Clay John | オリジナル手法。 |
| Terrain Erosion Noise by Felix Westin | 洗練されたバリエーション。 |
| Clean Terrain Erosion Filter (自分) | 周波数アプローチで再実装した初期版。 |
| Advanced Terrain Erosion Filter (自分) | アニメーション付き最終イテレーション。 |
| Mouse‑Paint Eroded Mountains (自分) | インタラクティブな地形描画。 |
| Phacelle Noise Animation (自分) | 独立したノイズ関数デモ。 |
Shadertoy 動画エクスポーター
- Jonathan Giroux のオリジナルエクスポーターは Cloudflare により停止。
- Lara Davidova のフォーク版は一時的に動作。
- Godot 版(krazyjakee)では Windows 専用、バグが限定的。
野外の侵食フィルタ
| プロジェクト | ソース |
|---|---|
| Erosion on a sphere | metarapi |
| Peak erosion noise | lemon (Desmos) |
| Houdini erosion filter | eetu |
追加メモ
- フェードターゲット:デモでは高度を使っていますが、曲率や他の指標も可能です。曲率は計算が難しく、自然に ([-1, 1]) にマップできません。
- 第2微分:すべての高さ関数が曲率を返す必要があるため、統合が複雑になります。
この技術を使ったプロジェクトをぜひ共有してください!見せてもらえると嬉しいです。