r3f-performance について
React Three Fiber のシーン開発者向けパフォーマンス最適化スキルです。ドローコール、ジオメトリ、アセット読み込み、メモリ管理、プロファイリングを扱います。
主な機能
- 01インスタンシングと統合でドローコールを削減
- 02距離に応じて詳細度を切り替え
- 03大きなアセットを遅延読み込み
- 04未使用のグラフィックリソースを解放
- 05パフォーマンスパネルでボトルネックを分析
活用シーン
- 01同じオブジェクトが多いシーンを最適化
- 02大きなモデルの読み込み時の停止を軽減
- 03低フレームレートやメモリ増加を調査
- 04モバイルシーンの描画負荷を調整
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ bbeierle12/ skill-mcp-claude --skill r3f-performanceインストール後、Claude Code で/r3f-performanceを入力して読み込まれたか確認します。
同梱ファイル_meta.json
詳細
R3F のパフォーマンス
ドローコールの削減、ジオメトリの最適化、スマートな読み込み、プロファイリングによってレンダリングのパフォーマンスを最適化します。
クイックスタート
// Performance-optimized Canvas
<Canvas
dpr={[1, 2]} // Limit pixel ratio
performance={{ min: 0.5 }} // Adaptive performance
frameloop="demand" // Only render on change
gl={{
powerPreference: 'high-performance',
antialias: false // Disable for mobile
}}
>
<Suspense fallback={null}>
<Scene />
</Suspense>
</Canvas>
フレームバジェット
60fps(1フレームあたり16.67ms)を目標にします。予算の内訳:
| フェーズ | 目標 | 備考 |
|---|---|---|
| JavaScript | < 4ms | useFrame のロジック、状態の更新 |
| GPU レンダリング | < 10ms | ドローコール、シェーダー |
| コンポジット | < 2ms | ポストプロセス、オーバーレイ |
| バッファー | 約1ms | 安全マージン |
ドローコールの最適化
黄金律
三角形を減らすより、ドローコールを減らす
それぞれが1000個の三角形を持つメッシュ100個のシーンは、三角形が100,000個のメッシュ1個のシーンよりも遅くなります。
削減手法
| 手法 | ドローコール数 | 使用する場面 |
|---|---|---|
| インスタンシング | 一意のメッシュごとに1 | 100個以上の同一オブジェクト |
| ジオメトリの結合 | 結合したバッチごとに1 | 静的なシーンのパーツ |
| テクスチャアトラス | マテリアル数を削減 | 類似したテクスチャが多数ある場合 |
| LOD | 複雑さを軽減 | 大きなオブジェクト、遠くにあるオブジェクト |
インスタンシング(同一メッシュに最適)
// 10,000 cubes = 1 draw call
<instancedMesh args={[undefined, undefined, 10000]}>
<boxGeometry />
<meshStandardMaterial />
</instancedMesh>
ジオメトリの結合(静的なシーン)
import { useMemo } from 'react';
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils';
import * as THREE from 'three';
function MergedScene() {
const mergedGeometry = useMemo(() => {
const geometries: THREE.BufferGeometry[] = [];
// Create many positioned geometries
for (let i = 0; i < 100; i++) {
const geo = new THREE.BoxGeometry(1, 1, 1);
geo.translate(
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20
);
geometries.push(geo);
}
return mergeGeometries(geometries);
}, []);
return (
<mesh geometry={mergedGeometry}>
<meshStandardMaterial />
</mesh>
);
}
詳細度(LOD)
カメラからの距離に応じてジオメトリを切り替えます:
import { useMemo } from 'react';
import * as THREE from 'three';
function LODMesh() {
const lod = useMemo(() => {
const lodObject = new THREE.LOD();
// High detail (close)
const highGeo = new THREE.SphereGeometry(1, 64, 64);
const highMesh = new THREE.Mesh(highGeo, new THREE.MeshStandardMaterial({ color: 'red' }));
lodObject.addLevel(highMesh, 0);
// Medium detail
const medGeo = new THREE.SphereGeometry(1, 32, 32);
const medMesh = new THREE.Mesh(medGeo, new THREE.MeshStandardMaterial({ color: 'orange' }));
lodObject.addLevel(medMesh, 10);
// Low detail (far)
const lowGeo = new THREE.SphereGeometry(1, 8, 8);
const lowMesh = new THREE.Mesh(lowGeo, new THREE.MeshStandardMaterial({ color: 'green' }));
lodObject.addLevel(lowMesh, 30);
return lodObject;
}, []);
return <primitive object={lod} />;
}
Drei LOD ヘルパー
import { Detailed } from '@react-three/drei';
function AdaptiveSphere() {
return (
<Detailed distances={[0, 10, 30]}>
{/* Close: high detail */}
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial />
</mesh>
{/* Medium distance */}
<mesh>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial />
</mesh>
{/* Far: low detail */}
<mesh>
<sphereGeometry args={[1, 8, 8]} />
<meshStandardMaterial />
</mesh>
</Detailed>
);
}
視錐台カリング
カメラの視界外にあるオブジェクトはレンダリングされません。デフォルトで有効ですが、次の点に注意してください:
// Disable for objects that animate into view unpredictably
<mesh frustumCulled={false}>
<boxGeometry />
<meshStandardMaterial />
</mesh>
// Force bounding sphere update for dynamic geometry
useEffect(() => {
geometry.computeBoundingSphere();
}, [geometry]);
アダプティブパフォーマンス
R3F のアダプティブパフォーマンスシステムは、DPR を自動的に調整します:
<Canvas
performance={{
min: 0.5, // Minimum DPR under stress
max: 1, // Maximum DPR
debounce: 200 // Debounce time for changes (ms)
}}
/>
手動でのパフォーマンス制御
import { useThree } from '@react-three/fiber';
function PerformanceMonitor() {
const { performance } = useThree();
useFrame(() => {
// Check current performance
if (performance.current < 1) {
// System is under stress, reduce complexity
}
});
// Trigger performance drop
const triggerRegress = () => {
performance.regress(); // Temporarily lower DPR
};
}
遅延読み込み
Suspense によるコード分割
import { Suspense, lazy } from 'react';
const HeavyModel = lazy(() => import('./HeavyModel'));
function Scene() {
return (
<Suspense fallback={<SimpleLoader />}>
<HeavyModel />
</Suspense>
);
}
プログレッシブ読み込み
import { useGLTF } from '@react-three/drei';
function Model() {
// Preload in background
useGLTF.preload('/model.glb');
const { scene } = useGLTF('/model.glb');
return <primitive object={scene} />;
}
// Preload before component mounts
useEffect(() => {
useGLTF.preload('/next-model.glb');
}, []);
ビューベースの読み込み
import { useInView } from 'react-intersection-observer';
function LazySection() {
const { ref, inView } = useInView({
triggerOnce: true,
rootMargin: '200px' // Start loading 200px before visible
});
return (
<group ref={ref}>
{inView && <HeavyContent />}
</group>
);
}
メモリ管理
未使用のリソースを破棄する
// Manual disposal
useEffect(() => {
return () => {
geometry.dispose();
material.dispose();
texture.dispose();
};
}, []);
// Drei helper for GLTF
import { useGLTF } from '@react-three/drei';
useEffect(() => {
return () => {
useGLTF.clear('/model.glb');
};
}, []);
テクスチャの最適化
import { useTexture } from '@react-three/drei';
import * as THREE from 'three';
// Compress and optimize
const texture = useTexture('/texture.jpg', (tex) => {
tex.minFilter = THREE.LinearMipmapLinearFilter;
tex.generateMipmaps = true;
tex.anisotropy = 4; // Lower = faster, higher = sharper
});
// Use compressed formats (KTX2)
import { useKTX2 } from '@react-three/drei';
const texture = useKTX2('/texture.ktx2');
プロファイリング
Stats パネル
import { Stats } from '@react-three/drei';
<Canvas>
<Stats /> {/* FPS, MS, MB counters */}
<Scene />
</Canvas>
パフォーマンスパネル
import { Perf } from 'r3f-perf';
<Canvas>
<Perf
position="top-left"
showGraph // Show FPS graph
minimal={false} // Full or minimal view
/>
<Scene />
</Canvas>
手動プロファイリング
import { useThree } from '@react-three/fiber';
function ProfileInfo() {
const { gl } = useThree();
useEffect(() => {
const info = gl.info;
console.log({
drawCalls: info.render.calls,
triangles: info.render.triangles,
points: info.render.points,
lines: info.render.lines,
textures: info.memory.textures,
geometries: info.memory.geometries
});
});
return null;
}
フレーム時間の測定
function FrameProfiler() {
const frameTimeRef = useRef<number[]>([]);
useFrame(() => {
const start = performance.now();
// ... your logic ...
const elapsed = performance.now() - start;
frameTimeRef.current.push(elapsed);
if (frameTimeRef.current.length > 60) {
const avg = frameTimeRef.current.reduce((a, b) => a + b) / 60;
console.log(`Avg frame time: ${avg.toFixed(2)}ms`);
frameTimeRef.current = [];
}
});
return null;
}
よくあるボトルネック
| 症状 | 考えられる原因 | 解決策 |
|---|---|---|
| FPS が低く、ドローコールが多い | メッシュが多すぎる | インスタンス化、結合、または LOD を使用する |
| FPS が低く、ドローコールが少ない | シェーダーやマテリアルが重い | シェーダーを簡素化し、軽量なマテリアルを使用する |
| 読み込み時にカクつく | アセットが大きい | 遅延読み込み、圧縮、LOD を使用する |
| メモリ使用量が増加する | リソースが破棄されていない | アンマウント時に破棄する |
| モバイルで問題が発生する | DPR が高い、AA | DPR を制限し、アンチエイリアスを無効にする |
最適化チェックリスト
[ ] Draw calls < 100 for complex scenes
[ ] Instancing for repeated objects
[ ] LOD for large/distant objects
[ ] Geometry merged where possible
[ ] Textures compressed (KTX2/Basis)
[ ] DPR capped at 2
[ ] Lazy loading for heavy assets
[ ] Proper disposal on unmount
[ ] Frustum culling enabled
[ ] Shadows optimized or disabled
ファイル構成
r3f-performance/
├── SKILL.md
├── references/
│ ├── profiling-guide.md # Deep profiling techniques
│ ├── mobile-optimization.md # Mobile-specific tips
│ └── large-scenes.md # Handling massive scenes
└── scripts/
├── utils/
│ ├── lod-helper.ts # LOD setup utilities
│ ├── merge-helper.ts # Geometry merging
│ └── perf-monitor.ts # Performance monitoring
└── presets/
├── mobile.ts # Mobile-optimized Canvas config
└── desktop.ts # Desktop-optimized Canvas config
参考資料
references/profiling-guide.md— ブラウザーの DevTools を使った詳細なプロファイリングreferences/mobile-optimization.md— モバイル固有の最適化references/large-scenes.md— 100k 以上のオブジェクトを含むシーンの処理
コメント
Markdown 対応