1 ポイント 投稿者 GN⁺ 2 시간 전 | 1件のコメント | WhatsAppで共有
  • ブラウザシェーダーが Rayleigh散乱、Mie散乱、オゾン吸収を組み合わせて、青空と夕焼け・朝焼けをリアルタイムにレンダリングする
  • カメラ光線の 光学的深さ と Beer's Law の透過率を積算し、位相関数で太陽方向に応じた散乱分布を計算する
  • 夕焼け効果は各サンプルで太陽方向に別途 light-march を実行し、太陽光が大気を通過しながら失う量を反映する
  • 平面スカイシェーダーは depth buffer とワールド座標の復元によって ポストプロセス効果 となり、シーンオブジェクト間の大気フォグまで処理する
  • 惑星スケールでは logarithmic depth buffer、ray-sphere intersection、LUT ベースの Transmittance・Sky-view・Aerial Perspective へと拡張される

大気散乱シェーダーの目標と参考資料

空のレンダリングの基本モデル

  • 単純なグラデーションでは不十分な理由

    • 空の色は単なる青い背景ではなく、光が空気とその構成要素と相互作用した結果として扱う必要がある
    • 観測者の高度、塵の量、時間帯といった変数を考慮する必要があり、計算は ボリューム(volume) の中で行われる
  • 大気密度のサンプリング

    • 大気は volumetric cloudsvolumetric light のように raymarching でサンプリングする
    • カメラ位置から光線を飛ばし、透明な媒質に沿って前進しながら、大気を通過して生き残る光である 透過率(transmittance) と、各サンプルでカメラ方向へ再指向される 散乱(scattering) を計算する
    • raymarching の復習資料として Painting with Math: A Gentle Study of Raymarching を参照できる
  • Rayleigh密度と光学的深さ

    • 透過率を求めるには、光線が通過しながら出会う大気密度を積算して 光学的深さ(optical depth) を計算する必要がある
    • Rayleigh密度関数は高度 h における「空気」の量を表し、高度が上がるほど大気が希薄になる効果を反映する
    • 実装例では RAYLEIGH_SCALE_HEIGHT = 8.0km、ATMOSPHERE_HEIGHT = 100.0km、VIEW_DISTANCE = 200.0km、PRIMARY_STEPS = 24 を使用する
    • rayleighDensity(h)exp(-max(h, 0.0) / RAYLEIGH_SCALE_HEIGHT) で、ループ内では viewOpticalDepth += dR * stepSize として積算される
  • Beer's Law と昼の空の青さ

    • 光学的深さから特定地点の透過率 T を計算し、T=1.0 は光損失なし、T=0.0 は光が完全に消えたことを意味する
    • 透過率は Beer's Law で計算され、実装例では vec3 transmittance = exp(-rayleighBeta * viewOpticalDepth) を使用する
    • rayleighBeta は Rayleigh散乱係数であり、シェーダーでは vec3(0.0058, 0.0135, 0.0331) として保存される
    • 太陽光方向と視線光線の間の角度は 3.0 / (16.0 * PI) * (1.0 + mu * mu) という形の Rayleigh phase function でモデル化される
    • Rayleigh散乱係数のため、赤はほとんど散乱されず、緑はやや多く散乱され、青が最も多く散乱されるため、昼の空は青く見える
    • これをピクセルごとに1本の光線へ拡張すると、地平線方向ではより多くの大気を通過するため明るい白いもやのように見え、高度が上がるほどより深く暗い青へと変化する

