mcpField
T
threejs-syntax-shaders

threejs-syntax-shaders

github.com/impertio-studio开发23143 次安装30 周前更新
代码仓库

关于 threejs-syntax-shaders

threejs-syntax-shaders 是面向 Three.js 开发者的着色器参考技能,整理材质、GLSL 语法与常见错误,帮助编写和排查自定义着色器。

主要功能

  1. 01对比 ShaderMaterial 与 RawShaderMaterial
  2. 02说明 uniform 类型与赋值格式
  3. 03整理 ShaderChunk 和 onBeforeCompile 用法
  4. 04涵盖 GLSL3 语法及 define 更新
  5. 05提示着色器常见编译错误

适用场景

  1. 01实现 Three.js 自定义材质着色器
  2. 02将外部 GLSL 着色器移植到 Three.js
  3. 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.md
examples.md
methods.md

详细介绍

threejs-syntax-shaders

快速参考

ShaderMaterial 与 RawShaderMaterial
方面ShaderMaterialRawShaderMaterial
内置 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,
});
属性
属性类型默认值描述
uniformsObject{}{ name: { value: ... } } 格式
uniformsGroupsArray[]Uniform 缓冲对象(UBO)
vertexShaderstring--GLSL 顶点着色器源码
fragmentShaderstring--GLSL 片元着色器源码
definesObject{}预处理器 #define 指令
extensionsObject{}要启用的 GLSL 扩展
wireframebooleanfalse线框渲染
lightsbooleanfalse将光照 uniform 传递给着色器
fogbooleanfalse将雾效 uniform 传递给着色器
clippingbooleanfalse启用裁剪平面
glslVersionstring | nullnullGLSL1 使用 null,GLSL 3.0 ES 使用 THREE.GLSL3
defaultAttributeValuesObject--缺失 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 语法对比
GLSL1GLSL3上下文
attributein顶点着色器输入
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 属性。替换对象会破坏内部引用。


参考链接

官方来源

评论

支持 Markdown