@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.
@@ -0,0 +1,874 @@
1
+ # React Three Fiber Shaders
2
+
3
+ ## Quick Start
4
+
5
+ ```tsx
6
+ import { Canvas, useFrame, extend } from '@react-three/fiber'
7
+ import { shaderMaterial } from '@react-three/drei'
8
+ import { useRef } from 'react'
9
+ import * as THREE from 'three'
10
+
11
+ // Create custom shader material
12
+ const ColorShiftMaterial = shaderMaterial(
13
+ // Uniforms
14
+ { time: 0, color: new THREE.Color(0.2, 0.0, 0.1) },
15
+ // Vertex shader
16
+ `
17
+ varying vec2 vUv;
18
+ void main() {
19
+ vUv = uv;
20
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
21
+ }
22
+ `,
23
+ // Fragment shader
24
+ `
25
+ uniform float time;
26
+ uniform vec3 color;
27
+ varying vec2 vUv;
28
+ void main() {
29
+ gl_FragColor = vec4(vUv.x + sin(time), vUv.y + cos(time), color.b, 1.0);
30
+ }
31
+ `
32
+ )
33
+
34
+ // Extend so it can be used as JSX
35
+ extend({ ColorShiftMaterial })
36
+
37
+ function ShaderMesh() {
38
+ const materialRef = useRef()
39
+
40
+ useFrame(({ clock }) => {
41
+ materialRef.current.time = clock.elapsedTime
42
+ })
43
+
44
+ return (
45
+ <mesh>
46
+ <planeGeometry args={[2, 2]} />
47
+ {/* key={Material.key} enables HMR for shader development */}
48
+ <colorShiftMaterial ref={materialRef} key={ColorShiftMaterial.key} />
49
+ </mesh>
50
+ )
51
+ }
52
+
53
+ export default function App() {
54
+ return (
55
+ <Canvas>
56
+ <ShaderMesh />
57
+ </Canvas>
58
+ )
59
+ }
60
+ ```
61
+
62
+ ## shaderMaterial (Drei)
63
+
64
+ The recommended way to create shader materials in R3F.
65
+
66
+ ### Basic Pattern
67
+
68
+ ```tsx
69
+ import { shaderMaterial } from '@react-three/drei'
70
+ import { extend } from '@react-three/fiber'
71
+ import * as THREE from 'three'
72
+
73
+ // 1. Define the material
74
+ const MyShaderMaterial = shaderMaterial(
75
+ // Uniforms object
76
+ {
77
+ time: 0,
78
+ color: new THREE.Color(1, 0, 0),
79
+ opacity: 1,
80
+ map: null,
81
+ },
82
+ // Vertex shader (GLSL)
83
+ `
84
+ varying vec2 vUv;
85
+ varying vec3 vPosition;
86
+
87
+ void main() {
88
+ vUv = uv;
89
+ vPosition = position;
90
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
91
+ }
92
+ `,
93
+ // Fragment shader (GLSL)
94
+ `
95
+ uniform float time;
96
+ uniform vec3 color;
97
+ uniform float opacity;
98
+ uniform sampler2D map;
99
+ varying vec2 vUv;
100
+
101
+ void main() {
102
+ vec4 texColor = texture2D(map, vUv);
103
+ gl_FragColor = vec4(color * texColor.rgb, opacity);
104
+ }
105
+ `
106
+ )
107
+
108
+ // 2. Extend R3F
109
+ extend({ MyShaderMaterial })
110
+
111
+ // 3. Use in component
112
+ function MyMesh() {
113
+ const materialRef = useRef()
114
+
115
+ useFrame(({ clock }) => {
116
+ materialRef.current.time = clock.elapsedTime
117
+ })
118
+
119
+ return (
120
+ <mesh>
121
+ <boxGeometry />
122
+ {/* key prop enables Hot Module Replacement during development */}
123
+ <myShaderMaterial
124
+ ref={materialRef}
125
+ key={MyShaderMaterial.key}
126
+ color="hotpink"
127
+ transparent
128
+ opacity={0.8}
129
+ />
130
+ </mesh>
131
+ )
132
+ }
133
+ ```
134
+
135
+ ### Hot Module Replacement (HMR)
136
+
137
+ The `key` prop on shaderMaterial enables live shader editing without page refresh:
138
+
139
+ ```tsx
140
+ const MyMaterial = shaderMaterial(
141
+ { time: 0 },
142
+ vertexShader,
143
+ fragmentShader
144
+ )
145
+
146
+ extend({ MyMaterial })
147
+
148
+ // MyMaterial.key changes when shader code changes
149
+ <myMaterial key={MyMaterial.key} />
150
+ ```
151
+
152
+ When you edit shader code, the material automatically updates. Without `key`, you'd need to refresh the page to see changes.
153
+
154
+ ### TypeScript Support
155
+
156
+ ```tsx
157
+ import { shaderMaterial } from '@react-three/drei'
158
+ import { extend, Object3DNode } from '@react-three/fiber'
159
+ import * as THREE from 'three'
160
+
161
+ // Define uniform types
162
+ type WaveMaterialUniforms = {
163
+ time: number
164
+ amplitude: number
165
+ color: THREE.Color
166
+ }
167
+
168
+ const WaveMaterial = shaderMaterial(
169
+ {
170
+ time: 0,
171
+ amplitude: 0.5,
172
+ color: new THREE.Color('hotpink'),
173
+ } as WaveMaterialUniforms,
174
+ // vertex shader
175
+ `...`,
176
+ // fragment shader
177
+ `...`
178
+ )
179
+
180
+ // Extend with proper types
181
+ extend({ WaveMaterial })
182
+
183
+ // Declare for TypeScript
184
+ declare module '@react-three/fiber' {
185
+ interface ThreeElements {
186
+ waveMaterial: Object3DNode<
187
+ typeof WaveMaterial & THREE.ShaderMaterial,
188
+ typeof WaveMaterial
189
+ >
190
+ }
191
+ }
192
+ ```
193
+
194
+ ## Raw THREE.ShaderMaterial
195
+
196
+ For full control without Drei helper.
197
+
198
+ ```tsx
199
+ import { useFrame } from '@react-three/fiber'
200
+ import { useMemo, useRef } from 'react'
201
+ import * as THREE from 'three'
202
+
203
+ function CustomShaderMesh() {
204
+ const materialRef = useRef()
205
+
206
+ const shaderMaterial = useMemo(() => {
207
+ return new THREE.ShaderMaterial({
208
+ uniforms: {
209
+ time: { value: 0 },
210
+ color: { value: new THREE.Color('cyan') },
211
+ resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
212
+ },
213
+ vertexShader: `
214
+ varying vec2 vUv;
215
+ void main() {
216
+ vUv = uv;
217
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
218
+ }
219
+ `,
220
+ fragmentShader: `
221
+ uniform float time;
222
+ uniform vec3 color;
223
+ uniform vec2 resolution;
224
+ varying vec2 vUv;
225
+
226
+ void main() {
227
+ vec2 st = gl_FragCoord.xy / resolution;
228
+ float pattern = sin(st.x * 20.0 + time) * sin(st.y * 20.0 + time);
229
+ gl_FragColor = vec4(color * pattern, 1.0);
230
+ }
231
+ `,
232
+ side: THREE.DoubleSide,
233
+ transparent: true,
234
+ })
235
+ }, [])
236
+
237
+ useFrame(({ clock }) => {
238
+ shaderMaterial.uniforms.time.value = clock.elapsedTime
239
+ })
240
+
241
+ return (
242
+ <mesh material={shaderMaterial}>
243
+ <planeGeometry args={[4, 4, 32, 32]} />
244
+ </mesh>
245
+ )
246
+ }
247
+ ```
248
+
249
+ ## Uniforms
250
+
251
+ ### Common Uniform Types
252
+
253
+ ```tsx
254
+ const MyMaterial = shaderMaterial(
255
+ {
256
+ // Numbers
257
+ time: 0,
258
+ intensity: 1.5,
259
+
260
+ // Vectors
261
+ resolution: new THREE.Vector2(1920, 1080),
262
+ lightPosition: new THREE.Vector3(5, 10, 5),
263
+ bounds: new THREE.Vector4(0, 0, 1, 1),
264
+
265
+ // Color (becomes vec3)
266
+ color: new THREE.Color('#ff0000'),
267
+
268
+ // Matrices
269
+ customMatrix: new THREE.Matrix4(),
270
+
271
+ // Textures
272
+ map: null, // sampler2D
273
+ cubeMap: null, // samplerCube
274
+
275
+ // Arrays
276
+ positions: [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()],
277
+ },
278
+ vertexShader,
279
+ fragmentShader
280
+ )
281
+ ```
282
+
283
+ ### GLSL Declarations
284
+
285
+ ```glsl
286
+ // In shader code
287
+ uniform float time;
288
+ uniform float intensity;
289
+ uniform vec2 resolution;
290
+ uniform vec3 lightPosition;
291
+ uniform vec3 color; // THREE.Color becomes vec3
292
+ uniform vec4 bounds;
293
+ uniform mat4 customMatrix;
294
+ uniform sampler2D map;
295
+ uniform samplerCube cubeMap;
296
+ uniform vec3 positions[3];
297
+ ```
298
+
299
+ ### Updating Uniforms
300
+
301
+ ```tsx
302
+ function AnimatedShader() {
303
+ const materialRef = useRef()
304
+
305
+ useFrame(({ clock, mouse, viewport }) => {
306
+ // Direct value update
307
+ materialRef.current.time = clock.elapsedTime
308
+
309
+ // Vector update
310
+ materialRef.current.resolution.set(viewport.width, viewport.height)
311
+
312
+ // Color update
313
+ materialRef.current.color.setHSL((clock.elapsedTime * 0.1) % 1, 1, 0.5)
314
+
315
+ // Or via uniforms object (for THREE.ShaderMaterial)
316
+ // materialRef.current.uniforms.time.value = clock.elapsedTime
317
+ })
318
+
319
+ return (
320
+ <mesh>
321
+ <boxGeometry />
322
+ <myShaderMaterial ref={materialRef} />
323
+ </mesh>
324
+ )
325
+ }
326
+ ```
327
+
328
+ ## Varyings
329
+
330
+ Pass data from vertex to fragment shader.
331
+
332
+ ```glsl
333
+ // Vertex shader
334
+ varying vec2 vUv;
335
+ varying vec3 vNormal;
336
+ varying vec3 vPosition;
337
+ varying vec3 vWorldPosition;
338
+
339
+ void main() {
340
+ vUv = uv;
341
+ vNormal = normalize(normalMatrix * normal);
342
+ vPosition = position;
343
+ vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
344
+
345
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
346
+ }
347
+
348
+ // Fragment shader
349
+ varying vec2 vUv;
350
+ varying vec3 vNormal;
351
+ varying vec3 vPosition;
352
+ varying vec3 vWorldPosition;
353
+
354
+ void main() {
355
+ // Use interpolated values
356
+ gl_FragColor = vec4(vNormal * 0.5 + 0.5, 1.0);
357
+ }
358
+ ```
359
+
360
+ ## Common Shader Patterns
361
+
362
+ ### Texture Sampling
363
+
364
+ ```tsx
365
+ import { useTexture } from '@react-three/drei'
366
+
367
+ function TexturedShaderMesh() {
368
+ const texture = useTexture('/textures/color.jpg')
369
+ const materialRef = useRef()
370
+
371
+ return (
372
+ <mesh>
373
+ <planeGeometry args={[2, 2]} />
374
+ <myShaderMaterial ref={materialRef} map={texture} />
375
+ </mesh>
376
+ )
377
+ }
378
+
379
+ // Shader
380
+ const TextureMaterial = shaderMaterial(
381
+ { map: null },
382
+ `
383
+ varying vec2 vUv;
384
+ void main() {
385
+ vUv = uv;
386
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
387
+ }
388
+ `,
389
+ `
390
+ uniform sampler2D map;
391
+ varying vec2 vUv;
392
+
393
+ void main() {
394
+ vec4 texColor = texture2D(map, vUv);
395
+ gl_FragColor = texColor;
396
+ }
397
+ `
398
+ )
399
+ ```
400
+
401
+ ### Vertex Displacement
402
+
403
+ ```tsx
404
+ const WaveMaterial = shaderMaterial(
405
+ { time: 0, amplitude: 0.5, frequency: 2.0 },
406
+ `
407
+ uniform float time;
408
+ uniform float amplitude;
409
+ uniform float frequency;
410
+ varying vec2 vUv;
411
+
412
+ void main() {
413
+ vUv = uv;
414
+ vec3 pos = position;
415
+
416
+ // Wave displacement
417
+ pos.z += sin(pos.x * frequency + time) * amplitude;
418
+ pos.z += sin(pos.y * frequency + time) * amplitude;
419
+
420
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
421
+ }
422
+ `,
423
+ `
424
+ varying vec2 vUv;
425
+ void main() {
426
+ gl_FragColor = vec4(vUv, 1.0, 1.0);
427
+ }
428
+ `
429
+ )
430
+
431
+ extend({ WaveMaterial })
432
+
433
+ function WavePlane() {
434
+ const ref = useRef()
435
+
436
+ useFrame(({ clock }) => {
437
+ ref.current.time = clock.elapsedTime
438
+ })
439
+
440
+ return (
441
+ <mesh rotation={[-Math.PI / 2, 0, 0]}>
442
+ <planeGeometry args={[10, 10, 64, 64]} />
443
+ <waveMaterial ref={ref} />
444
+ </mesh>
445
+ )
446
+ }
447
+ ```
448
+
449
+ ### Fresnel Effect
450
+
451
+ ```tsx
452
+ const FresnelMaterial = shaderMaterial(
453
+ { fresnelColor: new THREE.Color('cyan'), baseColor: new THREE.Color('navy') },
454
+ `
455
+ varying vec3 vNormal;
456
+ varying vec3 vWorldPosition;
457
+
458
+ void main() {
459
+ vNormal = normalize(normalMatrix * normal);
460
+ vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;
461
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
462
+ }
463
+ `,
464
+ `
465
+ uniform vec3 fresnelColor;
466
+ uniform vec3 baseColor;
467
+ varying vec3 vNormal;
468
+ varying vec3 vWorldPosition;
469
+
470
+ void main() {
471
+ vec3 viewDirection = normalize(cameraPosition - vWorldPosition);
472
+ float fresnel = pow(1.0 - dot(viewDirection, vNormal), 3.0);
473
+
474
+ gl_FragColor = vec4(mix(baseColor, fresnelColor, fresnel), 1.0);
475
+ }
476
+ `
477
+ )
478
+ ```
479
+
480
+ ### Noise Functions
481
+
482
+ ```glsl
483
+ // Simple random
484
+ float random(vec2 st) {
485
+ return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);
486
+ }
487
+
488
+ // Value noise
489
+ float noise(vec2 st) {
490
+ vec2 i = floor(st);
491
+ vec2 f = fract(st);
492
+
493
+ float a = random(i);
494
+ float b = random(i + vec2(1.0, 0.0));
495
+ float c = random(i + vec2(0.0, 1.0));
496
+ float d = random(i + vec2(1.0, 1.0));
497
+
498
+ vec2 u = f * f * (3.0 - 2.0 * f);
499
+
500
+ return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
501
+ }
502
+
503
+ // FBM (Fractal Brownian Motion)
504
+ float fbm(vec2 st) {
505
+ float value = 0.0;
506
+ float amplitude = 0.5;
507
+
508
+ for (int i = 0; i < 5; i++) {
509
+ value += amplitude * noise(st);
510
+ st *= 2.0;
511
+ amplitude *= 0.5;
512
+ }
513
+
514
+ return value;
515
+ }
516
+ ```
517
+
518
+ ### Gradient
519
+
520
+ ```glsl
521
+ // Linear gradient
522
+ vec3 gradient = mix(colorA, colorB, vUv.y);
523
+
524
+ // Radial gradient
525
+ float dist = distance(vUv, vec2(0.5));
526
+ vec3 radial = mix(centerColor, edgeColor, dist * 2.0);
527
+
528
+ // Smooth gradient
529
+ float t = smoothstep(0.0, 1.0, vUv.y);
530
+ vec3 smooth = mix(colorA, colorB, t);
531
+ ```
532
+
533
+ ### Dissolve Effect
534
+
535
+ ```tsx
536
+ const DissolveMaterial = shaderMaterial(
537
+ { progress: 0, noiseScale: 10.0, edgeColor: new THREE.Color('orange') },
538
+ `
539
+ varying vec2 vUv;
540
+ void main() {
541
+ vUv = uv;
542
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
543
+ }
544
+ `,
545
+ `
546
+ uniform float progress;
547
+ uniform float noiseScale;
548
+ uniform vec3 edgeColor;
549
+ varying vec2 vUv;
550
+
551
+ float random(vec2 st) {
552
+ return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453);
553
+ }
554
+
555
+ float noise(vec2 st) {
556
+ vec2 i = floor(st);
557
+ vec2 f = fract(st);
558
+ float a = random(i);
559
+ float b = random(i + vec2(1.0, 0.0));
560
+ float c = random(i + vec2(0.0, 1.0));
561
+ float d = random(i + vec2(1.0, 1.0));
562
+ vec2 u = f * f * (3.0 - 2.0 * f);
563
+ return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
564
+ }
565
+
566
+ void main() {
567
+ float n = noise(vUv * noiseScale);
568
+
569
+ if (n < progress) {
570
+ discard;
571
+ }
572
+
573
+ float edge = smoothstep(progress, progress + 0.1, n);
574
+ vec3 baseColor = vec3(0.5);
575
+
576
+ gl_FragColor = vec4(mix(edgeColor, baseColor, edge), 1.0);
577
+ }
578
+ `
579
+ )
580
+ ```
581
+
582
+ ## Extending Built-in Materials
583
+
584
+ ### onBeforeCompile
585
+
586
+ Modify existing material shaders.
587
+
588
+ ```tsx
589
+ import { useRef, useEffect } from 'react'
590
+ import { useFrame } from '@react-three/fiber'
591
+ import * as THREE from 'three'
592
+
593
+ function ModifiedStandardMaterial() {
594
+ const materialRef = useRef()
595
+ const shaderRef = useRef()
596
+
597
+ useEffect(() => {
598
+ if (materialRef.current) {
599
+ materialRef.current.onBeforeCompile = (shader) => {
600
+ // Add custom uniform
601
+ shader.uniforms.time = { value: 0 }
602
+ shaderRef.current = shader
603
+
604
+ // Add uniform declaration
605
+ shader.vertexShader = 'uniform float time;\n' + shader.vertexShader
606
+
607
+ // Modify vertex shader
608
+ shader.vertexShader = shader.vertexShader.replace(
609
+ '#include <begin_vertex>',
610
+ `
611
+ #include <begin_vertex>
612
+ transformed.y += sin(position.x * 10.0 + time) * 0.1;
613
+ `
614
+ )
615
+ }
616
+ }
617
+ }, [])
618
+
619
+ useFrame(({ clock }) => {
620
+ if (shaderRef.current) {
621
+ shaderRef.current.uniforms.time.value = clock.elapsedTime
622
+ }
623
+ })
624
+
625
+ return (
626
+ <mesh>
627
+ <planeGeometry args={[5, 5, 32, 32]} />
628
+ <meshStandardMaterial ref={materialRef} color="green" />
629
+ </mesh>
630
+ )
631
+ }
632
+ ```
633
+
634
+ ### Common Injection Points
635
+
636
+ ```javascript
637
+ // Vertex shader chunks
638
+ '#include <begin_vertex>' // After position is calculated
639
+ '#include <project_vertex>' // After gl_Position
640
+ '#include <beginnormal_vertex>' // Normal calculation start
641
+
642
+ // Fragment shader chunks
643
+ '#include <color_fragment>' // After diffuse color
644
+ '#include <output_fragment>' // Final output
645
+ '#include <fog_fragment>' // After fog applied
646
+ ```
647
+
648
+ ## GLSL Built-in Functions
649
+
650
+ ### Math Functions
651
+
652
+ ```glsl
653
+ // Basic
654
+ abs(x), sign(x), floor(x), ceil(x), fract(x)
655
+ mod(x, y), min(x, y), max(x, y), clamp(x, min, max)
656
+ mix(a, b, t), step(edge, x), smoothstep(edge0, edge1, x)
657
+
658
+ // Trigonometry
659
+ sin(x), cos(x), tan(x)
660
+ asin(x), acos(x), atan(y, x), atan(x)
661
+
662
+ // Exponential
663
+ pow(x, y), exp(x), log(x), sqrt(x)
664
+ ```
665
+
666
+ ### Vector Functions
667
+
668
+ ```glsl
669
+ length(v), distance(p0, p1), dot(x, y), cross(x, y)
670
+ normalize(v), reflect(I, N), refract(I, N, eta)
671
+ ```
672
+
673
+ ## Instanced Shaders
674
+
675
+ ```tsx
676
+ import { useRef, useMemo } from 'react'
677
+ import { useFrame } from '@react-three/fiber'
678
+ import * as THREE from 'three'
679
+
680
+ function InstancedShaderMesh({ count = 1000 }) {
681
+ const meshRef = useRef()
682
+
683
+ // Create instance attributes
684
+ const { offsets, colors } = useMemo(() => {
685
+ const offsets = new Float32Array(count * 3)
686
+ const colors = new Float32Array(count * 3)
687
+
688
+ for (let i = 0; i < count; i++) {
689
+ offsets[i * 3] = (Math.random() - 0.5) * 20
690
+ offsets[i * 3 + 1] = (Math.random() - 0.5) * 20
691
+ offsets[i * 3 + 2] = (Math.random() - 0.5) * 20
692
+
693
+ colors[i * 3] = Math.random()
694
+ colors[i * 3 + 1] = Math.random()
695
+ colors[i * 3 + 2] = Math.random()
696
+ }
697
+
698
+ return { offsets, colors }
699
+ }, [count])
700
+
701
+ const shaderMaterial = useMemo(() => {
702
+ return new THREE.ShaderMaterial({
703
+ uniforms: {
704
+ time: { value: 0 }
705
+ },
706
+ vertexShader: `
707
+ attribute vec3 offset;
708
+ attribute vec3 instanceColor;
709
+ varying vec3 vColor;
710
+
711
+ void main() {
712
+ vColor = instanceColor;
713
+ vec3 pos = position + offset;
714
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
715
+ }
716
+ `,
717
+ fragmentShader: `
718
+ varying vec3 vColor;
719
+
720
+ void main() {
721
+ gl_FragColor = vec4(vColor, 1.0);
722
+ }
723
+ `
724
+ })
725
+ }, [])
726
+
727
+ useFrame(({ clock }) => {
728
+ shaderMaterial.uniforms.time.value = clock.elapsedTime
729
+ })
730
+
731
+ return (
732
+ <instancedMesh ref={meshRef} args={[null, null, count]} material={shaderMaterial}>
733
+ <boxGeometry args={[0.5, 0.5, 0.5]}>
734
+ <instancedBufferAttribute attach="attributes-offset" args={[offsets, 3]} />
735
+ <instancedBufferAttribute attach="attributes-instanceColor" args={[colors, 3]} />
736
+ </boxGeometry>
737
+ </instancedMesh>
738
+ )
739
+ }
740
+ ```
741
+
742
+ ## External Shader Files
743
+
744
+ ### With Vite/Webpack
745
+
746
+ ```tsx
747
+ // shaders/vertex.glsl
748
+ varying vec2 vUv;
749
+ void main() {
750
+ vUv = uv;
751
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
752
+ }
753
+
754
+ // shaders/fragment.glsl
755
+ uniform float time;
756
+ varying vec2 vUv;
757
+ void main() {
758
+ gl_FragColor = vec4(vUv, sin(time), 1.0);
759
+ }
760
+
761
+ // Component.tsx
762
+ import vertexShader from './shaders/vertex.glsl?raw'
763
+ import fragmentShader from './shaders/fragment.glsl?raw'
764
+
765
+ const MyMaterial = shaderMaterial(
766
+ { time: 0 },
767
+ vertexShader,
768
+ fragmentShader
769
+ )
770
+ ```
771
+
772
+ ### Vite Config for GLSL
773
+
774
+ ```javascript
775
+ // vite.config.js
776
+ import glsl from 'vite-plugin-glsl'
777
+
778
+ export default {
779
+ plugins: [glsl()]
780
+ }
781
+ ```
782
+
783
+ ## Material Properties
784
+
785
+ ```tsx
786
+ <myShaderMaterial
787
+ // Rendering
788
+ transparent={true}
789
+ opacity={1.0}
790
+ side={THREE.DoubleSide}
791
+ depthTest={true}
792
+ depthWrite={true}
793
+
794
+ // Blending
795
+ blending={THREE.NormalBlending}
796
+ // NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending
797
+
798
+ // Wireframe
799
+ wireframe={false}
800
+
801
+ // Custom uniforms
802
+ time={0}
803
+ color="hotpink"
804
+ />
805
+ ```
806
+
807
+ ## Debugging Shaders
808
+
809
+ ```tsx
810
+ function DebugShaderMesh() {
811
+ const materialRef = useRef()
812
+
813
+ useEffect(() => {
814
+ // Log compiled shaders
815
+ if (materialRef.current) {
816
+ console.log('Vertex:', materialRef.current.vertexShader)
817
+ console.log('Fragment:', materialRef.current.fragmentShader)
818
+ }
819
+ }, [])
820
+
821
+ return (
822
+ <mesh>
823
+ <boxGeometry />
824
+ {/* Debug with visual output */}
825
+ <shaderMaterial
826
+ ref={materialRef}
827
+ fragmentShader={`
828
+ varying vec2 vUv;
829
+ void main() {
830
+ // Debug UV
831
+ gl_FragColor = vec4(vUv, 0.0, 1.0);
832
+
833
+ // Debug normals (in vertex: vNormal = normal)
834
+ // gl_FragColor = vec4(vNormal * 0.5 + 0.5, 1.0);
835
+ }
836
+ `}
837
+ vertexShader={`
838
+ varying vec2 vUv;
839
+ void main() {
840
+ vUv = uv;
841
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
842
+ }
843
+ `}
844
+ />
845
+ </mesh>
846
+ )
847
+ }
848
+ ```
849
+
850
+ ## Performance Tips
851
+
852
+ 1. **Minimize uniforms**: Group related values into vectors
853
+ 2. **Avoid conditionals**: Use `mix`/`step` instead of `if/else`
854
+ 3. **Precalculate in JS**: Move static calculations out of shaders
855
+ 4. **Use textures for lookup**: Complex functions as texture lookups
856
+ 5. **Limit overdraw**: Avoid unnecessary transparent objects
857
+
858
+ ```glsl
859
+ // Instead of:
860
+ if (value > 0.5) {
861
+ color = colorA;
862
+ } else {
863
+ color = colorB;
864
+ }
865
+
866
+ // Use:
867
+ color = mix(colorB, colorA, step(0.5, value));
868
+ ```
869
+
870
+ ## See Also
871
+
872
+ - `r3f-materials` - Built-in material types
873
+ - `r3f-postprocessing` - Full-screen shader effects
874
+ - `r3f-textures` - Texture sampling in shaders