Mie散乱とオゾン吸収

  • Rayleighだけでは足りない効果

    • Rayleigh散乱だけでも十分に見栄えのする結果は得られるが、より現実的な空には追加の大気効果が必要である
    • Mie散乱 は塵やエアロゾルのようなより大きな粒子と光の相互作用を表し、密度関数と方向ごとの再分配を表す位相関数を持つ
    • オゾン吸収 は上層大気を通過する光の一部波長を散乱させるのではなく経路から取り除く
    • オゾン吸収は特に地平線、夕焼け、朝焼け前後の薄明で空の色をより深くし、色相を移動させる
  • Mieとオゾンの積算

    • Rayleigh、Mie、オゾンを併用する実装では、それぞれの光学的深さを viewODRviewODMviewODO に積算する
    • 各サンプルでは dR = rayleighDensity(h)dM = mieDensity(h)dO = ozoneDensity(h) を計算し、tauBETA_R * viewODRBETA_M_EXT * viewODMBETA_OZONE_ABS * viewODO の和で構成される
    • 透過率は exp(-tau) で計算され、sumRsumMsumO には各密度と透過率、stepSize が積算される
    • 最終的な散乱は SUN_INTENSITY * (phaseR * BETA_R * sumR + phaseM * BETA_M_SCATTER * sumM + BETA_OZONE_SCATTER * sumO) の形で計算される
  • 主な定数と効果

    • MIE_SCALE_HEIGHT はエアロゾル用の RAYLEIGH_SCALE_HEIGHT に相当し、粒子は通常地平線近くに集中するため、より小さい 1.2km に設定される
    • MIE_BETA_SCATTER は粒子がどれだけ光をカメラ方向へ散乱するかを制御し、ほとんどが波長非依存であるため vec3(0.003) に設定される
    • MIE_BETA_EXT は経路からどれだけの光が除去されるかを示す Mie 消滅係数であり、遠方の大気をより霞んで見せる
    • MIE_G は異方性を制御し、0.0 は一様散乱、1.0 はより強い前方散乱バイアスを意味する
    • OZONE_BETA_ABSvec3(0.00065, 0.00188, 0.00008) の値を持ち、緑や黄橙系をより多く吸収して、空の色を青・赤・紫方向へ移動させる
    • Mieとオゾンを統合すると、より自然な「sky blue」の色と太陽周辺の霞んだ光のにじみが生まれ、太陽が地平線近くにあるときには Mie散乱の効果がよりはっきり現れる

光の経路と夕焼け・日の出

  • 既存実装の限界

    • sky fragment shader はさまざまな高度で自然な色をレンダリングでき、Mie、Rayleigh、オゾンの透過率モデルを反映できる
    • しかし太陽を地平線近くへ移動させても、光の減衰や夕焼け・日の出の効果はなく、白くぼんやりした光の塊が現れるだけだった
    • 既存の raymarching ループが、カメラから各サンプルまでの視線レイ上でしか光の減衰を計算していなかったためである
    • サンプル地点に到達する前に、太陽光が大気を通過する間にどれだけ失われるかも計算する必要がある
  • light-march のネストされたループ

    • 各サンプル地点で光源方向に別のネストされたループを回し、その経路の透過率をサンプリングする
    • 関連するアプローチは real-time cloudscapesvolumetric lighting でも使われている
    • lightMarch(float start, float sunY)LIGHTMARCH_STEPS 回繰り返しながら odRodModO を蓄積する
    • 既存実装の光学的深さ viewODRviewODMviewODO に、太陽方向の光学的深さ sunOD を加える
    • 最終的な tauBETA_R * (viewODR + sunOD.x)BETA_M_EXT * (viewODM + sunOD.y)BETA_OZONE_ABS * (viewODO + sunOD.z) を足し合わせて構成される
    • この実装により、夕焼け、日の出、天頂の太陽、その中間の照明条件にある空をレンダリングできる
    • sun angle uniform により、一日の中での空の青の変化を作り出し、Mie 散乱は夕焼けや日の出で光を地平線と自然に混ぜ合わせる
    • 太陽が低いとき、オゾンは空に紫がかったトーンを加える

