【Godot】Godotの3Dライティング入門:3つのライトとWorldEnvironmentで、同じ広場を昼と夜に切り替える

作成: 2026-09-23最終更新: 2026-10-10

実行すると影の側が背景の灰色に沈む理由と、3つのライトと WorldEnvironment で同じ広場を昼と夜に切り替える方法を解説します。

3Dシーンに太陽のライトを1本置いて実行すると、箱の影の側が背景と同じ灰色に沈んで、輪郭が溶けます。夜にしようと背景を暗い色にすると、今度は影の側が真っ黒になります。

どちらも原因は同じです。面の明るさは、ライトから届く光と、光の当たらない面まで底上げする環境光の足し算で決まります。実行したゲームには、エディタで見えていた環境光が付いてきません。代わりに、背景の色が環境光として使われます。

この記事では、WorldEnvironment で環境光と空を決め、3つのライトを使い分けて、同じ広場を昼と夜に切り替えるところまでを解説します。

昼の広場と夜の広場。昼は箱から影が伸び、夜は2本の柱の足元に暖色の光だまりができている

この記事でわかること

  • 面の明るさが、ライトの光と環境光の足し算で決まり、実行すると環境光がエディタと変わること
  • 太陽・電球・懐中電灯の3つのライトの使い分けと、影の出し方
  • 白く飛んだ画面を Tonemap で戻すこと
  • 夜にして真っ黒になったときに見る場所

動作確認環境: Godot 4.7(描画の方式を決めるレンダラーは Forward+)

Sponsored

面の明るさの仕組み:ライトの光と環境光

3Dの面の明るさは、2種類の光を足して決まります。

  • ライトの光: DirectionalLight3D などのライトから届く光。ライトのほうを向いた面だけを照らす。影をオンにすると、途中の物に遮られて影ができる
  • 環境光: 光の当たらない面も含めて、全体を底上げする光。影を作らない
面の明るさの足し算。ライトの当たる面は「ライトの光+環境光」、影の側の面と床の影は「環境光だけ」で照らされている

影の中が真っ黒にならないのは、そこに環境光が残っているからです。実行すると影の側が灰色に沈むのも、夜が真っ黒になるのも、影が薄くて見えにくいのも、この足し算のどちらかが足りないか、多すぎるときに起きます。

エディタの3Dビューが最初から明るいのは、編集用の太陽と環境光が入っているからです。これはシーンに置いたノードではないので、実行したゲームには付いてきません。実行したゲームでは、Environment が無いと、プロジェクト設定の背景色(既定は灰色)がそのまま環境光になります。白い箱の影の側が背景とほぼ同じ灰色になり、輪郭が溶けるのはこのためです。

エディタでは箱の影の側も明るく見え、実行すると影の側が背景と同じ灰色に沈んで輪郭が溶ける

WorldEnvironmentで環境光と空を決める

最初に置くのは WorldEnvironment です。これは Environment というリソース(ファイルに保存できる設定のまとまり)を1枚持つノードで、シーン全体の背景と環境光を、この1枚でまとめて決めます。

入門で触るのは4つだけです。

  • Background: 何も無い場所に何を映すか。空にするか、単色にするか
  • Ambient Light: 環境光。光の当たらない面をどれだけ明るくするか
  • Tonemap: 足した結果が明るすぎるときに、画面の色へどう収めるか
  • Glow: 明るい部分の周りをにじませるか

Ambient Light の Source は既定で Background になっていて、背景の色から環境光が作られます。空の色を変えると地面の明るさまで一緒に変わるので、この記事では Color にして、色と Energy を自分で決めます。Color にした環境光は、面の向きに関係なく同じだけ足されます。

Energy の効き方は、ライトの当たらない側の面を見ると分かります。

Ambient Light の Energy を 0・0.4・1.0 にした比較。0 では影の側の面が真っ黒、0.4 で形が読め、1.0 では日なたとの差が縮む

0 では真っ黒です。上げるほど影の側が明るくなり、既定の 1 のままだと日なたとの差が縮んで、のっぺりして見えます。昼なら 0.3 から 0.5 くらいが、面の向きの違いと影の両方が見える範囲です。

3つのライトの使い分け

