create-threejs-game 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -0
- package/bin/cli.js +370 -0
- package/package.json +29 -0
- package/template/.claude/skills/threejs-animation/SKILL.md +552 -0
- package/template/.claude/skills/threejs-fundamentals/SKILL.md +488 -0
- package/template/.claude/skills/threejs-geometry/SKILL.md +548 -0
- package/template/.claude/skills/threejs-interaction/SKILL.md +660 -0
- package/template/.claude/skills/threejs-lighting/SKILL.md +481 -0
- package/template/.claude/skills/threejs-loaders/SKILL.md +623 -0
- package/template/.claude/skills/threejs-materials/SKILL.md +520 -0
- package/template/.claude/skills/threejs-postprocessing/SKILL.md +602 -0
- package/template/.claude/skills/threejs-shaders/SKILL.md +642 -0
- package/template/.claude/skills/threejs-textures/SKILL.md +628 -0
- package/template/.codex/skills/threejs-animation/SKILL.md +552 -0
- package/template/.codex/skills/threejs-fundamentals/SKILL.md +488 -0
- package/template/.codex/skills/threejs-geometry/SKILL.md +548 -0
- package/template/.codex/skills/threejs-interaction/SKILL.md +660 -0
- package/template/.codex/skills/threejs-lighting/SKILL.md +481 -0
- package/template/.codex/skills/threejs-loaders/SKILL.md +623 -0
- package/template/.codex/skills/threejs-materials/SKILL.md +520 -0
- package/template/.codex/skills/threejs-postprocessing/SKILL.md +602 -0
- package/template/.codex/skills/threejs-shaders/SKILL.md +642 -0
- package/template/.codex/skills/threejs-textures/SKILL.md +628 -0
- package/template/README.md +352 -0
- package/template/docs/.gitkeep +0 -0
- package/template/plans/.gitkeep +0 -0
- package/template/prompts/01-mockup-generation.md +44 -0
- package/template/prompts/02-prd-generation.md +119 -0
- package/template/prompts/03-tdd-generation.md +127 -0
- package/template/prompts/04-execution-plan.md +89 -0
- package/template/prompts/05-implementation.md +61 -0
- package/template/public/assets/.gitkeep +0 -0
- package/template/scripts/config.example.json +12 -0
- package/template/scripts/generate-assets-json.js +149 -0
- package/template/scripts/generate-mockup.js +197 -0
- package/template/scripts/generate-plan.js +295 -0
- package/template/scripts/generate-prd.js +297 -0
- package/template/scripts/generate-tdd.js +283 -0
- package/template/scripts/pipeline.js +229 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: threejs-geometry
|
|
3
|
+
description: Three.js geometry creation - built-in shapes, BufferGeometry, custom geometry, instancing. Use when creating 3D shapes, working with vertices, building custom meshes, or optimizing with instanced rendering.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Three.js Geometry
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
import * as THREE from "three";
|
|
12
|
+
|
|
13
|
+
// Built-in geometry
|
|
14
|
+
const box = new THREE.BoxGeometry(1, 1, 1);
|
|
15
|
+
const sphere = new THREE.SphereGeometry(0.5, 32, 32);
|
|
16
|
+
const plane = new THREE.PlaneGeometry(10, 10);
|
|
17
|
+
|
|
18
|
+
// Create mesh
|
|
19
|
+
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
|
20
|
+
const mesh = new THREE.Mesh(box, material);
|
|
21
|
+
scene.add(mesh);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Built-in Geometries
|
|
25
|
+
|
|
26
|
+
### Basic Shapes
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
// Box - width, height, depth, widthSegments, heightSegments, depthSegments
|
|
30
|
+
new THREE.BoxGeometry(1, 1, 1, 1, 1, 1);
|
|
31
|
+
|
|
32
|
+
// Sphere - radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength
|
|
33
|
+
new THREE.SphereGeometry(1, 32, 32);
|
|
34
|
+
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI * 2, 0, Math.PI); // Full sphere
|
|
35
|
+
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI); // Hemisphere
|
|
36
|
+
|
|
37
|
+
// Plane - width, height, widthSegments, heightSegments
|
|
38
|
+
new THREE.PlaneGeometry(10, 10, 1, 1);
|
|
39
|
+
|
|
40
|
+
// Circle - radius, segments, thetaStart, thetaLength
|
|
41
|
+
new THREE.CircleGeometry(1, 32);
|
|
42
|
+
new THREE.CircleGeometry(1, 32, 0, Math.PI); // Semicircle
|
|
43
|
+
|
|
44
|
+
// Cylinder - radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded
|
|
45
|
+
new THREE.CylinderGeometry(1, 1, 2, 32, 1, false);
|
|
46
|
+
new THREE.CylinderGeometry(0, 1, 2, 32); // Cone
|
|
47
|
+
new THREE.CylinderGeometry(1, 1, 2, 6); // Hexagonal prism
|
|
48
|
+
|
|
49
|
+
// Cone - radius, height, radialSegments, heightSegments, openEnded
|
|
50
|
+
new THREE.ConeGeometry(1, 2, 32, 1, false);
|
|
51
|
+
|
|
52
|
+
// Torus - radius, tube, radialSegments, tubularSegments, arc
|
|
53
|
+
new THREE.TorusGeometry(1, 0.4, 16, 100);
|
|
54
|
+
|
|
55
|
+
// TorusKnot - radius, tube, tubularSegments, radialSegments, p, q
|
|
56
|
+
new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3);
|
|
57
|
+
|
|
58
|
+
// Ring - innerRadius, outerRadius, thetaSegments, phiSegments
|
|
59
|
+
new THREE.RingGeometry(0.5, 1, 32, 1);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Advanced Shapes
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
// Capsule - radius, length, capSegments, radialSegments
|
|
66
|
+
new THREE.CapsuleGeometry(0.5, 1, 4, 8);
|
|
67
|
+
|
|
68
|
+
// Dodecahedron - radius, detail
|
|
69
|
+
new THREE.DodecahedronGeometry(1, 0);
|
|
70
|
+
|
|
71
|
+
// Icosahedron - radius, detail (0 = 20 faces, higher = smoother)
|
|
72
|
+
new THREE.IcosahedronGeometry(1, 0);
|
|
73
|
+
|
|
74
|
+
// Octahedron - radius, detail
|
|
75
|
+
new THREE.OctahedronGeometry(1, 0);
|
|
76
|
+
|
|
77
|
+
// Tetrahedron - radius, detail
|
|
78
|
+
new THREE.TetrahedronGeometry(1, 0);
|
|
79
|
+
|
|
80
|
+
// Polyhedron - vertices, indices, radius, detail
|
|
81
|
+
const vertices = [1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1];
|
|
82
|
+
const indices = [2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1];
|
|
83
|
+
new THREE.PolyhedronGeometry(vertices, indices, 1, 0);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Path-Based Shapes
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
// Lathe - points[], segments, phiStart, phiLength
|
|
90
|
+
const points = [
|
|
91
|
+
new THREE.Vector2(0, 0),
|
|
92
|
+
new THREE.Vector2(0.5, 0),
|
|
93
|
+
new THREE.Vector2(0.5, 1),
|
|
94
|
+
new THREE.Vector2(0, 1),
|
|
95
|
+
];
|
|
96
|
+
new THREE.LatheGeometry(points, 32);
|
|
97
|
+
|
|
98
|
+
// Extrude - shape, options
|
|
99
|
+
const shape = new THREE.Shape();
|
|
100
|
+
shape.moveTo(0, 0);
|
|
101
|
+
shape.lineTo(1, 0);
|
|
102
|
+
shape.lineTo(1, 1);
|
|
103
|
+
shape.lineTo(0, 1);
|
|
104
|
+
shape.lineTo(0, 0);
|
|
105
|
+
|
|
106
|
+
const extrudeSettings = {
|
|
107
|
+
steps: 2,
|
|
108
|
+
depth: 1,
|
|
109
|
+
bevelEnabled: true,
|
|
110
|
+
bevelThickness: 0.1,
|
|
111
|
+
bevelSize: 0.1,
|
|
112
|
+
bevelSegments: 3,
|
|
113
|
+
};
|
|
114
|
+
new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
|
115
|
+
|
|
116
|
+
// Tube - path, tubularSegments, radius, radialSegments, closed
|
|
117
|
+
const curve = new THREE.CatmullRomCurve3([
|
|
118
|
+
new THREE.Vector3(-1, 0, 0),
|
|
119
|
+
new THREE.Vector3(0, 1, 0),
|
|
120
|
+
new THREE.Vector3(1, 0, 0),
|
|
121
|
+
]);
|
|
122
|
+
new THREE.TubeGeometry(curve, 64, 0.2, 8, false);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Text Geometry
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
|
|
129
|
+
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
|
|
130
|
+
|
|
131
|
+
const loader = new FontLoader();
|
|
132
|
+
loader.load("fonts/helvetiker_regular.typeface.json", (font) => {
|
|
133
|
+
const geometry = new TextGeometry("Hello", {
|
|
134
|
+
font: font,
|
|
135
|
+
size: 1,
|
|
136
|
+
depth: 0.2, // Was 'height' in older versions
|
|
137
|
+
curveSegments: 12,
|
|
138
|
+
bevelEnabled: true,
|
|
139
|
+
bevelThickness: 0.03,
|
|
140
|
+
bevelSize: 0.02,
|
|
141
|
+
bevelSegments: 5,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Center text
|
|
145
|
+
geometry.computeBoundingBox();
|
|
146
|
+
geometry.center();
|
|
147
|
+
|
|
148
|
+
const mesh = new THREE.Mesh(geometry, material);
|
|
149
|
+
scene.add(mesh);
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## BufferGeometry
|
|
154
|
+
|
|
155
|
+
The base class for all geometries. Stores data as typed arrays for GPU efficiency.
|
|
156
|
+
|
|
157
|
+
### Custom BufferGeometry
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
const geometry = new THREE.BufferGeometry();
|
|
161
|
+
|
|
162
|
+
// Vertices (3 floats per vertex: x, y, z)
|
|
163
|
+
const vertices = new Float32Array([
|
|
164
|
+
-1,
|
|
165
|
+
-1,
|
|
166
|
+
0, // vertex 0
|
|
167
|
+
1,
|
|
168
|
+
-1,
|
|
169
|
+
0, // vertex 1
|
|
170
|
+
1,
|
|
171
|
+
1,
|
|
172
|
+
0, // vertex 2
|
|
173
|
+
-1,
|
|
174
|
+
1,
|
|
175
|
+
0, // vertex 3
|
|
176
|
+
]);
|
|
177
|
+
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
|
|
178
|
+
|
|
179
|
+
// Indices (for indexed geometry - reuse vertices)
|
|
180
|
+
const indices = new Uint16Array([
|
|
181
|
+
0,
|
|
182
|
+
1,
|
|
183
|
+
2, // triangle 1
|
|
184
|
+
0,
|
|
185
|
+
2,
|
|
186
|
+
3, // triangle 2
|
|
187
|
+
]);
|
|
188
|
+
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
|
|
189
|
+
|
|
190
|
+
// Normals (required for lighting)
|
|
191
|
+
const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
|
|
192
|
+
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
|
|
193
|
+
|
|
194
|
+
// UVs (for texturing)
|
|
195
|
+
const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
|
|
196
|
+
geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));
|
|
197
|
+
|
|
198
|
+
// Colors (per-vertex colors)
|
|
199
|
+
const colors = new Float32Array([
|
|
200
|
+
1,
|
|
201
|
+
0,
|
|
202
|
+
0, // red
|
|
203
|
+
0,
|
|
204
|
+
1,
|
|
205
|
+
0, // green
|
|
206
|
+
0,
|
|
207
|
+
0,
|
|
208
|
+
1, // blue
|
|
209
|
+
1,
|
|
210
|
+
1,
|
|
211
|
+
0, // yellow
|
|
212
|
+
]);
|
|
213
|
+
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
|
|
214
|
+
// Use with: material.vertexColors = true
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### BufferAttribute Types
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
// Common attribute types
|
|
221
|
+
new THREE.BufferAttribute(array, itemSize);
|
|
222
|
+
|
|
223
|
+
// Typed array options
|
|
224
|
+
new Float32Array(count * itemSize); // Positions, normals, UVs
|
|
225
|
+
new Uint16Array(count); // Indices (up to 65535 vertices)
|
|
226
|
+
new Uint32Array(count); // Indices (larger meshes)
|
|
227
|
+
new Uint8Array(count * itemSize); // Colors (0-255 range)
|
|
228
|
+
|
|
229
|
+
// Item sizes
|
|
230
|
+
// Position: 3 (x, y, z)
|
|
231
|
+
// Normal: 3 (x, y, z)
|
|
232
|
+
// UV: 2 (u, v)
|
|
233
|
+
// Color: 3 (r, g, b) or 4 (r, g, b, a)
|
|
234
|
+
// Index: 1
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Modifying BufferGeometry
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
const positions = geometry.attributes.position;
|
|
241
|
+
|
|
242
|
+
// Modify vertex
|
|
243
|
+
positions.setXYZ(index, x, y, z);
|
|
244
|
+
|
|
245
|
+
// Access vertex
|
|
246
|
+
const x = positions.getX(index);
|
|
247
|
+
const y = positions.getY(index);
|
|
248
|
+
const z = positions.getZ(index);
|
|
249
|
+
|
|
250
|
+
// Flag for GPU update
|
|
251
|
+
positions.needsUpdate = true;
|
|
252
|
+
|
|
253
|
+
// Recompute normals after position changes
|
|
254
|
+
geometry.computeVertexNormals();
|
|
255
|
+
|
|
256
|
+
// Recompute bounding box/sphere after changes
|
|
257
|
+
geometry.computeBoundingBox();
|
|
258
|
+
geometry.computeBoundingSphere();
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Interleaved Buffers (Advanced)
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
// More efficient memory layout for large meshes
|
|
265
|
+
const interleavedBuffer = new THREE.InterleavedBuffer(
|
|
266
|
+
new Float32Array([
|
|
267
|
+
// pos.x, pos.y, pos.z, uv.u, uv.v (repeated per vertex)
|
|
268
|
+
-1, -1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, 0, 0, 1,
|
|
269
|
+
]),
|
|
270
|
+
5, // stride (floats per vertex)
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
geometry.setAttribute(
|
|
274
|
+
"position",
|
|
275
|
+
new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0),
|
|
276
|
+
); // size 3, offset 0
|
|
277
|
+
geometry.setAttribute(
|
|
278
|
+
"uv",
|
|
279
|
+
new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3),
|
|
280
|
+
); // size 2, offset 3
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## EdgesGeometry & WireframeGeometry
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
// Edge lines (only hard edges)
|
|
287
|
+
const edges = new THREE.EdgesGeometry(boxGeometry, 15); // 15 = threshold angle
|
|
288
|
+
const edgeMesh = new THREE.LineSegments(
|
|
289
|
+
edges,
|
|
290
|
+
new THREE.LineBasicMaterial({ color: 0xffffff }),
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
// Wireframe (all triangles)
|
|
294
|
+
const wireframe = new THREE.WireframeGeometry(boxGeometry);
|
|
295
|
+
const wireMesh = new THREE.LineSegments(
|
|
296
|
+
wireframe,
|
|
297
|
+
new THREE.LineBasicMaterial({ color: 0xffffff }),
|
|
298
|
+
);
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Points
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
// Create point cloud
|
|
305
|
+
const geometry = new THREE.BufferGeometry();
|
|
306
|
+
const positions = new Float32Array(1000 * 3);
|
|
307
|
+
|
|
308
|
+
for (let i = 0; i < 1000; i++) {
|
|
309
|
+
positions[i * 3] = (Math.random() - 0.5) * 10;
|
|
310
|
+
positions[i * 3 + 1] = (Math.random() - 0.5) * 10;
|
|
311
|
+
positions[i * 3 + 2] = (Math.random() - 0.5) * 10;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
|
|
315
|
+
|
|
316
|
+
const material = new THREE.PointsMaterial({
|
|
317
|
+
size: 0.1,
|
|
318
|
+
sizeAttenuation: true, // Size decreases with distance
|
|
319
|
+
color: 0xffffff,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const points = new THREE.Points(geometry, material);
|
|
323
|
+
scene.add(points);
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Lines
|
|
327
|
+
|
|
328
|
+
```javascript
|
|
329
|
+
// Line (connected points)
|
|
330
|
+
const points = [
|
|
331
|
+
new THREE.Vector3(-1, 0, 0),
|
|
332
|
+
new THREE.Vector3(0, 1, 0),
|
|
333
|
+
new THREE.Vector3(1, 0, 0),
|
|
334
|
+
];
|
|
335
|
+
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
|
336
|
+
const line = new THREE.Line(
|
|
337
|
+
geometry,
|
|
338
|
+
new THREE.LineBasicMaterial({ color: 0xff0000 }),
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
// LineLoop (closed loop)
|
|
342
|
+
const loop = new THREE.LineLoop(geometry, material);
|
|
343
|
+
|
|
344
|
+
// LineSegments (pairs of points)
|
|
345
|
+
const segmentsGeometry = new THREE.BufferGeometry();
|
|
346
|
+
segmentsGeometry.setAttribute(
|
|
347
|
+
"position",
|
|
348
|
+
new THREE.BufferAttribute(
|
|
349
|
+
new Float32Array([
|
|
350
|
+
-1,
|
|
351
|
+
0,
|
|
352
|
+
0,
|
|
353
|
+
0,
|
|
354
|
+
1,
|
|
355
|
+
0, // segment 1
|
|
356
|
+
0,
|
|
357
|
+
1,
|
|
358
|
+
0,
|
|
359
|
+
1,
|
|
360
|
+
0,
|
|
361
|
+
0, // segment 2
|
|
362
|
+
]),
|
|
363
|
+
3,
|
|
364
|
+
),
|
|
365
|
+
);
|
|
366
|
+
const segments = new THREE.LineSegments(segmentsGeometry, material);
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## InstancedMesh
|
|
370
|
+
|
|
371
|
+
Efficiently render many copies of the same geometry.
|
|
372
|
+
|
|
373
|
+
```javascript
|
|
374
|
+
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
|
375
|
+
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
|
376
|
+
const count = 1000;
|
|
377
|
+
|
|
378
|
+
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
|
|
379
|
+
|
|
380
|
+
// Set transforms for each instance
|
|
381
|
+
const dummy = new THREE.Object3D();
|
|
382
|
+
const matrix = new THREE.Matrix4();
|
|
383
|
+
|
|
384
|
+
for (let i = 0; i < count; i++) {
|
|
385
|
+
dummy.position.set(
|
|
386
|
+
(Math.random() - 0.5) * 20,
|
|
387
|
+
(Math.random() - 0.5) * 20,
|
|
388
|
+
(Math.random() - 0.5) * 20,
|
|
389
|
+
);
|
|
390
|
+
dummy.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, 0);
|
|
391
|
+
dummy.scale.setScalar(0.5 + Math.random());
|
|
392
|
+
dummy.updateMatrix();
|
|
393
|
+
|
|
394
|
+
instancedMesh.setMatrixAt(i, dummy.matrix);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Flag for GPU update
|
|
398
|
+
instancedMesh.instanceMatrix.needsUpdate = true;
|
|
399
|
+
|
|
400
|
+
// Optional: per-instance colors
|
|
401
|
+
instancedMesh.instanceColor = new THREE.InstancedBufferAttribute(
|
|
402
|
+
new Float32Array(count * 3),
|
|
403
|
+
3,
|
|
404
|
+
);
|
|
405
|
+
for (let i = 0; i < count; i++) {
|
|
406
|
+
instancedMesh.setColorAt(
|
|
407
|
+
i,
|
|
408
|
+
new THREE.Color(Math.random(), Math.random(), Math.random()),
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
instancedMesh.instanceColor.needsUpdate = true;
|
|
412
|
+
|
|
413
|
+
scene.add(instancedMesh);
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Update Instance at Runtime
|
|
417
|
+
|
|
418
|
+
```javascript
|
|
419
|
+
// Update single instance
|
|
420
|
+
const matrix = new THREE.Matrix4();
|
|
421
|
+
instancedMesh.getMatrixAt(index, matrix);
|
|
422
|
+
// Modify matrix...
|
|
423
|
+
instancedMesh.setMatrixAt(index, matrix);
|
|
424
|
+
instancedMesh.instanceMatrix.needsUpdate = true;
|
|
425
|
+
|
|
426
|
+
// Raycasting with instanced mesh
|
|
427
|
+
const intersects = raycaster.intersectObject(instancedMesh);
|
|
428
|
+
if (intersects.length > 0) {
|
|
429
|
+
const instanceId = intersects[0].instanceId;
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## InstancedBufferGeometry (Advanced)
|
|
434
|
+
|
|
435
|
+
For custom per-instance attributes beyond transform/color.
|
|
436
|
+
|
|
437
|
+
```javascript
|
|
438
|
+
const geometry = new THREE.InstancedBufferGeometry();
|
|
439
|
+
geometry.copy(new THREE.BoxGeometry(1, 1, 1));
|
|
440
|
+
|
|
441
|
+
// Add per-instance attribute
|
|
442
|
+
const offsets = new Float32Array(count * 3);
|
|
443
|
+
for (let i = 0; i < count; i++) {
|
|
444
|
+
offsets[i * 3] = Math.random() * 10;
|
|
445
|
+
offsets[i * 3 + 1] = Math.random() * 10;
|
|
446
|
+
offsets[i * 3 + 2] = Math.random() * 10;
|
|
447
|
+
}
|
|
448
|
+
geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3));
|
|
449
|
+
|
|
450
|
+
// Use in shader
|
|
451
|
+
// attribute vec3 offset;
|
|
452
|
+
// vec3 transformed = position + offset;
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## Geometry Utilities
|
|
456
|
+
|
|
457
|
+
```javascript
|
|
458
|
+
import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
|
459
|
+
|
|
460
|
+
// Merge geometries (must have same attributes)
|
|
461
|
+
const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2, geo3]);
|
|
462
|
+
|
|
463
|
+
// Merge with groups (for multi-material)
|
|
464
|
+
const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2], true);
|
|
465
|
+
|
|
466
|
+
// Compute tangents (required for normal maps)
|
|
467
|
+
BufferGeometryUtils.computeTangents(geometry);
|
|
468
|
+
|
|
469
|
+
// Interleave attributes for better performance
|
|
470
|
+
const interleaved = BufferGeometryUtils.interleaveAttributes([
|
|
471
|
+
geometry.attributes.position,
|
|
472
|
+
geometry.attributes.normal,
|
|
473
|
+
geometry.attributes.uv,
|
|
474
|
+
]);
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
## Common Patterns
|
|
478
|
+
|
|
479
|
+
### Center Geometry
|
|
480
|
+
|
|
481
|
+
```javascript
|
|
482
|
+
geometry.computeBoundingBox();
|
|
483
|
+
geometry.center(); // Move vertices so center is at origin
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Scale to Fit
|
|
487
|
+
|
|
488
|
+
```javascript
|
|
489
|
+
geometry.computeBoundingBox();
|
|
490
|
+
const size = new THREE.Vector3();
|
|
491
|
+
geometry.boundingBox.getSize(size);
|
|
492
|
+
const maxDim = Math.max(size.x, size.y, size.z);
|
|
493
|
+
geometry.scale(1 / maxDim, 1 / maxDim, 1 / maxDim);
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Clone and Transform
|
|
497
|
+
|
|
498
|
+
```javascript
|
|
499
|
+
const clone = geometry.clone();
|
|
500
|
+
clone.rotateX(Math.PI / 2);
|
|
501
|
+
clone.translate(0, 1, 0);
|
|
502
|
+
clone.scale(2, 2, 2);
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Morph Targets
|
|
506
|
+
|
|
507
|
+
```javascript
|
|
508
|
+
// Base geometry
|
|
509
|
+
const geometry = new THREE.BoxGeometry(1, 1, 1, 4, 4, 4);
|
|
510
|
+
|
|
511
|
+
// Create morph target
|
|
512
|
+
const morphPositions = geometry.attributes.position.array.slice();
|
|
513
|
+
for (let i = 0; i < morphPositions.length; i += 3) {
|
|
514
|
+
morphPositions[i] *= 2; // Scale X
|
|
515
|
+
morphPositions[i + 1] *= 0.5; // Squash Y
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
geometry.morphAttributes.position = [
|
|
519
|
+
new THREE.BufferAttribute(new Float32Array(morphPositions), 3),
|
|
520
|
+
];
|
|
521
|
+
|
|
522
|
+
const mesh = new THREE.Mesh(geometry, material);
|
|
523
|
+
mesh.morphTargetInfluences[0] = 0.5; // 50% blend
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## Performance Tips
|
|
527
|
+
|
|
528
|
+
1. **Use indexed geometry**: Reuse vertices with indices
|
|
529
|
+
2. **Merge static meshes**: Reduce draw calls with `mergeGeometries`
|
|
530
|
+
3. **Use InstancedMesh**: For many identical objects
|
|
531
|
+
4. **Choose appropriate segment counts**: More segments = smoother but slower
|
|
532
|
+
5. **Dispose unused geometry**: `geometry.dispose()`
|
|
533
|
+
|
|
534
|
+
```javascript
|
|
535
|
+
// Good segment counts for common uses
|
|
536
|
+
new THREE.SphereGeometry(1, 32, 32); // Good quality
|
|
537
|
+
new THREE.SphereGeometry(1, 64, 64); // High quality
|
|
538
|
+
new THREE.SphereGeometry(1, 16, 16); // Performance mode
|
|
539
|
+
|
|
540
|
+
// Dispose when done
|
|
541
|
+
geometry.dispose();
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## See Also
|
|
545
|
+
|
|
546
|
+
- `threejs-fundamentals` - Scene setup and Object3D
|
|
547
|
+
- `threejs-materials` - Material types for meshes
|
|
548
|
+
- `threejs-shaders` - Custom vertex manipulation
|