惑星大気への拡張

  • 平面背景からポストプロセス効果へ

    • 先に作成したシェーダーは優れた空の背景を提供するが、React Three Fiber シーンの平面背景に近い
    • 次の段階は、これを**ポストプロセス効果(post-processing effect)**に変えて、シーンの深度を考慮するボリュームとして、また惑星メッシュを取り囲む大気のシェルとしてレンダリングすることだ
    • そのために screenUV 座標からワールド空間座標を再構成し、シーンの depth buffer を raymarching に反映する
  • ワールド空間の再構成と 3D レイ

    • 大気散乱をシーンに適用するには、空だけを描くのではなく、カメラと画面にレンダリングされたオブジェクトの間の空間を満たす必要がある
    • 必要なデータはシーンの depth buffer、カメラの projectionMatrixInversematrixWorldposition であり、これらの値をポストプロセス効果の uniform として渡す
    • getWorldPosition(vec2 uv, float depth)depth * 2.0 - 1.0clipZ を作り、uv * 2.0 - 1.0 で NDC 座標を作ったあと、projectionMatrixInverseviewMatrixInverse を適用する
    • 同じ手順は On Shaping Light の volumetric lighting ポストプロセス効果でも使われている
    • 現在のピクセルの worldPosition を取得したあと、rayOrigin はカメラ位置、rayDirnormalize(worldPosition - rayOrigin) として計算し、画面上のピクセルごとの3D レイに沿って進む
  • 深度バッファで raymarch 区間を調整

    • シーンジオメトリを考慮するには、固定の stepSize ではなく、depth buffer によって現在のレイの raymarch 区間を決める必要がある
    • sceneDepth = depthToRayDistance(uv, depth) により、レイ上のシーン深度を求める
    • 背景ピクセルは depth >= 1.0 - 1e-7 で判定し、“sky pixels” には sceneDepth = atmosphereHeight * SKY_MARCH_DISTANCE_MULTIPLIER を適用する
    • レイが下向きなら tGround = observerAltitude / max(-rayDir.y, 1e-4) で地面との交差を計算し、rayEnd = min(rayEnd, tGround) で制限する
    • 最終的な stepSize(rayEnd - rayStart) / float(PRIMARY_STEPS) で計算する
    • 近いオブジェクトや地面に当たるレイは小さな stepSize でより正確にサンプリングされ、遠くまで進むレイは同じ数のサンプルをより長い距離に分布させる
  • シーン内の大気フォグ

    • ポストプロセス効果として実装されたシェーダーは、シーン全体のボリュームに大気散乱を適用し、シーンジオメトリを考慮しながら sky shader を背景として使える
    • カメラに近いオブジェクトはより鮮明に見え、遠くのオブジェクトはより強くぼやける
    • Raycaster でドラッグ可能な天体を入れたインタラクティブな例は、MaximeHeckel のツイート で確認できる

