@react-three/drei 7.25.4 → 7.25.5

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 ADDED
@@ -0,0 +1,1620 @@
1
+ ![logo](logo.jpg)
2
+
3
+ [![Version](https://img.shields.io/npm/v/@react-three/drei?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/@react-three/drei)
4
+ [![Downloads](https://img.shields.io/npm/dt/@react-three/drei.svg?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/@react-three/drei)
5
+ [![Discord Shield](https://img.shields.io/discord/740090768164651008?style=flat&colorA=000000&colorB=000000&label=discord&logo=discord&logoColor=ffffff)](https://discord.gg/poimandres)
6
+
7
+ A growing collection of useful helpers and fully functional, ready-made abstractions for [react-three-fiber](https://github.com/pmndrs/react-three-fiber). If you make a component that is generic enough to be useful to others, think about making it available here through a PR!
8
+
9
+ ```bash
10
+ npm install @react-three/drei
11
+ ```
12
+
13
+ :point_right: this package is using the stand-alone [`three-stdlib`](https://github.com/pmndrs/three-stdlib) instead of [`three/examples/jsm`](https://github.com/mrdoob/three.js/tree/dev/examples/jsm). :point_left:
14
+
15
+ ### Basic usage:
16
+
17
+ ```jsx
18
+ import { PerspectiveCamera, PositionalAudio, ... } from '@react-three/drei'
19
+ ```
20
+
21
+ ### React-native:
22
+
23
+ ```jsx
24
+ import { PerspectiveCamera, PositionalAudio, ... } from '@react-three/drei/native'
25
+ ```
26
+
27
+ The `native` route of the library **does not** export `Html` or `Loader`. The default export of the library is `web` which **does** export `Html` and `Loader`.
28
+
29
+ ### Index
30
+
31
+ <table>
32
+ <tr>
33
+ <td valign="top">
34
+ <ul>
35
+ <li><a href="#cameras">Cameras</a></li>
36
+ <ul>
37
+ <li><a href="#perspectivecamera">PerspectiveCamera</a></li>
38
+ <li><a href="#orthographiccamera">OrthographicCamera</a></li>
39
+ <li><a href="#cubecamera">CubeCamera</a></li>
40
+ </ul>
41
+ <li><a href="#controls">Controls</a></li>
42
+ <ul>
43
+ <li><a href="#controls">Controls</a></li>
44
+ <li><a href="#controls">FlyControls</a></li>
45
+ <li><a href="#controls">MapControls</a></li>
46
+ <li><a href="#controls">DeviceOrientationControls</a></li>
47
+ <li><a href="#controls">TrackballControls</a></li>
48
+ <li><a href="#controls">ArcballControls</a></li>
49
+ <li><a href="#controls">PointerLockControls</a></li>
50
+ <li><a href="#controls">FirstPersonControls</a></li>
51
+ <li><a href="#transformcontrols">TransformControls</a></li>
52
+ <li><a href="#scrollcontrols">ScrollControls</a></li>
53
+ </ul>
54
+ <li><a href="#abstractions">Abstractions</a></li>
55
+ <ul>
56
+ <li><a href="#image">Image</a></li>
57
+ <li><a href="#text">Text</a></li>
58
+ <li><a href="#line">Line</a></li>
59
+ <li><a href="#quadraticbezierline">QuadraticBezierLine</a></li>
60
+ <li><a href="#cubicbezierline">CubicBezierLine</a></li>
61
+ <li><a href="#positionalaudio">PositionalAudio</a></li>
62
+ <li><a href="#billboard">Billboard</a></li>
63
+ <li><a href="#gizmohelper">GizmoHelper</a></li>
64
+ <li><a href="#effects">Effects</a></li>
65
+ <li><a href="#gradienttexture">GradientTexture</a></li>
66
+ <li><a href="#useanimations">useAnimations</a></li>
67
+ </ul>
68
+ <li><a href="#shaders">Shaders</a></li>
69
+ <ul>
70
+ <li><a href="#meshwobblematerial">MeshWobbleMaterial</a></li>
71
+ <li><a href="#meshdistortmaterial">MeshDistortMaterial</a></li>
72
+ <li><a href="#pointmaterial">PointMaterial</a></li>
73
+ <li><a href="#softshadows">softShadows</a></li>
74
+ <li><a href="#shadermaterial">shaderMaterial</a></li>
75
+ </ul>
76
+ <li><a href="#modifiers">Modifiers</a></li>
77
+ <ul>
78
+ <li><a href="#curvemodifier">CurveModifier</a></li>
79
+ <li><a href="#useedgesplit">useEdgeSplit</a></li>
80
+ <li><a href="#usetessellation">useTessellation</a></li>
81
+ <li><a href="#usesimplification">useSimplification</a></li>
82
+ </ul>
83
+ </ul>
84
+ </td>
85
+ <td valign="top">
86
+ <ul>
87
+ <li><a href="#misc">Misc</a></li>
88
+ <ul>
89
+ <li><a href="#html">Html</a></li>
90
+ <li><a href="#cycleraycast">CycleRaycast</a></li>
91
+ <li><a href="#stats">Stats</a></li>
92
+ <li><a href="#usedepthbuffer">useDepthBuffer</a></li>
93
+ <li><a href="#usecontextbridge">useContextBridge</a></li>
94
+ <li><a href="#usefbo">useFBO</a></li>
95
+ <li><a href="#usecamera">useCamera</a></li>
96
+ <li><a href="#usedetectgpu">useDetectGPU</a></li>
97
+ <li><a href="#usehelper">useHelper</a></li>
98
+ <li><a href="#useaspect">useAspect</a></li>
99
+ <li><a href="#usecursor">useCursor</a></li>
100
+ <li><a href="#useintersect">useIntersect</a></li>
101
+ </ul>
102
+ <li><a href="#loading">Loaders</a></li>
103
+ <ul>
104
+ <li><a href="#loader">Loader</a></li>
105
+ <li><a href="#useprogress">useProgress</a></li>
106
+ <li><a href="#usegltf">useGLTF</a></li>
107
+ <li><a href="#usefbx">useFBX</a></li>
108
+ <li><a href="#usetexture">useTexture</a></li>
109
+ <li><a href="#usecubetexture">useCubeTexture</a></li>
110
+ </ul>
111
+ <li><a href="#performance">Performance</a></li>
112
+ <ul>
113
+ <li><a href="#instances">Instances</a></li>
114
+ <li><a href="#merged">Merged</a></li>
115
+ <li><a href="#points">Points</a></li>
116
+ <li><a href="#segments">Segments</a></li>
117
+ <li><a href="#detailed">Detailed</a></li>
118
+ <li><a href="#preload">Preload</a></li>
119
+ <li><a href="#bakeshadows">BakeShadows</a></li>
120
+ <li><a href="#meshbounds">meshBounds</a></li>
121
+ <li><a href="#adaptivedpr">AdaptiveDpr</a></li>
122
+ <li><a href="#adaptiveevents">AdaptiveEvents</a></li>
123
+ <li><a href="#usebvh">useBVH</a></li>
124
+ </ul>
125
+ </ul>
126
+ </td>
127
+ <td valign="top">
128
+ <ul>
129
+ <li><a href="#shapes">Shapes</a></li>
130
+ <ul>
131
+ <li><a href="#shapes">Plane</a></li>
132
+ <li><a href="#shapes">Box</a></li>
133
+ <li><a href="#shapes">Sphere</a></li>
134
+ <li><a href="#shapes">Circle</a></li>
135
+ <li><a href="#shapes">Cone</a></li>
136
+ <li><a href="#shapes">Cylinder</a></li>
137
+ <li><a href="#shapes">Tube</a></li>
138
+ <li><a href="#shapes">Torus</a></li>
139
+ <li><a href="#shapes">TorusKnot</a></li>
140
+ <li><a href="#shapes">Ring</a></li>
141
+ <li><a href="#shapes">Tetrahedron</a></li>
142
+ <li><a href="#shapes">Polyhedron</a></li>
143
+ <li><a href="#shapes">Icosahedron</a></li>
144
+ <li><a href="#shapes">Octahedron</a></li>
145
+ <li><a href="#shapes">Dodecahedron</a></li>
146
+ <li><a href="#shapes">Extrude</a></li>
147
+ <li><a href="#shapes">Lathe</a></li>
148
+ <li><a href="#shapes">Parametric</a></li>
149
+ <li><a href="#roundedbox">RoundedBox</a></li>
150
+ <li><a href="#screenquad">Screenquad</a></li>
151
+ </ul>
152
+ <li><a href="#staging">Staging</a></li>
153
+ <ul>
154
+ <li><a href="#center">Center</a></li>
155
+ <li><a href="#bounds">Bounds</a></li>
156
+ <li><a href="#camerashake">CameraShake</a></li>
157
+ <li><a href="#float">Float</a></li>
158
+ <li><a href="#stage">Stage</a></li>
159
+ <li><a href="#backdrop">Backdrop</a></li>
160
+ <li><a href="#environment">Environment</a></li>
161
+ <li><a href="#reflector">SpotLight</a></li>
162
+ <li><a href="#shadow">Shadow</a></li>
163
+ <li><a href="#contactshadows">ContactShadows</a></li>
164
+ <li><a href="#reflector">Reflector</a></li>
165
+ <li><a href="#sky">Sky</a></li>
166
+ <li><a href="#stars">Stars</a></li>
167
+ <li><a href="#cloud">Cloud</a></li>
168
+ <li><a href="#usematcaptexture">useMatcapTexture</a></li>
169
+ <li><a href="#usenormaltexture">useNormalTexture</a></li>
170
+ </ul>
171
+ </ul>
172
+ </td>
173
+ </tr>
174
+ </table>
175
+
176
+ # Cameras
177
+
178
+ #### PerspectiveCamera
179
+
180
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/camera-perspectivecamera--perspective-camera-scene-st)
181
+
182
+ A responsive [THREE.PerspectiveCamera](https://threejs.org/docs/index.html#api/en/cameras/PerspectiveCamera) that can set itself as the default.
183
+
184
+ ```jsx
185
+ <PerspectiveCamera makeDefault {...props}>
186
+ <mesh />
187
+ </PerspectiveCamera>
188
+ ```
189
+
190
+ #### OrthographicCamera
191
+
192
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/camera-orthographiccamera--orthographic-camera-scene-st)
193
+
194
+ A responsive [THREE.OrthographicCamera](https://threejs.org/docs/index.html#api/en/cameras/OrthographicCamera) that can set itself as the default.
195
+
196
+ ```jsx
197
+ <OrthographicCamera makeDefault {...props}>
198
+ <mesh />
199
+ </OrthographicCamera>
200
+ ```
201
+
202
+ #### CubeCamera
203
+
204
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/camera-cubecamera--default-story)
205
+
206
+ A [THREE.CubeCamera](https://threejs.org/docs/index.html#api/en/cameras/CubeCamera) that returns its texture as a render-prop. It makes children invisible while rendering to the internal buffer so that they are not included in the reflection.
207
+
208
+ Using the `frames` prop you can control if this camera renders indefinitively or statically (a given number of times).
209
+ If you have two static objects in the scene, make it `frames={2}` for instance, so that both objects get to "see" one another in the reflections, which takes multiple renders.
210
+ If you have moving objects, unset the prop and use a smaller `resolution` instead.
211
+
212
+ ```jsx
213
+ <CubeCamera resolution={256} frames={Infinity} fog={customFog} near={1} far={1000}>
214
+ {(texture) => (
215
+ <mesh>
216
+ <sphereGeometry />
217
+ <meshStandardMaterial envMap={texture} />
218
+ </mesh>
219
+ )}
220
+ </CubeCamera>
221
+ ```
222
+
223
+ # Controls
224
+
225
+ If available controls have damping enabled by default, they manage their own updates, remove themselves on unmount, are compatible with the `invalidateFrameloop` canvas-flag. They inherit all props from their underlying [THREE controls](https://github.com/mrdoob/three.js/tree/dev/examples/jsm/controls).
226
+
227
+ Some controls allow you to set `makeDefault`, similar to, for instance, PerspectiveCamera. This will set react-three-fiber's `controls` field in the root store. This can make it easier in situations where you want controls to be known and other parts of the app could respond to it. Some drei controls already take it into account, like CameraShake, Gizmo and TransformControls.
228
+
229
+ Drei currently exports OrbitControls [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/controls-orbitcontrols--orbit-controls-story), MapControls [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/controls-mapcontrols--map-controls-scene-st), TrackballControls, ArcballControls, FlyControls, DeviceOrientationControls, PointerLockControls [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/controls-pointerlockcontrols--pointer-lock-controls-scene-st), FirstPersonControls [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/controls-firstpersoncontrols--first-person-controls-story)
230
+
231
+ All controls react to the default camera. If you have a `<PerspectiveCamera makeDefault />` in your scene, they will control it. If you need to inject an imperative camera or one that isn't the default, use the `camera` prop: `<OrbitControls camera={MyCamera} />`.
232
+
233
+ PointerLockControls additionally supports a `selector` prop, which enables the binding of `click` event handlers for control activation to other elements than `document` (e.g. a 'Click here to play' button). All elements matching the `selector` prop will activate the controls.
234
+
235
+ # TransformControls
236
+
237
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/controls-transformcontrols--transform-controls-story)
238
+
239
+ An abstraction around [THREE.TransformControls](https://threejs.org/docs/index.html?q=transfor#examples/en/controls/TransformControls).
240
+
241
+ You can wrap objects which then receive a transform gizmo.
242
+
243
+ ```jsx
244
+ <TransformControls mode="translate">
245
+ <mesh />
246
+ </TransformControls>
247
+ ```
248
+
249
+ You could also reference the object which might make it easier to exchange the target. Now the object does not have to be part of the same sub-graph. References can be plain objects or React.MutableRefObjects.
250
+
251
+ ```jsx
252
+ <TransformControls object={mesh} mode="translate">
253
+ <mesh ref={mesh} />
254
+ ```
255
+
256
+ If you are using other controls (Orbit, Trackball, etc), you will notice how they interfere, dragging one will affect the other. Default-controls will temporarily be disabled automatically when the user is pulling on the transform gizmo.
257
+
258
+ ```jsx
259
+ <TransformControls mode="translate" />
260
+ <OrbitControls makeDefault />
261
+ ```
262
+
263
+ # ScrollControls
264
+
265
+ <p align="center">
266
+ <a href="https://codesandbox.io/s/l4klb"><img width="16%" src="https://codesandbox.io/api/v1/sandboxes/l4klb/screenshot.png" alt="Horizintal tiles"/></a>
267
+ <a href="https://codesandbox.io/s/4m0d0"><img width="16%" src="https://codesandbox.io/api/v1/sandboxes/4m0d0/screenshot.png" alt="M1 scroll"/></a>
268
+ <a href="https://codesandbox.io/s/gsm1y"><img width="16%" src="https://codesandbox.io/api/v1/sandboxes/gsm1y/screenshot.png" alt="useIntersect"/></a>
269
+ <a href="https://codesandbox.io/s/x8gvs"><img width="16%" src="https://codesandbox.io/api/v1/sandboxes/x8gvs/screenshot.png" alt="Infinite scroll"/></a>
270
+ <a href="https://codesandbox.io/s/yjhzv"><img width="16%" src="https://codesandbox.io/api/v1/sandboxes/yjhzv/screenshot.png" alt="Vertical scroll"/></a>
271
+ <a href="https://codesandbox.io/s/4jr4p"><img width="16%" src="https://codesandbox.io/api/v1/sandboxes/4jr4p/screenshot.png" alt="GLTF and useScroll"/></a>
272
+ </p>
273
+
274
+ Scroll controls create a HTML scroll container in front of the canvas. Everything you drop into the `<Scroll>` component will be affected.
275
+
276
+ You can listen and react to scroll with the `useScroll` hook which gives you useful data like the current scroll `offset`, `delta` and functions for range finding: `range`, `curve` and `visible`. The latter functions are especially useful if you want to react to the scroll offset, for instance if you wanted to fade things in and out if they are in or out of view.
277
+
278
+ ```jsx
279
+ <ScrollControls
280
+ pages={3} // Each page takes 100% of the height of the canvas
281
+ distance={1} // A factor that increases scroll bar travel (default: 1)
282
+ damping={4} // Friction, higher is faster (default: 4)
283
+ horizontal={false} // Can also scroll horizontally (default: false)
284
+ infinite={false} // Can also scroll infinitely (default: false)
285
+ >
286
+ {/* You can have components in here, they are not scrolled, but they can still
287
+ react to scroll by using useScroll! */}
288
+ <Scroll>
289
+ <Foo position={[0, 0, 0]} />
290
+ <Foo position={[0, viewport.height, 0]} />
291
+ <Foo position={[0, viewport.height * 1, 0]} />
292
+ </Scroll>
293
+ <Scroll html>
294
+ <h1>html in here (optional)</h1>
295
+ <h1 style={{ top: '100vh' }}>second page</h1>
296
+ <h1 style={{ top: '200vh' }}>third page</h1>
297
+ </Scroll>
298
+ </ScrollControls>
299
+
300
+ function Foo() {
301
+ const ref = useRef()
302
+ const data = useScroll()
303
+ useFrame(() => {
304
+ // data.offset = current scroll position, between 0 and 1, dampened
305
+ // data.delta = current delta, between 0 and 1, dampened
306
+
307
+ // Will be 0 when the scrollbar is at the starting position,
308
+ // then increase to 1 until 1 / 3 of the scroll distance is reached
309
+ const a = data.range(0, 1 / 3)
310
+ // Will start increasing when 1 / 3 of the scroll distance is reached,
311
+ // and reach 1 when it reaches 2 / 3rds.
312
+ const b = data.range(1 / 3, 1 / 3)
313
+ // Same as above but with a margin of 0.1 on both ends
314
+ const c = data.range(1 / 3, 1 / 3, 0.1)
315
+ // Will move between 0-1-0 for the selected range
316
+ const d = data.curve(1 / 3, 1 / 3)
317
+ // Same as above, but with a margin of 0.1 on both ends
318
+ const d = data.curve(1 / 3, 1 / 3, 0.1)
319
+ // Returns true if the offset is in range and false if it isn't
320
+ const e = data.visible(2 / 3, 1 / 3)
321
+ // The visible function can also receive a margin
322
+ const f = data.visible(2 / 3, 1 / 3, 0.1)
323
+ })
324
+ return <mesh ref={ref} {...props} />
325
+ ```
326
+
327
+ # Shapes
328
+
329
+ [Buffer-geometry](https://threejs.org/docs/index.html#api/en/core/BufferGeometry) short-cuts for Plane, Box, Sphere, Circle, Cone, Cylinder, Tube, Torus, TorusKnot, Ring, Tetrahedron, Polyhedron, Icosahedron, Octahedron, Dodecahedron, Extrude, Lathe, Parametric.
330
+
331
+ ```jsx
332
+ <Plane args={[2, 2]} />
333
+ <Sphere>
334
+ <meshBasicMaterial attach="material" color="hotpink" />
335
+ </Sphere>
336
+ ```
337
+
338
+ #### RoundedBox
339
+
340
+ A box buffer geometry with rounded corners, done with extrusion.
341
+
342
+ ```jsx
343
+ <RoundedBox args={[1, 1, 1]} radius={0.05} smoothness={4} {...meshProps}>
344
+ <meshPhongMaterial attach="material" color="#f3f3f3" wireframe />
345
+ </RoundedBox>
346
+ ```
347
+
348
+ #### ScreenQuad
349
+
350
+ ```jsx
351
+ <ScreenQuad>
352
+ <myMaterial />
353
+ </ScreenQuad>
354
+ ```
355
+
356
+ A triangle that fills the screen, ideal for full-screen fragment shader work (raymarching, postprocessing).
357
+ 👉 [Why a triangle?](https://www.cginternals.com/en/blog/2018-01-10-screen-aligned-quads-and-triangles.html)
358
+ 👉 [Use as a post processing mesh](https://medium.com/@luruke/simple-postprocessing-in-three-js-91936ecadfb7)
359
+
360
+ # Abstractions
361
+
362
+ #### Image
363
+
364
+ A shader-based image component with auto-cover (similar to css/background: cover).
365
+
366
+ ```jsx
367
+ function Foo() {
368
+ const ref = useRef()
369
+ useFrame(() => {
370
+ ref.current.material.zoom = ... // 1 and higher
371
+ ref.current.material.grayscale = ... // between 0 and 1
372
+ ref.current.material.color.set(...) // mix-in color
373
+ })
374
+ return <Image ref={ref} url="/file.jpg" />
375
+ ```
376
+
377
+ #### Text
378
+
379
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/abstractions-text--text-st)
380
+
381
+ Hi-quality text rendering w/ signed distance fields (SDF) and antialiasing, using [troika-3d-text](https://github.com/protectwise/troika/tree/master/packages/troika-3d-text). All of troikas props are valid!
382
+
383
+ ```jsx
384
+ <Text color="black" anchorX="center" anchorY="middle">
385
+ hello world!
386
+ </Text>
387
+ ```
388
+
389
+ #### Line
390
+
391
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/abstractions-line--basic-line)
392
+
393
+ Renders a THREE.Line2.
394
+
395
+ ```jsx
396
+ <Line
397
+ points={[[0, 0, 0], ...]} // Array of points
398
+ color="black" // Default
399
+ lineWidth={1} // In pixels (default)
400
+ dashed={false} // Default
401
+ vertexColors={[[0, 0, 0], ...]} // Optional array of RGB values for each point
402
+ {...lineProps} // All THREE.Line2 props are valid
403
+ {...materialProps} // All THREE.LineMaterial props are valid
404
+ />
405
+ ```
406
+
407
+ #### QuadraticBezierLine
408
+
409
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/abstractions-line--quadratic-bezier)
410
+
411
+ Renders a THREE.Line2 using THREE.QuadraticBezierCurve3 for interpolation.
412
+
413
+ ```jsx
414
+ <QuadraticBezierLine
415
+ start={[0, 0, 0]} // Starting point, can be an array or a vec3
416
+ end={[10, 0, 10]} // Ending point, can be an array or a vec3
417
+ mid={[5, 0, 5]} // Optional control point, can be an array or a vec3
418
+ color="black" // Default
419
+ lineWidth={1} // In pixels (default)
420
+ dashed={false} // Default
421
+ vertexColors={[[0, 0, 0], ...]} // Optional array of RGB values for each point
422
+ {...lineProps} // All THREE.Line2 props are valid
423
+ {...materialProps} // All THREE.LineMaterial props are valid
424
+ />
425
+ ```
426
+
427
+ You can also update the line runtime.
428
+
429
+ ```jsx
430
+ const ref = useRef()
431
+ useFrame((state) => {
432
+ ref.current.setPoints(
433
+ [0, 0, 0],
434
+ [10, 0, 0],
435
+ // [5, 0, 0] // Optional: mid-point
436
+ )
437
+ }, [])
438
+ return <QuadraticBezierLine ref={ref} />
439
+ }
440
+ ```
441
+
442
+ #### CubicBezierLine
443
+
444
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/abstractions-line--cubic-bezier)
445
+
446
+ Renders a THREE.Line2 using THREE.CubicBezierCurve3 for interpolation.
447
+
448
+ ```jsx
449
+ <CubicBezierLine
450
+ start={[0, 0, 0]} // Starting point
451
+ end={[10, 0, 10]} // Ending point
452
+ midA={[5, 0, 0]} // First control point
453
+ midB={[0, 0, 5]} // Second control point
454
+ color="black" // Default
455
+ lineWidth={1} // In pixels (default)
456
+ dashed={false} // Default
457
+ vertexColors={[[0, 0, 0], ...]} // Optional array of RGB values for each point
458
+ {...lineProps} // All THREE.Line2 props are valid
459
+ {...materialProps} // All THREE.LineMaterial props are valid
460
+ />
461
+ ```
462
+
463
+ #### PositionalAudio
464
+
465
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/abstractions-positionalaudio--positional-audio-scene-st) ![](https://img.shields.io/badge/-suspense-brightgreen)
466
+
467
+ A wrapper around [THREE.PositionalAudio](https://threejs.org/docs/index.html#api/en/audio/PositionalAudio). Add this to groups or meshes to tie them to a sound that plays when the camera comes near.
468
+
469
+ ```jsx
470
+ <PositionalAudio
471
+ url="/sound.mp3"
472
+ distance={1}
473
+ loop
474
+ {...props} // All THREE.PositionalAudio props are valid
475
+ />
476
+ ```
477
+
478
+ #### Billboard
479
+
480
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/abstractions-billboard--billboard-st)
481
+
482
+ Adds a `<group />` that always faces the camera.
483
+
484
+ ```jsx
485
+ <Billboard
486
+ follow={true}
487
+ lockX={false}
488
+ lockY={false}
489
+ lockZ={false} // Lock the rotation on the z axis (default=false)
490
+ >
491
+ <Text fontSize={1}>I'm a billboard</Text>
492
+ </Billboard>
493
+ ```
494
+
495
+ #### GizmoHelper
496
+
497
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/gizmos-gizmohelper--default-story)
498
+
499
+ Used by widgets that visualize and control camera position.
500
+
501
+ Two example gizmos are included: GizmoViewport and GizmoViewcube, and `useGizmoContext` makes it easy to create your own.
502
+
503
+ Make sure to set the `makeDefault` prop on your controls, in that case you do not have to define the onTarget and onUpdate props.
504
+
505
+ ```jsx
506
+ <GizmoHelper
507
+ alignment="bottom-right" // widget alignment within scene
508
+ margin={[80, 80]} // widget margins (X, Y)
509
+ onUpdate={/* called during camera animation */}
510
+ onTarget={/* return current camera target (e.g. from orbit controls) to center animation */}
511
+ renderPriority={/* use renderPriority to prevent the helper from disappearing if there is another useFrame(..., 1)*/}
512
+ >
513
+ <GizmoViewport axisColors={['red', 'green', 'blue']} labelColor="black" />
514
+ {/* alternative: <GizmoViewcube /> */}
515
+ </GizmoHelper>
516
+ ```
517
+
518
+ #### Effects
519
+
520
+ Abstraction around threes own [EffectComposer](https://threejs.org/docs/index.html#examples/en/postprocessing/EffectComposer).
521
+
522
+ ```jsx
523
+ <Effects multisamping={8} renderIndex={1} disableGamma={false} disableRenderPass={false}>
524
+ <lUTPass attachArray="passes" lut={texture3D} />
525
+ </Effects>
526
+ ```
527
+
528
+ #### GradientTexture
529
+
530
+ A declarative THREE.Texture which attaches to "map" by default. You can use this to create gradient backgrounds.
531
+
532
+ ```jsx
533
+ <mesh>
534
+ <planeGeometry />
535
+ <meshBasicMaterial depthWrite={false}>
536
+ <GradientTexture
537
+ stops={[0, 1]} // As many stops as you want
538
+ colors={['aquamarine', 'hotpink']} // Colors need to match the number of stops
539
+ size={1024} // Size is optional, default = 1024
540
+ />
541
+ </meshBasicMaterial>
542
+ </mesh>
543
+ ```
544
+
545
+ #### useAnimations
546
+
547
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/abstractions-useanimations--use-animations-st)
548
+
549
+ A hook that abstracts [AnimationMixer](https://threejs.org/docs/index.html#api/en/animation/AnimationMixer).
550
+
551
+ ```jsx
552
+ const { nodes, materials, animations } = useGLTF(url)
553
+ const { ref, mixer, names, actions, clips } = useAnimations(animations)
554
+ useEffect(() => {
555
+ actions?.jump.play()
556
+ })
557
+ return (
558
+ <mesh ref={ref} />
559
+ ```
560
+
561
+ The hook can also take a pre-existing root (which can be a plain object3d or a reference to one):
562
+
563
+ ```jsx
564
+ const { scene, animations } = useGLTF(url)
565
+ const { actions } = useAnimations(animations, scene)
566
+ return <primitive object={scene} />
567
+ ```
568
+
569
+ # Shaders
570
+
571
+ #### MeshWobbleMaterial
572
+
573
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/shaders-meshwobblematerial--mesh-wobble-material-st)
574
+
575
+ This material makes your geometry wobble and wave around. It was taken from the [threejs-examples](https://threejs.org/examples/#webgl_materials_modified) and adapted into a self-contained material.
576
+
577
+ ```jsx
578
+ <mesh>
579
+ <boxBufferGeometry attach="geometry" />
580
+ <MeshWobbleMaterial attach="material" factor={1} speed={10} />
581
+ </mesh>
582
+ ```
583
+
584
+ #### MeshDistortMaterial
585
+
586
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/shaders-meshdistortmaterial--mesh-distort-material-st)
587
+
588
+ This material makes your geometry distort following simplex noise.
589
+
590
+ ```jsx
591
+ <mesh>
592
+ <boxBufferGeometry attach="geometry" />
593
+ <MeshDistortMaterial attach="material" distort={1} speed={10} />
594
+ </mesh>
595
+ ```
596
+
597
+ #### PointMaterial
598
+
599
+ An antialiased round dot that always keeps the same size.
600
+
601
+ ```jsx
602
+ <points>
603
+ <PointMaterial scale={20} />
604
+ </points>
605
+ ```
606
+
607
+ #### softShadows
608
+
609
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/shaders-softshadows--soft-shadows-st)
610
+
611
+ Injects [percent closer soft shadows (pcss)](https://threejs.org/examples/?q=pcss#webgl_shadowmap_pcss) into threes shader chunk.
612
+
613
+ ```jsx
614
+ softShadows({
615
+ frustum: 3.75,
616
+ size: 0.005,
617
+ near: 9.5,
618
+ samples: 17,
619
+ rings: 11, // Rings (default: 11) must be a int
620
+ })
621
+ ```
622
+
623
+ #### shaderMaterial
624
+
625
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/shaders-shadermaterial--shader-material-story)
626
+
627
+ Creates a THREE.ShaderMaterial for you with easier handling of uniforms, which are also automatically declared as setter/getters on the object.
628
+
629
+ ```jsx
630
+ import { extend } from 'react-three-fiber'
631
+ import glsl from 'babel-plugin-glsl/macro'
632
+
633
+ const ColorShiftMaterial = shaderMaterial(
634
+ { time: 0, color: new THREE.Color(0.2, 0.0, 0.1) },
635
+ // vertex shader
636
+ glsl`
637
+ varying vec2 vUv;
638
+ void main() {
639
+ vUv = uv;
640
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
641
+ }
642
+ `,
643
+ // fragment shader
644
+ glsl`
645
+ uniform float time;
646
+ uniform vec3 color;
647
+ varying vec2 vUv;
648
+ void main() {
649
+ gl_FragColor.rgba = vec4(0.5 + 0.3 * sin(vUv.yxx + time) + color, 1.0);
650
+ }
651
+ `
652
+ )
653
+
654
+ extend({ ColorShiftMaterial })
655
+
656
+ // in your component
657
+ <mesh>
658
+ <colorShiftMaterial attach="material" color="hotpink" time={1} />
659
+ </mesh>
660
+ ```
661
+
662
+ # Modifiers
663
+
664
+ #### CurveModifier
665
+
666
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/modifiers-curvemodifier)
667
+
668
+ Given a curve will replace the children of this component with a mesh that move along said curve calling the property `moveAlongCurve` on the passed ref. Uses [three's Curve Modifier](https://threejs.org/examples/?q=curve#webgl_modifier_curve)
669
+
670
+ ```jsx
671
+ const curveRef = useRef()
672
+
673
+ const curve = React.useMemo(() => new THREE.CatmullRomCurve3([...handlePos], true, 'centripetal'), [handlePos])
674
+
675
+ return (
676
+ <CurveModifier ref={curveRef} curve={curve}>
677
+ <mesh>
678
+ <boxBufferGeometry args={[10, 10]} />
679
+ </mesh>
680
+ </CurveModifier>
681
+ )
682
+ ```
683
+
684
+ #### useEdgeSplit
685
+
686
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/modifiers-useedgesplit)
687
+
688
+ This hook mutates a mesh geometry using [three's Edge Split modifier](https://threejs.org/examples/?q=modifier#webgl_modifier_edgesplit). The first parameter is the cut-off angle, and the second parameter is a `tryKeepNormals` flag (default `true`).
689
+
690
+ ```jsx
691
+ const meshRef = useEdgeSplit(Math.PI / 2)
692
+
693
+ return (
694
+ <mesh ref={meshRef}>
695
+ <boxBufferGeometry args={[10, 10]} />
696
+ </mesh>
697
+ )
698
+ ```
699
+
700
+ #### useSimplification
701
+
702
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/modifiers-usesimplification)
703
+
704
+ This hook mutates a mesh geometry using [three's Simplification modifier](https://threejs.org/examples/webgl_modifier_simplifier.html).
705
+
706
+ 👉 The simplification code is based on [this algorithm](http://www.melax.com/polychop/).
707
+
708
+ ```jsx
709
+ const meshRef = useSimplification(0.5)
710
+
711
+ return (
712
+ <mesh ref={meshRef}>
713
+ <octahedronBufferGeometry args={[2, 5]} />
714
+ </mesh>
715
+ )
716
+ ```
717
+
718
+ #### useTessellation
719
+
720
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/modifiers-usetessellation)
721
+
722
+ This hook mutates a mesh geometry using [three's Tessellation modifier](https://threejs.org/examples/?q=tess#webgl_modifier_tessellation). It will break-up faces withe edge longer than the maxEdgeLength parameter.
723
+
724
+ ```jsx
725
+ const meshRef = useTessellation(2, 8)
726
+
727
+ return (
728
+ <mesh ref={meshRef}>
729
+ <octahedronBufferGeometry args={[2, 2]} />
730
+ </mesh>
731
+ )
732
+ ```
733
+
734
+ # Misc
735
+
736
+ #### useContextBridge
737
+
738
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/misc-usecontextbridge--use-context-bridge-st)
739
+
740
+ Allows you to forward contexts provided above the `<Canvas />` to be consumed from within the `<Canvas />` normally
741
+
742
+ ```jsx
743
+ function SceneWrapper() {
744
+ // bridge any number of contexts
745
+ // Note: These contexts must be provided by something above this SceneWrapper component
746
+ // You cannot render the providers for these contexts inside this component
747
+ const ContextBridge = useContextBridge(ThemeContext, GreetingContext)
748
+ return (
749
+ <Canvas>
750
+ <ContextBridge>
751
+ <Scene />
752
+ </ContextBridge>
753
+ </Canvas>
754
+ )
755
+ }
756
+
757
+ function Scene() {
758
+ // we can now consume a context within the Canvas
759
+ const theme = React.useContext(ThemeContext)
760
+ const greeting = React.useContext(GreetingContext)
761
+ return (
762
+ //...
763
+ )
764
+ }
765
+ ```
766
+
767
+ #### Html
768
+
769
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-html--html-st) ![](https://img.shields.io/badge/-Dom only-red)
770
+
771
+ Allows you to tie HTML content to any object of your scene. It will be projected to the objects whereabouts automatically.
772
+
773
+ ```jsx
774
+ <Html
775
+ as='div' // Wrapping element (default: 'div')
776
+ prepend // Project content behind the canvas (default: false)
777
+ center // Adds a -50%/-50% css transform (default: false) [ignored in transform mode]
778
+ fullscreen // Aligns to the upper-left corner, fills the screen (default:false) [ignored in transform mode]
779
+ distanceFactor={10} // If set (default: undefined), children will be scaled by this factor, and also by distance to a PerspectiveCamera / zoom by a OrthographicCamera.
780
+ zIndexRange={[100, 0]} // Z-order range (default=[16777271, 0])
781
+ portal={domnodeRef} // Reference to target container (default=undefined)
782
+ transform // If true, applies matrix3d transformations (default=false)
783
+ sprite // Renders as sprite, but only in transform mode (default=false)
784
+ calculatePosition={(el: Object3D, camera: Camera, size: { width: number; height: number }) => number[]} // Override default positioning function. (default=undefined) [ignored in transform mode]
785
+ occlude={[ref]} // Can be true or a Ref<Object3D>[], true occludes the entire scene (default: undefined)
786
+ onOcclude={(visible) => null} // Callback when the visibility changes (default: undefined)
787
+ {...groupProps} // All THREE.Group props are valid
788
+ {...divProps} // All HTMLDivElement props are valid
789
+ >
790
+ <h1>hello</h1>
791
+ <p>world</p>
792
+ </Html>
793
+ ```
794
+
795
+ Html can hide behind geometry using the `occlude` prop.
796
+
797
+ ```jsx
798
+ // Raytrace the entire scene
799
+ <Html occlude />
800
+ // Raytrace only specific elements
801
+ <Html occlude={[ref1, ref2]} />
802
+ ```
803
+
804
+ When the Html object hides it sets the opacity prop on the innermost div. If you want to animate or control the transition yourself then you can use `onOcclude`.
805
+
806
+ ```jsx
807
+ const [hidden, set] = useState()
808
+
809
+ <Html
810
+ occlude
811
+ onOcclude={set}
812
+ style={{
813
+ transition: 'all 0.5s',
814
+ opacity: hidden ? 0 : 1,
815
+ transform: `scale(${hidden ? 0.5 : 1})`
816
+ }} />
817
+ ```
818
+
819
+ #### CycleRaycast
820
+
821
+ This component allows you to cycle through all objects underneath the cursor with optional visual feedback. This can be useful for non-trivial selection, CAD data, housing, everything that has layers. It does this by changing the raycasters filter function and then refreshing the raycaster.
822
+
823
+ For this to work properly your event handler have to call `event.stopPropagation()`, for instance in `onPointerOver` or `onClick`, only one element can be selective for cycling to make sense.
824
+
825
+ ```jsx
826
+ <CycleRaycast
827
+ preventDefault={true} // Call event.preventDefault() (default: true)
828
+ scroll={true} // Wheel events (default: true)
829
+ keyCode={9} // Keyboard events (default: 9 [Tab])
830
+ onChanged={(objects, cycle) => console.log(objects, cycle)} // Optional onChanged event
831
+ />
832
+ ```
833
+
834
+ #### Stats
835
+
836
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-stats--default-story)
837
+
838
+ Adds [stats](https://github.com/mrdoob/stats.js/) to document.body. It takes over the render-loop!
839
+
840
+ ```jsx
841
+ <Stats showPanel={0} className="stats" {...props} />
842
+ ```
843
+
844
+ You can choose to mount Stats to a different DOM Element - for example, for custom styling:
845
+
846
+ ```jsx
847
+ const node = useRef(document.createElement('div'))
848
+
849
+ useEffect(() => {
850
+ node.current.id = 'test'
851
+ document.body.appendChild(node.current)
852
+
853
+ return () => document.body.removeChild(node.current)
854
+ }, [])
855
+
856
+ return <Stats parent={parent} />
857
+ ```
858
+
859
+ #### useDepthBuffer
860
+
861
+ Renders the scene into a depth-buffer. Often effects depend on it and this allows you to render a single buffer and share it, which minimizes the performance impact. It returns the buffer's `depthTexture`.
862
+
863
+ Since this is a rather expensive effect you can limit the amount of frames it renders when your objects are static. For instance making it render only once by setting `frames: 1`.
864
+
865
+ ```jsx
866
+ const depthBuffer = useDepthBuffer({
867
+ size: 256, // Size of the FBO, 256 by default
868
+ frames: Infinity, // How many frames it renders, Infinity by default
869
+ })
870
+ return <SomethingThatNeedsADepthBuffer depthBuffer={depthBuffer} />
871
+ ```
872
+
873
+ #### useFBO
874
+
875
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-usefbo--use-fbo-st)
876
+
877
+ Creates a `THREE.WebGLRenderTarget` or `THREE.WebGLMultisampleRenderTarget`.
878
+
879
+ ```jsx
880
+ const target = useFBO({
881
+ multisample: true,
882
+ stencilBuffer: false,
883
+ })
884
+ ```
885
+
886
+ The rendertarget is automatically disposed when unmounted.
887
+
888
+ #### useCamera
889
+
890
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-usecamera--use-camera-st)
891
+
892
+ A hook for the rare case when you are using non-default cameras for heads-up-displays or portals, and you need events/raytracing to function properly (raycasting uses the default camera otherwise).
893
+
894
+ ```jsx
895
+ <mesh raycast={useCamera(customCamera)} />
896
+ ```
897
+
898
+ #### useHelper
899
+
900
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-usehelper--default-story)
901
+
902
+ A hook for a quick way to add helpers to existing nodes in the scene. It handles removal of the helper on unmount and auto-updates it by default.
903
+
904
+ ```jsx
905
+ const mesh = useRef()
906
+ useHelper(mesh, BoxHelper, 'cyan')
907
+
908
+ <mesh ref={mesh} ... />
909
+ ```
910
+
911
+ #### useDetectGPU
912
+
913
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/misc-usedetectgpu)
914
+
915
+ This hook uses [DetectGPU by @TimvanScherpenzeel](https://github.com/TimvanScherpenzeel/detect-gpu), wrapped into suspense, to determine what tier should be assigned to the user's GPU.
916
+
917
+ 👉 This hook CAN be used outside the react-three-fiber `Canvas`.
918
+
919
+ ```jsx
920
+ function App() {
921
+ const GPUTier = useDetectGPU()
922
+ // show a fallback for mobile or lowest tier GPUs
923
+ return (
924
+ {(GPUTier.tier === "0" || GPUTier.isMobile) ? <Fallback /> : <Canvas>...</Canvas>
925
+
926
+ <Suspense fallback={null}>
927
+ <App />
928
+ ```
929
+
930
+ #### useAspect
931
+
932
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-useaspect--default-story)
933
+
934
+ This hook calculates aspect ratios (for now only what in css would be `image-size: cover` is supported). You can use it to make an image fill the screen. It is responsive and adapts to viewport resize. Just give the hook the image bounds in pixels. It returns an array: `[width, height, 1]`.
935
+
936
+ ```jsx
937
+ const scale = useAspect(
938
+ 1024, // Pixel-width
939
+ 512, // Pixel-height
940
+ 1 // Optional scaling factor
941
+ )
942
+ return (
943
+ <mesh scale={scale}>
944
+ <planeBufferGeometry />
945
+ <meshBasicMaterial map={imageTexture} />
946
+ ```
947
+
948
+ #### useCursor
949
+
950
+ A small hook that sets the css body cursor according to the hover state of a mesh, so that you can give the use visual feedback when the mouse enters a shape. Arguments 1 and 2 determine the style, the defaults are: onPointerOver = 'pointer', onPointerOut = 'auto'.
951
+
952
+ ```jsx
953
+ const [hovered, set] = useState()
954
+ useCursor(hovered, /*'pointer', 'auto'*/)
955
+ return (
956
+ <mesh onPointerOver={() => set(true)} onPointerOut={() => set(false)}>
957
+ ```
958
+
959
+ #### useIntersect
960
+
961
+ A very cheap frustum check that gives you a reference you can observe in order to know if the object has entered the view or is outside of it. This relies on [THREE.Object3D.onBeforeRender](https://threejs.org/docs/index.html?q=obj#api/en/core/Object3D.onBeforeRender) so it only works on objects that are effectively rendered, like meshes, lines, sprites. It won't work on groups, object3d's, bones, etc.
962
+
963
+ ```jsx
964
+ const ref = useIntersect((visible) => console.log('object is visible', visible))
965
+ return <mesh ref={ref} />
966
+ ```
967
+
968
+ # Loading
969
+
970
+ #### Loader
971
+
972
+ ![](https://img.shields.io/badge/-Dom only-red)
973
+
974
+ A quick and easy loading overlay component that you can drop on top of your canvas. It's intended to "hide" the whole app, so if you have multiple suspense wrappers in your application, you should use multiple loaders. It will show an animated loadingbar and a percentage.
975
+
976
+ ```jsx
977
+ <Canvas>
978
+ <Suspense fallback={null}>
979
+ <AsyncModels />
980
+ </Suspense>
981
+ </Canvas>
982
+ <Loader />
983
+ ```
984
+
985
+ You can override styles, too.
986
+
987
+ ```jsx
988
+ <Loader
989
+ containerStyles={...container} // Flex layout styles
990
+ innerStyles={...inner} // Inner container styles
991
+ barStyles={...bar} // Loading-bar styles
992
+ dataStyles={...data} // Text styles
993
+ dataInterpolation={(p) => `Loading ${p.toFixed(2)}%`} // Text
994
+ initialState={(active) => active} // Initial black out state
995
+ >
996
+ ```
997
+
998
+ #### useProgress
999
+
1000
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-useprogress--use-progress-scene-st)
1001
+
1002
+ A convenience hook that wraps `THREE.DefaultLoadingManager`'s progress status.
1003
+
1004
+ ```jsx
1005
+ function Loader() {
1006
+ const { active, progress, errors, item, loaded, total } = useProgress()
1007
+ return <Html center>{progress} % loaded</Html>
1008
+ }
1009
+
1010
+ return (
1011
+ <Suspense fallback={<Loader />}>
1012
+ <AsyncModels />
1013
+ </Suspense>
1014
+ )
1015
+ ```
1016
+
1017
+ If you don't want your progress component to re-render on all changes you can be specific as to what you need, for instance if the component is supposed to collect errors only. Look into [zustand](https://github.com/react-spring/zustand) for more info about selectors.
1018
+
1019
+ ```jsx
1020
+ const errors = useProgress((state) => state.errors)
1021
+ ```
1022
+
1023
+ 👉 Note that your loading component does not have to be a suspense fallback. You can use it anywhere, even in your dom tree, for instance for overlays.
1024
+
1025
+ #### useGLTF
1026
+
1027
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/loaders-gltf)
1028
+
1029
+ A convenience hook that uses `useLoader` and `GLTFLoader`, it defaults to CDN loaded draco binaries (`https://www.gstatic.com/draco/v1/decoders/`) which are only loaded for compressed models.
1030
+
1031
+ ```jsx
1032
+ useGLTF(url)
1033
+
1034
+ useGLTF(url, '/draco-gltf')
1035
+
1036
+ useGLTF.preload(url)
1037
+ ```
1038
+
1039
+ #### useFBX
1040
+
1041
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/loaders-fbx)
1042
+
1043
+ A convenience hook that uses `useLoader` and `FBXLoader`:
1044
+
1045
+ ```jsx
1046
+ useFBX(url)
1047
+
1048
+ function SuzanneFBX() {
1049
+ let fbx = useFBX('suzanne/suzanne.fbx')
1050
+ return <primitive object={fbx} dispose={null} />
1051
+ }
1052
+ ```
1053
+
1054
+ #### useTexture
1055
+
1056
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/loaders-texture)
1057
+
1058
+ A convenience hook that uses `useLoader` and `TextureLoader`
1059
+
1060
+ ```jsx
1061
+ const texture = useTexture(url)
1062
+ const [texture1, texture2] = useTexture([texture1, texture2])
1063
+ ```
1064
+
1065
+ You can also use key: url objects:
1066
+
1067
+ ```jsx
1068
+ const props = useTexture({
1069
+ metalnessMap: url1,
1070
+ map: url2,
1071
+ })
1072
+ return <meshStandardMaterial {...props} />
1073
+ ```
1074
+
1075
+ #### useCubeTexture
1076
+
1077
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/loaders-cubetexture)
1078
+
1079
+ A convenience hook that uses `useLoader` and `CubeTextureLoader`
1080
+
1081
+ ```jsx
1082
+ const envMap = useCubeTexture(['px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png'], { path: 'cube/' })
1083
+ ```
1084
+
1085
+ # Performance
1086
+
1087
+ #### Instances
1088
+
1089
+ A wrapper around [THREE.InstancedMesh](https://threejs.org/docs/index.html?q=instan#api/en/objects/InstancedMesh). This allows you to define hundreds of thousands of objects in a single draw call, but declaratively!
1090
+
1091
+ ```jsx
1092
+ <Instances
1093
+ limit={1000} // Optional: max amount of items (for calculating buffer size)
1094
+ range={1000} // Optional: draw-range
1095
+ >
1096
+ <boxGeometry />
1097
+ <meshStandardMaterial />
1098
+ <Instance
1099
+ color="red"
1100
+ scale={2}
1101
+ position={[1, 2, 3]}
1102
+ rotation={[Math.PI / 3, 0, 0]}
1103
+ onClick={onClick} ... />
1104
+ // As many as you want, make them conditional, mount/unmount them, lazy load them, etc ...
1105
+ </Instances>
1106
+ ```
1107
+
1108
+ You can nest Instances and use relative coordinates!
1109
+
1110
+ ```jsx
1111
+ <group position={[1, 2, 3]} rotation={[Math.PI / 2, 0, 0]}>
1112
+ <Instance />
1113
+ </group>
1114
+ ```
1115
+
1116
+ Instances can also receive non-instanced objects, for instance annotations!
1117
+
1118
+ ```jsx
1119
+ <Instance>
1120
+ <Html>hello from the dom</Html>
1121
+ </Instance>
1122
+ ```
1123
+
1124
+ You can define events on them!
1125
+
1126
+ ```jsx
1127
+ <Instance onClick={...} onPointerOver={...} />
1128
+ ```
1129
+
1130
+ #### Merged
1131
+
1132
+ This creates instances for existing meshes and allows you to use them cheaply in the same scene graph. Each type will cost you exactly one draw call, no matter how many you use. `meshes` has to be a collection of pre-existing THREE.Mesh objects.
1133
+
1134
+ ```jsx
1135
+ <Merged meshes={[box, sphere]}>
1136
+ {(Box, Sphere) => (
1137
+ <>
1138
+ <Box position={[-2, -2, 0]} color="red" />
1139
+ <Box position={[-3, -3, 0]} color="tomato" />
1140
+ <Sphere scale={0.7} position={[2, 1, 0]} color="green" />
1141
+ <Sphere scale={0.7} position={[3, 2, 0]} color="teal" />
1142
+ </>
1143
+ )}
1144
+ </Merged>
1145
+ ```
1146
+
1147
+ You may also use object notation, which is good for loaded models.
1148
+
1149
+ ```jsx
1150
+ function Model({ url }) {
1151
+ const { nodes } = useGLTF(url)
1152
+ return (
1153
+ <Merged meshes={nodes}>
1154
+ {({ Screw, Filter, Pipe }) => (
1155
+ <>
1156
+ <Screw />
1157
+ <Filter position={[1, 2, 3]} />
1158
+ <Pipe position={[4, 5, 6]} />
1159
+ </>
1160
+ )}
1161
+ </Merged>
1162
+ )
1163
+ }
1164
+ ```
1165
+
1166
+ #### Points
1167
+
1168
+ A wrapper around [THREE.Points](https://threejs.org/docs/index.html?q=points#api/en/objects/Points). It has the same api and properties as Instances.
1169
+
1170
+ ```jsx
1171
+ <Points
1172
+ limit={1000} // Optional: max amount of items (for calculating buffer size)
1173
+ range={1000} // Optional: draw-range
1174
+ >
1175
+ <pointsMaterial />
1176
+ <Point position={[1, 2, 3]} color="red" onClick={onClick} onPointerOver={onPointerOver} ... />
1177
+ // As many as you want, make them conditional, mount/unmount them, lazy load them, etc ...
1178
+ </Points>
1179
+ ```
1180
+
1181
+ If you have a material that supports vertex colors (like drei/PointMaterial) you can have individual colors!
1182
+
1183
+ ```jsx
1184
+ <Points>
1185
+ <PointMaterial />
1186
+ <Point color="hotpink" />
1187
+ ```
1188
+
1189
+ Otherwise use any material you like:
1190
+
1191
+ ```jsx
1192
+ <Points>
1193
+ <pointsMaterial vertexColors size={10} />
1194
+ ```
1195
+
1196
+ If you just want to use buffers for position, color and size, you can use the alternative API:
1197
+
1198
+ ```jsx
1199
+ <Points positions={positionsBuffer} colors={colorsBuffer} sizes={sizesBuffer}>
1200
+ <pointsMaterial />
1201
+ </Points>
1202
+ ```
1203
+
1204
+ #### Segments
1205
+
1206
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/performance-segments--many-segments)
1207
+
1208
+ A wrapper around [THREE.LineSegments](https://threejs.org/docs/#api/en/objects/LineSegments). This allows you to use thousands of segments under the same geometry.
1209
+
1210
+ ##### Prop based:
1211
+
1212
+ ```jsx
1213
+ <Segments limit={1000} lineWidth={1.0}>
1214
+ <Segment start={[0, 0, 0]} end={[0, 10, 0]} color="red" />
1215
+ <Segment start={[0, 0, 0]} end={[0, 10, 10]} color={[1, 0, 1]} />
1216
+ </Segments>
1217
+ ```
1218
+
1219
+ ##### Ref based (for fast updates):
1220
+
1221
+ ```jsx
1222
+ const ref = useRef()
1223
+
1224
+ // E.g. to change segment position each frame.
1225
+ useFrame(() => {
1226
+ ref.current.start.set(0,0,0)
1227
+ ref.current.end.set(10,10,0)
1228
+ ref.current.color.setRGB(0,0,0)
1229
+ })
1230
+ // ...
1231
+ <Segments
1232
+ limit={1000}
1233
+ lineWidth={1.0}
1234
+ >
1235
+ <Segment ref={ref} />
1236
+ </Segments>
1237
+ ```
1238
+
1239
+ #### Detailed
1240
+
1241
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/abstractions-detailed--detailed-st)
1242
+
1243
+ A wrapper around [THREE.LOD](https://threejs.org/docs/index.html#api/en/objects/LOD) (Level of detail).
1244
+
1245
+ ```jsx
1246
+ <Detailed distances={[0, 10, 20]} {...props}>
1247
+ <mesh geometry={highDetail} />
1248
+ <mesh geometry={mediumDetail} />
1249
+ <mesh geometry={lowDetail} />
1250
+ </Detailed>
1251
+ ```
1252
+
1253
+ #### Preload
1254
+
1255
+ The WebGLRenderer will compile materials only when they hit the frustrum, which can cause jank. This component precompiles the scene using [gl.compile](https://threejs.org/docs/index.html#api/en/renderers/WebGLRenderer.compile) which makes sure that your app is responsive from the get go.
1256
+
1257
+ By default gl.compile will only preload visible objects, if you supply the `all` prop, it will circumvent that. With the `scene` and `camera` props you could also use it in portals.
1258
+
1259
+ ```jsx
1260
+ <Canvas>
1261
+ <Suspense fallback={null}>
1262
+ <Model />
1263
+ <Preload all />
1264
+ ```
1265
+
1266
+ #### BakeShadows
1267
+
1268
+ Sets `gl.shadowMap.autoUpdate` to `false` while mounted and requests a single `gl.shadowMap.needsUpdate = true` afterwards. This freezes all shadow maps the moment this component comes in, which makes shadows performant again (with the downside that they are now static). Mount this component in lock-step with your models, for instance by dropping it into the same suspense boundary of a model that loads.
1269
+
1270
+ ```jsx
1271
+ <Canvas>
1272
+ <Suspense fallback={null}>
1273
+ <Model />
1274
+ <BakeShadows />
1275
+ ```
1276
+
1277
+ #### meshBounds
1278
+
1279
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-meshbounds--mesh-bounds-st)
1280
+
1281
+ A very fast, but often good-enough bounds-only raycast for meshes. You can use this if performance has precedence over pointer precision.
1282
+
1283
+ ```jsx
1284
+ <mesh raycast={meshBounds} />
1285
+ ```
1286
+
1287
+ #### AdaptiveDpr
1288
+
1289
+ Drop this component into your scene and it will cut the pixel-ratio on [regress](#) according to the canvases perrformance min/max settings. This allows you to temporarily reduce visuals for more performance, for instance when the camera moves (look into drei's controls `regress` flag). Optionally you can set the canvas to a pixelated filter, which would be even faster.
1290
+
1291
+ ```jsx
1292
+ <AdaptiveDpr pixelated />
1293
+ ```
1294
+
1295
+ #### AdaptiveEvents
1296
+
1297
+ Drop this component into your scene and it will switch off the raycaster while the system is in regress.
1298
+
1299
+ ```jsx
1300
+ <AdaptiveEvents />
1301
+ ```
1302
+
1303
+ #### useBVH
1304
+
1305
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/performance-usebvh--default-story)
1306
+
1307
+ A hook to speed up the default raycasting by using the [BVH Implementation by @gkjohnnson](https://github.com/gkjohnson/three-mesh-bvh).
1308
+
1309
+ ```jsx
1310
+ const mesh = useRef()
1311
+ useBVH(mesh)
1312
+
1313
+ <mesh ref={mesh} ... />
1314
+ ```
1315
+
1316
+ # Staging
1317
+
1318
+ #### Center
1319
+
1320
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-center--default-story)
1321
+
1322
+ Calculates a boundary box and centers its children accordingly. `alignTop` makes adjusts it so that it's sits flush on y=0.
1323
+
1324
+ ```jsx
1325
+ <Center alignTop>
1326
+ <mesh />
1327
+ </Center>
1328
+ ```
1329
+
1330
+ #### Bounds
1331
+
1332
+ Calculates a boundary box and centers the camera accordingly. If you are using controls, make sure to pass them the `makeDefault` prop. `fit` fits the current view on first render. `clip` sets the cameras near/far planes.
1333
+
1334
+ ```jsx
1335
+ <Bounds fit clip damping={6} margin={1.2}>
1336
+ <mesh />
1337
+ </Bounds>
1338
+ ```
1339
+
1340
+ The Bounds component also acts as a context provider, use the `useBounds` hook to refresh the bounds, fit the camera, clip near/far planes or focus objects. `refresh(object?: THREE.Object3D | THREE.Box3)` will recalculate bounds, since this can be expensive only call it when you know the view has changed. `clip` sets the cameras near/far planes. `fit` zooms and centers the view.
1341
+
1342
+ ```jsx
1343
+ function Foo() {
1344
+ const bounds = useBounds()
1345
+ useEffect(() => {
1346
+ // Calculate scene bounds
1347
+ bounds.refresh().clip().fit()
1348
+ // Or, focus a specific object or box3
1349
+ // bounds.refresh(ref.current).clip().fit()
1350
+ // bounds.refresh(new THREE.Box3()).clip().fit()
1351
+
1352
+ <Bounds>
1353
+ <Foo />
1354
+ ```
1355
+
1356
+ #### CameraShake
1357
+
1358
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/camera-camerashake--camera-shake-st)
1359
+
1360
+ A component for applying a configurable camera shake effect. Currently only supports rotational camera shake. Pass a ref to recieve the `ShakeController` API.
1361
+
1362
+ If you use shake in combination with controls make sure to set the `makeDefault` prop on your controls, in that case you do not have to pass them via the `controls` prop.
1363
+
1364
+ ```js
1365
+ const config = {
1366
+ maxYaw: 0.1, // Max amount camera can yaw in either direction
1367
+ maxPitch: 0.1, // Max amount camera can pitch in either direction
1368
+ maxRoll: 0.1, // Max amount camera can roll in either direction
1369
+ yawFrequency: 0.1, // Frequency of the the yaw rotation
1370
+ pitchFrequency: 0.1, // Frequency of the pitch rotation
1371
+ rollFrequency: 0.1, // Frequency of the roll rotation
1372
+ intensity: 1, // initial intensity of the shake
1373
+ decay: false, // should the intensity decay over time
1374
+ decayRate: 0.65, // if decay = true this is the rate at which intensity will reduce at
1375
+ controls: undefined, // if using orbit controls, pass a ref here so we can update the rotation
1376
+ }
1377
+
1378
+ ;<CameraShake {...config} />
1379
+ ```
1380
+
1381
+ ```ts
1382
+ interface ShakeController {
1383
+ getIntensity: () => number
1384
+ setIntensity: (val: number) => void
1385
+ }
1386
+ ```
1387
+
1388
+ #### Float
1389
+
1390
+ This component makes its contents float or hover.
1391
+
1392
+ ```js
1393
+ <Float
1394
+ speed={1} // Animation speed, defaults to 1
1395
+ rotationIntensity={1} // XYZ rotation intensity, defaults to 1
1396
+ floatIntensity={1} // Up/down float intensity, defaults to 1
1397
+ >
1398
+ <mesh />
1399
+ </Float>
1400
+ ```
1401
+
1402
+ #### Stage
1403
+
1404
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/prototyping-stage--stage-st)
1405
+
1406
+ Creates a "stage" with proper studio lighting, content centered and planar, shadows and ground-contact shadows.
1407
+
1408
+ Make sure to set the `makeDefault` prop on your controls, in that case you do not need to provide `controls` via prop.
1409
+
1410
+ ```jsx
1411
+ <Stage contactShadow shadows adjustCamera intensity={1} environment="city" preset="rembrandt" controls={controlsRef}>
1412
+ <mesh />
1413
+ </Stage>
1414
+ ```
1415
+
1416
+ #### Backdrop
1417
+
1418
+ A curved plane, like a studio backdrop. This is for presentational purposes, to break up light and shadows more interestingly.
1419
+
1420
+ ```jsx
1421
+ <Backdrop
1422
+ floor={0.25} // Stretches the floor segment, 0.25 by default
1423
+ segments={20} // Mesh-resolution, 20 by default
1424
+ >
1425
+ <meshStandardMaterial color="#353540" />
1426
+ </Backdrop>
1427
+ ```
1428
+
1429
+ #### Shadow
1430
+
1431
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-shadow--shadow-st)
1432
+
1433
+ A cheap canvas-texture-based circular gradient.
1434
+
1435
+ ```jsx
1436
+ <Shadow
1437
+ color="black"
1438
+ colorStop={0}
1439
+ opacity={0.5}
1440
+ fog={false} // Reacts to fog (default=false)
1441
+ />
1442
+ ```
1443
+
1444
+ #### ContactShadows
1445
+
1446
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/shaders-contactshadows--contact-shadow-st)
1447
+
1448
+ A [contact shadow](https://threejs.org/examples/?q=con#webgl_shadow_contact) implementation, facing upwards (positive Y) by default. `scale` can be a positive number or a 2D array `[x: number, y: number]`.
1449
+
1450
+ ```jsx
1451
+ <ContactShadows opacity={1} scale={10} blur={1} far={10} resolution={256} />
1452
+ ```
1453
+
1454
+ Since this is a rather expensive effect you can limit the amount of frames it renders when your objects are static. For instance making it render only once:
1455
+
1456
+ ```jsx
1457
+ <ContactShadows frames={1} />
1458
+ ```
1459
+
1460
+ #### SpotLight
1461
+
1462
+ A Volumetric spotlight.
1463
+
1464
+ ```jsx
1465
+ <SpotLight
1466
+ distance={5}
1467
+ angle={0.15}
1468
+ attenuation={5}
1469
+ anglePower={5} // Diffuse-cone anglePower (default: 5)
1470
+ />
1471
+ ```
1472
+
1473
+ Optionally you can provide a depth-buffer which converts the spotlight into a soft particle.
1474
+
1475
+ ```jsx
1476
+ function Foo() {
1477
+ const depthBuffer = useDepthBuffer()
1478
+ return <SpotLight depthBuffer={depthBuffer} />
1479
+ ```
1480
+
1481
+ #### Reflector
1482
+
1483
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/misc-reflector--reflector-st)
1484
+
1485
+ Easily add reflections and/or blur to a planar surface. This reflector can also blur and takes surface roughness into account for a more realistic effect.
1486
+
1487
+ ```jsx
1488
+ <Reflector
1489
+ args={[1, 1]} // PlaneBufferGeometry arguments
1490
+ blur={[0, 0]} // Blur ground reflections (width, heigt), 0 skips blur
1491
+ mixBlur={1.0} // How much blur mixes with surface roughness (default = 0), note that this can affect performance
1492
+ mixStrength={0.5} // Strength of the reflections
1493
+ resolution={256} // Off-buffer resolution, lower=faster, higher=better quality
1494
+ mirror={0.5} // Mirror environment, 0 = texture colors, 1 = pick up env colors
1495
+ depthScale={1} // Scale the depth factor (0 = no depth, default = 0)
1496
+ minDepthThreshold={0.9} // Lower edge for the depthTexture interpolation (default = 0)
1497
+ maxDepthThreshold={1} // Upper edge for the depthTexture interpolation (default = 0)
1498
+ depthToBlurRatioBias={0.25} // Adds a bias factor to the depthTexture before calculating the blur amount [blurFactor = blurTexture * (depthTexture + bias)]. It accepts values between 0 and 1, default is 0.25. An amount > 0 of bias makes sure that the blurTexture is not too sharp because of the multiplication with the depthTexture
1499
+ distortion={0} // Amount of distortion based on the distortionMap texture
1500
+ distortionMap={distortionTexture} // The red channel of this texture is used as the distortion map. Default is null
1501
+ debug={0} /* Depending on the assigned value, one of the following channels is shown:
1502
+ 0 = no debug
1503
+ 1 = depth channel
1504
+ 2 = base channel
1505
+ 3 = distortion channel
1506
+ 4 = lod channel (based on the roughness)
1507
+ */
1508
+ >
1509
+ {(Material, props) => <Material {...props}>}
1510
+ </Reflector>
1511
+ ```
1512
+
1513
+ #### Environment
1514
+
1515
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/abstractions-environment--environment-st)
1516
+
1517
+ Sets up a global cubemap, which affects the default `scene.environment`, and optionally `scene.background`, unless a custom scene has been passed. A selection of [presets](src/helpers/environment-assets.ts) from [HDRI Haven](https://hdrihaven.com/) are available for convenience. If you pass an array of files it will use THREE.CubeTextureLoader.
1518
+
1519
+ ```jsx
1520
+ <Environment
1521
+ background={false}
1522
+ files={['px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png']}
1523
+ path="/"
1524
+ preset={null}
1525
+ scene={undefined} // adds the ability to pass a custom THREE.Scene
1526
+ />
1527
+ ```
1528
+
1529
+ If you provide a single string it will use THREE.RGBELoader.
1530
+
1531
+ ```jsx
1532
+ <Environment files="file.hdr" />
1533
+ ```
1534
+
1535
+ #### Sky
1536
+
1537
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/shaders-sky--sky-st)
1538
+
1539
+ Adds a [sky](https://threejs.org/examples/webgl_shaders_sky.html) to your scene.
1540
+
1541
+ ```jsx
1542
+ <Sky distance={450000} sunPosition={[0, 1, 0]} inclination={0} azimuth={0.25} {...props} />
1543
+ ```
1544
+
1545
+ #### Stars
1546
+
1547
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.vercel.app/?path=/story/shaders-stars--stars-st)
1548
+
1549
+ Adds a blinking shader-based starfield to your scene.
1550
+
1551
+ ```jsx
1552
+ <Stars radius={100} depth={50} count={5000} factor={4} saturation={0} fade />
1553
+ ```
1554
+
1555
+ #### Cloud
1556
+
1557
+ Particle based cloud.
1558
+
1559
+ ```jsx
1560
+ <Cloud
1561
+ opacity={0.5}
1562
+ speed={0.4} // Rotation speed
1563
+ width={10} // Width of the full cloud
1564
+ depth={1.5} // Z-dir depth
1565
+ segments={20} // Number of particles
1566
+ />
1567
+ ```
1568
+
1569
+ #### useMatcapTexture
1570
+
1571
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/prototyping-usematcaptexture) ![](https://img.shields.io/badge/-suspense-brightgreen)
1572
+
1573
+ Loads matcap textures from this repository: https://github.com/emmelleppi/matcaps
1574
+
1575
+ (It is a fork of this repository: https://github.com/nidorx/matcaps)
1576
+
1577
+ ```jsx
1578
+ const [matcap, url] = useMatcapTexture(
1579
+ 0, // index of the matcap texture https://github.com/emmelleppi/matcaps/blob/master/matcap-list.json
1580
+ 1024 // size of the texture ( 64, 128, 256, 512, 1024 )
1581
+ )
1582
+
1583
+ return (
1584
+ ...
1585
+ <meshMatcapMaterial matcap={matcap} />
1586
+ ...
1587
+ )
1588
+ ```
1589
+
1590
+ 👉 You can also use the exact name of the matcap texture, like so:
1591
+
1592
+ ```jsx
1593
+ const [matcap] = useMatcapTexture('3E2335_D36A1B_8E4A2E_2842A5')
1594
+ ```
1595
+
1596
+ 👉 Use the `url` to download the texture when you are ready for production!
1597
+
1598
+ #### useNormalTexture
1599
+
1600
+ [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.pmnd.rs/?path=/story/prototyping-usenormaltexture) ![](https://img.shields.io/badge/-suspense-brightgreen)
1601
+
1602
+ Loads normal textures from this repository: https://github.com/emmelleppi/normal-maps
1603
+
1604
+ ```jsx
1605
+ const [normalMap, url] = useNormalTexture(
1606
+ 1, // index of the normal texture - https://github.com/emmelleppi/normal-maps/blob/master/normals.json
1607
+ // second argument is texture attributes
1608
+ {
1609
+ offset: [0, 0],
1610
+ repeat: [normRepeat, normRepeat],
1611
+ anisotropy: 8
1612
+ }
1613
+ )
1614
+
1615
+ return (
1616
+ ...
1617
+ <meshStandardMaterial normalMap={normalMap} />
1618
+ ...
1619
+ )
1620
+ ```