光を当てるノードは、入門では3つ覚えれば足ります。

3つのライト。太陽は平行な光で影が平行に伸び、電球は足元に丸い光だまりを、懐中電灯は床に楕円を落とす
  • 太陽(DirectionalLight3D): 向きだけを持つ光。距離で弱まらず、どこまでも届く。影は平行に伸びる
  • 電球(OmniLight3D): 1点から全方向へ広がる光。届く距離(Range)がある。床には丸い光だまりができる
  • 懐中電灯(SpotLight3D): 1点から円錐形に広がる光。向きと届く距離の両方を持つ。斜めに当てると床に楕円ができる

太陽でいちばん多い勘違いが位置です。DirectionalLight3D はどこに置いても結果が変わりません。効くのは回転だけで、光はノードの -Z の向きへ進みます。

他のエンジンでいうと: 3つのライトは、Unity と Unreal Engine の Directional/Point/Spot Light にあたります(明るさの数値は共通ではありません)。

影の出し方

ライトを置いても、影は出ません。3種類とも Shadow の Enabled が既定でオフだからです。ライトのインスペクタで Enabled にチェックを入れてください。

太陽の影の中は、太陽の光が遮られて、環境光だけが残った場所です。オンにしても影が見えないときは、次の3つを見ます。

  • 影を受ける床があるか。浮いた箱だけでは、影の落ちる先がありません
  • 光が箱に当たっているか。太陽なら回転の向き、電球と懐中電灯なら Range の内側か
  • 環境光の Energy が高すぎないか。影の中まで明るくなって、影が埋もれます

影を出すライトは少なくします。この記事の実践でも、影を出すのは太陽だけです。

Sponsored

Tonemapで白飛びを戻す

太陽と環境光を足していくと、床や箱の上面が真っ白に飛ぶことがあります。足した結果が、画面に出せる明るさの上限を超えたところです。

Tonemap の比較。Linear では床と箱の上面が白く飛び、AgX では同じ場面に階調が戻る

Environment の Tonemap は、明るすぎる値を画面の色へ収め直す設定です。既定の Linear は、上限を超えた部分をそのまま白にします。

Mode を AgX にすると、飛んでいた部分に階調が戻ります(4.3以前のGodotなら ACES)。AgX は、明るい部分ほどなだらかに白へ近づける方式です。白飛びを消そうとして先にライトを弱めると、飛んでいない部分まで暗くなります。先に Tonemap を変え、それでも明るすぎるときにライトの Energy を下げます。

夜のライティング

夜にしようと太陽を消すと、ライトの光がほとんど無くなります。残るのは環境光だけなので、そこが 0 に近ければ、画面は計算どおり真っ黒になります。

夜は、次の4つをまとめて変えます。

  • 太陽の DirectionalLight3D を非表示にする
  • Background を暗い紺の単色にする
  • 環境光は Source を Color にして暗い青を選び、Energy を 0.3 くらい残す。0 にはしない
  • 街灯の OmniLight3D を置き、色を暖色にする

ここで引っかかるのが街灯の Range です。既定は 5 で、その外側には光が一切届きません。

高さ4の街灯を横から見た図。Range 5 �では床を照らす範囲が足元の小さな円にとどまり、Range 8 では床の広い範囲に届く

Range はライトから光が届く距離なので、高さのぶんも含めて考えます。高さ4メートルの街灯で、足元から4〜5メートル先まで照らすなら、Range は 8 くらいです。既定の 5 では、床に届くのは足元から3メートルまでで、その光も弱くなります。

Sponsored

実践:同じ広場を昼と夜に切り替える

屋外のRPG、見下ろしのサバイバル、一人称の探索 —— 昼と夜のある3Dゲームは、どれもこの切り替えを持っています。箱を並べた広場を1つ作り、キー1つで昼と夜を行き来できるようにします。

広場を上から見た配置図。3つの箱と2本の柱、手前の Torch とカメラ、左奥へ進む太陽の光

① 置くもの

新しい3Dシーンを1つ作ります。角度はインスペクタの Rotation に度で入れ、すべてのノードの Scale は (1, 1, 1) のままにします。

  • ルートに Node3D を置いて Main にし、Main Scene に指定する
  • Main の子に WorldEnvironment を置く。中身は②で作る
  • Main の子に CSGBox3D(大きさを数値で決められる箱)を6つ置く
