ライトと影
Standard / Physical / Lambert / Phong / Toon Material はライトがないと真っ黒。 逆にライトを当てる位置・強さで雰囲気はガラリと変わる。影は別途3点セットを揃えると出る。
ライト一覧
| ライト | 性質 | 影 |
|---|---|---|
AmbientLight | 全方向から一様。陰影なし。底上げ専用。 | 不可 |
HemisphereLight | 上半球と下半球で色違い。屋外の擬似 GI。 | 不可 |
DirectionalLight | 並行光。太陽光。 | 可(よく使う) |
PointLight | 点光源。電球。距離減衰あり。 | 可 |
SpotLight | 円錐状。angle / penumbra。 | 可 |
RectAreaLight | 矩形の面光源。Standard/Physical のみ反応。影は不可。 | 不可 |
基本セット(3点照明)
悩んだら以下の3点を入れておく。ambient + directional + 環境光でだいたいまとまる。
// 全体の底上げ
scene.add(new THREE.AmbientLight(0xffffff, 0.4))
// 太陽光相当
const dl = new THREE.DirectionalLight(0xffffff, 1.2)
dl.position.set(3, 5, 4)
scene.add(dl)
// 環境光(IBL)— Standard/Physical を一気にリッチに
const pmrem = new THREE.PMREMGenerator(renderer)
const env = pmrem.fromScene(new THREE.Scene()).texture // 自前の単色scene
scene.environment = env
環境光は HDR ファイルから作るのが一般的。テクスチャと ローダーに詳しく書く。
各ライトの詳細
AmbientLight
new THREE.AmbientLight(color = 0xffffff, intensity = 1)
全方向から均一に光が当たる。シャドウは出ない。暗部を持ち上げる用に弱めに入れるのが基本。
HemisphereLight
new THREE.HemisphereLight(skyColor, groundColor, intensity)
屋外で「空が青、地面が茶」みたいな擬似 GI を簡単に。Ambient の代わりに使うと一気に雰囲気が出る。
DirectionalLight
const dl = new THREE.DirectionalLight(0xffffff, 1.2)
dl.position.set(3, 5, 4)
dl.target.position.set(0, 0, 0) // どこを照らすか
scene.add(dl)
scene.add(dl.target) // target もシーンに add 必要
- 並行光なので位置と target の差ベクトルが光の方向になる。
- 距離減衰なし(無限遠の平行光のため)。
PointLight
const pl = new THREE.PointLight(0xffaa55, 2, 10, 2)
// color intensity dist decay
pl.position.set(0, 2, 0)
scene.add(pl)
distanceで減衰する範囲を制限(0 = 無限)。decay= 2 は物理的に正しい逆二乗減衰。
SpotLight
const sl = new THREE.SpotLight(0xffffff, 5, 20, Math.PI / 6, 0.3, 2)
// color intensity dist angle penumbra decay
sl.position.set(2, 5, 2)
sl.target.position.set(0, 0, 0)
scene.add(sl, sl.target)
angle= 円錐の半角(最大 PI/2)。penumbra= エッジの柔らかさ(0..1)。
RectAreaLight
import { RectAreaLightUniformsLib } from "three/addons/lights/RectAreaLightUniformsLib.js"
RectAreaLightUniformsLib.init() // 初回1回呼ぶ
const ral = new THREE.RectAreaLight(0xffffff, 5, 4, 2)
ral.position.set(0, 5, 0)
ral.lookAt(0, 0, 0)
scene.add(ral)
矩形の面光源。Standard / Physical でしか反応しない。 影は出せない。スタジオ照明っぽい雰囲気に強い。
ライトヘルパー
ライトの位置や向きを視覚化するヘルパーがある。デバッグに必須。
scene.add(new THREE.DirectionalLightHelper(dl, 1))
scene.add(new THREE.PointLightHelper(pl, 0.2))
scene.add(new THREE.SpotLightHelper(sl))
scene.add(new THREE.HemisphereLightHelper(hl, 1))
// Shadow camera のフラスタム可視化
scene.add(new THREE.CameraHelper(dl.shadow.camera))
影(シャドウマップ)
Three.js の影はシャドウマップ方式。光源視点から「深度マップ」を撮って、レンダリング時に 各点が遮蔽されているか判定する。3点セットを必ず揃える。
Step 1: レンダラを有効化
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap
// 候補:
// THREE.BasicShadowMap — 高速・カクカク
// THREE.PCFShadowMap — 既定。ふつう
// THREE.PCFSoftShadowMap — 柔らかい
// THREE.VSMShadowMap — 別方式(要対応)
Step 2: 光源側
dl.castShadow = true
dl.shadow.mapSize.set(2048, 2048)
dl.shadow.camera.near = 0.5
dl.shadow.camera.far = 30
dl.shadow.camera.left = -10
dl.shadow.camera.right = 10
dl.shadow.camera.top = 10
dl.shadow.camera.bottom = -10
dl.shadow.bias = -0.0005 // shadow acne 対策
- shadow camera のフラスタムを被写体にぴったり合わせるのがコツ。広すぎると解像度が無駄、狭すぎると影が切れる。
mapSizeは 1024 / 2048 が標準。4096 は重い。biasはシャドウ・アクネ(自分の影で表面が縞模様)を抑える。-0.0001 〜 -0.001あたりが多い。
Step 3: メッシュ側
obj.castShadow = true // この物体が影を「落とす」
floor.receiveShadow = true // この物体が影を「受ける」
3つどれかが欠けると影は出ない。よくあるバグなのでチェックリスト化しておくと楽。
影のクオリティと負荷
- 解像度:
mapSizeを上げるほど綺麗だが GPU 負荷が増える。 - 距離:
shadow.camera.farは必要な範囲だけ。広いと精度が落ちる。 - 柔らかさ:
shadow.radius(PCFSoft, VSM 用)。 - 更新頻度: 動かない光源・物体なら1回計算して止める。
shadow.autoUpdate = false+shadow.needsUpdate = true。
静的シーンでは焼き付ける
renderer.shadowMap.autoUpdate = false
renderer.shadowMap.needsUpdate = true
// 1回レンダリングしたあとは、影は固定される
renderer.render(scene, camera)
renderer.shadowMap.needsUpdate = false
環境光(IBL)
Standard / Physical を一気にリアルにするには、HDR の環境光を scene.environment に当てる。
import { RGBELoader } from "three/addons/loaders/RGBELoader.js"
new RGBELoader().load("/hdr/studio.hdr", (hdr) => {
hdr.mapping = THREE.EquirectangularReflectionMapping
scene.environment = hdr
scene.background = hdr // 背景にも使う場合
})
個別マテリアルだけに反映したい時は material.envMap = hdr。
典型的なライティング例
商品紹介(スタジオ風)
AmbientLight弱めDirectionalLightをキー(強)+ フィル(弱)+ リム(背後)の3灯scene.environmentに studio HDR
屋外(昼)
HemisphereLight(空 + 地面色)DirectionalLightの太陽(影あり)scene.environmentに sunset / day HDR
夜・暗いシーン
AmbientLightをかなり弱く(0.05 とか)- キーになる
PointLight/SpotLightを1〜2個 - 適宜
emissiveで発光体を作る
Three.js のライトは純粋に加算される。intensity を雑に上げるとサチる(白飛び)。
全体の調整は renderer.toneMappingExposure でやるのが綺麗。