mcpField
T
threejs-errors-rendering

threejs-errors-rendering

github.com/impertio-studio開発23143 回インストール30 週間前に更新
リポジトリ

threejs-errors-rendering について

Three.js 開発者向けのレンダリング障害対応スキルです。表示、色、影、WebGL などの症状別に確認手順と修正方法をまとめています。

主な機能

  1. 01黒画面と非表示オブジェクトの確認
  2. 02色空間とトーンマッピングの確認
  3. 03Z-Fighting と影の修正
  4. 04WebGL コンテキストの復旧
  5. 05バッファーとマテリアルの更新確認

活用シーン

  1. 01シーンが表示されない原因の特定
  2. 02オブジェクトの非表示や色の異常の修正
  3. 03影のアーティファクトやちらつきへの対処
  4. 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 と一緒にインストールされる参考資料やスクリプト。

.gitkeep
references/
anti-patterns.md
examples.md
methods.md

詳細

threejs-errors-rendering

デバッグワークフローのチェックリスト

Three.js のシーンが正しくレンダリングされない場合は、必ず次の手順に従ってください。

  1. ブラウザーのコンソールを開き、WebGL エラーや Three.js の警告がないか確認します
  2. レンダラーのサイズがゼロ以外であることを確認します(renderer.getSize(new THREE.Vector2()))
  3. キャンバスが DOM 内にあり、表示されていることを確認します(display: none になっていないこと)
  4. renderer.render(scene, camera) が(ループ内または少なくとも一度)呼び出されていることを確認します
  5. カメラがシーンを向いていることを確認します(位置、ターゲット、near/far)
  6. ライティングが必要なマテリアルを使う場合、ライトが少なくとも1つ存在することを確認します
  7. マテリアルの side、visible、opacity、transparent の各プロパティを確認します
  8. オブジェクトの visible、layers、frustumCulled の各プロパティを確認します
  9. レンダラーとテクスチャの色空間設定を確認します

症状 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.fov
  • camera.aspect
  • camera.near
  • camera.far
  • camera.zoom
  • camera.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 errorGLSL のコンパイルエラーカスタムシェーダーコードに構文エラーがないか確認します
THREE.PropertyBinding: Can not bind to...アニメーションの対象にプロパティがありませんスケルトン/モーフターゲットがアニメーションクリップと一致していることを確認します
THREE.BufferGeometry: .addAttribute() removed非推奨の API を使用しています代わりに setAttribute() を使用します
GL_INVALID_OPERATION: Feedback loopレンダーターゲットでもあるテクスチャから読み取っています読み取り用と書き込み用に別々のテクスチャを使用します

参考リンク

公式ソース

コメント