名前SizePosition
Ground(20, 0.5, 20)(0, -0.25, 0)
BoxTall(2, 4, 2)(-3, 2, 0)
BoxShort(2, 2, 2)(2, 1, 0)
FarBox(2, 2, 2)(0, 1, -8)
PoleA(0.2, 4, 0.2)(-6, 2, 4)
PoleB(0.2, 4, 0.2)(6, 2, 4)
  • Ground の Material に New StandardMaterial3D を作り、Albedo(面の色)の Color を #808080 にする。ほかの箱は白のまま
  • Main の子に DirectionalLight3D を置いて Sun 。Rotation を (-45, 60, 0) 、Shadow の Enabled をオン
  • Main の子に Node3D を置いて Lamps 。その子に OmniLight3D を2つ置き、LampA の Position を (-6, 4, 4) 、LampB を (6, 4, 4) にする。どちらも Range を 8 、Energy を 2 、Color を #FFD39A に
  • Main の子に SpotLight3D を置いて Torch 。Position (0, 5, 9) 、Rotation (-60, 0, 0) 、Range を 10 、Energy を 4 、Spot Angle を 20 に
  • Main の子に Camera3D を置き、Position (0, 6, 13) 、Rotation (-20, 0, 0) 、Current(このカメラで映す)をオン。Environment は空にしておく(ここに入れると WorldEnvironment より優先される)
  • Main の子に Label を置いて StateLabel 。Position を (16, 16) に
  • WorldEnvironment ・ Sun ・ Lamps ・ Torch ・ StateLabel を1つずつ右クリックし、Access as Unique Name を付ける。スクリプトから %Sun のように名前で呼べるようになる(ノード参照入門)

ライトの Energy は明るさの倍率なので、2 や 4 のように1を超えてかまいません。床だけを灰色にするのは、白い箱との差を作るためです。Spot Angle は中心から外側までの角度なので、20 なら円錐全体で40度開きます。

② 昼と夜の Environment を作る

WorldEnvironment を選び、インスペクタの Environment の欄で New Environment を選びます。できた Environment を昼の値にしたら、欄のメニューから Save As... を選び、res://day.tres として保存します。

昼も夜も、Ambient Light の Source は Color 、Tonemap の Mode は AgX にします。違うのは背景と環境光だけです。

項目昼(day.tres)夜(night.tres)
Background → ModeSkyCustom Color
Background の中身Sky に New Sky 、その中の Sky Material に New ProceduralSkyMaterialColor を #080D20
Ambient Light → Color#AAB8CC#263A66
Ambient Light → Energy0.40.3

夜は、もう一度 New Environment から新しく作り、res://night.tres に保存します。昼の Environment の数値を書き換えて夜にすると、day.tres そのものが夜になります。

Background を Sky にするときは2段です。Sky の欄で New Sky を作り、その中の Sky Material に New ProceduralSkyMaterial を入れます。途中の Sky を飛ばすと、空が描かれません。

Main にスクリプトを付けます。

# main.gd(Main の Node3D)
extends Node3D

const DAY := preload("res://day.tres")       # ファイルを先に読み込んでおく
const NIGHT := preload("res://night.tres")

@onready var world: WorldEnvironment = %WorldEnvironment
@onready var sun: DirectionalLight3D = %Sun
@onready var lamps: Node3D = %Lamps
@onready var torch: SpotLight3D = %Torch
@onready var state: Label = %StateLabel

var is_night := false

func _ready() -> void:
	_apply()

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_accept"):   # Space か Enter
		is_night = not is_night
		_apply()

func _apply() -> void:
	world.environment = NIGHT if is_night else DAY   # 背景と環境光をまとめて差し替える
	sun.visible = not is_night
	lamps.visible = is_night                         # 親を隠すと、子の2灯も消える
	torch.visible = is_night
	state.text = "NIGHT" if is_night else "DAY"

数値はスクリプトに書きません。昼と夜の違いは、2つの .tres と、どのライトを表示するかだけです。昼は Sun 、夜は Lamps と Torch を表示します。Lamps を親にしてあるので、2本の街灯を1行で消せます。

