@lark-apaas/coding-steering 0.1.3 → 0.1.4
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/package.json +8 -13
- package/steering/vite-react/skills/react-three-fiber/SKILL.md +214 -0
- package/steering/vite-react/skills/react-three-fiber/references/animation.md +1001 -0
- package/steering/vite-react/skills/react-three-fiber/references/fundamentals.md +877 -0
- package/steering/vite-react/skills/react-three-fiber/references/geometry.md +717 -0
- package/steering/vite-react/skills/react-three-fiber/references/interaction.md +880 -0
- package/steering/vite-react/skills/react-three-fiber/references/lighting.md +668 -0
- package/steering/vite-react/skills/react-three-fiber/references/loaders.md +607 -0
- package/steering/vite-react/skills/react-three-fiber/references/materials.md +601 -0
- package/steering/vite-react/skills/react-three-fiber/references/physics.md +820 -0
- package/steering/vite-react/skills/react-three-fiber/references/postprocessing.md +754 -0
- package/steering/vite-react/skills/react-three-fiber/references/shaders.md +874 -0
- package/steering/vite-react/skills/react-three-fiber/references/textures.md +635 -0
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
# React Three Fiber Geometry
|
|
2
|
+
|
|
3
|
+
## Quick Start
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Canvas } from '@react-three/fiber'
|
|
7
|
+
|
|
8
|
+
function Scene() {
|
|
9
|
+
return (
|
|
10
|
+
<Canvas>
|
|
11
|
+
<ambientLight />
|
|
12
|
+
<mesh position={[0, 0, 0]}>
|
|
13
|
+
<boxGeometry args={[1, 1, 1]} />
|
|
14
|
+
<meshStandardMaterial color="hotpink" />
|
|
15
|
+
</mesh>
|
|
16
|
+
</Canvas>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Built-in Geometries
|
|
22
|
+
|
|
23
|
+
All Three.js geometries are available as JSX elements. The `args` prop passes constructor arguments.
|
|
24
|
+
|
|
25
|
+
### Basic Shapes
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
// BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)
|
|
29
|
+
<boxGeometry args={[1, 1, 1]} />
|
|
30
|
+
<boxGeometry args={[2, 1, 0.5, 2, 2, 2]} />
|
|
31
|
+
|
|
32
|
+
// SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
|
|
33
|
+
<sphereGeometry args={[1, 32, 32]} />
|
|
34
|
+
<sphereGeometry args={[1, 64, 64]} /> // High quality
|
|
35
|
+
<sphereGeometry args={[1, 32, 32, 0, Math.PI]} /> // Hemisphere
|
|
36
|
+
|
|
37
|
+
// PlaneGeometry(width, height, widthSegments, heightSegments)
|
|
38
|
+
<planeGeometry args={[10, 10]} />
|
|
39
|
+
<planeGeometry args={[10, 10, 32, 32]} /> // Subdivided for displacement
|
|
40
|
+
|
|
41
|
+
// CircleGeometry(radius, segments, thetaStart, thetaLength)
|
|
42
|
+
<circleGeometry args={[1, 32]} />
|
|
43
|
+
<circleGeometry args={[1, 32, 0, Math.PI]} /> // Semicircle
|
|
44
|
+
|
|
45
|
+
// CylinderGeometry(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded)
|
|
46
|
+
<cylinderGeometry args={[1, 1, 2, 32]} />
|
|
47
|
+
<cylinderGeometry args={[0, 1, 2, 32]} /> // Cone
|
|
48
|
+
<cylinderGeometry args={[1, 1, 2, 6]} /> // Hexagonal prism
|
|
49
|
+
|
|
50
|
+
// ConeGeometry(radius, height, radialSegments, heightSegments, openEnded)
|
|
51
|
+
<coneGeometry args={[1, 2, 32]} />
|
|
52
|
+
|
|
53
|
+
// TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)
|
|
54
|
+
<torusGeometry args={[1, 0.4, 16, 100]} />
|
|
55
|
+
|
|
56
|
+
// TorusKnotGeometry(radius, tube, tubularSegments, radialSegments, p, q)
|
|
57
|
+
<torusKnotGeometry args={[1, 0.4, 100, 16, 2, 3]} />
|
|
58
|
+
|
|
59
|
+
// RingGeometry(innerRadius, outerRadius, thetaSegments, phiSegments)
|
|
60
|
+
<ringGeometry args={[0.5, 1, 32]} />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Advanced Shapes
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
// CapsuleGeometry(radius, length, capSegments, radialSegments)
|
|
67
|
+
<capsuleGeometry args={[0.5, 1, 4, 16]} />
|
|
68
|
+
|
|
69
|
+
// Polyhedrons
|
|
70
|
+
<dodecahedronGeometry args={[1, 0]} /> // radius, detail
|
|
71
|
+
<icosahedronGeometry args={[1, 0]} />
|
|
72
|
+
<octahedronGeometry args={[1, 0]} />
|
|
73
|
+
<tetrahedronGeometry args={[1, 0]} />
|
|
74
|
+
|
|
75
|
+
// Higher detail = more subdivisions
|
|
76
|
+
<icosahedronGeometry args={[1, 4]} /> // Approximates sphere
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Path-Based Shapes
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import * as THREE from 'three'
|
|
83
|
+
|
|
84
|
+
// LatheGeometry - revolve points around Y axis
|
|
85
|
+
function LatheShape() {
|
|
86
|
+
const points = [
|
|
87
|
+
new THREE.Vector2(0, 0),
|
|
88
|
+
new THREE.Vector2(0.5, 0),
|
|
89
|
+
new THREE.Vector2(0.5, 0.5),
|
|
90
|
+
new THREE.Vector2(0.3, 1),
|
|
91
|
+
new THREE.Vector2(0, 1),
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<mesh>
|
|
96
|
+
<latheGeometry args={[points, 32]} />
|
|
97
|
+
<meshStandardMaterial color="gold" side={THREE.DoubleSide} />
|
|
98
|
+
</mesh>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// TubeGeometry - extrude along a curve
|
|
103
|
+
function TubeShape() {
|
|
104
|
+
const curve = new THREE.CatmullRomCurve3([
|
|
105
|
+
new THREE.Vector3(-2, 0, 0),
|
|
106
|
+
new THREE.Vector3(-1, 1, 0),
|
|
107
|
+
new THREE.Vector3(1, -1, 0),
|
|
108
|
+
new THREE.Vector3(2, 0, 0),
|
|
109
|
+
])
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<mesh>
|
|
113
|
+
<tubeGeometry args={[curve, 64, 0.2, 8, false]} />
|
|
114
|
+
<meshStandardMaterial color="blue" />
|
|
115
|
+
</mesh>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ExtrudeGeometry - extrude a 2D shape
|
|
120
|
+
function ExtrudedShape() {
|
|
121
|
+
const shape = new THREE.Shape()
|
|
122
|
+
shape.moveTo(0, 0)
|
|
123
|
+
shape.lineTo(1, 0)
|
|
124
|
+
shape.lineTo(1, 1)
|
|
125
|
+
shape.lineTo(0, 1)
|
|
126
|
+
shape.lineTo(0, 0)
|
|
127
|
+
|
|
128
|
+
const extrudeSettings = {
|
|
129
|
+
steps: 2,
|
|
130
|
+
depth: 0.5,
|
|
131
|
+
bevelEnabled: true,
|
|
132
|
+
bevelThickness: 0.1,
|
|
133
|
+
bevelSize: 0.1,
|
|
134
|
+
bevelSegments: 3,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<mesh>
|
|
139
|
+
<extrudeGeometry args={[shape, extrudeSettings]} />
|
|
140
|
+
<meshStandardMaterial color="purple" />
|
|
141
|
+
</mesh>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Drei Shape Helpers
|
|
147
|
+
|
|
148
|
+
@react-three/drei provides convenient shape components.
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import {
|
|
152
|
+
Box, Sphere, Plane, Circle, Cylinder, Cone,
|
|
153
|
+
Torus, TorusKnot, Ring, Capsule, Dodecahedron,
|
|
154
|
+
Icosahedron, Octahedron, Tetrahedron, RoundedBox
|
|
155
|
+
} from '@react-three/drei'
|
|
156
|
+
|
|
157
|
+
function DreiShapes() {
|
|
158
|
+
return (
|
|
159
|
+
<>
|
|
160
|
+
{/* All shapes accept mesh props directly */}
|
|
161
|
+
<Box args={[1, 1, 1]} position={[-3, 0, 0]}>
|
|
162
|
+
<meshStandardMaterial color="red" />
|
|
163
|
+
</Box>
|
|
164
|
+
|
|
165
|
+
<Sphere args={[0.5, 32, 32]} position={[-1, 0, 0]}>
|
|
166
|
+
<meshStandardMaterial color="blue" />
|
|
167
|
+
</Sphere>
|
|
168
|
+
|
|
169
|
+
<Cylinder args={[0.5, 0.5, 1, 32]} position={[1, 0, 0]}>
|
|
170
|
+
<meshStandardMaterial color="green" />
|
|
171
|
+
</Cylinder>
|
|
172
|
+
|
|
173
|
+
{/* RoundedBox - box with rounded edges */}
|
|
174
|
+
<RoundedBox
|
|
175
|
+
args={[1, 1, 1]} // width, height, depth
|
|
176
|
+
radius={0.1} // border radius
|
|
177
|
+
smoothness={4} // smoothness of rounded edges
|
|
178
|
+
position={[3, 0, 0]}
|
|
179
|
+
>
|
|
180
|
+
<meshStandardMaterial color="orange" />
|
|
181
|
+
</RoundedBox>
|
|
182
|
+
</>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Custom BufferGeometry
|
|
188
|
+
|
|
189
|
+
### Basic Custom Geometry
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
import { useMemo, useRef } from 'react'
|
|
193
|
+
import * as THREE from 'three'
|
|
194
|
+
|
|
195
|
+
function CustomTriangle() {
|
|
196
|
+
const geometry = useMemo(() => {
|
|
197
|
+
const geo = new THREE.BufferGeometry()
|
|
198
|
+
|
|
199
|
+
// Vertices (3 floats per vertex: x, y, z)
|
|
200
|
+
const vertices = new Float32Array([
|
|
201
|
+
-1, -1, 0, // vertex 0
|
|
202
|
+
1, -1, 0, // vertex 1
|
|
203
|
+
0, 1, 0, // vertex 2
|
|
204
|
+
])
|
|
205
|
+
|
|
206
|
+
// Normals (pointing toward camera)
|
|
207
|
+
const normals = new Float32Array([
|
|
208
|
+
0, 0, 1,
|
|
209
|
+
0, 0, 1,
|
|
210
|
+
0, 0, 1,
|
|
211
|
+
])
|
|
212
|
+
|
|
213
|
+
// UVs
|
|
214
|
+
const uvs = new Float32Array([
|
|
215
|
+
0, 0,
|
|
216
|
+
1, 0,
|
|
217
|
+
0.5, 1,
|
|
218
|
+
])
|
|
219
|
+
|
|
220
|
+
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
|
|
221
|
+
geo.setAttribute('normal', new THREE.BufferAttribute(normals, 3))
|
|
222
|
+
geo.setAttribute('uv', new THREE.BufferAttribute(uvs, 2))
|
|
223
|
+
|
|
224
|
+
return geo
|
|
225
|
+
}, [])
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<mesh geometry={geometry}>
|
|
229
|
+
<meshStandardMaterial color="cyan" side={THREE.DoubleSide} />
|
|
230
|
+
</mesh>
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Indexed Geometry
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
function CustomQuad() {
|
|
239
|
+
const geometry = useMemo(() => {
|
|
240
|
+
const geo = new THREE.BufferGeometry()
|
|
241
|
+
|
|
242
|
+
// 4 vertices for a quad
|
|
243
|
+
const vertices = new Float32Array([
|
|
244
|
+
-1, -1, 0, // 0: bottom-left
|
|
245
|
+
1, -1, 0, // 1: bottom-right
|
|
246
|
+
1, 1, 0, // 2: top-right
|
|
247
|
+
-1, 1, 0, // 3: top-left
|
|
248
|
+
])
|
|
249
|
+
|
|
250
|
+
// Indices to form 2 triangles
|
|
251
|
+
const indices = new Uint16Array([
|
|
252
|
+
0, 1, 2, // triangle 1
|
|
253
|
+
0, 2, 3, // triangle 2
|
|
254
|
+
])
|
|
255
|
+
|
|
256
|
+
const normals = new Float32Array([
|
|
257
|
+
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
|
258
|
+
])
|
|
259
|
+
|
|
260
|
+
const uvs = new Float32Array([
|
|
261
|
+
0, 0, 1, 0, 1, 1, 0, 1,
|
|
262
|
+
])
|
|
263
|
+
|
|
264
|
+
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
|
|
265
|
+
geo.setAttribute('normal', new THREE.BufferAttribute(normals, 3))
|
|
266
|
+
geo.setAttribute('uv', new THREE.BufferAttribute(uvs, 2))
|
|
267
|
+
geo.setIndex(new THREE.BufferAttribute(indices, 1))
|
|
268
|
+
|
|
269
|
+
return geo
|
|
270
|
+
}, [])
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<mesh geometry={geometry}>
|
|
274
|
+
<meshStandardMaterial color="lime" side={THREE.DoubleSide} />
|
|
275
|
+
</mesh>
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Dynamic Geometry
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
import { useRef } from 'react'
|
|
284
|
+
import { useFrame } from '@react-three/fiber'
|
|
285
|
+
|
|
286
|
+
function WavyPlane() {
|
|
287
|
+
const meshRef = useRef()
|
|
288
|
+
|
|
289
|
+
useFrame(({ clock }) => {
|
|
290
|
+
const positions = meshRef.current.geometry.attributes.position
|
|
291
|
+
const time = clock.elapsedTime
|
|
292
|
+
|
|
293
|
+
for (let i = 0; i < positions.count; i++) {
|
|
294
|
+
const x = positions.getX(i)
|
|
295
|
+
const y = positions.getY(i)
|
|
296
|
+
positions.setZ(i, Math.sin(x * 2 + time) * Math.cos(y * 2 + time) * 0.5)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
positions.needsUpdate = true
|
|
300
|
+
meshRef.current.geometry.computeVertexNormals()
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
return (
|
|
304
|
+
<mesh ref={meshRef} rotation={[-Math.PI / 2, 0, 0]}>
|
|
305
|
+
<planeGeometry args={[10, 10, 32, 32]} />
|
|
306
|
+
<meshStandardMaterial color="royalblue" side={THREE.DoubleSide} />
|
|
307
|
+
</mesh>
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Drei Instancing
|
|
313
|
+
|
|
314
|
+
Efficient rendering of many identical objects.
|
|
315
|
+
|
|
316
|
+
### Instances Component
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
import { Instances, Instance } from '@react-three/drei'
|
|
320
|
+
import { useFrame } from '@react-three/fiber'
|
|
321
|
+
import { useRef } from 'react'
|
|
322
|
+
|
|
323
|
+
function InstancedBoxes() {
|
|
324
|
+
const count = 1000
|
|
325
|
+
|
|
326
|
+
return (
|
|
327
|
+
<Instances limit={count} range={count}>
|
|
328
|
+
<boxGeometry args={[0.5, 0.5, 0.5]} />
|
|
329
|
+
<meshStandardMaterial />
|
|
330
|
+
|
|
331
|
+
{Array.from({ length: count }, (_, i) => (
|
|
332
|
+
<AnimatedInstance key={i} index={i} />
|
|
333
|
+
))}
|
|
334
|
+
</Instances>
|
|
335
|
+
)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function AnimatedInstance({ index }) {
|
|
339
|
+
const ref = useRef()
|
|
340
|
+
|
|
341
|
+
// Random initial position
|
|
342
|
+
const position = useMemo(() => [
|
|
343
|
+
(Math.random() - 0.5) * 20,
|
|
344
|
+
(Math.random() - 0.5) * 20,
|
|
345
|
+
(Math.random() - 0.5) * 20,
|
|
346
|
+
], [])
|
|
347
|
+
|
|
348
|
+
const color = useMemo(() =>
|
|
349
|
+
['red', 'blue', 'green', 'yellow', 'purple'][index % 5],
|
|
350
|
+
[index])
|
|
351
|
+
|
|
352
|
+
useFrame(({ clock }) => {
|
|
353
|
+
const t = clock.elapsedTime
|
|
354
|
+
ref.current.rotation.x = t + index
|
|
355
|
+
ref.current.rotation.y = t * 0.5 + index
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
return (
|
|
359
|
+
<Instance
|
|
360
|
+
ref={ref}
|
|
361
|
+
position={position}
|
|
362
|
+
color={color}
|
|
363
|
+
scale={0.5 + Math.random() * 0.5}
|
|
364
|
+
/>
|
|
365
|
+
)
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Merged Geometry
|
|
370
|
+
|
|
371
|
+
For static instances, merge geometry for best performance:
|
|
372
|
+
|
|
373
|
+
```tsx
|
|
374
|
+
import { Merged } from '@react-three/drei'
|
|
375
|
+
import { useMemo } from 'react'
|
|
376
|
+
import * as THREE from 'three'
|
|
377
|
+
|
|
378
|
+
function MergedMeshes() {
|
|
379
|
+
// Create geometries to merge
|
|
380
|
+
const meshes = useMemo(() => ({
|
|
381
|
+
Sphere: new THREE.SphereGeometry(0.5, 32, 32),
|
|
382
|
+
Box: new THREE.BoxGeometry(1, 1, 1),
|
|
383
|
+
Cone: new THREE.ConeGeometry(0.5, 1, 32),
|
|
384
|
+
}), [])
|
|
385
|
+
|
|
386
|
+
return (
|
|
387
|
+
<Merged meshes={meshes}>
|
|
388
|
+
{({ Sphere, Box, Cone }) => (
|
|
389
|
+
<>
|
|
390
|
+
<Sphere position={[-2, 0, 0]} color="red" />
|
|
391
|
+
<Sphere position={[-2, 2, 0]} color="orange" />
|
|
392
|
+
<Box position={[0, 0, 0]} color="blue" />
|
|
393
|
+
<Box position={[0, 2, 0]} color="cyan" />
|
|
394
|
+
<Cone position={[2, 0, 0]} color="green" />
|
|
395
|
+
<Cone position={[2, 2, 0]} color="lime" />
|
|
396
|
+
</>
|
|
397
|
+
)}
|
|
398
|
+
</Merged>
|
|
399
|
+
)
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Points (Particle Systems)
|
|
404
|
+
|
|
405
|
+
### Basic Points
|
|
406
|
+
|
|
407
|
+
```tsx
|
|
408
|
+
import { Points, Point, PointMaterial } from '@react-three/drei'
|
|
409
|
+
|
|
410
|
+
function ParticleField() {
|
|
411
|
+
const count = 5000
|
|
412
|
+
|
|
413
|
+
return (
|
|
414
|
+
<Points limit={count}>
|
|
415
|
+
<PointMaterial
|
|
416
|
+
transparent
|
|
417
|
+
vertexColors
|
|
418
|
+
size={0.05}
|
|
419
|
+
sizeAttenuation
|
|
420
|
+
depthWrite={false}
|
|
421
|
+
/>
|
|
422
|
+
{Array.from({ length: count }, (_, i) => (
|
|
423
|
+
<Point
|
|
424
|
+
key={i}
|
|
425
|
+
position={[
|
|
426
|
+
(Math.random() - 0.5) * 10,
|
|
427
|
+
(Math.random() - 0.5) * 10,
|
|
428
|
+
(Math.random() - 0.5) * 10,
|
|
429
|
+
]}
|
|
430
|
+
color={`hsl(${Math.random() * 360}, 100%, 50%)`}
|
|
431
|
+
/>
|
|
432
|
+
))}
|
|
433
|
+
</Points>
|
|
434
|
+
)
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Buffer-Based Points (High Performance)
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
import { useMemo, useRef } from 'react'
|
|
442
|
+
import { useFrame } from '@react-three/fiber'
|
|
443
|
+
import * as THREE from 'three'
|
|
444
|
+
|
|
445
|
+
function BufferParticles() {
|
|
446
|
+
const count = 10000
|
|
447
|
+
const pointsRef = useRef()
|
|
448
|
+
|
|
449
|
+
const { positions, colors } = useMemo(() => {
|
|
450
|
+
const positions = new Float32Array(count * 3)
|
|
451
|
+
const colors = new Float32Array(count * 3)
|
|
452
|
+
|
|
453
|
+
for (let i = 0; i < count; i++) {
|
|
454
|
+
positions[i * 3] = (Math.random() - 0.5) * 10
|
|
455
|
+
positions[i * 3 + 1] = (Math.random() - 0.5) * 10
|
|
456
|
+
positions[i * 3 + 2] = (Math.random() - 0.5) * 10
|
|
457
|
+
|
|
458
|
+
colors[i * 3] = Math.random()
|
|
459
|
+
colors[i * 3 + 1] = Math.random()
|
|
460
|
+
colors[i * 3 + 2] = Math.random()
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return { positions, colors }
|
|
464
|
+
}, [])
|
|
465
|
+
|
|
466
|
+
useFrame(({ clock }) => {
|
|
467
|
+
pointsRef.current.rotation.y = clock.elapsedTime * 0.1
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
return (
|
|
471
|
+
<points ref={pointsRef}>
|
|
472
|
+
<bufferGeometry>
|
|
473
|
+
<bufferAttribute
|
|
474
|
+
attach="attributes-position"
|
|
475
|
+
count={count}
|
|
476
|
+
array={positions}
|
|
477
|
+
itemSize={3}
|
|
478
|
+
/>
|
|
479
|
+
<bufferAttribute
|
|
480
|
+
attach="attributes-color"
|
|
481
|
+
count={count}
|
|
482
|
+
array={colors}
|
|
483
|
+
itemSize={3}
|
|
484
|
+
/>
|
|
485
|
+
</bufferGeometry>
|
|
486
|
+
<pointsMaterial size={0.05} vertexColors sizeAttenuation />
|
|
487
|
+
</points>
|
|
488
|
+
)
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## Lines
|
|
493
|
+
|
|
494
|
+
### Basic Line
|
|
495
|
+
|
|
496
|
+
```tsx
|
|
497
|
+
import { Line } from '@react-three/drei'
|
|
498
|
+
|
|
499
|
+
function BasicLine() {
|
|
500
|
+
const points = [
|
|
501
|
+
[0, 0, 0],
|
|
502
|
+
[1, 1, 0],
|
|
503
|
+
[2, 0, 0],
|
|
504
|
+
[3, 1, 0],
|
|
505
|
+
]
|
|
506
|
+
|
|
507
|
+
return (
|
|
508
|
+
<Line
|
|
509
|
+
points={points}
|
|
510
|
+
color="red"
|
|
511
|
+
lineWidth={2}
|
|
512
|
+
/>
|
|
513
|
+
)
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Curved Line
|
|
518
|
+
|
|
519
|
+
```tsx
|
|
520
|
+
import { CatmullRomLine, QuadraticBezierLine, CubicBezierLine } from '@react-three/drei'
|
|
521
|
+
|
|
522
|
+
function CurvedLines() {
|
|
523
|
+
return (
|
|
524
|
+
<>
|
|
525
|
+
{/* Smooth curve through points */}
|
|
526
|
+
<CatmullRomLine
|
|
527
|
+
points={[[0, 0, 0], [1, 1, 0], [2, 0, 0], [3, 1, 0]]}
|
|
528
|
+
color="blue"
|
|
529
|
+
lineWidth={2}
|
|
530
|
+
segments={64}
|
|
531
|
+
/>
|
|
532
|
+
|
|
533
|
+
{/* Quadratic bezier */}
|
|
534
|
+
<QuadraticBezierLine
|
|
535
|
+
start={[0, 0, 0]}
|
|
536
|
+
mid={[1, 2, 0]}
|
|
537
|
+
end={[2, 0, 0]}
|
|
538
|
+
color="green"
|
|
539
|
+
lineWidth={2}
|
|
540
|
+
/>
|
|
541
|
+
|
|
542
|
+
{/* Cubic bezier */}
|
|
543
|
+
<CubicBezierLine
|
|
544
|
+
start={[0, 0, 0]}
|
|
545
|
+
midA={[0.5, 2, 0]}
|
|
546
|
+
midB={[1.5, -1, 0]}
|
|
547
|
+
end={[2, 0, 0]}
|
|
548
|
+
color="purple"
|
|
549
|
+
lineWidth={2}
|
|
550
|
+
/>
|
|
551
|
+
</>
|
|
552
|
+
)
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Dashed Line
|
|
557
|
+
|
|
558
|
+
```tsx
|
|
559
|
+
<Line
|
|
560
|
+
points={[[0, 0, 0], [5, 0, 0]]}
|
|
561
|
+
color="white"
|
|
562
|
+
lineWidth={2}
|
|
563
|
+
dashed
|
|
564
|
+
dashScale={50}
|
|
565
|
+
dashSize={0.5}
|
|
566
|
+
dashOffset={0}
|
|
567
|
+
gapSize={0.2}
|
|
568
|
+
/>
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Edges and Wireframe
|
|
572
|
+
|
|
573
|
+
```tsx
|
|
574
|
+
import { Edges } from '@react-three/drei'
|
|
575
|
+
|
|
576
|
+
function BoxWithEdges() {
|
|
577
|
+
return (
|
|
578
|
+
<mesh>
|
|
579
|
+
<boxGeometry />
|
|
580
|
+
<meshStandardMaterial color="orange" />
|
|
581
|
+
<Edges
|
|
582
|
+
scale={1.1}
|
|
583
|
+
threshold={15} // Display edges with angle > 15 degrees
|
|
584
|
+
color="black"
|
|
585
|
+
/>
|
|
586
|
+
</mesh>
|
|
587
|
+
)
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Wireframe material
|
|
591
|
+
function WireframeBox() {
|
|
592
|
+
return (
|
|
593
|
+
<mesh>
|
|
594
|
+
<boxGeometry />
|
|
595
|
+
<meshBasicMaterial color="cyan" wireframe />
|
|
596
|
+
</mesh>
|
|
597
|
+
)
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
## Text Geometry
|
|
602
|
+
|
|
603
|
+
### Using Drei Text3D
|
|
604
|
+
|
|
605
|
+
```tsx
|
|
606
|
+
import { Text3D, Center } from '@react-three/drei'
|
|
607
|
+
|
|
608
|
+
function Text3DExample() {
|
|
609
|
+
return (
|
|
610
|
+
<Center>
|
|
611
|
+
<Text3D
|
|
612
|
+
font="/fonts/helvetiker_regular.typeface.json"
|
|
613
|
+
size={1}
|
|
614
|
+
height={0.2}
|
|
615
|
+
curveSegments={12}
|
|
616
|
+
bevelEnabled
|
|
617
|
+
bevelThickness={0.02}
|
|
618
|
+
bevelSize={0.02}
|
|
619
|
+
bevelOffset={0}
|
|
620
|
+
bevelSegments={5}
|
|
621
|
+
>
|
|
622
|
+
Hello R3F
|
|
623
|
+
<meshStandardMaterial color="gold" />
|
|
624
|
+
</Text3D>
|
|
625
|
+
</Center>
|
|
626
|
+
)
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
## Geometry Utilities
|
|
631
|
+
|
|
632
|
+
### Center Geometry
|
|
633
|
+
|
|
634
|
+
```tsx
|
|
635
|
+
import { Center } from '@react-three/drei'
|
|
636
|
+
|
|
637
|
+
function CenteredModel() {
|
|
638
|
+
return (
|
|
639
|
+
<Center>
|
|
640
|
+
<mesh>
|
|
641
|
+
<boxGeometry args={[2, 1, 0.5]} />
|
|
642
|
+
<meshStandardMaterial />
|
|
643
|
+
</mesh>
|
|
644
|
+
</Center>
|
|
645
|
+
)
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// With options
|
|
649
|
+
<Center top left> {/* Align to top-left */}
|
|
650
|
+
<Model />
|
|
651
|
+
</Center>
|
|
652
|
+
|
|
653
|
+
// Get bounding info
|
|
654
|
+
<Center onCentered={({ width, height, depth, boundingBox }) => {
|
|
655
|
+
console.log('Dimensions:', width, height, depth)
|
|
656
|
+
}}>
|
|
657
|
+
<Model />
|
|
658
|
+
</Center>
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Compute Bounds
|
|
662
|
+
|
|
663
|
+
```tsx
|
|
664
|
+
import { useBounds, Bounds } from '@react-three/drei'
|
|
665
|
+
|
|
666
|
+
function FitToView() {
|
|
667
|
+
return (
|
|
668
|
+
<Bounds fit clip observe margin={1.2}>
|
|
669
|
+
<SelectToZoom />
|
|
670
|
+
</Bounds>
|
|
671
|
+
)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function SelectToZoom() {
|
|
675
|
+
const bounds = useBounds()
|
|
676
|
+
|
|
677
|
+
return (
|
|
678
|
+
<mesh
|
|
679
|
+
onClick={(e) => {
|
|
680
|
+
e.stopPropagation()
|
|
681
|
+
bounds.refresh(e.object).fit()
|
|
682
|
+
}}
|
|
683
|
+
>
|
|
684
|
+
<boxGeometry />
|
|
685
|
+
<meshStandardMaterial />
|
|
686
|
+
</mesh>
|
|
687
|
+
)
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
## Performance Tips
|
|
692
|
+
|
|
693
|
+
1. **Reuse geometries**: Same geometry instance = better batching
|
|
694
|
+
2. **Use Instances**: For many identical objects
|
|
695
|
+
3. **Merge static meshes**: Use `<Merged>` for static scenes
|
|
696
|
+
4. **Appropriate segment counts**: Balance quality vs performance
|
|
697
|
+
5. **Dispose unused geometry**: R3F handles this automatically
|
|
698
|
+
|
|
699
|
+
```tsx
|
|
700
|
+
// Good segment counts
|
|
701
|
+
<sphereGeometry args={[1, 32, 32]} /> // Standard quality
|
|
702
|
+
<sphereGeometry args={[1, 64, 64]} /> // High quality
|
|
703
|
+
<sphereGeometry args={[1, 16, 16]} /> // Performance mode
|
|
704
|
+
|
|
705
|
+
// Reuse geometry
|
|
706
|
+
const sharedGeometry = useMemo(() => new THREE.BoxGeometry(), [])
|
|
707
|
+
|
|
708
|
+
<mesh geometry={sharedGeometry} position={[0, 0, 0]} />
|
|
709
|
+
<mesh geometry={sharedGeometry} position={[2, 0, 0]} />
|
|
710
|
+
<mesh geometry={sharedGeometry} position={[4, 0, 0]} />
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
## See Also
|
|
714
|
+
|
|
715
|
+
- `r3f-fundamentals` - JSX elements and refs
|
|
716
|
+
- `r3f-materials` - Materials for meshes
|
|
717
|
+
- `r3f-shaders` - Custom vertex manipulation
|