シーンの光 — 三つの灯りと一度だけ計算する影

半球光が環境色、キーライトが向きと影、リムライトが島を背景から引き剥がし、残る七つの点光源は灯りを足すだけです。

島には十の光源がありますが、画面を決めているのは最初の三つです。

三つの灯りがそれぞれ一つを担当する

const hemisphere = new THREE.HemisphereLight('#b3d6e0', '#283f41', 2.5);
const sun = new THREE.DirectionalLight('#ffe3bd', 3.5);
const rim = new THREE.DirectionalLight('#7de3ed', 3);

半球光の二色は空と地面で、全体の環境色を担います。キーライトは唯一の影を落とす光で、暖色の白を左上から。リムライトは青緑で背後から当たり、島の輪郭に冷たい縁を作ります。リムライトがないと島は霧に溶けます — 最も忘れられやすく、最も画面を変える灯りです。

影は一度だけ計算する

主島で影を落とすものはすべて静的です(木、あずまや、橋は動きません)。だから影マップを毎フレーム計算し直す必要はありません。

renderer.shadowMap.autoUpdate = false;
renderer.shadowMap.needsUpdate = true;

影カメラの範囲は手で主島だけに合わせます。

Object.assign(sun.shadow.camera, { left: -9, right: 9, top: 10, bottom: -8, near: 0.5, far: 40 });

範囲が狭いほど 2048 の解像度が効きます。normalBias を少し入れて自己影のモアレを消します。

夜は灯りを替えるのではなく色を替える

夜に切り替えても、灯りの位置も数も変わりません。変わるのは色、強度、露出、ブルームです。

sun.color.copy(sunDay).lerp(sunNight, themeMix);
hemisphere.color.copy(ambientDay).lerp(ambientNight, themeMix);
sun.intensity = 3.5 - themeMix * 1.8;
renderer.toneMappingExposure = 1.13 - themeMix * 0.08;
bloom.strength = 0.32 + themeMix * 0.17;

themeMix はフレームレートに依存しない指数近似で 0 か 1 に近づくので、二つの雰囲気は切り替わるのではなく混ざります。

提灯はただの点光源

六つの提灯とあずまやの中の一つは点光源で、強度は 0.5 から 1.6 へ上がります。影は落としません。点光源の影はキューブマップが必要で、平行光源の六倍の費用がかかります。ここでは「明るくなる」だけで足ります。

数も控えめにしています。点光源が増えるほど、各マテリアルがコンパイルするシェーダーバリアントが増えます。七つがこのシーンの上限です。

まとめ

ライティングの原則は一つの灯りに一つの役割です。環境、向き、輪郭、彩り。混ぜると「どこも明るく、どこも主役でない」画面になり、それが一番直しにくい — どの灯りを消せばよいか分からないからです。

← 記事一覧に戻る

コメント

…