③ 動かして確かめる

実践の結果。昼は2つの箱から左奥へ影が伸び、夜は柱の足元に暖色の光だまり、手前に白い楕円の光が落ち、奥の箱の輪郭が見える

再生すると昼から始まり、Space か Enter を押すたびに昼と夜が入れ替わります。見るのは3つです。

昼は、2つの箱から画面の左奥へ影が伸び、高い箱の影のほうがはっきり長くなります。箱の根元から影の先までの伸びは、高い箱が4メートル、低い箱が2メートルです。影が見えなければ Sun の Shadow を確かめてください。止めて Sun の Position を動かしても影は変わらず、Rotation の Y を変えると影の向きが回ります。

夜は、2本の柱の足元に暖色の丸い光だまりができ、手前の床には Torch の白い楕円が落ちます。光だまりが小さく暗いなら、まず街灯の Range が既定の 5 のままになっていないかを見ます。

仕上げに、夜のまま奥の FarBox を見てください。街灯の Range にも Torch の円錐にも入っていないので、照らしているのは環境光だけです。真っ黒でも昼の明るさでもない暗い青になり、灰色の床との明るさの差で輪郭が見えます。一度止めて night.tres の Ambient Light の Energy を 0 にし、再生して夜に切り替えると、FarBox の青みが消えて床と同じ黒に沈みます。

ポイントは2つです。

  • 光の届かない場所は環境光だけ: ライトの光は、届いた面にだけ足されます。届かない面の明るさは、環境光の色と Energy がそのまま決めます
  • 切り替えるのはリソース: シーンを2つ作らず、Environment を2つのファイルに分けます。箱の位置が同じままなので、違いは光だけになります

この広場を歩き回れるようにするなら、Ground の Use Collision をオンにしてから CharacterBody3D入門 の移動を足してください。

うまくいかないときは

症状原因直し方
影の輪郭がギザギザで粗い太陽の影を遠くまで用意していて、近くの影の解像度が足りないDirectional Shadow の Max Distance(カメラから影を描く距離・既定 100 )を、影を見せたい範囲まで下げる
面に縞模様が出る/影が足元から浮く影のずれを補正する値が合っていない縞なら Shadow の Normal Bias を少し上げる。影が浮くなら Bias を下げる
街灯を増やしたら、広い床の一部に光が当たらないCompatibility と Mobile では、1つのメッシュに効く電球は8本まで床を小さく分けるか、Range を絞って重なる本数を減らす

おまけ:先に知っておくと良いこと

  • Glow は明るいところだけにじむ: Glow をオンにしても、既定では明るさが HDR Threshold(既定 1)を超えた部分しかにじみません。この記事の光量では床の光だまりは届かないので、確かめるならしきい値を少し下げます
  • Fog はライトが決まってから: Enabled と Density だけで、遠くの箱が空気に溶けて見えます。濃いと光が届いているか見分けにくくなるので、最後に足します
  • 2Dのライトは別の仕組み: PointLight2D などの2D用のライトは、3Dのライトとは別物です。2Dは 2Dライティング入門 で扱っています

まとめ

  • 明るさは足し算: 面の明るさは、ライトの光と環境光の合計。光の届かない面の明るさは、WorldEnvironment の Ambient Light の色と Energy が決める
  • 当てる光は3つ: 太陽は向き、電球は距離、懐中電灯は向きと距離。床の上で見比べると違いが分かる
  • 影は既定でオフ: Shadow の Enabled をオンにする。影を出すライトは少なく
  • 白飛びは Tonemap: 既定の Linear から AgX へ。ライトを弱める前にここを変える
  • 夜は環境光を残す: 太陽を消したら、環境光と街灯で明るさを組み立て直す

まずは WorldEnvironment を1つ置いて、Ambient Light の Energy を 0 と 0.4 で見比べてみてください。影の側の面がどう変わるかが分かれば、昼も夜も数値で作れるようになります。あなたのゲームの夜は、どの光で照らしますか。

次に読む学習パスの次の記事
3D

GodotのStandardMaterial3D入門:MetallicとRoughnessで質感を塗り分け、テクスチャを貼る

この記事を読む
Godot このセクションのノート104