Reorganize: Move all skills to skills/ folder
- Created skills/ directory - Moved 272 skills to skills/ subfolder - Kept agents/ at root level - Kept installation scripts and docs at root level Repository structure: - skills/ - All 272 skills from skills.sh - agents/ - Agent definitions - *.sh, *.ps1 - Installation scripts - README.md, etc. - Documentation Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
548
skills/threejs-geometry/skill.md
Normal file
548
skills/threejs-geometry/skill.md
Normal file
@@ -0,0 +1,548 @@
|
||||
---
|
||||
name: threejs-geometry
|
||||
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.
|
||||
---
|
||||
|
||||
# Three.js Geometry
|
||||
|
||||
## Quick Start
|
||||
|
||||
```javascript
|
||||
import * as THREE from "three";
|
||||
|
||||
// Built-in geometry
|
||||
const box = new THREE.BoxGeometry(1, 1, 1);
|
||||
const sphere = new THREE.SphereGeometry(0.5, 32, 32);
|
||||
const plane = new THREE.PlaneGeometry(10, 10);
|
||||
|
||||
// Create mesh
|
||||
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
||||
const mesh = new THREE.Mesh(box, material);
|
||||
scene.add(mesh);
|
||||
```
|
||||
|
||||
## Built-in Geometries
|
||||
|
||||
### Basic Shapes
|
||||
|
||||
```javascript
|
||||
// Box - width, height, depth, widthSegments, heightSegments, depthSegments
|
||||
new THREE.BoxGeometry(1, 1, 1, 1, 1, 1);
|
||||
|
||||
// Sphere - radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength
|
||||
new THREE.SphereGeometry(1, 32, 32);
|
||||
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI * 2, 0, Math.PI); // Full sphere
|
||||
new THREE.SphereGeometry(1, 32, 32, 0, Math.PI); // Hemisphere
|
||||
|
||||
// Plane - width, height, widthSegments, heightSegments
|
||||
new THREE.PlaneGeometry(10, 10, 1, 1);
|
||||
|
||||
// Circle - radius, segments, thetaStart, thetaLength
|
||||
new THREE.CircleGeometry(1, 32);
|
||||
new THREE.CircleGeometry(1, 32, 0, Math.PI); // Semicircle
|
||||
|
||||
// Cylinder - radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded
|
||||
new THREE.CylinderGeometry(1, 1, 2, 32, 1, false);
|
||||
new THREE.CylinderGeometry(0, 1, 2, 32); // Cone
|
||||
new THREE.CylinderGeometry(1, 1, 2, 6); // Hexagonal prism
|
||||
|
||||
// Cone - radius, height, radialSegments, heightSegments, openEnded
|
||||
new THREE.ConeGeometry(1, 2, 32, 1, false);
|
||||
|
||||
// Torus - radius, tube, radialSegments, tubularSegments, arc
|
||||
new THREE.TorusGeometry(1, 0.4, 16, 100);
|
||||
|
||||
// TorusKnot - radius, tube, tubularSegments, radialSegments, p, q
|
||||
new THREE.TorusKnotGeometry(1, 0.4, 100, 16, 2, 3);
|
||||
|
||||
// Ring - innerRadius, outerRadius, thetaSegments, phiSegments
|
||||
new THREE.RingGeometry(0.5, 1, 32, 1);
|
||||
```
|
||||
|
||||
### Advanced Shapes
|
||||
|
||||
```javascript
|
||||
// Capsule - radius, length, capSegments, radialSegments
|
||||
new THREE.CapsuleGeometry(0.5, 1, 4, 8);
|
||||
|
||||
// Dodecahedron - radius, detail
|
||||
new THREE.DodecahedronGeometry(1, 0);
|
||||
|
||||
// Icosahedron - radius, detail (0 = 20 faces, higher = smoother)
|
||||
new THREE.IcosahedronGeometry(1, 0);
|
||||
|
||||
// Octahedron - radius, detail
|
||||
new THREE.OctahedronGeometry(1, 0);
|
||||
|
||||
// Tetrahedron - radius, detail
|
||||
new THREE.TetrahedronGeometry(1, 0);
|
||||
|
||||
// Polyhedron - vertices, indices, radius, detail
|
||||
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);
|
||||
```
|
||||
|
||||
### Path-Based Shapes
|
||||
|
||||
```javascript
|
||||
// Lathe - points[], segments, phiStart, phiLength
|
||||
const points = [
|
||||
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(points, 32);
|
||||
|
||||
// Extrude - shape, options
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(0, 0);
|
||||
shape.lineTo(1, 0);
|
||||
shape.lineTo(1, 1);
|
||||
shape.lineTo(0, 1);
|
||||
shape.lineTo(0, 0);
|
||||
|
||||
const extrudeSettings = {
|
||||
steps: 2,
|
||||
depth: 1,
|
||||
bevelEnabled: true,
|
||||
bevelThickness: 0.1,
|
||||
bevelSize: 0.1,
|
||||
bevelSegments: 3,
|
||||
};
|
||||
new THREE.ExtrudeGeometry(shape, extrudeSettings);
|
||||
|
||||
// Tube - path, tubularSegments, radius, radialSegments, closed
|
||||
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);
|
||||
```
|
||||
|
||||
### Text Geometry
|
||||
|
||||
```javascript
|
||||
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
|
||||
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
|
||||
|
||||
const loader = new FontLoader();
|
||||
loader.load("fonts/helvetiker_regular.typeface.json", (font) => {
|
||||
const geometry = new TextGeometry("Hello", {
|
||||
font: font,
|
||||
size: 1,
|
||||
depth: 0.2, // Was 'height' in older versions
|
||||
curveSegments: 12,
|
||||
bevelEnabled: true,
|
||||
bevelThickness: 0.03,
|
||||
bevelSize: 0.02,
|
||||
bevelSegments: 5,
|
||||
});
|
||||
|
||||
// Center text
|
||||
geometry.computeBoundingBox();
|
||||
geometry.center();
|
||||
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
scene.add(mesh);
|
||||
});
|
||||
```
|
||||
|
||||
## BufferGeometry
|
||||
|
||||
The base class for all geometries. Stores data as typed arrays for GPU efficiency.
|
||||
|
||||
### Custom BufferGeometry
|
||||
|
||||
```javascript
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
|
||||
// Vertices (3 floats per vertex: x, y, z)
|
||||
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 indexed geometry - reuse vertices)
|
||||
const indices = new Uint16Array([
|
||||
0,
|
||||
1,
|
||||
2, // triangle 1
|
||||
0,
|
||||
2,
|
||||
3, // triangle 2
|
||||
]);
|
||||
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
|
||||
|
||||
// Normals (required for lighting)
|
||||
const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
|
||||
geometry.setAttribute("normal", new THREE.BufferAttribute(normals, 3));
|
||||
|
||||
// UVs (for texturing)
|
||||
const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
|
||||
geometry.setAttribute("uv", new THREE.BufferAttribute(uvs, 2));
|
||||
|
||||
// Colors (per-vertex colors)
|
||||
const colors = new Float32Array([
|
||||
1,
|
||||
0,
|
||||
0, // red
|
||||
0,
|
||||
1,
|
||||
0, // green
|
||||
0,
|
||||
0,
|
||||
1, // blue
|
||||
1,
|
||||
1,
|
||||
0, // yellow
|
||||
]);
|
||||
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
|
||||
// Use with: material.vertexColors = true
|
||||
```
|
||||
|
||||
### BufferAttribute Types
|
||||
|
||||
```javascript
|
||||
// Common attribute types
|
||||
new THREE.BufferAttribute(array, itemSize);
|
||||
|
||||
// Typed array options
|
||||
new Float32Array(count * itemSize); // Positions, normals, UVs
|
||||
new Uint16Array(count); // Indices (up to 65535 vertices)
|
||||
new Uint32Array(count); // Indices (larger meshes)
|
||||
new Uint8Array(count * itemSize); // Colors (0-255 range)
|
||||
|
||||
// Item sizes
|
||||
// Position: 3 (x, y, z)
|
||||
// Normal: 3 (x, y, z)
|
||||
// UV: 2 (u, v)
|
||||
// Color: 3 (r, g, b) or 4 (r, g, b, a)
|
||||
// Index: 1
|
||||
```
|
||||
|
||||
### Modifying BufferGeometry
|
||||
|
||||
```javascript
|
||||
const positions = geometry.attributes.position;
|
||||
|
||||
// Modify vertex
|
||||
positions.setXYZ(index, x, y, z);
|
||||
|
||||
// Access vertex
|
||||
const x = positions.getX(index);
|
||||
const y = positions.getY(index);
|
||||
const z = positions.getZ(index);
|
||||
|
||||
// Flag for GPU update
|
||||
positions.needsUpdate = true;
|
||||
|
||||
// Recompute normals after position changes
|
||||
geometry.computeVertexNormals();
|
||||
|
||||
// Recompute bounding box/sphere after changes
|
||||
geometry.computeBoundingBox();
|
||||
geometry.computeBoundingSphere();
|
||||
```
|
||||
|
||||
### Interleaved Buffers (Advanced)
|
||||
|
||||
```javascript
|
||||
// More efficient memory layout for large meshes
|
||||
const interleavedBuffer = new THREE.InterleavedBuffer(
|
||||
new Float32Array([
|
||||
// pos.x, pos.y, pos.z, uv.u, uv.v (repeated per vertex)
|
||||
-1, -1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, 0, 1, 1, -1, 1, 0, 0, 1,
|
||||
]),
|
||||
5, // stride (floats per vertex)
|
||||
);
|
||||
|
||||
geometry.setAttribute(
|
||||
"position",
|
||||
new THREE.InterleavedBufferAttribute(interleavedBuffer, 3, 0),
|
||||
); // size 3, offset 0
|
||||
geometry.setAttribute(
|
||||
"uv",
|
||||
new THREE.InterleavedBufferAttribute(interleavedBuffer, 2, 3),
|
||||
); // size 2, offset 3
|
||||
```
|
||||
|
||||
## EdgesGeometry & WireframeGeometry
|
||||
|
||||
```javascript
|
||||
// Edge lines (only hard edges)
|
||||
const edges = new THREE.EdgesGeometry(boxGeometry, 15); // 15 = threshold angle
|
||||
const edgeMesh = new THREE.LineSegments(
|
||||
edges,
|
||||
new THREE.LineBasicMaterial({ color: 0xffffff }),
|
||||
);
|
||||
|
||||
// Wireframe (all triangles)
|
||||
const wireframe = new THREE.WireframeGeometry(boxGeometry);
|
||||
const wireMesh = new THREE.LineSegments(
|
||||
wireframe,
|
||||
new THREE.LineBasicMaterial({ color: 0xffffff }),
|
||||
);
|
||||
```
|
||||
|
||||
## Points
|
||||
|
||||
```javascript
|
||||
// Create point cloud
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
const positions = new Float32Array(1000 * 3);
|
||||
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
positions[i * 3] = (Math.random() - 0.5) * 10;
|
||||
positions[i * 3 + 1] = (Math.random() - 0.5) * 10;
|
||||
positions[i * 3 + 2] = (Math.random() - 0.5) * 10;
|
||||
}
|
||||
|
||||
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
|
||||
|
||||
const material = new THREE.PointsMaterial({
|
||||
size: 0.1,
|
||||
sizeAttenuation: true, // Size decreases with distance
|
||||
color: 0xffffff,
|
||||
});
|
||||
|
||||
const points = new THREE.Points(geometry, material);
|
||||
scene.add(points);
|
||||
```
|
||||
|
||||
## Lines
|
||||
|
||||
```javascript
|
||||
// Line (connected points)
|
||||
const points = [
|
||||
new THREE.Vector3(-1, 0, 0),
|
||||
new THREE.Vector3(0, 1, 0),
|
||||
new THREE.Vector3(1, 0, 0),
|
||||
];
|
||||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||||
const line = new THREE.Line(
|
||||
geometry,
|
||||
new THREE.LineBasicMaterial({ color: 0xff0000 }),
|
||||
);
|
||||
|
||||
// LineLoop (closed loop)
|
||||
const loop = new THREE.LineLoop(geometry, material);
|
||||
|
||||
// LineSegments (pairs of points)
|
||||
const segmentsGeometry = new THREE.BufferGeometry();
|
||||
segmentsGeometry.setAttribute(
|
||||
"position",
|
||||
new THREE.BufferAttribute(
|
||||
new Float32Array([
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0, // segment 1
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0, // segment 2
|
||||
]),
|
||||
3,
|
||||
),
|
||||
);
|
||||
const segments = new THREE.LineSegments(segmentsGeometry, material);
|
||||
```
|
||||
|
||||
## InstancedMesh
|
||||
|
||||
Efficiently render many copies of the same geometry.
|
||||
|
||||
```javascript
|
||||
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
|
||||
const count = 1000;
|
||||
|
||||
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
|
||||
|
||||
// Set transforms for each instance
|
||||
const dummy = new THREE.Object3D();
|
||||
const matrix = new THREE.Matrix4();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Flag for GPU update
|
||||
instancedMesh.instanceMatrix.needsUpdate = true;
|
||||
|
||||
// Optional: per-instance colors
|
||||
instancedMesh.instanceColor = new THREE.InstancedBufferAttribute(
|
||||
new Float32Array(count * 3),
|
||||
3,
|
||||
);
|
||||
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);
|
||||
```
|
||||
|
||||
### Update Instance at Runtime
|
||||
|
||||
```javascript
|
||||
// Update single instance
|
||||
const matrix = new THREE.Matrix4();
|
||||
instancedMesh.getMatrixAt(index, matrix);
|
||||
// Modify matrix...
|
||||
instancedMesh.setMatrixAt(index, matrix);
|
||||
instancedMesh.instanceMatrix.needsUpdate = true;
|
||||
|
||||
// Raycasting with instanced mesh
|
||||
const intersects = raycaster.intersectObject(instancedMesh);
|
||||
if (intersects.length > 0) {
|
||||
const instanceId = intersects[0].instanceId;
|
||||
}
|
||||
```
|
||||
|
||||
## InstancedBufferGeometry (Advanced)
|
||||
|
||||
For custom per-instance attributes beyond transform/color.
|
||||
|
||||
```javascript
|
||||
const geometry = new THREE.InstancedBufferGeometry();
|
||||
geometry.copy(new THREE.BoxGeometry(1, 1, 1));
|
||||
|
||||
// Add per-instance attribute
|
||||
const offsets = new Float32Array(count * 3);
|
||||
for (let i = 0; i < count; i++) {
|
||||
offsets[i * 3] = Math.random() * 10;
|
||||
offsets[i * 3 + 1] = Math.random() * 10;
|
||||
offsets[i * 3 + 2] = Math.random() * 10;
|
||||
}
|
||||
geometry.setAttribute("offset", new THREE.InstancedBufferAttribute(offsets, 3));
|
||||
|
||||
// Use in shader
|
||||
// attribute vec3 offset;
|
||||
// vec3 transformed = position + offset;
|
||||
```
|
||||
|
||||
## Geometry Utilities
|
||||
|
||||
```javascript
|
||||
import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
||||
|
||||
// Merge geometries (must have same attributes)
|
||||
const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2, geo3]);
|
||||
|
||||
// Merge with groups (for multi-material)
|
||||
const merged = BufferGeometryUtils.mergeGeometries([geo1, geo2], true);
|
||||
|
||||
// Compute tangents (required for normal maps)
|
||||
BufferGeometryUtils.computeTangents(geometry);
|
||||
|
||||
// Interleave attributes for better performance
|
||||
const interleaved = BufferGeometryUtils.interleaveAttributes([
|
||||
geometry.attributes.position,
|
||||
geometry.attributes.normal,
|
||||
geometry.attributes.uv,
|
||||
]);
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Center Geometry
|
||||
|
||||
```javascript
|
||||
geometry.computeBoundingBox();
|
||||
geometry.center(); // Move vertices so center is at origin
|
||||
```
|
||||
|
||||
### Scale to Fit
|
||||
|
||||
```javascript
|
||||
geometry.computeBoundingBox();
|
||||
const size = new THREE.Vector3();
|
||||
geometry.boundingBox.getSize(size);
|
||||
const maxDim = Math.max(size.x, size.y, size.z);
|
||||
geometry.scale(1 / maxDim, 1 / maxDim, 1 / maxDim);
|
||||
```
|
||||
|
||||
### Clone and Transform
|
||||
|
||||
```javascript
|
||||
const clone = geometry.clone();
|
||||
clone.rotateX(Math.PI / 2);
|
||||
clone.translate(0, 1, 0);
|
||||
clone.scale(2, 2, 2);
|
||||
```
|
||||
|
||||
### Morph Targets
|
||||
|
||||
```javascript
|
||||
// Base geometry
|
||||
const geometry = new THREE.BoxGeometry(1, 1, 1, 4, 4, 4);
|
||||
|
||||
// Create morph target
|
||||
const morphPositions = geometry.attributes.position.array.slice();
|
||||
for (let i = 0; i < morphPositions.length; i += 3) {
|
||||
morphPositions[i] *= 2; // Scale X
|
||||
morphPositions[i + 1] *= 0.5; // Squash Y
|
||||
}
|
||||
|
||||
geometry.morphAttributes.position = [
|
||||
new THREE.BufferAttribute(new Float32Array(morphPositions), 3),
|
||||
];
|
||||
|
||||
const mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.morphTargetInfluences[0] = 0.5; // 50% blend
|
||||
```
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Use indexed geometry**: Reuse vertices with indices
|
||||
2. **Merge static meshes**: Reduce draw calls with `mergeGeometries`
|
||||
3. **Use InstancedMesh**: For many identical objects
|
||||
4. **Choose appropriate segment counts**: More segments = smoother but slower
|
||||
5. **Dispose unused geometry**: `geometry.dispose()`
|
||||
|
||||
```javascript
|
||||
// Good segment counts for common uses
|
||||
new THREE.SphereGeometry(1, 32, 32); // Good quality
|
||||
new THREE.SphereGeometry(1, 64, 64); // High quality
|
||||
new THREE.SphereGeometry(1, 16, 16); // Performance mode
|
||||
|
||||
// Dispose when done
|
||||
geometry.dispose();
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- `threejs-fundamentals` - Scene setup and Object3D
|
||||
- `threejs-materials` - Material types for meshes
|
||||
- `threejs-shaders` - Custom vertex manipulation
|
||||
Reference in New Issue
Block a user