关于 threejs-syntax-shaders
threejs-syntax-shaders 是面向 Three.js 开发者的着色器参考技能,整理材质、GLSL 语法与常见错误,帮助编写和排查自定义着色器。
主要功能
- 01对比 ShaderMaterial 与 RawShaderMaterial
- 02说明 uniform 类型与赋值格式
- 03整理 ShaderChunk 和 onBeforeCompile 用法
- 04涵盖 GLSL3 语法及 define 更新
- 05提示着色器常见编译错误
适用场景
- 01实现 Three.js 自定义材质着色器
- 02将外部 GLSL 着色器移植到 Three.js
- 03排查 uniform 或 GLSL 编译问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-syntax-shaders安装后在 Claude Code 中输入/threejs-syntax-shaders确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/anti-patterns.mdexamples.mdmethods.md详细介绍
threejs-syntax-shaders
快速参考
ShaderMaterial 与 RawShaderMaterial
| 方面 | ShaderMaterial | RawShaderMaterial |
|---|---|---|
| 内置 uniform | 自动注入 | 无——你必须声明所有内容 |
| 内置 attribute | 自动声明 | 无——你必须声明所有内容 |
#include <chunk> | 支持 | 不支持 |
| 精度声明 | 自动 | 你必须添加 precision mediump float; |
| 使用场景 | 扩展 Three.js 渲染 | 完全控制着色器、移植外部着色器 |
| 性能 | 未使用的内置项会带来轻微开销 | 着色器开销极小 |
Uniform 类型映射
| GLSL 类型 | JavaScript 值 |
|---|---|
float | { value: 1.0 } |
int | { value: 1 } |
bool | { value: true } |
vec2 | { value: new THREE.Vector2() } |
vec3 | { value: new THREE.Vector3() } 或 { value: new THREE.Color() } |
vec4 | { value: new THREE.Vector4() } |
mat3 | { value: new THREE.Matrix3() } |
mat4 | { value: new THREE.Matrix4() } |
sampler2D | { value: texture }(THREE.Texture 实例) |
samplerCube | { value: cubeTexture } |
float[] | { value: [1.0, 2.0, 3.0] } |
vec3[] | { value: [new THREE.Vector3(), ...] } |
重要警告
绝不要将裸值作为 uniform 传入——始终将其包装在 { value: ... } 中。写成 uniforms: { uTime: 0.0 } 会静默失败;始终写成 uniforms: { uTime: { value: 0.0 } }。
在 ShaderMaterial 着色器中,绝不要声明内置 uniform 或 attribute——Three.js 会自动注入。重复声明会导致 GLSL 编译错误。
在 RawShaderMaterial 着色器中,始终声明所有 uniform、attribute 和精度——不会自动注入任何内容。
当 glslVersion 为 THREE.GLSL3 时,绝不要使用 gl_FragColor 或 texture2D()——应改用已声明的 out vec4 变量和 texture()。
更改 defines 后,始终调用 material.needsUpdate = true——defines 会编译进着色器,因此更改后需要重新编译。
ShaderMaterial
构造函数
import * as THREE from 'three';
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0.0 },
uColor: { value: new THREE.Color(0x00ff00) },
uTexture: { value: someTexture },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform float uTime;
uniform vec3 uColor;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(uColor * vUv.x, 1.0);
}
`,
transparent: false,
wireframe: false,
side: THREE.FrontSide,
});
属性
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
uniforms | Object | {} | { name: { value: ... } } 格式 |
uniformsGroups | Array | [] | Uniform 缓冲对象(UBO) |
vertexShader | string | -- | GLSL 顶点着色器源码 |
fragmentShader | string | -- | GLSL 片元着色器源码 |
defines | Object | {} | 预处理器 #define 指令 |
extensions | Object | {} | 要启用的 GLSL 扩展 |
wireframe | boolean | false | 线框渲染 |
lights | boolean | false | 将光照 uniform 传递给着色器 |
fog | boolean | false | 将雾效 uniform 传递给着色器 |
clipping | boolean | false | 启用裁剪平面 |
glslVersion | string | null | null | GLSL1 使用 null,GLSL 3.0 ES 使用 THREE.GLSL3 |
defaultAttributeValues | Object | -- | 缺失 attribute 的备用值 |
内置 Uniform(仅限 ShaderMaterial)
这些内容会自动注入。绝不要自行声明。
// Transform matrices
uniform mat4 modelMatrix; // Object -> World
uniform mat4 modelViewMatrix; // Object -> Camera
uniform mat4 projectionMatrix; // Camera -> Clip
uniform mat4 viewMatrix; // World -> Camera
uniform mat3 normalMatrix; // Transpose inverse of modelViewMatrix
// Camera
uniform vec3 cameraPosition; // Camera world position
// When lights: true
uniform vec3 ambientLightColor;
// Plus structured arrays for directional, point, spot, hemisphere lights
内置 Attribute(仅限 ShaderMaterial)
这些内容会自动注入。绝不要自行声明。
attribute vec3 position; // Vertex position
attribute vec3 normal; // Vertex normal
attribute vec2 uv; // Primary UV coordinates
attribute vec2 uv2; // Secondary UV (for aoMap, lightMap)
attribute vec4 tangent; // Tangent vector (if computeTangents was called)
attribute vec3 color; // Vertex color (if geometry has color attribute)
RawShaderMaterial
需要完全控制着色器源码时使用。不会注入任何内容。
const material = new THREE.RawShaderMaterial({
uniforms: {
uModelViewMatrix: { value: new THREE.Matrix4() },
uProjectionMatrix: { value: new THREE.Matrix4() },
},
vertexShader: `
precision highp float;
attribute vec3 position;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
void main() {
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
precision highp float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});
在 RawShaderMaterial 的两个着色器顶部,始终添加 precision highp float;(或 mediump)。省略精度声明会导致移动设备和部分桌面驱动上出现 GLSL 编译错误。
ShaderChunk——复用 Three.js 着色器代码
THREE.ShaderChunk 包含所有内部着色器片段。在 ShaderMaterial 中使用 #include <chunk_name>(不要用于 RawShaderMaterial)。
常用代码块
| 代码块 | 用途 |
|---|---|
<common> | 共享常量和函数(PI、saturate 等) |
<fog_pars_vertex> / <fog_vertex> | 雾效支持(顶点) |
<fog_pars_fragment> / <fog_fragment> | 雾效支持(片元) |
<shadowmap_pars_vertex> / <shadowmap_vertex> | 阴影支持(顶点) |
<shadowmap_pars_fragment> / <shadowmap_fragment> | 阴影支持(片元) |
<lights_pars_begin> | 光照结构声明 |
<begin_vertex> | 根据 position 初始化 transformed 变量 |
<project_vertex> | 应用 modelViewMatrix 和 projectionMatrix |
<normal_fragment_begin> | 法线映射设置 |
<color_pars_vertex> / <color_vertex> | 顶点颜色支持 |
以编程方式访问代码块
// Read the source of any chunk
console.log(THREE.ShaderChunk.common);
console.log(THREE.ShaderChunk.fog_pars_vertex);
onBeforeCompile —— 修改内置材质
在编译时修改现有材质的着色器。这样可以保留 PBR 光照、阴影和所有内置功能。
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
material.onBeforeCompile = (shader) => {
shader.uniforms.uTime = { value: 0.0 };
shader.vertexShader = shader.vertexShader.replace(
'#include <begin_vertex>',
`
#include <begin_vertex>
transformed.y += sin(transformed.x * 5.0 + uTime) * 0.5;
`
);
// Store reference for uniform updates
material.userData.shader = shader;
};
// ALWAYS override customProgramCacheKey when using onBeforeCompile
material.customProgramCacheKey = () => 'my-wavy-material';
// In animation loop
if (material.userData.shader) {
material.userData.shader.uniforms.uTime.value = clock.getElapsedTime();
}
使用 onBeforeCompile 时,务必重写 customProgramCacheKey()——否则,Three.js 可能会重用缓存中未修改的着色器程序,导致你的修改悄然失效。
访问 uniforms 前,务必检查 material.userData.shader 是否存在——着色器对象会在首次渲染时延迟创建,并且在设置 material.needsUpdate = true 时可能会重新创建。
Defines —— 预处理指令
const material = new THREE.ShaderMaterial({
defines: {
USE_FOG: '', // #define USE_FOG
MAX_LIGHTS: 4, // #define MAX_LIGHTS 4
EPSILON: '0.001', // #define EPSILON 0.001
},
// ...shaders
});
运行时更改 defines:
material.defines.MAX_LIGHTS = 8;
material.needsUpdate = true; // REQUIRED -- triggers recompilation
GLSL3 模式
const material = new THREE.ShaderMaterial({
glslVersion: THREE.GLSL3,
vertexShader: `
in vec3 position; // 'attribute' becomes 'in'
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
out vec3 vPosition; // 'varying' becomes 'out'
void main() {
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
precision highp float;
in vec3 vPosition; // 'varying' becomes 'in'
out vec4 fragColor; // replaces gl_FragColor
void main() {
fragColor = vec4(vPosition * 0.5 + 0.5, 1.0);
}
`,
});
GLSL1 与 GLSL3 语法对比
| GLSL1 | GLSL3 | 上下文 |
|---|---|---|
attribute | in | 顶点着色器输入 |
varying(顶点) | out | 顶点着色器输出 |
varying(片元) | in | 片元着色器输入 |
gl_FragColor | 声明的 out vec4 | 片元着色器输出 |
texture2D() | texture() | 纹理采样 |
textureCube() | texture() | 立方体纹理采样 |
Uniform 更新模式
// At creation
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0.0 },
uResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
uMouse: { value: new THREE.Vector2() },
},
vertexShader: '...',
fragmentShader: '...',
});
// In animation loop -- update the .value property directly
function animate() {
material.uniforms.uTime.value = performance.now() / 1000;
material.uniforms.uMouse.value.set(mouseX, mouseY);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
切勿替换 uniform 对象本身(例如,material.uniforms.uTime = { value: 5 })。务必修改现有的 .value 属性。替换对象会破坏内部引用。
参考链接
- references/methods.md —— 完整的 API 签名
- references/examples.md —— 可运行的代码示例
- references/anti-patterns.md —— 错误做法