Communityコーディング&開発github.com

UtkarshBirla28/threejs-geometry

Three.jsジオメトリの作成と加工:組み込み形状、3Dテキスト、頂点バッファと属性、マージ、インスタンシング、バッチング、ポイントクラウドとライン。WebGLまたはWebGPUとTSLに対応。3D形状やテキスト、カスタム頂点データ、カスタムメッシュ、インスタンスメッシュ、ポイントクラウドの構築時に使用します。

threejs-geometry とは?

このスキルは、three.jsライブラリ(バージョンr186をターゲット)におけるジオメトリの作成と操作に関する包括的なガイドです。組み込み形状(ボックス、球、平面、円柱など)から、高度な形状(多面体、カプセル)、パスベースの形状(押し出し、チューブ)、テキストジオメトリまでをカバーします。また、BufferGeometryを使用したカスタム頂点データの定義方法、属性の更新方法、インタリーブバッファの使用方法についても詳しく解説しています。さらに、エッジとワイヤーフレームの生成、ポイントクラウドとラインの描画、InstancedMeshを使用した効率的なインスタンシング、InstancedBufferGeometryによるインスタンスごとの属性のカスタマイズについても説明しています。WebGPUとTSLに関するセクションも含まれており、最新のレンダリング技術に対応しています。このスキルは、three.jsプロジェクトでジオメトリ関連のタスクに取り組むあらゆる開発者にとって不可欠なリソースです。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/UtkarshBirla28/animated-shorts-pipeline/tree/HEAD/.claude/skills/threejs-geometry

Installed? Explore more コーディング&開発 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Three.js ジオメトリ

three.js r186 を対象としています。サンプルは WebGLRenderer を使用します。WebGPU と TSL のセクションでは WebGPURenderer を使用します。

ローカルオーバーライド (2026-11-10 に Claude がこの PC 用に追加。元のスキルには含まれません)。 弊社のアニメーションショートパイプライン (<ROOT>\studio、mromidev/claude-animated-shorts より) は three 0.175 (r175)

  • Remotion 4.0.290 + @react-three/fiber 9.1.2 + pmndrs ポストプロセッシング 6.37.2 に固定されています。three は固定されたままにしてください: shade.ts/cardshade.ts は three シェーダチャンクを文字列パッチします。このパイプラインで作業する場合:
  • r176 以降が必要な「よくある間違い」/ API アドバイス (HDRLoader、Timer、PCFSoftShadowMap の非推奨、setEffects、 RenderPipeline、outputBufferType、mesh.pivot、Capsule height、TSL/WebGPU) は無視してください。まず r175 に API が存在するか確認してください。
  • useFrame、Clock、Timer、デルタ時間、setAnimationLoop、requestAnimationFrame でアニメーションさせないでください。Remotion は フレームごとにレンダリングします: すべての値を useCurrentFrame() / fps (およびクリップの場合は mixer.setTime(frame / fps)) から導出してください。
  • ポストプロセッシングは pmndrs postprocessing であり、three/addons EffectComposer ではありません: OutputPass を追加しないでください (sRGB が二重エンコードされます)。
  • トゥーンカラー: 当社のコンポーザーではトーンマッピングは NEUTRAL です。ACES のデフォルトと tonemapping_fragment の色付けに注意してください。
  • その他の three.js プロジェクトについては、以下の元の r186 ガイダンスがそのまま適用されます。

クイックスタート

import * as THREE from "three";

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 5);

// ジオメトリは形状であり、多くのメッシュが1つのジオメトリインスタンスを共有できます
const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshNormalMaterial());
scene.add(mesh);

renderer.setAnimationLoop(animate);

function animate() {
  mesh.rotation.y += 0.01;
  renderer.render(scene, camera);
}

組み込みジオメトリ

基本形状