惑星のレンダリング

  • 必要な2つのステップ

    • 惑星の周囲に現実的な大気をレンダリングするには、大きなスケールを扱うための logarithmic depth buffer と、光線が大気中のどこで始まりどこで終わるかを定義する球状の大気シェルが必要
  • logarithmic depth buffer

    • 惑星スケールでは遠方から見たときに、大気と惑星シェルの深度差をシェーダーが区別しづらくなり、depth fighting が発生することがある
    • 大気の高さは数 km にすぎないため、シーンの depth buffer の定義と、後処理エフェクトでの読み取り方法の両方を調整する必要がある
    • React Three Fiber の Canvas を包む gl prop で logarithmicDepthBuffer: true を設定する
    • 設定例は <Canvas shadows gl={{ alpha: true, logarithmicDepthBuffer: true }}> の形
    • シェーダーでは logarithmic depth buffer を光線上の距離へ戻すため、sceneDepth の計算を再定義する
    • logDepthToViewZ(depth)pow(2.0, depth * log2(cameraFar + 1.0)) - 1.0 を使い、-d を返す
  • ray-sphere intersection で大気区間を見つける

    • 視線の光線が 大気球(atmospheric sphere) に入る地点と出る地点を見つけるために、ray-sphere intersection test を使う
    • 2つの交点を得られれば、大気の外でサンプルを無駄にせず、その区間だけに raymarching ループを制限できる
    • 惑星は球形メッシュで、それより少し大きな大気球が取り囲む形なので、同じ交差テストを惑星自体にも行う
    • 光線が大気を抜ける前に地表に当たる場合は、地表との交点を raymarching 区間の終点として使う
    • 使用した raySphereIntersect の実装は Inigo Quilez の Ray-Surface intersection functions を参考にしている
  • シーンオブジェクトと大気の終了条件

    • 大気は惑星表面に達した時点、または地表に達する前に別のシーンオブジェクトに当たった時点で終了しなければならない
    • 惑星に当たる場合は基本的に atmosphereFar = min(atmosphereFar, planetHit.x) として地表で止める
    • 他のメッシュが地表より手前にレンダリングされている場合は、sceneDepth < planetHit.x - 2.0 条件で判定し、atmosphereFar = min(atmosphereFar, sceneDepth) を適用する
    • このロジックがないと、惑星表面がオブジェクトより前に現れてしまう問題が生じる
  • React Three Fiber デモと残っているグリッチ

    • 2つの調整をコードに反映すると、大気散乱を後処理エフェクトとして実装し、惑星周囲の大気をレンダリングできる
    • デモシーンでは React Three Fiber でシンプルな “Sun - Earth system” をレンダリングし、カスタムエフェクトを適用している
    • 太陽の位置を調整してズームアウトすると、地上から軌道までさまざまな角度でシェーダーが作る空の色を見られる
    • 同じ効果は4月初旬の記事予告用ポスター画像にも使われており、レンダリング画像は ツイート で共有されている
    • シーン内の torus は日没後でも依然として “lit-up” 状態に見えることがある
    • 原因は主 directional light の shadow-map または shadow-camera のスケールが小さく、遠すぎる torus をカバーできないため
    • 回避策として volumetric lighting article の shadow-mapping アプローチを再利用できるが、実際には試していない

日食の処理

  • 大きな天体が太陽を遮る場合lightMarch の後で sunVisibility 関数を呼び出し、その戻り値 [0, 1] を透過率に掛ける形で追加できる
  • 基本的なアイデアは、現在のサンプル地点から見た 月の方向太陽の方向 の内積を比較すること
  • 2つの方向がほぼ同じで内積が 1.0 に近ければ月が太陽を遮っている状態で、直交して 0.0 に近ければ遮りはない
  • 単純な内積だけではシーン内オブジェクトの サイズとスケール を反映できないため、実装では太陽と月の角距離、およびそれぞれの角半径を比較する
  • sunVisibility は、月が太陽を遮らない場合、カメラ視点から月が太陽より大きいか同程度の大きさに見える状態で遮る場合、カメラ視点から月が太陽半径の内側に入る状態で遮る場合を扱う
  • デモでは既存の大気散乱サンプルに sunVisibility月メッシュ を追加し、月を太陽と整列させたときの光不足の状況を Atmospheric Scattering シェーダーが処理するようにしている
  • より精密な日食とコロナのシミュレーションは Physically Based Real-Time Rendering of Eclipses の論文で扱われているが、その実装は WebGL へ移植していない

他の惑星の大気

  • 使用した大気密度と散乱モデルは、惑星と大気の半径、RayleighScaleHeight, RayleighBeta, MieScaleHeight, MieBeta, mieBetaExt, mieG, OzoneHeight, OzoneWidth といったいくつかの定数によってほぼ決まる
  • これらの値を調整すれば、火星の大気 や他の惑星の大気に近い結果を作れる
  • 火星向けに使った値は近似値
    • planetRadius: 3390
    • atmosphereRadius: 3500, 約 110 km の厚さ
    • rayleighScaleHeight: 11.1
    • rayleighBeta: new THREE.Vector3(0.019, 0.013, 0.0057)
    • mieScaleHeight: 1.5
    • mieBeta: 0.04
    • mieBetaExt: 0.044
    • mieG: 0.65
    • ozoneCenterHeight: 0.0
    • ozoneWidth: 1.0
    • ozoneBetaAbs: new THREE.Vector3(0.0, 0.0, 0.0)
    • sunIntensity: 15.0
    • planetSurfaceColor: '#8B4513'
  • 既存の定数をこれらの値に置き換えると、より ほこりっぽくオレンジがかった大気 になり、火星特有の 夕焼け時の青み も得られる
  • 関連論文として Physically Based Rendering of the Martian Atmosphere がある

