--- name: r3f-geometry description: React Three Fiber geometry - built-in shapes, BufferGeometry, instancing with Drei. Use when creating 3D shapes, custom meshes, point clouds, lines, or optimizing with instanced rendering. --- # React Three Fiber Geometry ## Quick Start ```tsx import { Canvas } from '@react-three/fiber' function Scene() { return ( ) } ``` ## Built-in Geometries All Three.js geometries are available as JSX elements. The `args` prop passes constructor arguments. ### Basic Shapes ```tsx // BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments) // SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) // High quality // Hemisphere // PlaneGeometry(width, height, widthSegments, heightSegments) // Subdivided for displacement // CircleGeometry(radius, segments, thetaStart, thetaLength) // Semicircle // CylinderGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded) // Cone // Hexagonal prism // ConeGeometry(radius, height, radialSegments, heightSegments, openEnded) // TorusGeometry(radius, tube, radialSegments, tubularSegments, arc) // TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q) // RingGeometry(innerRadius, outerRadius, thetaSegments, phiSegments) ``` ### Advanced Shapes ```tsx // CapsuleGeometry(radius, length, capSegments, radialSegments) // Polyhedrons // radius, detail // Higher detail = more subdivisions // Approximates sphere ``` ### Path-Based Shapes ```tsx import * as THREE from 'three' // LatheGeometry - revolve points around Y axis function LatheShape() { const points = [ new THREE.Vector2(0, 0), new THREE.Vector2(0.5, 0), new THREE.Vector2(0.5, 0.5), new THREE.Vector2(0.3, 1), new THREE.Vector2(0, 1), ] return ( ) } // TubeGeometry - extrude along a curve function TubeShape() { const curve = new THREE.CatmullRomCurve3([ new THREE.Vector3(-2, 0, 0), new THREE.Vector3(-1, 1, 0), new THREE.Vector3(1, -1, 0), new THREE.Vector3(2, 0, 0), ]) return ( ) } // ExtrudeGeometry - extrude a 2D shape function ExtrudedShape() { 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: 0.5, bevelEnabled: true, bevelThickness: 0.1, bevelSize: 0.1, bevelSegments: 3, } return ( ) } ``` ## Drei Shape Helpers @react-three/drei provides convenient shape components. ```tsx import { Box, Sphere, Plane, Circle, Cylinder, Cone, Torus, TorusKnot, Ring, Capsule, Dodecahedron, Icosahedron, Octahedron, Tetrahedron, RoundedBox } from '@react-three/drei' function DreiShapes() { return ( <> {/* All shapes accept mesh props directly */} {/* RoundedBox - box with rounded edges */} ) } ``` ## Custom BufferGeometry ### Basic Custom Geometry ```tsx import { useMemo, useRef } from 'react' import * as THREE from 'three' function CustomTriangle() { const geometry = useMemo(() => { const geo = 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 0, 1, 0, // vertex 2 ]) // Normals (pointing toward camera) const normals = new Float32Array([ 0, 0, 1, 0, 0, 1, 0, 0, 1, ]) // UVs const uvs = new Float32Array([ 0, 0, 1, 0, 0.5, 1, ]) geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3)) geo.setAttribute('normal', new THREE.BufferAttribute(normals, 3)) geo.setAttribute('uv', new THREE.BufferAttribute(uvs, 2)) return geo }, []) return ( ) } ``` ### Indexed Geometry ```tsx function CustomQuad() { const geometry = useMemo(() => { const geo = new THREE.BufferGeometry() // 4 vertices for a quad const vertices = new Float32Array([ -1, -1, 0, // 0: bottom-left 1, -1, 0, // 1: bottom-right 1, 1, 0, // 2: top-right -1, 1, 0, // 3: top-left ]) // Indices to form 2 triangles const indices = new Uint16Array([ 0, 1, 2, // triangle 1 0, 2, 3, // triangle 2 ]) const normals = new Float32Array([ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ]) const uvs = new Float32Array([ 0, 0, 1, 0, 1, 1, 0, 1, ]) geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3)) geo.setAttribute('normal', new THREE.BufferAttribute(normals, 3)) geo.setAttribute('uv', new THREE.BufferAttribute(uvs, 2)) geo.setIndex(new THREE.BufferAttribute(indices, 1)) return geo }, []) return ( ) } ``` ### Dynamic Geometry ```tsx import { useRef } from 'react' import { useFrame } from '@react-three/fiber' function WavyPlane() { const meshRef = useRef() useFrame(({ clock }) => { const positions = meshRef.current.geometry.attributes.position const time = clock.elapsedTime for (let i = 0; i < positions.count; i++) { const x = positions.getX(i) const y = positions.getY(i) positions.setZ(i, Math.sin(x * 2 + time) * Math.cos(y * 2 + time) * 0.5) } positions.needsUpdate = true meshRef.current.geometry.computeVertexNormals() }) return ( ) } ``` ## Drei Instancing Efficient rendering of many identical objects. ### Instances Component ```tsx import { Instances, Instance } from '@react-three/drei' import { useFrame } from '@react-three/fiber' import { useRef } from 'react' function InstancedBoxes() { const count = 1000 return ( {Array.from({ length: count }, (_, i) => ( ))} ) } function AnimatedInstance({ index }) { const ref = useRef() // Random initial position const position = useMemo(() => [ (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, ], []) const color = useMemo(() => ['red', 'blue', 'green', 'yellow', 'purple'][index % 5], [index]) useFrame(({ clock }) => { const t = clock.elapsedTime ref.current.rotation.x = t + index ref.current.rotation.y = t * 0.5 + index }) return ( ) } ``` ### Merged Geometry For static instances, merge geometry for best performance: ```tsx import { Merged } from '@react-three/drei' import { useMemo } from 'react' import * as THREE from 'three' function MergedMeshes() { // Create geometries to merge const meshes = useMemo(() => ({ Sphere: new THREE.SphereGeometry(0.5, 32, 32), Box: new THREE.BoxGeometry(1, 1, 1), Cone: new THREE.ConeGeometry(0.5, 1, 32), }), []) return ( {({ Sphere, Box, Cone }) => ( <> )} ) } ``` ## Points (Particle Systems) ### Basic Points ```tsx import { Points, Point, PointMaterial } from '@react-three/drei' function ParticleField() { const count = 5000 return ( {Array.from({ length: count }, (_, i) => ( ))} ) } ``` ### Buffer-Based Points (High Performance) ```tsx import { useMemo, useRef } from 'react' import { useFrame } from '@react-three/fiber' import * as THREE from 'three' function BufferParticles() { const count = 10000 const pointsRef = useRef() const { positions, colors } = useMemo(() => { const positions = new Float32Array(count * 3) const colors = new Float32Array(count * 3) for (let i = 0; i < count; 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 colors[i * 3] = Math.random() colors[i * 3 + 1] = Math.random() colors[i * 3 + 2] = Math.random() } return { positions, colors } }, []) useFrame(({ clock }) => { pointsRef.current.rotation.y = clock.elapsedTime * 0.1 }) return ( ) } ``` ## Lines ### Basic Line ```tsx import { Line } from '@react-three/drei' function BasicLine() { const points = [ [0, 0, 0], [1, 1, 0], [2, 0, 0], [3, 1, 0], ] return ( ) } ``` ### Curved Line ```tsx import { CatmullRomLine, QuadraticBezierLine, CubicBezierLine } from '@react-three/drei' function CurvedLines() { return ( <> {/* Smooth curve through points */} {/* Quadratic bezier */} {/* Cubic bezier */} ) } ``` ### Dashed Line ```tsx ``` ## Edges and Wireframe ```tsx import { Edges } from '@react-three/drei' function BoxWithEdges() { return ( 15 degrees color="black" /> ) } // Wireframe material function WireframeBox() { return ( ) } ``` ## Text Geometry ### Using Drei Text3D ```tsx import { Text3D, Center } from '@react-three/drei' function Text3DExample() { return (
Hello R3F
) } ``` ## Geometry Utilities ### Center Geometry ```tsx import { Center } from '@react-three/drei' function CenteredModel() { return (
) } // With options
{/* Align to top-left */}
// Get bounding info
{ console.log('Dimensions:', width, height, depth) }}>
``` ### Compute Bounds ```tsx import { useBounds, Bounds } from '@react-three/drei' function FitToView() { return ( ) } function SelectToZoom() { const bounds = useBounds() return ( { e.stopPropagation() bounds.refresh(e.object).fit() }} > ) } ``` ## Performance Tips 1. **Reuse geometries**: Same geometry instance = better batching 2. **Use Instances**: For many identical objects 3. **Merge static meshes**: Use `` for static scenes 4. **Appropriate segment counts**: Balance quality vs performance 5. **Dispose unused geometry**: R3F handles this automatically ```tsx // Good segment counts // Standard quality // High quality // Performance mode // Reuse geometry const sharedGeometry = useMemo(() => new THREE.BoxGeometry(), []) ``` ## See Also - `r3f-fundamentals` - JSX elements and refs - `r3f-materials` - Materials for meshes - `r3f-shaders` - Custom vertex manipulation