关于 r3f-shaders
面向 React Three Fiber 开发者的着色器编写技能,提供 WebGL 自定义材质及内置材质修改的实现指导,并涵盖版本、渲染管线与着色器常见问题。
主要功能
- 01选择 WebGL 或 WebGPU 着色器路径
- 02使用 Drei shaderMaterial 创建动画材质
- 03管理 uniform 与着色器编译
- 04处理坐标空间和颜色管理
- 05为变形几何体配置法线与阴影
- 06通过 onBeforeCompile 修改内置材质
适用场景
- 01为 React Three Fiber 场景编写动画材质
- 02排查 GLSL 编译及颜色输出问题
- 03让顶点变形与光照、阴影保持一致
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ enzed/ r3f-skills --skill r3f-shaders安装后在 Claude Code 中输入/r3f-shaders确认已加载。
附带文件references/webgpu.md
详细介绍
React Three Fiber 着色器
选择着色器路径
先检查已安装的 Fiber、Drei、Three.js 和渲染器版本。此示例使用 Fiber 9 / React 19 和 WebGL。保留现有项目的版本。
- 如果内置材质的属性能够表达所需效果,就使用内置材质。对于自定义 WebGL 着色,使用 Drei
shaderMaterial或原生<shaderMaterial>。 - WebGPU 使用节点材质和 TSL;GLSL
ShaderMaterial和onBeforeCompile无法移植到 WebGPU。只有在相关渲染器适用时,才阅读 WebGPU and TSL。 - 着色器不会自动支持光照、阴影、雾效、实例化或蒙皮。替换内置材质前,先确定所需功能。
WebGL 动画材质
在 Canvas 下挂载。将材质类和 extend 调用放在渲染函数外;局部组件可避免全局 JSX 扩展。
import { useRef } from 'react'
import { extend, useFrame } from '@react-three/fiber'
import { shaderMaterial } from '@react-three/drei'
import { Color } from 'three'
const WaveMaterial = shaderMaterial(
{ uTime: 0, uColor: new Color('coral') },
`uniform float uTime;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 p = position;
p.z += sin(p.x * 4.0 + uTime) * 0.15;
gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);
}`,
`uniform vec3 uColor;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(uColor * (0.4 + 0.6 * vUv.y), 1.0);
#include <tonemapping_fragment>
#include <colorspace_fragment>
}`,
)
const Wave = extend(WaveMaterial)
export default function Example() {
const material = useRef<InstanceType<typeof WaveMaterial>>(null)
useFrame((_, delta) => {
if (material.current) material.current.uTime += delta
})
return (
<mesh>
<planeGeometry args={[3, 3, 32, 32]} />
<Wave ref={material} key={WaveMaterial.key} />
</mesh>
)
}
Uniform 和编译
- Drei
shaderMaterial会创建 uniform 访问器:赋值给material.uTime。原生 ShaderMaterial 使用material.uniforms.uTime.value。 - 保持 uniform 容器稳定;每帧只修改值,不要设置 React state。仅更改 uniform 值时,不要设置
material.needsUpdate。 - 着色器源码、定义和功能变更可能需要重新编译。热重载时使用类的
key;动画期间不要更改 React key。 - Fiber 9 提供
extend(Class)。对于小写的全局元素,使用ThreeElement<typeof Class>扩展ThreeElements;已移除的Object3DNode不能替代材质类型定义。 - TypeScript 不会检查 GLSL 字符串。请运行并渲染它们,检查着色器编译器错误,包括使用实际渲染器和效果的配置。
- 着色器源码位于 JavaScript 模板字面量中,因此 GLSL 中任何位置(包括注释)出现反引号或
${,都会悄无声息地结束字符串并破坏模块。编写着色器注释时不要使用反引号,并让类型检查器发现此类问题,而不是靠阅读查找。
空间、颜色和几何体
- 法线、光照方向和视线方向必须处于相同坐标空间。
normalMatrix * normal是视图空间向量;不要将它与世界空间的相机方向点乘。 - 通过
Color传入的 CSS / 十六进制颜色会转换到线性工作空间。数值型 uniform 向量已经是线性的;避免重复转换。 - 将颜色输入纹理标记为
SRGBColorSpace;数据纹理使用NoColorSpace。纹理采样和输出转换必须与材质 / 渲染器管线匹配。 - 对于直接向画布写入内容的 WebGL 着色器,请像示例一样应用色调映射和输出颜色转换。不要手动进行伽马校正后又应用输出代码块。通过合成器渲染时,应由合成器负责最终输出。
- 顶点变形需要足够细分的几何体。若需要光照,应同步更新法线。若需要阴影,深度 / 距离材质中的变形必须保持一致;CPU 射线投射和边界不会自动跟随 GPU 变形。
- 原生自定义实例化着色器必须处理
instanceMatrix和所有逐实例属性。蒙皮和形态目标同样需要对应的着色器逻辑。
修补内置 WebGL 材质
只有在需要保留内置材质的光照时,才使用 onBeforeCompile。着色器代码块名称会随版本变化:检查已安装版本的源码,并在更新 Three.js 后进行渲染测试。
在首次编译前设置回调。如果配置变更会生成不同的 GLSL,请提供匹配的 customProgramCacheKey 并触发重新编译;动画值应保存在 uniform 中。不要假设 .clone() 或序列化会保留回调。如果任务本身面向 WebGPU,优先使用节点材质。
来源
- Drei shaderMaterial、Fiber 类型迁移。
- ShaderMaterial、色彩管理。
- Three.js 迁移指南 — 仅检查截至已安装版本的变更。
评论
支持 Markdown