LUT ベースの大気散乱

  • アプローチと簡略化した部分

    • 従来のシェーダーは小さなスケールと大きなスケールの大気を直感的にレンダリングできる一方、PRIMARY_STEPS の多いレイマーチングループ、入れ子になった lightmarching ループ、フルスクリーン解像度での計算のため実行コストが高い
    • Sebastian Hillaire の A Scalable and Production Ready Sky and Atmosphere Rendering Technique は、コストの高い散乱計算をテクスチャに保存し、最終レンダリングでは事前計算済みのテクスチャをサンプリング・合成する Look Up Tables(LUTs) ベースの方式を提案している
    • 扱う LUT は、光が大気を通過する間にどれだけ生き残るかを保存する Transmittance LUT、特定のカメラ位置での空の色を保存する Sky-view LUT、カメラと見えているシーンジオメトリの間の大気ヘイズと散乱光を保存する Aerial Perspective LUT である
    • 論文全体の実装をそのまま移植したわけではなく、LUT は WebGPU の compute shader に向いているが、時間不足と記事の連続性のため WebGL を維持している
    • 論文では Aerial Perspective LUT は 3D texture だが、実装では 2D render target を使用している
    • この方式ではカメラが動くたびに正しいピクセル値のためにテクスチャを再生成する必要があり、事前計算しておくのが難しい
    • Multi-Scattering は時間不足のため省略した
  • Transmittance LUT

    • 従来のシェーダーでは、すべてのサンプル地点が lightmarch を呼び出して太陽光がどれだけ到達するかを計算しており、この処理は高コストだった
    • Transmittance LUT はこのデータを低解像度で事前保存し、その後ほかの LUT が光データを必要とするときに読み出して使えるようにする
    • 実装では 250 x 64 解像度の専用 Frame Buffer Object を定義し、カスタムシェーダー material を専用シーン transmittanceLUTScene の full-screen quad に適用したうえで、レンダリング結果のテクスチャを downstream LUT の uniform として渡す
    • 各ピクセルでは vec3(0.0, radius, 0.0) からレイマーチングを行い、radiusvUv.y 座標に沿って planetRadius から atmosphereRadius まで増加する
    • LUT の x 軸 は光の角度、y 軸 は高度を表し、純白は 100% 透過率、黒または色の付いた領域は地面または空気が最も厚い部分を示す
    • 以降の LUT は「与えられた角度と高度で大気を通過して生き残る光の量」をテクスチャ参照だけで取得できる
  • Sky-view LUT

    • Sky-view LUT は、特定の方向を地上から見上げたとき空がどのような色になるかを計算する
    • getSkyViewRayDirvUv.xazimuth [-PI, PI] に、vUv.yelevation [-PI/2, PI/2] にマッピングしてレイマーチング方向を定義する
    • elevation には (vUv.y * vUv.y - 0.5) * PI という quadratic mapping を使っており、遠距離で Sky View が過度にちらつくのを避けるための回避策である
    • レイが大気に入らなければ黒を返し、惑星に当たるレイは見えている大気区間だけをレイマーチングし、惑星に到達したらさらに早く停止する
    • 散乱ループは以前と同じだが、Sky View 方向に沿って進み、太陽光には Transmittance LUT を使う
  • Aerial Perspective LUT

    • Hillaire 論文とは異なり、実装結果は 2D テクスチャ であり、各ピクセルは見えている画面ピクセル 1 つに対応する
    • シーンの depth buffer を使って、そのレイに沿ってどこまで進み、どれだけ散乱を蓄積するかを決定する
    • 従来の散乱コードをほぼ再利用しつつ、各サンプルが Transmittance LUT から太陽光の可視性を取得する
    • 出力は RGB に蓄積した大気散乱を保存し、アルファには合成時に使う packed view transmittance 値を保存する
    • 実装の流れは、depthBuffer から深度を読み、getWorldPosition(vUv, depth) で画面ピクセルのワールド空間位置を復元した後、カメラ位置からワールド位置までの rayDir を計算するというものだ
    • 続いて logDepthToRayDistance(vUv, depth) でシーン深度をレイ距離に変換し、大気と惑星の交差を計算したうえで、見えている大気区間だけを march する
  • 合成

    • Sky-view LUT と Aerial Perspective LUT を生成したあと、最後の post-processing pass で両者を結合する
    • 中核となる作業は、現在の rayDirSky View UV 座標 に変換することだ
    • シーンジオメトリには Aerial Perspective LUT を適用し、アルファチャンネルを view transmittance として、RGB チャンネルを散乱光として使い、color = color * aerialPerspective.a + aerialPerspective.rgb を計算する
    • 背景ピクセルには Sky View LUT をサンプリングし、depth >= 1.0 - 1e-7 であれば背景と見なして color = inputColor.rgb + sampleSkyViewLUT(rayDir, planetCenter) を適用する
    • 最後に ACESFilm(color)pow(color, vec3(1.0 / 2.2)) を適用する
    • LUT ベースの大気実装コード全体は Github link で確認できる

