threejs について
Three.jsで3D Web体験を開発する人向けのリファレンススキルです。API資料や実践的な指針、コード例を、描画やアニメーション、操作などの分野別にまとめています。
主な機能
- 01シーン、カメラ、レンダラーの設定
- 02ジオメトリ、マテリアル、ライティング
- 03テクスチャ、ローダー、アニメーション
- 04シェーダーとポストプロセス
- 05レイキャストとカメラ操作
- 06パフォーマンスとリソース解放の指針
活用シーン
- 01Three.jsのシーンとレンダラーの構築
- 02GLTFモデルの読み込みとアニメーション
- 03カスタムシェーダーや視覚効果の追加
- 043Dシーンのパフォーマンス手法の確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill threejsインストール後、Claude Code で/threejsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/threejs-animation.mdthreejs-fundamentals.mdthreejs-geometry.mdthreejs-interaction.mdthreejs-lighting.mdthreejs-loaders.mdthreejs-materials.mdthreejs-postprocessing.mdthreejs-shaders.mdthreejs-textures.md詳細
Three.js スキル
概要
Three.js を使った 3D ウェブ体験の構築に役立つ包括的なナレッジベースです。このスキルでは、Three.js の主要なすべての領域について、正確な API リファレンス、ベストプラクティス、動作するコード例を提供します。
Three.js のバージョン:r160+(2024年1月)
クイックリファレンス
主なトピック
このスキルでは、Three.js の重要な 10 の領域を扱います。
- 基礎 - シーンのセットアップ、カメラ、レンダラー、Object3D の階層構造
- ジオメトリ - 組み込み形状、BufferGeometry、カスタムジオメトリ、インスタンシング
- マテリアル - PBR マテリアル、シェーダーマテリアル、マテリアルのプロパティ
- ライティング - ライトの種類、シャドウ、環境ライティング
- テクスチャ - UV マッピング、環境マップ、レンダーターゲット
- アニメーション - キーフレームアニメーション、スケルタルアニメーション、アニメーションのミキシング
- ローダー - GLTF/GLB の読み込み、非同期処理のパターン、キャッシュ
- シェーダー - GLSL の基本、ShaderMaterial、カスタムエフェクト
- ポストプロセッシング - EffectComposer、ブルーム、被写界深度、カスタムパス
- インタラクション - レイキャスティング、カメラコントロール、マウス/タッチ入力
リファレンスを読み込むタイミング
現在のタスクに応じて、詳細なリファレンスファイルを読み込んでください。
- 基本的なシーンのセットアップ、カメラ、レンダラー →
references/threejs-fundamentals.mdを読み込む - 形状の作成、カスタムジオメトリ、インスタンシング →
references/threejs-geometry.mdを読み込む - マテリアルのプロパティ、PBR、シェーダーマテリアル →
references/threejs-materials.mdを読み込む - ライトの追加、シャドウの設定 →
references/threejs-lighting.mdを読み込む - テクスチャの読み込み、UV マッピング、環境マップ →
references/threejs-textures.mdを読み込む - オブジェクトのアニメーション、GLTF アニメーション、ミキシング →
references/threejs-animation.mdを読み込む - GLTF/GLB モデルの読み込み、Draco 圧縮 →
references/threejs-loaders.mdを読み込む - GLSL シェーダーの作成、カスタム視覚効果 →
references/threejs-shaders.mdを読み込む - ブルーム、被写界深度、画面エフェクトの追加 →
references/threejs-postprocessing.mdを読み込む - レイキャスティング、マウスによるオブジェクト選択、カメラコントロール →
references/threejs-interaction.mdを読み込む
クイックスタートの例
1. 基礎:基本的なシーン
import * as THREE from 'three';
// Scene, camera, renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
// Create cube
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Add light
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 5, 5);
scene.add(dirLight);
camera.position.z = 5;
// Animation loop
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
// Responsive
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
2. ジオメトリ:形状の作成
// Built-in geometries
const box = new THREE.BoxGeometry(1, 1, 1);
const sphere = new THREE.SphereGeometry(0.5, 32, 32);
const plane = new THREE.PlaneGeometry(10, 10);
// Custom BufferGeometry
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-1, -1, 0, // vertex 0
1, -1, 0, // vertex 1
1, 1, 0, // vertex 2
-1, 1, 0 // vertex 3
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
// Indices for triangles
const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
// Instancing for many copies
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20
);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(instancedMesh);
3. マテリアル:PBR マテリアル
// Standard PBR material
const material = new THREE.MeshStandardMaterial({
color: 0xffffff,
metalness: 0.5,
roughness: 0.5,
map: colorTexture,
normalMap: normalTexture,
roughnessMap: roughnessTexture,
metalnessMap: metalnessTexture,
envMap: environmentMap,
envMapIntensity: 1
});
// Physical material (advanced PBR)
const glassMaterial = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0,
roughness: 0,
transmission: 1, // Glass transparency
thickness: 0.5,
ior: 1.5, // Index of refraction
envMapIntensity: 1
});
// Shader material (custom)
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
color: { value: new THREE.Color(0xff0000) }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform float time;
uniform vec3 color;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(color * sin(vUv.x * 10.0 + time), 1.0);
}
`
});
4. ライティング:基本的なライティング
// Ambient light (uniform everywhere)
const ambient = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambient);
// Directional light (sun)
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 10, 5);
dirLight.castShadow = true;
// Shadow configuration
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
dirLight.shadow.camera.left = -10;
dirLight.shadow.camera.right = 10;
dirLight.shadow.camera.top = 10;
dirLight.shadow.camera.bottom = -10;
scene.add(dirLight);
// Point light (bulb)
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 5, 0);
scene.add(pointLight);
// Enable shadows on renderer
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Enable on objects
mesh.castShadow = true;
mesh.receiveShadow = true;
5. テクスチャ:テクスチャの読み込み
const loader = new THREE.TextureLoader();
// Load color texture
const colorTexture = loader.load('texture.jpg');
colorTexture.colorSpace = THREE.SRGBColorSpace; // Important for color accuracy
// Configure texture
colorTexture.wrapS = THREE.RepeatWrapping;
colorTexture.wrapT = THREE.RepeatWrapping;
colorTexture.repeat.set(4, 4);
// HDR environment map
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
const rgbeLoader = new RGBELoader();
rgbeLoader.load('environment.hdr', (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
scene.background = texture;
});
// Cube texture (skybox)
const cubeLoader = new THREE.CubeTextureLoader();
const cubeTexture = cubeLoader.load([
'px.jpg', 'nx.jpg', // +X, -X
'py.jpg', 'ny.jpg', // +Y, -Y
'pz.jpg', 'nz.jpg' // +Z, -Z
]);
scene.background = cubeTexture;
6. アニメーション:シンプルなアニメーション
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load('model.glb', (gltf) => {
const model = gltf.scene;
scene.add(model);
// Create animation mixer
const mixer = new THREE.AnimationMixer(model);
// Play all animations
gltf.animations.forEach((clip) => {
const action = mixer.clipAction(clip);
action.play();
});
// Update in animation loop
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
mixer.update(delta);
renderer.render(scene, camera);
}
animate();
});
// Procedural animation
function animate() {
const time = clock.getElapsedTime();
mesh.rotation.y = time;
mesh.position.y = Math.sin(time) * 0.5;
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
7. ローダー:GLTF モデルの読み込み
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
// Setup Draco compression support
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
// Load model
gltfLoader.load('model.glb', (gltf) => {
const model = gltf.scene;
// Enable shadows
model.traverse((child) => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
// Center and scale
const box = new THREE.Box3().setFromObject(model);
const center = box.getCenter(new THREE.Vector3());
model.position.sub(center);
scene.add(model);
});
// Async/Promise pattern
async function loadModel(url) {
return new Promise((resolve, reject) => {
gltfLoader.load(url, resolve, undefined, reject);
});
}
const gltf = await loadModel('model.glb');
scene.add(gltf.scene);
8. シェーダー:カスタムシェーダーマテリアル
const material = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
amplitude: { value: 0.5 }
},
vertexShader: `
uniform float time;
uniform float amplitude;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
// Wave displacement
pos.z += sin(pos.x * 5.0 + time) * amplitude;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`,
fragmentShader: `
uniform float time;
varying vec2 vUv;
void main() {
vec3 color = vec3(vUv, 0.5 + 0.5 * sin(time));
gl_FragColor = vec4(color, 1.0);
}
`
});
// Update in animation loop
function animate() {
material.uniforms.time.value = clock.getElapsedTime();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
9. ポストプロセッシング:ブルームの追加
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
// Create composer
const composer = new EffectComposer(renderer);
// Render scene pass
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
// Bloom pass
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // strength
0.4, // radius
0.85 // threshold
);
composer.addPass(bloomPass);
// Use composer instead of renderer
function animate() {
requestAnimationFrame(animate);
composer.render(); // NOT renderer.render()
}
// Handle resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize(window.innerWidth, window.innerHeight);
});
10. インタラクション:レイキャスティング
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Camera controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// Raycasting setup
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function onMouseClick(event) {
// Convert mouse to normalized coordinates
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// Raycast from camera
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
const object = intersects[0].object;
console.log('Clicked:', object);
console.log('Point:', intersects[0].point);
// Highlight selected object
object.material.emissive.set(0x444444);
}
}
window.addEventListener('click', onMouseClick);
// Update controls in animation loop
function animate() {
requestAnimationFrame(animate);
controls.update(); // Required if enableDamping is true
renderer.render(scene, camera);
}
よくあるパターン
適切な破棄
// Dispose geometries, materials, textures
geometry.dispose();
material.dispose();
texture.dispose();
// Remove from scene
scene.remove(mesh);
// Dispose renderer
renderer.dispose();
レスポンシブなレンダリング
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
パフォーマンスの最適化
- 繰り返し使うオブジェクトにはインスタンシングを使用する(
InstancedMesh) - フラスタムカリングを有効にする(デフォルトで有効)
- 使用しないリソースを破棄する
- 複雑なシーンでは適切な LOD(詳細度)を使用する
- ジオメトリを統合してドローコールを最小限に抑える
- アクティブなライトの数を制限する(ライトごとにシェーダーの複雑さが増します)
- テクスチャアトラスを使ってテクスチャの切り替えを減らす
バージョン情報
Three.js のバージョン:r160+(2024年1月)
インポート形式:ES6 モジュール(three、three/addons/*)
確認日:2024-01
関連項目
- 公式ドキュメント:https://threejs.org/docs/
- 例:https://threejs.org/examples/
- エディター:https://threejs.org/editor/
- ソース:CloudAI-X/threejs-skills を基にしています
コメント
Markdown 対応