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,488 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: threejs-fundamentals
|
|
3
|
+
description: Three.js scene setup, cameras, renderer, Object3D hierarchy, coordinate systems. Use when setting up 3D scenes, creating cameras, configuring renderers, managing object hierarchies, or working with transforms.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Three.js Fundamentals
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```javascript
|
|
11
|
+
import * as THREE from "three";
|
|
12
|
+
|
|
13
|
+
// Create scene, camera, renderer
|
|
14
|
+
const scene = new THREE.Scene();
|
|
15
|
+
const camera = new THREE.PerspectiveCamera(
|
|
16
|
+
75,
|
|
17
|
+
window.innerWidth / window.innerHeight,
|
|
18
|
+
0.1,
|
|
19
|
+
1000,
|
|
20
|
+
);
|
|
21
|
+
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
|
22
|
+
|
|
23
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
24
|
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
25
|
+
document.body.appendChild(renderer.domElement);
|
|
26
|
+
|
|
27
|
+
// Add a mesh
|
|
28
|
+
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
|
29
|
+
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
|
30
|
+
const cube = new THREE.Mesh(geometry, material);
|
|
31
|
+
scene.add(cube);
|
|
32
|
+
|
|
33
|
+
// Add light
|
|
34
|
+
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
|
|
35
|
+
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
|
|
36
|
+
dirLight.position.set(5, 5, 5);
|
|
37
|
+
scene.add(dirLight);
|
|
38
|
+
|
|
39
|
+
camera.position.z = 5;
|
|
40
|
+
|
|
41
|
+
// Animation loop
|
|
42
|
+
function animate() {
|
|
43
|
+
requestAnimationFrame(animate);
|
|
44
|
+
cube.rotation.x += 0.01;
|
|
45
|
+
cube.rotation.y += 0.01;
|
|
46
|
+
renderer.render(scene, camera);
|
|
47
|
+
}
|
|
48
|
+
animate();
|
|
49
|
+
|
|
50
|
+
// Handle resize
|
|
51
|
+
window.addEventListener("resize", () => {
|
|
52
|
+
camera.aspect = window.innerWidth / window.innerHeight;
|
|
53
|
+
camera.updateProjectionMatrix();
|
|
54
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Core Classes
|
|
59
|
+
|
|
60
|
+
### Scene
|
|
61
|
+
|
|
62
|
+
Container for all 3D objects, lights, and cameras.
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const scene = new THREE.Scene();
|
|
66
|
+
scene.background = new THREE.Color(0x000000); // Solid color
|
|
67
|
+
scene.background = texture; // Skybox texture
|
|
68
|
+
scene.background = cubeTexture; // Cubemap
|
|
69
|
+
scene.environment = envMap; // Environment map for PBR
|
|
70
|
+
scene.fog = new THREE.Fog(0xffffff, 1, 100); // Linear fog
|
|
71
|
+
scene.fog = new THREE.FogExp2(0xffffff, 0.02); // Exponential fog
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Cameras
|
|
75
|
+
|
|
76
|
+
**PerspectiveCamera** - Most common, simulates human eye.
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
// PerspectiveCamera(fov, aspect, near, far)
|
|
80
|
+
const camera = new THREE.PerspectiveCamera(
|
|
81
|
+
75, // Field of view (degrees)
|
|
82
|
+
window.innerWidth / window.innerHeight, // Aspect ratio
|
|
83
|
+
0.1, // Near clipping plane
|
|
84
|
+
1000, // Far clipping plane
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
camera.position.set(0, 5, 10);
|
|
88
|
+
camera.lookAt(0, 0, 0);
|
|
89
|
+
camera.updateProjectionMatrix(); // Call after changing fov, aspect, near, far
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**OrthographicCamera** - No perspective distortion, good for 2D/isometric.
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// OrthographicCamera(left, right, top, bottom, near, far)
|
|
96
|
+
const aspect = window.innerWidth / window.innerHeight;
|
|
97
|
+
const frustumSize = 10;
|
|
98
|
+
const camera = new THREE.OrthographicCamera(
|
|
99
|
+
(frustumSize * aspect) / -2,
|
|
100
|
+
(frustumSize * aspect) / 2,
|
|
101
|
+
frustumSize / 2,
|
|
102
|
+
frustumSize / -2,
|
|
103
|
+
0.1,
|
|
104
|
+
1000,
|
|
105
|
+
);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**ArrayCamera** - Multiple viewports with sub-cameras.
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const cameras = [];
|
|
112
|
+
for (let i = 0; i < 4; i++) {
|
|
113
|
+
const subcamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);
|
|
114
|
+
subcamera.viewport = new THREE.Vector4(
|
|
115
|
+
Math.floor(i % 2) * 0.5,
|
|
116
|
+
Math.floor(i / 2) * 0.5,
|
|
117
|
+
0.5,
|
|
118
|
+
0.5,
|
|
119
|
+
);
|
|
120
|
+
cameras.push(subcamera);
|
|
121
|
+
}
|
|
122
|
+
const arrayCamera = new THREE.ArrayCamera(cameras);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**CubeCamera** - Renders environment maps for reflections.
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256);
|
|
129
|
+
const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget);
|
|
130
|
+
scene.add(cubeCamera);
|
|
131
|
+
|
|
132
|
+
// Use for reflections
|
|
133
|
+
material.envMap = cubeRenderTarget.texture;
|
|
134
|
+
|
|
135
|
+
// Update each frame (expensive!)
|
|
136
|
+
cubeCamera.position.copy(reflectiveMesh.position);
|
|
137
|
+
cubeCamera.update(renderer, scene);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### WebGLRenderer
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
const renderer = new THREE.WebGLRenderer({
|
|
144
|
+
canvas: document.querySelector("#canvas"), // Optional existing canvas
|
|
145
|
+
antialias: true, // Smooth edges
|
|
146
|
+
alpha: true, // Transparent background
|
|
147
|
+
powerPreference: "high-performance", // GPU hint
|
|
148
|
+
preserveDrawingBuffer: true, // For screenshots
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
renderer.setSize(width, height);
|
|
152
|
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
153
|
+
|
|
154
|
+
// Tone mapping
|
|
155
|
+
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
156
|
+
renderer.toneMappingExposure = 1.0;
|
|
157
|
+
|
|
158
|
+
// Color space (Three.js r152+)
|
|
159
|
+
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
|
160
|
+
|
|
161
|
+
// Shadows
|
|
162
|
+
renderer.shadowMap.enabled = true;
|
|
163
|
+
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
164
|
+
|
|
165
|
+
// Clear color
|
|
166
|
+
renderer.setClearColor(0x000000, 1);
|
|
167
|
+
|
|
168
|
+
// Render
|
|
169
|
+
renderer.render(scene, camera);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Object3D
|
|
173
|
+
|
|
174
|
+
Base class for all 3D objects. Mesh, Group, Light, Camera all extend Object3D.
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
const obj = new THREE.Object3D();
|
|
178
|
+
|
|
179
|
+
// Transform
|
|
180
|
+
obj.position.set(x, y, z);
|
|
181
|
+
obj.rotation.set(x, y, z); // Euler angles (radians)
|
|
182
|
+
obj.quaternion.set(x, y, z, w); // Quaternion rotation
|
|
183
|
+
obj.scale.set(x, y, z);
|
|
184
|
+
|
|
185
|
+
// Local vs World transforms
|
|
186
|
+
obj.getWorldPosition(targetVector);
|
|
187
|
+
obj.getWorldQuaternion(targetQuaternion);
|
|
188
|
+
obj.getWorldDirection(targetVector);
|
|
189
|
+
|
|
190
|
+
// Hierarchy
|
|
191
|
+
obj.add(child);
|
|
192
|
+
obj.remove(child);
|
|
193
|
+
obj.parent;
|
|
194
|
+
obj.children;
|
|
195
|
+
|
|
196
|
+
// Visibility
|
|
197
|
+
obj.visible = false;
|
|
198
|
+
|
|
199
|
+
// Layers (for selective rendering/raycasting)
|
|
200
|
+
obj.layers.set(1);
|
|
201
|
+
obj.layers.enable(2);
|
|
202
|
+
obj.layers.disable(0);
|
|
203
|
+
|
|
204
|
+
// Traverse hierarchy
|
|
205
|
+
obj.traverse((child) => {
|
|
206
|
+
if (child.isMesh) child.material.color.set(0xff0000);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Matrix updates
|
|
210
|
+
obj.matrixAutoUpdate = true; // Default: auto-update matrices
|
|
211
|
+
obj.updateMatrix(); // Manual matrix update
|
|
212
|
+
obj.updateMatrixWorld(true); // Update world matrix recursively
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Group
|
|
216
|
+
|
|
217
|
+
Empty container for organizing objects.
|
|
218
|
+
|
|
219
|
+
```javascript
|
|
220
|
+
const group = new THREE.Group();
|
|
221
|
+
group.add(mesh1);
|
|
222
|
+
group.add(mesh2);
|
|
223
|
+
scene.add(group);
|
|
224
|
+
|
|
225
|
+
// Transform entire group
|
|
226
|
+
group.position.x = 5;
|
|
227
|
+
group.rotation.y = Math.PI / 4;
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Mesh
|
|
231
|
+
|
|
232
|
+
Combines geometry and material.
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
const mesh = new THREE.Mesh(geometry, material);
|
|
236
|
+
|
|
237
|
+
// Multiple materials (one per geometry group)
|
|
238
|
+
const mesh = new THREE.Mesh(geometry, [material1, material2]);
|
|
239
|
+
|
|
240
|
+
// Useful properties
|
|
241
|
+
mesh.geometry;
|
|
242
|
+
mesh.material;
|
|
243
|
+
mesh.castShadow = true;
|
|
244
|
+
mesh.receiveShadow = true;
|
|
245
|
+
|
|
246
|
+
// Frustum culling
|
|
247
|
+
mesh.frustumCulled = true; // Default: skip if outside camera view
|
|
248
|
+
|
|
249
|
+
// Render order
|
|
250
|
+
mesh.renderOrder = 10; // Higher = rendered later
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Coordinate System
|
|
254
|
+
|
|
255
|
+
Three.js uses a **right-handed coordinate system**:
|
|
256
|
+
|
|
257
|
+
- **+X** points right
|
|
258
|
+
- **+Y** points up
|
|
259
|
+
- **+Z** points toward viewer (out of screen)
|
|
260
|
+
|
|
261
|
+
```javascript
|
|
262
|
+
// Axes helper
|
|
263
|
+
const axesHelper = new THREE.AxesHelper(5);
|
|
264
|
+
scene.add(axesHelper); // Red=X, Green=Y, Blue=Z
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Math Utilities
|
|
268
|
+
|
|
269
|
+
### Vector3
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
const v = new THREE.Vector3(x, y, z);
|
|
273
|
+
v.set(x, y, z);
|
|
274
|
+
v.copy(otherVector);
|
|
275
|
+
v.clone();
|
|
276
|
+
|
|
277
|
+
// Operations (modify in place)
|
|
278
|
+
v.add(v2);
|
|
279
|
+
v.sub(v2);
|
|
280
|
+
v.multiply(v2);
|
|
281
|
+
v.multiplyScalar(2);
|
|
282
|
+
v.divideScalar(2);
|
|
283
|
+
v.normalize();
|
|
284
|
+
v.negate();
|
|
285
|
+
v.clamp(min, max);
|
|
286
|
+
v.lerp(target, alpha);
|
|
287
|
+
|
|
288
|
+
// Calculations (return new value)
|
|
289
|
+
v.length();
|
|
290
|
+
v.lengthSq(); // Faster than length()
|
|
291
|
+
v.distanceTo(v2);
|
|
292
|
+
v.dot(v2);
|
|
293
|
+
v.cross(v2); // Modifies v
|
|
294
|
+
v.angleTo(v2);
|
|
295
|
+
|
|
296
|
+
// Transform
|
|
297
|
+
v.applyMatrix4(matrix);
|
|
298
|
+
v.applyQuaternion(q);
|
|
299
|
+
v.project(camera); // World to NDC
|
|
300
|
+
v.unproject(camera); // NDC to world
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Matrix4
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
const m = new THREE.Matrix4();
|
|
307
|
+
m.identity();
|
|
308
|
+
m.copy(other);
|
|
309
|
+
m.clone();
|
|
310
|
+
|
|
311
|
+
// Build transforms
|
|
312
|
+
m.makeTranslation(x, y, z);
|
|
313
|
+
m.makeRotationX(theta);
|
|
314
|
+
m.makeRotationY(theta);
|
|
315
|
+
m.makeRotationZ(theta);
|
|
316
|
+
m.makeRotationFromQuaternion(q);
|
|
317
|
+
m.makeScale(x, y, z);
|
|
318
|
+
|
|
319
|
+
// Compose/decompose
|
|
320
|
+
m.compose(position, quaternion, scale);
|
|
321
|
+
m.decompose(position, quaternion, scale);
|
|
322
|
+
|
|
323
|
+
// Operations
|
|
324
|
+
m.multiply(m2); // m = m * m2
|
|
325
|
+
m.premultiply(m2); // m = m2 * m
|
|
326
|
+
m.invert();
|
|
327
|
+
m.transpose();
|
|
328
|
+
|
|
329
|
+
// Camera matrices
|
|
330
|
+
m.makePerspective(left, right, top, bottom, near, far);
|
|
331
|
+
m.makeOrthographic(left, right, top, bottom, near, far);
|
|
332
|
+
m.lookAt(eye, target, up);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Quaternion
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
const q = new THREE.Quaternion();
|
|
339
|
+
q.setFromEuler(euler);
|
|
340
|
+
q.setFromAxisAngle(axis, angle);
|
|
341
|
+
q.setFromRotationMatrix(matrix);
|
|
342
|
+
|
|
343
|
+
q.multiply(q2);
|
|
344
|
+
q.slerp(target, t); // Spherical interpolation
|
|
345
|
+
q.normalize();
|
|
346
|
+
q.invert();
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Euler
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
const euler = new THREE.Euler(x, y, z, "XYZ"); // Order matters!
|
|
353
|
+
euler.setFromQuaternion(q);
|
|
354
|
+
euler.setFromRotationMatrix(m);
|
|
355
|
+
|
|
356
|
+
// Rotation orders: 'XYZ', 'YXZ', 'ZXY', 'XZY', 'YZX', 'ZYX'
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Color
|
|
360
|
+
|
|
361
|
+
```javascript
|
|
362
|
+
const color = new THREE.Color(0xff0000);
|
|
363
|
+
const color = new THREE.Color("red");
|
|
364
|
+
const color = new THREE.Color("rgb(255, 0, 0)");
|
|
365
|
+
const color = new THREE.Color("#ff0000");
|
|
366
|
+
|
|
367
|
+
color.setHex(0x00ff00);
|
|
368
|
+
color.setRGB(r, g, b); // 0-1 range
|
|
369
|
+
color.setHSL(h, s, l); // 0-1 range
|
|
370
|
+
|
|
371
|
+
color.lerp(otherColor, alpha);
|
|
372
|
+
color.multiply(otherColor);
|
|
373
|
+
color.multiplyScalar(2);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### MathUtils
|
|
377
|
+
|
|
378
|
+
```javascript
|
|
379
|
+
THREE.MathUtils.clamp(value, min, max);
|
|
380
|
+
THREE.MathUtils.lerp(start, end, alpha);
|
|
381
|
+
THREE.MathUtils.mapLinear(value, inMin, inMax, outMin, outMax);
|
|
382
|
+
THREE.MathUtils.degToRad(degrees);
|
|
383
|
+
THREE.MathUtils.radToDeg(radians);
|
|
384
|
+
THREE.MathUtils.randFloat(min, max);
|
|
385
|
+
THREE.MathUtils.randInt(min, max);
|
|
386
|
+
THREE.MathUtils.smoothstep(x, min, max);
|
|
387
|
+
THREE.MathUtils.smootherstep(x, min, max);
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Common Patterns
|
|
391
|
+
|
|
392
|
+
### Proper Cleanup
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
function dispose() {
|
|
396
|
+
// Dispose geometries
|
|
397
|
+
mesh.geometry.dispose();
|
|
398
|
+
|
|
399
|
+
// Dispose materials
|
|
400
|
+
if (Array.isArray(mesh.material)) {
|
|
401
|
+
mesh.material.forEach((m) => m.dispose());
|
|
402
|
+
} else {
|
|
403
|
+
mesh.material.dispose();
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Dispose textures
|
|
407
|
+
texture.dispose();
|
|
408
|
+
|
|
409
|
+
// Remove from scene
|
|
410
|
+
scene.remove(mesh);
|
|
411
|
+
|
|
412
|
+
// Dispose renderer
|
|
413
|
+
renderer.dispose();
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Clock for Animation
|
|
418
|
+
|
|
419
|
+
```javascript
|
|
420
|
+
const clock = new THREE.Clock();
|
|
421
|
+
|
|
422
|
+
function animate() {
|
|
423
|
+
const delta = clock.getDelta(); // Time since last frame (seconds)
|
|
424
|
+
const elapsed = clock.getElapsedTime(); // Total time (seconds)
|
|
425
|
+
|
|
426
|
+
mesh.rotation.y += delta * 0.5; // Consistent speed regardless of framerate
|
|
427
|
+
|
|
428
|
+
requestAnimationFrame(animate);
|
|
429
|
+
renderer.render(scene, camera);
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Responsive Canvas
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
function onWindowResize() {
|
|
437
|
+
const width = window.innerWidth;
|
|
438
|
+
const height = window.innerHeight;
|
|
439
|
+
|
|
440
|
+
camera.aspect = width / height;
|
|
441
|
+
camera.updateProjectionMatrix();
|
|
442
|
+
|
|
443
|
+
renderer.setSize(width, height);
|
|
444
|
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
445
|
+
}
|
|
446
|
+
window.addEventListener("resize", onWindowResize);
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Loading Manager
|
|
450
|
+
|
|
451
|
+
```javascript
|
|
452
|
+
const manager = new THREE.LoadingManager();
|
|
453
|
+
|
|
454
|
+
manager.onStart = (url, loaded, total) => console.log("Started loading");
|
|
455
|
+
manager.onLoad = () => console.log("All loaded");
|
|
456
|
+
manager.onProgress = (url, loaded, total) => console.log(`${loaded}/${total}`);
|
|
457
|
+
manager.onError = (url) => console.error(`Error loading ${url}`);
|
|
458
|
+
|
|
459
|
+
const textureLoader = new THREE.TextureLoader(manager);
|
|
460
|
+
const gltfLoader = new GLTFLoader(manager);
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Performance Tips
|
|
464
|
+
|
|
465
|
+
1. **Limit draw calls**: Merge geometries, use instancing, atlas textures
|
|
466
|
+
2. **Frustum culling**: Enabled by default, ensure bounding boxes are correct
|
|
467
|
+
3. **LOD (Level of Detail)**: Use `THREE.LOD` for distance-based mesh switching
|
|
468
|
+
4. **Object pooling**: Reuse objects instead of creating/destroying
|
|
469
|
+
5. **Avoid `getWorldPosition` in loops**: Cache results
|
|
470
|
+
|
|
471
|
+
```javascript
|
|
472
|
+
// Merge static geometries
|
|
473
|
+
import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
|
474
|
+
const merged = mergeGeometries([geo1, geo2, geo3]);
|
|
475
|
+
|
|
476
|
+
// LOD
|
|
477
|
+
const lod = new THREE.LOD();
|
|
478
|
+
lod.addLevel(highDetailMesh, 0);
|
|
479
|
+
lod.addLevel(medDetailMesh, 50);
|
|
480
|
+
lod.addLevel(lowDetailMesh, 100);
|
|
481
|
+
scene.add(lod);
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
## See Also
|
|
485
|
+
|
|
486
|
+
- `threejs-geometry` - Geometry creation and manipulation
|
|
487
|
+
- `threejs-materials` - Material types and properties
|
|
488
|
+
- `threejs-lighting` - Light types and shadows
|