ジオメトリ
ジオメトリは「形」のデータ。頂点・面(インデックス)・UV・法線を持つ BufferGeometry が中身。
Three.js には組み込みのプリミティブがたくさんあるが、自前で作ることもできる。
プリミティブ一覧
すべて new THREE.XxxGeometry(...)。引数の順序を覚えておくと早い。
| クラス | 主な引数 | 用途 |
|---|---|---|
BoxGeometry | (w, h, d, ws=1, hs=1, ds=1) | 箱 |
SphereGeometry | (r, ws=32, hs=16) | 球 |
PlaneGeometry | (w, h, ws=1, hs=1) | 板(床・パネル) |
CircleGeometry | (r, segments=32) | 円板 |
RingGeometry | (innerR, outerR, segments=32) | ドーナツ状の板 |
CylinderGeometry | (rTop, rBottom, h, radialSeg=32) | 円柱・円錐台 |
ConeGeometry | (r, h, radialSeg=32) | 円錐 |
TorusGeometry | (r, tube, radialSeg=12, tubularSeg=48) | ドーナツ |
TorusKnotGeometry | (r, tube, tubularSeg=64, radialSeg=8, p=2, q=3) | 結び目 |
CapsuleGeometry | (r, length, capSeg=4, radialSeg=8) | カプセル(薬カプセル状) |
TetrahedronGeometry | (r, detail=0) | 正四面体 |
OctahedronGeometry | (r, detail=0) | 正八面体 |
DodecahedronGeometry | (r, detail=0) | 正十二面体 |
IcosahedronGeometry | (r, detail=0) | 正二十面体(球の近似に便利) |
LatheGeometry | (points, segments=12) | 回転体(壺・グラスなど) |
TubeGeometry | (curve, tubularSeg=64, r=1, radialSeg=8) | カーブに沿ったチューブ |
ExtrudeGeometry | (shape, opts) | 2D Shape の押し出し(ロゴ等) |
ShapeGeometry | (shape) | 2D Shape のフラット版 |
EdgesGeometry | (geom, thresholdAngle=1) | 輪郭線(LineSegments と組む) |
WireframeGeometry | (geom) | ワイヤフレーム |
const box = new THREE.BoxGeometry(1, 1, 1)
const sphere = new THREE.SphereGeometry(0.5, 32, 16)
const plane = new THREE.PlaneGeometry(10, 10)
BufferGeometry の中身
全ジオメトリの内部は BufferGeometry。これは頂点属性(位置・UV・法線・色…)と
インデックスの集合。
const geom = new THREE.BoxGeometry()
console.log(geom.attributes.position) // BufferAttribute (Float32, itemSize 3)
console.log(geom.attributes.normal) // BufferAttribute (Float32, itemSize 3)
console.log(geom.attributes.uv) // BufferAttribute (Float32, itemSize 2)
console.log(geom.index) // インデックス(三角形リスト)
主な属性:
position— 頂点座標(必須)normal— 法線(ライティングに必要)uv— テクスチャ座標color— 頂点カラー(vertexColors: trueで有効化)tangent— 接線(normal map 使用時)skinIndex/skinWeight— スキニング用(GLTF キャラ)
自前 BufferGeometry を作る
独自の点群、メッシュ、形をプロシージャルに作るときは BufferGeometry を直接組む。
const geometry = new THREE.BufferGeometry()
const positions = new Float32Array([
0, 1, 0, // v0
-1, -1, 0, // v1
1, -1, 0, // v2
])
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3))
// 単一三角形なので index は不要。複雑な形では setIndex で頂点共有
geometry.computeVertexNormals()
geometry.computeBoundingBox()
geometry.computeBoundingSphere()
インデックスを使う
頂点を共有してメモリを節約したい時は setIndex。
const positions = new Float32Array([
-1, -1, 0, //0
1, -1, 0, //1
1, 1, 0, //2
-1, 1, 0, //3
])
const indices = new Uint16Array([
0, 1, 2, // 三角形 1
0, 2, 3, // 三角形 2
])
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3))
geometry.setIndex(new THREE.BufferAttribute(indices, 1))
UV を付ける
const uvs = new Float32Array([
0, 0,
1, 0,
1, 1,
0, 1,
])
geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2))
変形・最適化
法線の再計算
頂点を動かしたら法線が古いまま。必ず computeVertexNormals()。
geometry.attributes.position.needsUpdate = true
geometry.computeVertexNormals()
動的に頂点を変える
毎フレーム頂点を書き換えたい場合はposition.needsUpdate = trueを立てる。
ただし大量頂点を CPU から書き換えるのは遅い。シェーダ側で動かすほうが速い。
マージ・結合
addons の BufferGeometryUtils で複数の geometry を1つに合体できる。
ドローコール削減に有効。
import { mergeGeometries } from "three/addons/utils/BufferGeometryUtils.js"
const merged = mergeGeometries([geomA, geomB, geomC])
const mesh = new THREE.Mesh(merged, material)
輪郭線・ワイヤフレーム
シルエットだけ抜く(EdgesGeometry)
const edges = new THREE.EdgesGeometry(box, 15) // 15度以上の折れ目だけ拾う
const line = new THREE.LineSegments(
edges,
new THREE.LineBasicMaterial({ color: "white" }),
)
mesh.add(line)
全エッジ表示(WireframeGeometry)
const wire = new THREE.WireframeGeometry(box)
const line = new THREE.LineSegments(wire, new THREE.LineBasicMaterial({ color: "white" }))
単に色付きで「ワイヤ表示」にしたいだけならマテリアルの wireframe: true でも可能。
その場合 EdgesGeometry のような「閾値で残すエッジ」の制御はできない。
2D Shape からの押し出し
ロゴや文字を2D で描いて、押し出して 3D にするパターン。
const shape = new THREE.Shape()
shape.moveTo(0, 0)
shape.lineTo(2, 0)
shape.lineTo(2, 1)
shape.lineTo(0, 1)
shape.lineTo(0, 0)
const geometry = new THREE.ExtrudeGeometry(shape, {
depth: 0.5,
bevelEnabled: true,
bevelThickness: 0.05,
bevelSize: 0.05,
bevelSegments: 4,
})
カーブに沿ったチューブ
const curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-2, 0, 0),
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(2, 0, 0),
new THREE.Vector3(0, -1, 0),
], true) // closed
const tube = new THREE.TubeGeometry(curve, 200, 0.05, 16, true)
点と線
点群(パーティクル)や線は Mesh ではなく Points / Line / LineSegments を使う。
const N = 5000
const positions = new Float32Array(N * 3)
for (let i = 0; i < N; i++) {
positions[i*3+0] = (Math.random() - 0.5) * 10
positions[i*3+1] = (Math.random() - 0.5) * 10
positions[i*3+2] = (Math.random() - 0.5) * 10
}
const geom = new THREE.BufferGeometry()
geom.setAttribute("position", new THREE.BufferAttribute(positions, 3))
const points = new THREE.Points(
geom,
new THREE.PointsMaterial({ size: 0.02, color: "white" }),
)
scene.add(points)
Bounding ボックス・球
ヒット判定や frustum culling、自動カメラ調整で使う。
geometry.computeBoundingBox()
console.log(geometry.boundingBox.min, geometry.boundingBox.max)
geometry.computeBoundingSphere()
console.log(geometry.boundingSphere.center, geometry.boundingSphere.radius)
dispose() を忘れない
ジオメトリは GPU バッファを掴む。使い終わったら geometry.dispose()。
シーンから外しただけでは GPU メモリは戻らない。詳しくは 注意点。