new THREE.BoxGeometry(1, 1, 1); // 幅、高さ、奥行き、幅セグメント数、高さセグメント数、奥行きセグメント数
new THREE.SphereGeometry(1, 32, 16); // 半径、幅セグメント数、高さセグメント数、phiStart、phiLength、thetaStart、thetaLength
new THREE.SphereGeometry(1, 32, 16, 0, Math.PI); // 半球 (phi スイープ、極を通して切断)
new THREE.SphereGeometry(1, 32, 16, 0, Math.PI * 2, 0, Math.PI / 2); // ドーム (赤道で切断)
new THREE.PlaneGeometry(10, 10, 1, 1); // 幅、高さ、幅セグメント数、高さセグメント数
new THREE.CircleGeometry(1, 32); // 半径、セグメント数、thetaStart、thetaLength
new THREE.CylinderGeometry(1, 1, 2, 32); // 上部半径、下部半径、高さ、半径方向セグメント数、高さ方向セグメント数、openEnded、thetaStart、thetaLength
new THREE.CylinderGeometry(1, 1, 2, 6); // 六角柱
new THREE.ConeGeometry(1, 2, 32); // 半径、高さ、半径方向セグメント数、高さ方向セグメント数、openEnded、thetaStart、thetaLength
new THREE.TorusGeometry(1, 0.4, 16, 100); // 半径、チューブ半径、半径方向セグメント数、管方向セグメント数、弧、thetaStart、thetaLength
new THREE.TorusGeometry(1, 0.4, 16, 100, Math.PI); // 半弧
new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3); // 半径、チューブ半径、管方向セグメント数、半径方向セグメント数、p、q
new THREE.RingGeometry(0.5, 1, 32, 1); // 内側半径、外側半径、シータセグメント数、ファイセグメント数、thetaStart、thetaLength

高度な形状

new THREE.CapsuleGeometry(0.5, 1, 4, 8, 1); // 半径、高さ (中央部分のみ)、キャップセグメント数、半径方向セグメント数、高さ方向セグメント数

// 半径、詳細度 - 詳細度ごとにすべての面が分割されます
new THREE.IcosahedronGeometry(1, 0); // 詳細度0で20面
new THREE.DodecahedronGeometry(1, 0);
new THREE.OctahedronGeometry(1, 0);
new THREE.TetrahedronGeometry(1, 0);

// Polyhedron - フラットな頂点配列、インデックス、半径、詳細度
const vertices = [1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1];
const indices = [2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1];
new THREE.PolyhedronGeometry(vertices, indices, 1, 0);

パスベースの形状

// Lathe - Y軸を中心に回転するVector2プロファイル: ポイント、セグメント数、phiStart、phiLength
const profile = [
  new THREE.Vector2(0, 0), new THREE.Vector2(0.5, 0), new THREE.Vector2(0.5, 1), new THREE.Vector2(0, 1),
];
new THREE.LatheGeometry(profile, 32);

// Extrude - Z方向に押し出された2Dシェイプ
const shape = new THREE.Shape();
shape.moveTo(0, 0);
shape.lineTo(1, 0);
shape.lineTo(1, 1);
shape.lineTo(0, 1);
new THREE.ExtrudeGeometry(shape, {
  steps: 1, depth: 1, bevelEnabled: true,
  bevelThickness: 0.1, bevelSize: 0.1, bevelSegments: 3,
});

// Tube - 曲線に沿った円形スイープ: パス、管方向セグメント数、半径、半径方向セグメント数、閉じる
const curve = new THREE.CatmullRomCurve3([
  new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 0, 0),
]);
new THREE.TubeGeometry(curve, 64, 0.2, 8, false);

テキストジオメトリ

import { FontLoader } from "three/addons/loaders/FontLoader.js";
import { TextGeometry } from "three/addons/geometries/TextGeometry.js";

// three.jsリポジトリの examples/fonts からの .typeface.json フォント
const font = await new FontLoader().loadAsync("fonts/helvetiker_regular.typeface.json");
const geometry = new TextGeometry("Hello", {
  font: font,
  size: 1, // ワールド単位でのテキストサイズ
  depth: 0.2, // 押し出しの深さ
  curveSegments: 12,
  bevelEnabled: true,
  bevelThickness: 0.03,
  bevelSize: 0.02,
  direction: "ltr", // 'ltr'、'rtl' (右から左)、または 'tb' (上から下)
});

