サイン波から始める。
サイン波は−1から1の間を滑らかに繰り返します。 A を掛けて高さを決めます。空間方向の広がりは波長 λで決め、時間を引くと波の山が移動します。
- A · 振幅
- 基準の水面からの高さ。山から谷までは2Aです。
- λ · 波長
- 隣り合う山の間の距離。
- ω · 角周波数
- 位相が変化する速さ。単位はラジアン毎秒です。
波の形が進んでも、水がそのまま前へ流れるわけではありません。点を見てください。この高さ場のモデルでは、横方向に固定された場所が、山の通過に合わせて上下するだけです。
海は、一本の線から始まる。
リズムを与え、ほかの波を重ね、
最後に光を当ててみよう。
04 / 光を加える大きな世界の、小さな研究
形はメッシュ表示と同じです。細かな波紋が輝きを散らし、深さが色を変えます。波を止めてから太陽を動かしてみましょう。
色 = 透過光 + 空の反射 + 太陽の光考え方 / 単純なルールから生まれる美しさ
ゲームの水は、平らな面からつくれます。関数で各点の高さを決め、時間で模様を動かし、光で濡れた印象を与える。小さな判断を重ねながら、その仕組みをつくりましょう。
これは見た目を設計した波のモデルです。池や海の水面づくりの出発点になりますが、液体の流れ、水しぶき、砕ける波をシミュレーションするものではありません。
サイン波は−1から1の間を滑らかに繰り返します。 A を掛けて高さを決めます。空間方向の広がりは波長 λで決め、時間を引くと波の山が移動します。
波の形が進んでも、水がそのまま前へ流れるわけではありません。点を見てください。この高さ場のモデルでは、横方向に固定された場所が、山の通過に合わせて上下するだけです。
ひとつの波だけでは、少し整いすぎて見えます。間隔、方向、速度の違う小さな波を重ねましょう。山どうしは強め合い、山と谷は打ち消し合います。少数の単純なルールから、複雑な形が生まれます。
この例は4つの波を使います。どれも同じサインのルールに従い、それぞれの進行方向の距離を使います: dxx + dzz。2つの方向成分は単位ベクトルです。このデモでは、小さな波の振幅を主な波の45%、22%、10%にしています。
小さな三角形でできた平らなシートを想像してください。各頂点の横方向の座標から、 Hを計算し、その値を縦方向の位置に使います。頂点は横に動かず、高さだけを変えます。
メッシュ表示で構造が見えます。長い波は輪郭を、短い波は細部を決めます。細かな波を滑らかに見せるには、十分な頂点数が必要です。この研究では128 × 128のセルを使い、メッシュでは4本ごとの線を表示して読みやすくしています。
青く塗るだけでは、青いシートです。重要な手がかりは、 面の法線です。それぞれの小さな面が向く方向を表します。波の傾きから計算するので、形をつくる数学と光の反応が一致します。
光の計算に使う法線に細かな波紋を加え、空の反射、鋭い太陽の輝き、水を通る光を組み合わせます。大きな4つの波が形を決めます。フレネル近似により、浅い角度で見るほど反射が強くなります。波を止めても、太陽を回すと輝きが動きます。
屈折によって、砂と小石を手続き的に描いた底の見え方がずれます。深さは青よりも暖色の光を速く吸収します。動く明るい模様は、水面が集める光であるコースティクスを表します。「水の仕上げ」で透明度、波紋、深さを比べましょう。透明度は、側面を通る光も含めた屈折経路の吸収を変えます。側面は説明用の断面で、コースティクスも手続き的な近似です。岸の泡、砕ける波、物体との相互作用は、より本格的な描画で加える別の要素です。
自分で試す / ひとつの式、ふたつの雰囲気
低い振幅と広い間隔で、静かな池をつくりましょう。振幅を上げ、山を近づけると、にぎやかな水面になります。両方を止めて、傾きの違いを見てください。
次に、波の高さをゼロにします。面は平らになっても、空を反射できます。水らしさのどこまでが形で、どこからが光でしょうか?
自分の海へ戻る ↑これは高さを計算する中心部分です。描画では、光のためにその微分も計算します。デモは任意のシーン単位を使い、動きのスライダーは時間の速さを変えます。
function wave(x, z, time, A, wavelength, omega, direction) {
const distance = direction.x * x + direction.z * z;
const phase = 2 * Math.PI * distance / wavelength - omega * time;
return A * Math.sin(phase);
}
// Add waves with different amplitudes, wavelengths and directions.
const height = waves.reduce((sum, w) =>
sum + wave(x, z, time, w.A, w.wavelength, w.omega, w.direction), 0);
// Move the vertex to (x, height, z).物理的な深水波では、角周波数と波長はω² = gkで結ばれ、k = 2π/λです。ここでは見やすい研究になるよう周波数を選んでいます。スライダーは表現のための操作です。