threejs-errors-rendering について
Three.js 開発者向けのレンダリング障害対応スキルです。表示、色、影、WebGL などの症状別に確認手順と修正方法をまとめています。
主な機能
- 01黒画面と非表示オブジェクトの確認
- 02色空間とトーンマッピングの確認
- 03Z-Fighting と影の修正
- 04WebGL コンテキストの復旧
- 05バッファーとマテリアルの更新確認
活用シーン
- 01シーンが表示されない原因の特定
- 02オブジェクトの非表示や色の異常の修正
- 03影のアーティファクトやちらつきへの対処
- 04WebGL の喪失や更新漏れの調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-errors-renderingインストール後、Claude Code で/threejs-errors-renderingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.gitkeepreferences/anti-patterns.mdexamples.mdmethods.md詳細
threejs-errors-rendering
デバッグワークフローのチェックリスト
Three.js のシーンが正しくレンダリングされない場合は、必ず次の手順に従ってください。
- ブラウザーのコンソールを開き、WebGL エラーや Three.js の警告がないか確認します
- レンダラーのサイズがゼロ以外であることを確認します(
renderer.getSize(new THREE.Vector2())) - キャンバスが DOM 内にあり、表示されていることを確認します(
display: noneになっていないこと) renderer.render(scene, camera)が(ループ内または少なくとも一度)呼び出されていることを確認します- カメラがシーンを向いていることを確認します(位置、ターゲット、near/far)
- ライティングが必要なマテリアルを使う場合、ライトが少なくとも1つ存在することを確認します
- マテリアルの
side、visible、opacity、transparentの各プロパティを確認します - オブジェクトの
visible、layers、frustumCulledの各プロパティを確認します - レンダラーとテクスチャの色空間設定を確認します
症状 1:画面が真っ黒(何も表示されない)
原因 A:レンダラーのサイズがゼロ
キャンバスの幅と高さが 0 です。これは、コンテナが DOM に追加される前に setSize() が呼び出された場合や、コンテナに CSS のサイズが設定されていない場合に発生します。
修正方法:
// ALWAYS ensure the container is in the DOM and has dimensions before setSize
document.body.appendChild(renderer.domElement);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
原因 B:カメラがオブジェクトの内側にある、または反対方向を向いている
カメラとオブジェクトがどちらも (0, 0, 0) にあるため、カメラがメッシュの内側にあります。または、カメラが誤った方向を向いています。
修正方法:
camera.position.set(0, 2, 5); // ALWAYS move camera away from origin
camera.lookAt(0, 0, 0);
原因 C:near/far クリッピング面によってオブジェクトが除外されている
near より近い、または far より遠いオブジェクトはクリッピングされます。PerspectiveCamera のデフォルトの near は 0.1、far は 2000 です。
修正方法:
const camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
// NEVER set near to 0 -- causes z-fighting and depth buffer issues
// ALWAYS keep far/near ratio below 100000 for stable depth precision
原因 D:シーンにライトがない
MeshStandardMaterial、MeshPhongMaterial、MeshLambertMaterial にはライトが必要です。ライトがないと、黒くレンダリングされます。MeshBasicMaterial にはライトは不要です。
修正方法:
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
scene.add(new THREE.DirectionalLight(0xffffff, 1));
原因 E:render() が一度も呼び出されない
アニメーションループが開始されていないか、renderer.render(scene, camera) がありません。
修正方法:
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate(); // ALWAYS call the function to start the loop
原因 F:シーンまたはカメラの参照が誤っている
空のシーン、または初期化されていないカメラを render() に渡しています。
診断方法: レンダリング呼び出しの前に scene.children.length と camera.type をログに出力します。
症状 2:オブジェクトが表示されない
原因 A:マテリアルの side が誤っている
デフォルトでは、裏面はカリングされます(FrontSide)。カメラから平面や薄いジオメトリの裏面が見えている場合、表示されません。
修正方法:
const material = new THREE.MeshStandardMaterial({
side: THREE.DoubleSide // ALWAYS use for planes, leaves, thin objects
});
原因 B:transparent を指定せずに opacity を設定している
transparent: true を指定せずに opacity: 0.5 を設定しても、効果はありません。
修正方法:
const material = new THREE.MeshStandardMaterial({
opacity: 0.5,
transparent: true // ALWAYS pair with opacity < 1
});
原因 C:オブジェクトが別のレイヤーにある
カメラとオブジェクトは、少なくとも1つのレイヤーを共有する必要があります。デフォルトでは、どちらもレイヤー 0 にあります。オブジェクトを別のレイヤーに移動した場合は、カメラでもそのレイヤーを有効にする必要があります。
修正方法:
object.layers.set(1);
camera.layers.enable(1); // camera must see layer 1
原因 D:visible が false(親から継承)
親の visible = false によって、すべての子孫が非表示になります。親の階層全体を確認してください。
診断方法:
let node = object;
while (node) {
if (!node.visible) console.log('Hidden ancestor:', node.name || node.type);
node = node.parent;
}
原因 E:frustumCulled の設定が誤っている
バウンディングスフィアが正しくない場合(たとえば、頂点を手動で変更した後に computeBoundingSphere() を呼び出していない場合)、オブジェクトが表示範囲内にあってもカリングされることがあります。
修正方法:
geometry.computeBoundingSphere(); // ALWAYS call after modifying positions
// Or disable frustum culling for objects that must always render:
mesh.frustumCulled = false;
原因 F:オブジェクトの位置が誤っている、またはスケールが 0
オブジェクトがカメラから遠く離れた位置にあるか、scale.set(0, 0, 0) になっています。
診断方法: object.position、object.scale、object.matrixWorld をログに出力します。
症状 3:色が正しくない
原因 A:色空間が一致していない
これは Three.js r160 以降で最もよくある色のエラーです。
ルール:
- カラー/ディフューズ/エミッシブテクスチャ:必ず
texture.colorSpace = THREE.SRGBColorSpaceを設定します - データテクスチャ(ノーマル、ラフネス、メタルネス、AO、ディスプレースメント):必ず
THREE.LinearSRGBColorSpaceのままにします - レンダラーの出力:
renderer.outputColorSpace = THREE.SRGBColorSpace(r160 以降のデフォルト)
色空間が誤っている場合の症状:
- 色が薄くなる:データテクスチャが誤って
SRGBColorSpaceに設定されている(二重ガンマ) - 色が過剰に鮮やかになる:カラー テクスチャが
LinearSRGBColorSpaceのままになっている(ガンマが適用されない)
修正方法:
const texture = await loader.loadAsync('diffuse.png');
texture.colorSpace = THREE.SRGBColorSpace; // for color textures
const normalMap = await loader.loadAsync('normal.png');
// NEVER set SRGBColorSpace on normal maps -- corrupts surface data
原因 B:トーンマッピングが設定されていない
トーンマッピングがないと、HDR 値がクランプされ、平坦な色や不正な色になります。
修正方法:
renderer.toneMapping = THREE.ACESFilmicToneMapping; // or AgXToneMapping
renderer.toneMappingExposure = 1.0;
原因 C:構築後に設定したマテリアルの色が反映されない
material.color.set() は機能しますが、構築後に material.color = new THREE.Color() とする方法も機能します。よくある間違いは、色を16進数で直接設定することです。material.color = 0xff0000 は機能しません。
修正方法:
material.color.set(0xff0000); // Correct
material.color = new THREE.Color(0xff0000); // Correct
// material.color = 0xff0000; // WRONG -- silently fails
症状 4:Zファイティング(表面のちらつき)
Zファイティングは、2つの表面がほぼ同じ深度で重なり、深度バッファがそれらの間で切り替わることで発生します。
修正方法 A:ポリゴンオフセット
const material = new THREE.MeshStandardMaterial({
polygonOffset: true,
polygonOffsetFactor: -1,
polygonOffsetUnits: -1
});
修正方法 B:対数深度バッファ
const renderer = new THREE.WebGLRenderer({ logarithmicDepthBuffer: true });
// Trades performance for better depth precision across large near/far ranges
// NEVER use with EffectComposer post-processing -- causes artifacts
修正方法 C:位置オフセット
一方の表面を少し移動します:
decalMesh.position.z += 0.01; // small offset to prevent overlap
修正方法 D:near/far 比を小さくする
// ALWAYS keep the near plane as large as possible
camera.near = 1; // not 0.001
camera.far = 1000; // not 1000000
camera.updateProjectionMatrix();
症状 5:シャドウのアーティファクト
シャドウを完全に設定する方法については、threejs-impl-shadows スキルを参照してください。よく使われる簡単な修正方法:
- シャドウがまったく表示されない:
renderer.shadowMap.enabled = true、light.castShadow = true、mesh.castShadow = true、ground.receiveShadow = true - シャドウアクネ(縞模様):
light.shadow.biasを大きくします(例:-0.005) - ピーターパニング(シャドウが離れて表示される):
light.shadow.biasが大きすぎるため、小さくします - シャドウの解像度が低い:
light.shadow.mapSize.set(2048, 2048)で値を大きくします
症状 6:WebGL コンテキストの喪失
メモリ不足や GPU のリセットが発生すると、ブラウザーによって WebGL コンテキストが解放されます。
復旧パターン
renderer.domElement.addEventListener('webglcontextlost', (event) => {
event.preventDefault(); // ALWAYS prevent default to allow restoration
cancelAnimationFrame(animationId);
}, false);
renderer.domElement.addEventListener('webglcontextrestored', () => {
// Re-initialize materials, textures, render targets
initScene();
animate();
}, false);
コンテキストの喪失を絶対に無視しないでください。キャンバスが永久に黒くなります。イベントリスナーを両方とも必ず追加してください。
症状 7:needsUpdate の設定漏れ
BufferAttribute
頂点データを変更した後、GPU バッファが古い状態になります:
positions.array[0] = newX;
positions.needsUpdate = true; // ALWAYS set after modifying attribute data
Material
構造的なプロパティ(マップの追加・削除、defines の変更)を変更した後:
material.map = newTexture;
material.needsUpdate = true; // triggers shader recompilation
// NEVER set needsUpdate = true every frame -- causes constant recompilation
Texture
テクスチャ画像データを変更した後:
texture.image = newImage;
texture.needsUpdate = true; // triggers GPU re-upload
InstancedMesh
setMatrixAt() または setColorAt() の後:
mesh.instanceMatrix.needsUpdate = true; // ALWAYS after setMatrixAt
mesh.instanceColor.needsUpdate = true; // ALWAYS after setColorAt
症状 8:updateProjectionMatrix の呼び出しが必要
次の項目を変更した後は、必ず camera.updateProjectionMatrix() を呼び出してください:
camera.fovcamera.aspectcamera.nearcamera.farcamera.zoomcamera.left/right/top/bottom(OrthographicCamera)
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix(); // NEVER forget this
renderer.setSize(window.innerWidth, window.innerHeight);
});
症状 9:透過オブジェクトの描画問題
透過オブジェクトが誤った順序で描画されます(奥から手前へのソートが失敗します)。
修正方法 A:renderOrder
// Force specific rendering order
backgroundMesh.renderOrder = 0;
transparentMesh.renderOrder = 1;
frontMesh.renderOrder = 2;
修正方法 B:depthWrite
const material = new THREE.MeshStandardMaterial({
transparent: true,
opacity: 0.5,
depthWrite: false // prevents transparent objects from writing to depth buffer
});
修正方法 C:透明度の代わりに alphaTest を使用
アルファの境界がはっきりしたテクスチャ(葉、フェンス)に使用します:
const material = new THREE.MeshStandardMaterial({
map: leafTexture,
alphaTest: 0.5, // discards fragments below threshold
side: THREE.DoubleSide
// NEVER set transparent: true for hard-edge alpha -- use alphaTest instead
});
よくあるコンソール警告
| 警告 | 原因 | 修正方法 |
|---|---|---|
THREE.WebGLRenderer: Texture is not power of two | リピートラッピングを使用した NPOT テクスチャ | 2の累乗のテクスチャ、または ClampToEdgeWrapping を使用します |
THREE.WebGLProgram: shader error | GLSL のコンパイルエラー | カスタムシェーダーコードに構文エラーがないか確認します |
THREE.PropertyBinding: Can not bind to... | アニメーションの対象にプロパティがありません | スケルトン/モーフターゲットがアニメーションクリップと一致していることを確認します |
THREE.BufferGeometry: .addAttribute() removed | 非推奨の API を使用しています | 代わりに setAttribute() を使用します |
GL_INVALID_OPERATION: Feedback loop | レンダーターゲットでもあるテクスチャから読み取っています | 読み取り用と書き込み用に別々のテクスチャを使用します |
参考リンク
- references/methods.md -- 修正に関連する API シグネチャ
- references/examples.md -- 修正パターンの全例
- references/anti-patterns.md -- 避けるべき方法