geometry.center(); // グリフを原点に再配置
scene.add(new THREE.Mesh(geometry, new THREE.MeshNormalMaterial()));

BufferGeometry

すべてのジオメトリの基本クラス: 頂点データの型付き配列とオプションのインデックス。属性は、頂点ごとに itemSize 個の値を持つ名前付きバッファです。position、normal、uv は、マテリアルがデフォルトで読み取るものです。

カスタム BufferGeometry

const geometry = new THREE.BufferGeometry();

// 4頂点、それぞれ3つの浮動小数点数 (x, y, z)
const vertices = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0]);
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));

// インデックスは2つの三角形で頂点を再利用
const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));

// 法線はライティングを、UVはテクスチャアドレスを駆動
const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));
// オプションの頂点ごとの色。material.vertexColors = true でレンダリング
const colors = new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0]);
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));

scene.add(new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ vertexColors: true })));

属性タイプ

const count = 4;
const geometry = new THREE.BufferGeometry();
// 位置、法線、UV、および浮動小数点カラーには Float32
geometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(count * 3), 3));
// Uint16 インデックスは頂点 0 から 65534 をアドレス指定 (65535 はプリミティブ再起動値)。setIndex([...]) にプレーン配列を渡すと、Uint16 または Uint32 が自動選択されます
geometry.setIndex(new THREE.BufferAttribute(new Uint16Array(count), 1));
// Uint8 カラーは、バイトがシェーダに 0.0~1.0 として到達するように、normalized = true (第3引数) が必要
geometry.setAttribute("color", new THREE.BufferAttribute(new Uint8Array(count * 3), 3, true));

BufferGeometry の更新

const geometry = new THREE.PlaneGeometry(2, 2);
const positions = geometry.attributes.position;
positions.setXYZ(0, -2, -2, 0); // 頂点0を上書き
positions.getX(0); // getX / getY / getZ で単一コンポーネントを読み取り
positions.needsUpdate = true; // 変更をアップロード。配列は最初のレンダリング後に拡張できないため、最大値を割り当て、geometry.setDrawRange(0, n) を使用します
goometry.computeVertexNormals(); // 法線は新しい位置と一致する必要があります
goometry.computeBoundingBox(); // 境界ボリュームはフラスタムカリングとレイキャスティングを駆動
goometry.computeBoundingSphere();

インタリーブバッファ

// 頂点ごとに位置 (3 浮動小数点数) と uv (2 浮動小数点数) を保持する1つのバッファ
const interleavedBuffer = new THREE.InterleavedBuffer(
  new Float32Array([
    -1, -1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, 0, 0, 1, // 4頂点: xyz + uv
  ]),
  5, // ストライド: 頂点あたりの浮動小数点数
);
const geometry = new THREE.BufferGeometry();
goometry.setAttribute("position", new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0));
goometry.setAttribute("uv", new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3));
goometry.setIndex([0, 1, 2, 0, 2, 3]); // 4頂点にわたる2つの三角形
// BufferGeometryUtils.interleaveAttributes([position, normal, uv]) は既存の属性をこのようにパッケージ化します

エッジとワイヤーフレーム

const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
// 2つの面の法線が thresholdAngle (度、ここでは15) 以上異なるエッジ、および開いた境界エッジ
const edges = new THREE.EdgesGeometry(boxGeometry, 15);
const edgeLines = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0xffffff }));
// すべての三角形のエッジ、対角線を含む。2つの三角形で共有されるエッジは1回描画されます
const wireframe = new THREE.WireframeGeometry(boxGeometry);
const wireLines = new THREE.LineSegments(wireframe, new THREE.LineBasicMaterial({ color: 0xffffff }));
scene.add(edgeLines, wireLines);

ポイント

const count = 1000;
const positions = new Float32Array(count * 3).map(() => (Math.random() - 0.5) * 10);
const geometry = new THREE.BufferGeometry();
goometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
// sizeAttenuation (デフォルト true) は、透視カメラで奥行きに応じてポイントを縮小します。ポイントは size * (canvas CSS height / 2) / depth CSS ピクセルを範囲とします
const material = new THREE.PointsMaterial({ size: 0.1, color: 0xffffff });
const points = new THREE.Points(geometry, material);
scene.add(points);

