threejs-impl-shadows について
threejs-impl-shadowsは、リアルタイムシャドウを設定する開発者向けのThree.js実装リファレンスです。シャドウマップ、ライト別設定、問題診断、性能上の選択肢を扱います。
主な機能
- 013段階のシャドウ設定
- 02シャドウマップ種類の指針
- 03ライト別の設定
- 04CameraHelperによる問題診断
- 05静的シーンのシャドウ最適化
活用シーン
- 01シーンでのシャドウ有効化
- 02ディレクショナルライトの視錐台調整
- 03シャドウのアーティファクト調査
- 04静的シーンでの更新削減
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-impl-shadowsインストール後、Claude Code で/threejs-impl-shadowsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.gitkeepreferences/anti-patterns.mdexamples.mdmethods.md詳細
threejs-impl-shadows
クイックリファレンス
3 つの手順で有効にするシャドウ
Three.js でシャドウを使用するには、3 つの明示的な有効化手順が必要です。どれか 1 つでも欠けていると、シャドウは表示されません。
import * as THREE from 'three';
// Step 1: Enable shadow maps on the renderer
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Step 2: Enable shadow casting on the light
light.castShadow = true;
// Step 3: Enable per-mesh shadow behavior
mesh.castShadow = true; // this mesh casts shadows
ground.receiveShadow = true; // this mesh receives shadows
シャドウマップの種類
| 種類 | 定数 | 品質 | コスト | .radius に対応 |
|---|---|---|---|---|
| Basic | THREE.BasicShadowMap | エッジが硬く、エイリアスが発生 | 最低 | いいえ |
| PCF | THREE.PCFShadowMap | わずかに柔らかい | 中程度 | いいえ |
| PCF Soft | THREE.PCFSoftShadowMap | 柔らかな半影 | 高い | いいえ(無視されます) |
| VSM | THREE.VSMShadowMap | ガウスぼかし | 中程度 | はい |
- r160 以降のデフォルト:
THREE.PCFShadowMap - PCFSoftShadowMap:汎用的な用途に最適です。
shadow.radiusプロパティは無視されます。 - VSMShadowMap:
shadow.radiusとshadow.blurSamplesに対応しますが、薄いジオメトリでライトリークが発生することがあります。
重要な警告
3 つの有効化手順のいずれかを絶対に忘れないでください。1 つでも欠けると、エラーメッセージが表示されず、シャドウもまったく表示されません。
DirectionalLight のシャドウカメラのフラスタムをデフォルトサイズのままに絶対にしないでください。ほとんどの場合、シーンに適していません。必ず手動で設定してください。
シャドウを投影する PointLight は 1~2 個を超えて使用しないでください。PointLight のシャドウはフレームごとにキューブマップの 6 面をレンダリングします。
shadow.mapSize は必ず 2 の累乗の値(512、1024、2048、4096)に設定してください。
DirectionalLight または SpotLight のターゲットを移動する場合、light.target を必ずシーンに追加してください。
シャドウマップの種類 — 詳細な比較
BasicShadowMap
フィルタリングは適用されません。エッジが硬く、エイリアスのあるシャドウになります。デバッグ時、または硬いシャドウを意図したスタイライズドレンダリングにのみ使用してください。
PCFShadowMap(デフォルト)
固定サイズのカーネルを使ったパーセンテージ・クローサー・フィルタリングです。エッジがわずかに柔らかくなります。品質とパフォーマンスのバランスに優れています。shadow.radius プロパティは効果がありません。
PCFSoftShadowMap
可変カーネルを使って、より柔らかな半影をシミュレートします。PCF より高品質ですが、コストも高くなります。shadow.radius プロパティは無視され、フィルターによって柔らかさが自動的に決まります。
VSMShadowMap
Variance Shadow Maps はガウスぼかしのパスを使用します。shadow.radius(ぼかしのサイズ)と shadow.blurSamples(サンプル数)に対応します。滑らかで柔らかなシャドウを生成しますが、薄いジオメトリがシャドウを受けるオブジェクトに接する箇所で、ライトリークのアーティファクトが発生します。薄いシャドウキャスターが多数重なり合うシーンでは、VSM を絶対に使用しないでください。
ライトごとのシャドウ設定
DirectionalLight のシャドウ
正射影シャドウカメラを使用します。フラスタムは、シャドウを付ける領域を含むように必ず手動でサイズを調整してください。
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 10, 7.5);
dirLight.castShadow = true;
// Shadow map resolution
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
// Orthographic frustum -- MUST size manually
dirLight.shadow.camera.near = 0.5;
dirLight.shadow.camera.far = 500;
dirLight.shadow.camera.left = -50;
dirLight.shadow.camera.right = 50;
dirLight.shadow.camera.top = 50;
dirLight.shadow.camera.bottom = -50;
// Anti-acne bias
dirLight.shadow.bias = -0.0001;
dirLight.shadow.normalBias = 0.02;
scene.add(dirLight);
scene.add(dirLight.target); // REQUIRED if repositioning target
フラスタムのサイズ調整ルール:シャドウが必要な領域を囲むように、フラスタムをできるだけ小さくしてください。フラスタムが大きすぎるとシャドウマップの解像度を無駄にし、小さすぎるとシャドウが切れます。
SpotLight のシャドウ
SpotLight の .angle と .distance に基づいて自動設定される透視投影シャドウカメラを使用します。通常、フラスタムを手動で設定する必要はありません。
const spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(0, 10, 0);
spotLight.angle = Math.PI / 6;
spotLight.penumbra = 0.3;
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.bias = -0.0001;
scene.add(spotLight);
scene.add(spotLight.target);
SpotLightShadow が公開するプロパティ:
.focus(数値、デフォルトは1) — スポットライトの FOV に対するシャドウカメラの FOV を調整します。範囲は[0, 1]です。
PointLight のシャドウ
キューブマップ(面ごとに 1 つ、計 6 つの透視投影カメラ)を使用します。シャドウの種類の中で最もコストが高く、シャドウを投影する PointLight ごとに、フレームあたりシーンを 6 回レンダリングします。
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 5, 0);
pointLight.castShadow = true;
// Lower resolution to offset the 6x render cost
pointLight.shadow.mapSize.width = 512;
pointLight.shadow.mapSize.height = 512;
pointLight.shadow.bias = -0.001;
pointLight.shadow.camera.near = 0.5;
pointLight.shadow.camera.far = 50;
scene.add(pointLight);
パフォーマンスルール:PointLight のシャドウよりも SpotLight のシャドウを必ず優先してください。PointLight のシャドウのコストは、SpotLight のシャドウの 6 倍です。全方向へのシャドウ投影が絶対に必要な場合にのみ、PointLight のシャドウを使用してください。
CameraHelper を使ったシャドウのデバッグ
シャドウを設定する際は、シャドウカメラのフラスタムを可視化するため、必ず CameraHelper を使用してください。
const shadowHelper = new THREE.CameraHelper(dirLight.shadow.camera);
scene.add(shadowHelper);
このヘルパーは、フラスタムをワイヤーフレームの線で描画します。シャドウが切れている、表示されない、または解像度が低い場合、フラスタムが小さすぎるか、大きすぎるか、位置がずれているかを確認できます。
本番ビルドでは CameraHelper を必ず削除してください。
シャドウのアーティファクト診断フローチャート
Shadows not visible?
├── Check renderer.shadowMap.enabled === true
├── Check light.castShadow === true
├── Check mesh.castShadow / ground.receiveShadow === true
├── Check shadow camera frustum encompasses the scene (use CameraHelper)
└── Check shadow.camera.far is large enough
Striped lines on surfaces? (Shadow Acne)
├── Increase shadow.bias (start at -0.0001, go to -0.005)
├── Increase shadow.normalBias (0.02 to 0.1) for curved surfaces
└── Increase shadow.mapSize for more depth precision
Shadows float away from objects? (Peter Panning)
├── Reduce shadow.bias (you over-corrected for acne)
├── Use shadow.normalBias instead of shadow.bias
└── Increase shadow.mapSize resolution
Shadow edges shimmer when camera moves? (Shadow Swimming)
├── Increase shadow.mapSize resolution
├── Snap shadow camera to texel-aligned positions
└── Use Cascaded Shadow Maps (CSM) for large scenes
Light leaks through thin geometry? (Light Bleeding -- VSM only)
├── Switch from VSMShadowMap to PCFSoftShadowMap
├── Increase geometry thickness
└── Reduce shadow.radius value
Shadows on transparent/alpha-tested materials incorrect?
├── Set material.alphaTest threshold
├── Assign customDepthMaterial with matching alpha map
└── For fully transparent objects: use baked shadows or ContactShadows
透過マテリアルの影
デフォルトでは、影はすべてのジオメトリを完全に不透明として扱います。アルファテストを使用するマテリアル(例:木の葉)には、customDepthMaterialを割り当てます:
import * as THREE from 'three';
const alphaMap = new THREE.TextureLoader().load('leaf-alpha.png');
const leafMaterial = new THREE.MeshStandardMaterial({
map: texture,
alphaMap: alphaMap,
alphaTest: 0.5,
side: THREE.DoubleSide,
});
// Custom depth material for correct shadow casting
const depthMaterial = new THREE.MeshDepthMaterial({
depthPacking: THREE.RGBADepthPacking,
map: texture,
alphaMap: alphaMap,
alphaTest: 0.5,
});
leafMesh.material = leafMaterial;
leafMesh.customDepthMaterial = depthMaterial;
leafMesh.castShadow = true;
決して、透明オブジェクト(alphaTestを使用せずにopacity < 1を設定したもの)が正しいリアルタイムシャドウを落とすと期待しないでください。代わりに、ベイク済みの影またはスクリーンスペース技術を使用してください。
静的シャドウの最適化
ライトとシャドウキャスターが移動しないシーンでは、シャドウの自動更新を無効にします:
renderer.shadowMap.autoUpdate = false;
renderer.shadowMap.needsUpdate = true; // render shadows once
何かが変化したときにのみ、renderer.shadowMap.needsUpdate = trueを設定します。これにより、静的シーンではフレームごとのシャドウマップ描画が完全になくなります。
ライトごとの制御:
light.shadow.autoUpdate = false;
light.shadow.needsUpdate = true; // update this light's shadow once
ContactShadows の代替(Drei / React Three Fiber)
地面に落ちる影には、Drei の<ContactShadows>を使うと、シャドウマップより低コストで高品質のソフトシャドウを生成できます:
import { ContactShadows } from '@react-three/drei';
<ContactShadows
position={[0, 0, 0]}
opacity={0.5}
scale={10}
blur={1.5}
far={1}
/>
制限事項:地面に落ちる影にのみ機能します。任意のジオメトリには投影されません。複雑なシーンでシャドウマップの代わりにはなりません。
パフォーマンス予算
| 影の種類 | フレームあたりのコスト | 推奨最大数 |
|---|---|---|
| DirectionalLight のシャドウ | 1 回の描画パス | 1~2 個のライト |
| SpotLight のシャドウ | 1 回の描画パス | 2~4 個のライト |
| PointLight のシャドウ | 6 回の描画パス | 最大 1 個のライト |
シャドウマップ解像度の影響:mapSizeを 2 倍にすると、GPU メモリ使用量は 4 倍になります。モバイルでは 4096x4096 を絶対に超えないでください。2048x2048 以下を推奨します。
必ずrenderer.info.render.callsを使ってプロファイリングし、シャドウパスの数がフレーム予算を超えていないことを確認してください。
参考リンク
- references/methods.md -- LightShadow API のシグネチャとシャドウマップ型の定数
- references/examples.md -- 各ライトタイプのシャドウ設定例
- references/anti-patterns.md -- シャドウのアーティファクト、原因、修正方法
公式ソース
- https://threejs.org/docs/#api/en/lights/shadows/LightShadow
- https://threejs.org/docs/#api/en/lights/shadows/DirectionalLightShadow
- https://threejs.org/docs/#api/en/lights/shadows/SpotLightShadow
- https://threejs.org/docs/#api/en/lights/shadows/PointLightShadow
- https://threejs.org/docs/#api/en/renderers/WebGLRenderer (shadowMap property)
- https://threejs.org/docs/#api/en/helpers/CameraHelper