--- 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