WebGPURenderer では、WebGPU バックエンドはマテリアルサイズに関係なく1ピクセルでポイントを描画します。サイズを復元するインスタンス化スプライトについては、WebGPU と TSL のセクションを参照してください。

ライン

const linePoints = [
  new THREE.Vector3(-1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(1, 0, 0),
];
const geometry = new THREE.BufferGeometry().setFromPoints(linePoints);
const material = new THREE.LineBasicMaterial({ color: 0xff0000 });

// Line はポイントを順に接続。LineLoop は最初のポイントに戻って閉じます
const line = new THREE.Line(geometry, material);
const loop = new THREE.LineLoop(geometry, material);
scene.add(line, loop);

// LineSegments は独立したペアを描画: 頂点0-1、2-3、...
const segmentsGeometry = new THREE.BufferGeometry().setFromPoints([linePoints[0], linePoints[1], linePoints[1], linePoints[2]]);
const segments = new THREE.LineSegments(segmentsGeometry, material);
scene.add(segments);

LineLoop は WebGPURenderer ではサポートされていません。エラーをログ出力し、何もレンダリングしません。そこでループを閉じるには、最初のポイントを繰り返して Line を使用してください。

InstancedMesh

1つのジオメトリの多くのコピーを、それぞれ独自のトランスフォームで1回のドローコールで描画します。

const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
const material = new THREE.MeshBasicMaterial(); // インスタンスカラーで乗算。MeshNormalMaterial は無視
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.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0);
  dummy.scale.setScalar(0.5 + Math.random());
  dummy.updateMatrix();
  instancedMesh.setMatrixAt(i, dummy.matrix);
}
instancedMesh.instanceMatrix.needsUpdate = true; // メッシュがレンダリングされた後に変更があった場合に必要。変更前でも問題ありません

// setColorAt は最初の使用時に instanceColor を作成します。ループ後にフラグを立てます
for (let i = 0; i < count; i++) {
  instancedMesh.setColorAt(i, new THREE.Color(Math.random(), Math.random(), Math.random()));
}
instancedMesh.instanceColor.needsUpdate = true;

scene.add(instancedMesh);

実行時には、次のようにインスタンスを更新およびレイキャストします:

// ここでの mesh は InstancedMesh です
const matrix = new THREE.Matrix4();
const index = 7;
mesh.getMatrixAt(index, matrix);
matrix.setPosition(0, 2, 0); // このインスタンスのみ移動
mesh.setMatrixAt(index, matrix);
mesh.instanceMatrix.needsUpdate = true; // setMatrixAt のバッチ呼び出し後にフラグを立てます
mesh.computeBoundingSphere(); // インスタンスが移動しました: フラスタムカリングとレイキャスティングで使用される境界を更新

// レイキャスティングはどのインスタンスがヒットしたかを報告します
const raycaster = new THREE.Raycaster();
const hits = raycaster.intersectObject(mesh);
if (hits.length > 0) {
  const instanceId = hits[0].instanceId; // 非インスタンス化オブジェクトの場合は undefined
}

InstancedBufferGeometry

トランスフォームとカラーを超えたインスタンスごとの属性。

const count = 1000;
const geometry = new THREE.InstancedBufferGeometry();
goometry.copy(new THREE.BoxGeometry(1, 1, 1)); // インデックスとすべての属性をコピー
goometry.instanceCount = count; // 必須: copy() はインスタンスカウントを引き継ぎません

const offsets = new Float32Array(count * 3).map(() => Math.random() * 10);
goometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3));

// WebGLRenderer と ShaderMaterial を使用する場合、頂点シェーダで `in vec3 offset;` を自分で宣言し、
// それを position に追加します (threejs-shaders 参照)。WebGPURenderer では、
// インスタンスごとのデータは TSL ノードです - WebGPU と TSL のセクションを参照してください。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

関連スキル