Light・光源
最終更新日時: 2025年08月25日 12:57
- nothing
- 光源は光源のタイプによって性格が定まる
- 基本的には、減衰、反射、影は基本的に光源のタイプに対して独立にモデルを定義することができる
光源タイプの比較表
Section titled “光源タイプの比較表”| 光源タイプ | 指向性 | 減衰 | 反射 | 影 | 実装難易度 | 計算コスト | 特徴と使用場面 |
|---|---|---|---|---|---|---|---|
| 点光源 | × | ◎ | ◎ | △ | ★★ | 中 | 局所照明、ランプなど |
| 平行光源 | ◎ | × | ◎ | △ | ★☆ | 低 | 太陽光、一定方向の照明 |
| スポットライト | ◎ | ◎ | ◎ | ○ | ★★★ | 中?高 | 舞台、懐中電灯 |
| 環境光 | × | × | × | × | ★ | 低 | 全体照明の補助 |
| 面光源 | ◎ | ◎ | ◎ | △ | ★★★★ | 高 | 窓、蛍光灯、照明パネル |
| 環境光マップ | ◎ | × | ◎ | ? | ★★★ | 高 | 写実的PBR、反射、金属表現 |
- 平行光源は無限遠点からの太陽光のようなものであるので、近接的な減衰は考慮しないのが通例
- 演出的に減衰を付与することも可能
点光源(Point Light)
Section titled “点光源(Point Light)”| 種類 | 指向性 | 減衰 | 反射 | 影 | 実装難易度 | 特徴 |
|---|---|---|---|---|---|---|
| 基本点光源 | × | ◎ | ◎ | × | ★☆ | 距離に応じて明るさが減衰 |
| シャドウ付き点光源 | × | ◎ | ◎ | ○ | ★★★ | SDFで光線を飛ばして影判定 |
| ソフトシャドウ点光源 | × | ◎ | ◎ | ◎ | ★★★★ | 影のエッジが滑らか |
影をつける基本的な考え方
Section titled “影をつける基本的な考え方”- SDFでカメラから飛ばすRayと、「影を作るためののRay」が存在する
- 視線からシーンへ飛ばすRay
- 視点(カメラ)→ 各ピクセル → シーンへ向かってRayを発射
- 主目的:どのオブジェクトと交差するか(距離)
- → Ray Marching(メインのレイ)
- 影のために飛ばすRay
- 命中点(p)→ 光源方向(
lightDir)へ向かってRayを発射 - 主目的:光源との間に遮蔽物があるか
- → Shadow Ray(影判定Ray)
- 命中点(p)→ 光源方向(
hard shadow と soft shadow
Section titled “hard shadow と soft shadow”-
影のためのRayを1本だけ使うと影の境界が鋭い Hard Shadowになる
-
「複数Ray」を用いて遮蔽率を統計的に評価すると影の境界がなだらかな、Soft Shadowとなる
-
umbra 完全な影 光源が完全に遮られた領域
-
penumbra 半影 光源の一部が遮られたぼやけた領域
-
antumbra 逆半影 特定条件下の影の広がり(あまり使われない)
点光源が1つでも、penumbra/ペンブラを表現できる。
- 命中点から光源方向に向かって、わずかに方向や位置をずらした複数のRayを飛ばす
- 例:ノイズや円錐状のサンプリングで5~20本程度
- 現実の点光源も厳密には「面積を持つ」ので、その再現と考えてよい
- 各Rayで遮蔽されている割合を平均し、影の「濃さ」として使う
サンプル数Nで複数のRayを利用する例
Section titled “サンプル数Nで複数のRayを利用する例”float softShadow(vec3 ro, vec3 rd) { float shadow = 0.0; for (int i = 0; i < N; i++) { // jitterDirで複数方向にRayを飛ばして遮蔽を判定している。 // someOffset(i) により方向をばらしてペンブラ領域を表現 vec3 jitteredDir = rd + someOffset(i); shadow += rayMarch(ro, normalize(jitteredDir)) < distanceToLight ? 1.0 : 0.0; } return shadow / float(N);}Rayは1本で、
Section titled “Rayは1本で、”// この関数は、表面のある点から光源方向にRayを進めていって、影になっているかどうかを調べる。// ro Ray Origin(レイの出発点) =表面位置// rd Ray Direction(レイの進行方向)=光源方向float softShadow(vec3 ro, vec3 rd) { float res = 1.0; // 光がさえぎられている割合
float t = 0.01; for (int i = 0; i < 64; i++) { float h = sceneSDF(ro + rd * t); if (h < 0.00001) return 0.0; // 完全遮蔽 res = min(res, 8.0 * h / t); // 遮蔽度の推定、距離とSDF勾配比 t += clamp(h * 0.5, 0.01, 0.1); // ステップを最適化 } return clamp(res, 0.0, 1.0);} // 使う時 float diff = clamp(dot(normal, lightDir), 0.0, 1.0); float shadow = softShadow(p + normal * 0.01, lightDir); vec3 color = vec3(1.0) * diff * shadow;つまり:
平行光源(Directional Light)
Section titled “平行光源(Directional Light)”| 種類 | 指向性 | 減衰 | 反射 | 影 | 実装難易度 | 特徴 |
|---|---|---|---|---|---|---|
| 基本平行光源 | ◎ | × | ◎ | × | ★ | 一方向からの光 |
| シャドウ付き平行光源 | ◎ | × | ◎ | ○ | ★★★ | 一定方向のSDFシャドウ |
| ソフトシャドウ平行光源 | ◎ | × | ◎ | ◎ | ★★★★ | ペンブラ影表現 |
| ランダムゆらぎ平行光源 | △ | × | ◎ | △ | ★★ | ノイズによる動的な光方向 |
| 多方向合成平行光源 | ◎ | × | ◎ | △ | ★★★ | 複数方向からの合成照明 |
スポットライト(Spot Light)
Section titled “スポットライト(Spot Light)”| 種類 | 指向性 | 減衰 | 反射 | 影 | 実装難易度 | 特徴 |
|---|---|---|---|---|---|---|
| 基本スポットライト | ◎ | ○ | ◎ | × | ★★ | コーン角度内で照射 |
| 減衰付きスポットライト | ◎ | ◎ | ◎ | △ | ★★ | 角度に応じて照度減衰 |
| シャドウ付きスポット | ◎ | ◎ | ◎ | ○ | ★★★ | SDFによるコーン内影判定 |
| ソフトシャドウスポット | ◎ | ◎ | ◎ | ◎ | ★★★★ | コーン内部の影を滑らかに変化 |
| IES模倣スポット | ◎ | ◎ | ◎ | ◎ | ? | 配光パターンを画像から再現困難 |
環境光(Ambient Light)
Section titled “環境光(Ambient Light)”| 種類 | 指向性 | 減衰 | 反射 | 影 | 実装難易度 | 特徴 |
|---|---|---|---|---|---|---|
| 定数環境光 | × | × | × | × | ★ | 一定値加算、最も基本 |
| グラデーション環境光 | △ | × | × | × | ★ | 天空色などに応じた方向性のある明るさ |
| 球状環境光 | × | × | × | × | ★★ | 全方向から包み込む照明 |
| 疑似AO環境光 | × | × | × | △ | ★★★ | 距離ベースの遮蔽(近似) |
| シャドウ付き環境照明 | × | × | × | ◎ | ? | 真のglobal illuminationは不可 |
面光源(Area Light)
Section titled “面光源(Area Light)”| 種類 | 指向性 | 減衰 | 反射 | 影 | 実装難易度 | 特徴 |
|---|---|---|---|---|---|---|
| 点光源集合近似 | ◎ | ◎ | ◎ | △ | ★★ | 面を複数点光源で近似 |
| 方向積分による照度計算 | ◎ | ◎ | ◎ | ○ | ★★★★ | 法線方向からの光線積分 |
| 距離法線ベースの近似照明 | △ | △ | △ | × | ★★ | 擬似的な明るさ補正 |
| ソフトシャドウ付き面光源 | ◎ | ◎ | ◎ | ◎ | ★★★★ | ペンブラ影と面積照度 |
| エッジ光源(線状) | ◎ | ◎ | ◎ | △ | ★★★ | 蛍光灯など細長い発光 |
環境光マップ(IBL)
Section titled “環境光マップ(IBL)”| 種類 | 指向性 | 減衰 | 反射 | 影 | 実装難易度 | 特徴 |
|---|---|---|---|---|---|---|
| キューブマップ反射 | ◎ | × | ◎ | × | ★★★ | 反射ベクトルで環境テクスチャ参照 |
| ラフネス対応IBL | ◎ | × | ◎ | × | ★★★★ | 表面粗さに応じたブラー |
| プレフィルタIBL(PMREM) | ◎ | × | ◎ | × | ? | 方向別に事前平均されたHDR |
| HDR環境照明 | ◎ | × | ◎ | △ | ★★★★ | 明るさ情報を照明とする環境HDR |
| シャドウ付きIBL | ◎ | × | ◎ | ◎ | ? | グローバルシャドウ対応の環境照明 |
-
△:可能だが明確な制限や近似が必要な項目
- 指向性の△:ランダム性や方向強調が限定的に実装されるケース
- 減衰の△:視覚的な補正による近似や一定距離以降の補間で代替される
- 反射の△:環境光や近似表面でのみ反射が模倣される
- 影の△:ソフトシャドウやAOによる擬似的処理
-
AO(Ambient Occlusion)は、遮蔽環境光とも呼ばれ、近接した物体や凹部において環境光が届きにくくなる暗がりを表現する手法。
- 環境光自体は全方向から均等に届くが、物体の近接や壁面の角などでは周囲に遮られて暗く見える
- 単なる環境光(一定値加算)では凹みも平面も同じ明るさになるため、リアルさに欠ける
- AOはこの視覚的な陰影を、直接の影ではないが暗く見える効果として補完する
- 実装では、SDFやジオメトリ情報を使って周囲の遮蔽量を近似・積分して求めることが多い(例:周囲方向に短距離Rayを飛ばし、遮蔽率を統計的に評価)
- 簡略な近似でも立体感が劇的に向上するため、PBRやトゥーン表現でもよく併用される
-
SDFベースでは基本的に反射光や影をRay Marchingで確認することで対応可能
-
Area Lightの本格的な照度積分は重く、事前計算やサンプリングが必要
-
IBLは環境テクスチャが前提で、リアルな反射は可能だがシャドウには不向き
-
SpotやDirectionalなど影を扱う光源は、精度とパフォーマンスのバランス設計が必要
- Pharr, M., Jakob, W., & Humphreys, G. (2016). Physically Based Rendering: From Theory to Implementation (3rd ed.). Morgan Kaufmann.
- Shirley, P., Ashikhmin, M., Marschner, S., et al. (2009). Fundamentals of Computer Graphics (3rd ed.). AK Peters.
- McGuire, M. (2017). Real-Time Rendering Resources. https://graphicscodex.com/
- Karis, B. (2013). Real Shading in Unreal Engine 4. Epic Games, SIGGRAPH Course.
点光源における減衰モデルの技術レポート
Section titled “点光源における減衰モデルの技術レポート”減衰モデルとは
Section titled “減衰モデルとは”点光源から発せられる光は、距離に応じて減衰する。これを「減衰モデル(attenuation model)」と呼ぶ。減衰をモデル化することで、現実的な照明効果や奥行き感を再現できる。
主な減衰モデルの比較
Section titled “主な減衰モデルの比較”| モデル名 | 数式 | 特徴 | 視覚効果 | GLSL実装難度 | 用途例 |
|---|---|---|---|---|---|
| なし(定数) | 距離に依存しない | 奥行き感なし、のっぺりする | ★☆☆ | デバッグ、トゥーン表現など | |
| 逆二乗減衰 | 物理的に正確なモデル | 近距離で非常に明るく遠距離で暗い | ★★☆ | 写実的表現、屋外シーン | |
| 線形減衰 | 明るさが直線的に減衰 | 全体にフラットでコントロールしやすい | ★★☆ | ゲーム、ビジュアル制御 | |
| 指数減衰 | 滑らかに暗くなる | ソフトな遠景表現に向く | ★★☆ | 霧、煙、幻想的シーン | |
| カスタム式(3項) | 調整しやすくよく使われる式 | 任意の曲線でコントロール可能 | ★★★ | リアルタイム描画、ゲーム |
GLSLによる実装例
Section titled “GLSLによる実装例”現在の典型実装(逆二乗)
Section titled “現在の典型実装(逆二乗)”float distance = length(lightPos - p);float attenuation = 1.0 / (distance * distance);改良案1:カスタム式
Section titled “改良案1:カスタム式”float d = length(lightPos - p);float attenuation = 1.0 / (a + b * d + c * d * d); // a, b, cはuniformで調整改良案2:指数減衰
Section titled “改良案2:指数減衰”float d = length(lightPos - p);float attenuation = exp(-k * d); // kは減衰係数改良案3:線形減衰(クランプ付き)
Section titled “改良案3:線形減衰(クランプ付き)”float d = length(lightPos - p);float attenuation = max(0.0, 1.0 - k * d);実装時の注意点
Section titled “実装時の注意点”- 距離ゼロで無限大になることを防ぐため、 のような微小オフセットを入れることがある。
- 高解像度では、逆二乗モデルは近距離で明るすぎるため、視覚的に補正が必要なことがある。
- 複数光源の加算時は、各光源ごとに異なる減衰モデルを適用してもよい。
推奨パラメータ設計
Section titled “推奨パラメータ設計”| モデル | 推奨初期値例 |
|---|---|
| カスタム式 | a=0.2, b=0.1, c=0.02 |
| 指数減衰 | k=1.0?3.0 |
| 線形減衰 | k=0.05?0.2 |
今後の拡張可能性
Section titled “今後の拡張可能性”スクリーンスペースの奥行き情報と組み合わせたZフェード
Section titled “スクリーンスペースの奥行き情報と組み合わせたZフェード”Zフェードとは、視界奥(Z方向に遠い領域)で明るさや存在感を徐々に消す効果のこと。これを減衰と組み合わせることで、背景の光源やオブジェクトが遠ざかるほど自然に消えていく演出が可能になる。
実装例(GLSL)
Section titled “実装例(GLSL)”float z = gl_FragCoord.z / gl_FragCoord.w; // NDCではない深度float zFade = smoothstep(zNear, zFar, z);float finalIntensity = baseAttenuation * (1.0 - zFade);gl_FragCoord.zはスクリーンスペース上の深度zNear,zFarはフェードの開始・終了距離smoothstepによりなめらかに消えていく
減衰パターンをテクスチャで表現(LUT)
Section titled “減衰パターンをテクスチャで表現(LUT)”距離に応じた減衰値をテクスチャに前もって焼き込んでおき、GLSLではそのテクスチャを参照するだけにすることで、高精度な減衰表現を低コストで実現できる。
使い方(概念)
Section titled “使い方(概念)”float d = length(lightPos - p);float attenuation = texture(attenuationLUT, vec2(d / maxDistance, 0.5)).r;attenuationLUTは 1D もしくは横1ラインの2Dテクスチャ- 明るさを距離で事前にマッピングしておく
- 複雑な関数や非線形表現を効率よく実装できる
- 減衰カーブの形を直感的にデザインできる(画像編集ツールなどで)
- GLSL側では
texture()1行で済むため高速 - 他の視覚効果との統合がしやすい(例:グローやブラー)
- McGuire, M. (2017). Real-Time Rendering Resources. https://graphicscodex.com/
- Pharr, M., Jakob, W., & Humphreys, G. (2016). Physically Based Rendering.
- NVIDIA (2008). Light Attenuation in Real-Time Graphics. GDC Slides.