まとめ

  • LUT ベースの大気散乱の結果は以前の完全なレイマーチング版とほとんど同じに見えるかもしれないが、内部処理は異なる
  • 作業をより小さな LUT 群に分割し、最後の効果で合成することで、各サンプルごとに太陽方向へ繰り返しレイマーチングして到達光を計算しない
  • Transmittance LUT から照明情報を直接取得するため、高コストな入れ子ループを単純なテクスチャ参照に置き換え、最終シーンで無視できない性能向上を得られる
  • 実装は Sébastian Hillaire や他分野の実装と比べると不十分で、とくに Sky View には banding や flickering があり、簡略化した部分のため最適性も低い
  • 最初から WebGPU を使うべきだった可能性がある
  • 実際の production-grade 実装として、Shoda Matsuda(@shotamatsuda) の three-geospatial を勧める
  • さらに volumetric clouds を重ねる作業も行ったが、結果はまだ一長一短で、記事で見せられるほど満足のいくものではなく、さらに作業が必要である

1件のコメント

 
GN⁺ 2 시간 전
Hacker Newsのコメント
  • 以前に見たものなので完全に関係があるとは限らないけれど、Sebastian Lague が惑星生成の実験で 大気レンダリング を扱った動画も本当に面白かった https://www.youtube.com/watch?v=DxfEbulyFcY
    視覚効果を開発し、それがだんだん現実らしく実装されていくのを見るのには特別な面白さがあって、いつか自分でもこの分野を実験してみたい
    • Sebastian Lague でいちばん驚くのは、YouTubeアルゴリズム がどれほど人を振り回せるかという点だと思う
      以前は動画の再生数が数百万だったのに、今では50万をようやく超える程度。コロナ禍で皆が家にいて、ランダムなものに関心を持っていた影響かもしれない
    • Sebastian Lague に関する唯一の不満は、動画の数が十分ではないことだけ
      ふだん寝るときに流しているけれど、落ち着いていながら深く技術的なテーマを掘り下げるこういうコンテンツがもっとあればと思って、自分で作ってみようかと考えたこともある
  • 意図的に省いたのかは分からないけれど、夕焼けモデル では太陽が地平線の下に沈んだ瞬間に空が真っ黒になってはいけない、という点は触れておく価値がある
    日没後もしばらくの間、頭上の大気や地平線上の領域にはまだ日光が当たっており、地球の大気では太陽が地平線下 18度 まで下がるあいだは目立つ薄明が残る。レイトレーシングで実装するのは実用的でないかもしれないが、これをモデル化する一般的なアルゴリズムはある
  • 良いグラフィックス記事はいつでも歓迎。自分も手続き型の宇宙/惑星ジェネレーターで似たことをやってきたが、大気散乱 はボリューム雲レンダリングと組み合わせると見事な夕焼けや空のシーンを作れるのがいい
    https://www.threads.com/@mrsharpoblunto/post/DVS4wfYiG8f?xmt...
    https://www.threads.com/@mrsharpoblunto/post/C6Vc-S1O9mX?xmt...
    https://www.threads.com/@mrsharpoblunto/post/C6apksDRa8q?xmt...
  • 最近の スマートフォンとブラウザ ができることには本当に驚かされる
    1993年の論文であり、この分野の元祖に近く、とても読みやすい Nishita らの “Display of The Earth Taking into Account Atmospheric Scattering” を実装したことを思い出す: https://www.researchgate.net/publication/2933032_Display_of_...
    • 以前 Rayleigh散乱Mie散乱 を実装しながら読んだ論文を別のコメントで思い出したが、これで間違いない
      動くようにできたとき、「この複雑な現実世界の現象を、比較的単純な計算をいくつかするだけでかなりうまくモデル化できるんだな」という瞬間があった。静的な青空のスカイボックスから、一気に完全な昼夜サイクルへ進んだ
  • 本当に素晴らしい
    以前、Web で空を複数の グラデーション を重ねてレンダリングしたらどうだろうと考えたことがある。ある程度はうまくいって、そこそこの結果は得られたかもしれないが、ここで作られているものとは比べものにならない。成果物は印象的で刺激を受ける
    • 昔、趣味で作っていたゲームエンジンで Rayleigh散乱Mie散乱 を実装したことがある
      それだけでもかなりもっともらしい夕焼け/日の出のサイクルが出せて驚いたし、記憶が正しければ太陽そのものもそこから自然に現れてきた。Microsoft の C# ゲーム開発プラットフォーム XNA を使いながら、Riemer の優れたチュートリアルシリーズを追っていて、アーカイブはここにある https://github.com/SimonDarksideJ/XNAGameStudio/wiki/Riemers...
      ただ、散乱に関する内容は見当たらないので、その部分は別のところから持ってきたのかもしれない。数式入りの論文を読んでいた記憶はある
  • SpaceEngine もこの分野にかなり力を入れていることで有名なので、強くおすすめしたい: https://www.youtube.com/watch?v=_4TjdVAbXks
    https://spaceengine.org/
    • こういうものの FAQ は、スケール と質問の多様さが分かって面白い
      「SpaceEngine にはオブジェクトがいくつありますか?」への答えは、Hipparcos 星表の全体、既知の系外惑星のすべて、1万を超える銀河、太陽系の大半の天体を合わせて13万個で、さらに観測可能な宇宙全体に実際に存在する数よりも多い銀河や恒星系が追加されるというもの。「水の惑星はどうして熱くなり得るのですか?」には、上層大気の水は高温の水蒸気だが、下へ行くと高圧のもとで液体へと滑らかに遷移し、さらに深部では ice VII という固体相になると答えている。「どうやって移動するのですか?」の答えは WASD キー
    • 片方のタブに Wikipedia、もう片方のタブに SpaceEngine を開いておくのは、自分の好きな準教育的ゲーム体験の一つ
      素晴らしいゲームだし、かなり古いのに、これほど良いものはまだ見たことがない
    • 何年も前からある素晴らしいソフトウェアで、この話題に限らず多くの面で 細部へのこだわり がすごい
      この記事を見て自分も SpaceEngine を思い出した
  • 散乱 は、昔から写実的なレンダリング画像を作るうえで重要な要素だった
    自分の好きな論文の一つ: http://www.graphics.stanford.edu/papers/bssrdf/bssrdf.pdf
    牛乳をレンダリングするのが厄介な問題だということを、たぶんこのとき初めて知った
  • わあ、かなりすごい旅だった
    たぶん5%くらいしか理解できなかったけれど、本当に強く感心した
    • 自分も同じ。ビジュアル資料 だけでも読む価値があった
  • おお、これは本当に美しくて読みやすい記事だ
    しかも MITライセンス なら、自分のゲームのスカイボックス問題は解決したも同然。遠近は固定されるはずだから、太陽が空を横切るレンダリングさえあればよく、そこにサイン波周期で年間の太陽角度変化を拡張できる