
Threejs Syntax Shaders
- 18 installs
- 11 repo stars
- Updated July 8, 2026
- openaec-foundation/three.js-claude-skill-package
Helps with ai & agent building tasks.
About
threejs-syntax-shaders is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- threejs-syntax-shaders
- AI & Agent Building
- AI-coding skill
Threejs Syntax Shaders by the numbers
- 18 all-time installs (skills.sh)
- +2 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #10,710 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/three.js-claude-skill-package --skill threejs-syntax-shadersAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 18 |
|---|---|
| repo stars | ★ 11 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/three.js-claude-skill-package ↗ |
What it does
Helps with ai & agent building tasks.
Files
threejs-syntax-shaders
Quick Reference
ShaderMaterial vs RawShaderMaterial
| Aspect | ShaderMaterial | RawShaderMaterial |
|---|---|---|
| Built-in uniforms | Automatically injected | NONE -- you MUST declare everything |
| Built-in attributes | Automatically declared | NONE -- you MUST declare everything |
#include <chunk> | Supported | NOT supported |
| Precision declaration | Automatic | You MUST add precision mediump float; |
| Use case | Extend Three.js rendering | Full shader control, porting external shaders |
| Performance | Slight overhead from unused built-ins | Minimal shader overhead |
Uniform Type Map
| GLSL Type | JavaScript Value |
|---|---|
float | { value: 1.0 } |
int | { value: 1 } |
bool | { value: true } |
vec2 | { value: new THREE.Vector2() } |
vec3 | { value: new THREE.Vector3() } or { value: new THREE.Color() } |
vec4 | { value: new THREE.Vector4() } |
mat3 | { value: new THREE.Matrix3() } |
mat4 | { value: new THREE.Matrix4() } |
sampler2D | { value: texture } (a THREE.Texture instance) |
samplerCube | { value: cubeTexture } |
float[] | { value: [1.0, 2.0, 3.0] } |
vec3[] | { value: [new THREE.Vector3(), ...] } |
Critical Warnings
NEVER pass a bare value as a uniform -- ALWAYS wrap it in { value: ... }. Writing uniforms: { uTime: 0.0 } silently fails; ALWAYS write uniforms: { uTime: { value: 0.0 } }.
NEVER declare built-in uniforms or attributes in a ShaderMaterial shader -- Three.js injects them automatically. Redeclaring causes a GLSL compilation error.
ALWAYS declare ALL uniforms, attributes, and precision in RawShaderMaterial shaders -- nothing is injected for you.
NEVER use gl_FragColor or texture2D() when glslVersion is THREE.GLSL3 -- use a declared out vec4 variable and texture() instead.
ALWAYS call material.needsUpdate = true after changing defines -- defines are compiled into the shader, so changes require recompilation.
---
ShaderMaterial
Constructor
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,
});Properties
| Property | Type | Default | Description |
|---|---|---|---|
uniforms | Object | {} | { name: { value: ... } } format |
uniformsGroups | Array | [] | Uniform buffer objects (UBO) |
vertexShader | string | -- | GLSL vertex shader source |
fragmentShader | string | -- | GLSL fragment shader source |
defines | Object | {} | Preprocessor #define directives |
extensions | Object | {} | GLSL extensions to enable |
wireframe | boolean | false | Wireframe rendering |
lights | boolean | false | Pass light uniforms to shader |
fog | boolean | false | Pass fog uniforms to shader |
clipping | boolean | false | Enable clipping planes |
glslVersion | `string \ | null` | null |
defaultAttributeValues | Object | -- | Fallback values for missing attributes |
---
Built-in Uniforms (ShaderMaterial Only)
These are injected automatically. NEVER declare them yourself.
// 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 lightsBuilt-in Attributes (ShaderMaterial Only)
These are injected automatically. NEVER declare them yourself.
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
Use when you need full control over the shader source. NOTHING is injected.
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);
}
`,
});ALWAYS add precision highp float; (or mediump) at the top of both shaders in RawShaderMaterial. Omitting precision causes a GLSL compilation error on mobile and some desktop drivers.
---
ShaderChunk -- Reusing Three.js Shader Code
THREE.ShaderChunk contains all internal shader fragments. Use #include <chunk_name> in ShaderMaterial (NOT RawShaderMaterial).
Common Chunks
| Chunk | Purpose |
|---|---|
<common> | Shared constants and functions (PI, saturate, etc.) |
<fog_pars_vertex> / <fog_vertex> | Fog support (vertex) |
<fog_pars_fragment> / <fog_fragment> | Fog support (fragment) |
<shadowmap_pars_vertex> / <shadowmap_vertex> | Shadow support (vertex) |
<shadowmap_pars_fragment> / <shadowmap_fragment> | Shadow support (fragment) |
<lights_pars_begin> | Light structure declarations |
<begin_vertex> | Initializes transformed variable from position |
<project_vertex> | Applies modelViewMatrix and projectionMatrix |
<normal_fragment_begin> | Normal mapping setup |
<color_pars_vertex> / <color_vertex> | Vertex color support |
Accessing Chunks Programmatically
// Read the source of any chunk
console.log(THREE.ShaderChunk.common);
console.log(THREE.ShaderChunk.fog_pars_vertex);---
onBeforeCompile -- Patching Built-in Materials
Modify an existing material's shader at compile time. This preserves PBR lighting, shadows, and all built-in features.
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();
}ALWAYS override customProgramCacheKey() when using onBeforeCompile -- without it, Three.js may reuse a cached unpatched shader program, causing your modifications to silently disappear.
ALWAYS check material.userData.shader exists before accessing uniforms -- the shader object is created lazily on first render and can be recreated when material.needsUpdate = true.
---
Defines -- Preprocessor Directives
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
});Changing defines at runtime:
material.defines.MAX_LIGHTS = 8;
material.needsUpdate = true; // REQUIRED -- triggers recompilation---
GLSL3 Mode
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 vs GLSL3 Syntax
| GLSL1 | GLSL3 | Context |
|---|---|---|
attribute | in | Vertex shader inputs |
varying (vertex) | out | Vertex shader outputs |
varying (fragment) | in | Fragment shader inputs |
gl_FragColor | Declared out vec4 | Fragment shader output |
texture2D() | texture() | Texture sampling |
textureCube() | texture() | Cube texture sampling |
---
Uniform Update Pattern
// 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);
}NEVER replace the uniform object itself (e.g., material.uniforms.uTime = { value: 5 }). ALWAYS mutate the existing .value property. Replacing the object breaks the internal reference.
---
Reference Links
- references/methods.md -- Complete API signatures
- references/examples.md -- Working code examples
- references/anti-patterns.md -- What NOT to do
Official Sources
- https://threejs.org/docs/#api/en/materials/ShaderMaterial
- https://threejs.org/docs/#api/en/materials/RawShaderMaterial
- https://threejs.org/docs/#api/en/renderers/shaders/ShaderChunk
- https://threejs.org/docs/#api/en/renderers/shaders/UniformsLib
threejs-syntax-shaders -- Anti-Patterns
Anti-Pattern 1: Bare Uniform Values
WRONG:
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: 0.0, // WRONG -- bare value
uColor: new THREE.Color(), // WRONG -- bare value
},
});CORRECT:
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0.0 }, // ALWAYS wrap in { value: }
uColor: { value: new THREE.Color() }, // ALWAYS wrap in { value: }
},
});Why: Three.js expects every uniform to be an object with a value property. Bare values are silently ignored -- the uniform is never sent to the GPU, and the shader uses uninitialized data.
---
Anti-Pattern 2: Replacing Uniform Objects Instead of Mutating .value
WRONG:
// In animation loop
material.uniforms.uTime = { value: performance.now() }; // WRONG -- replaces objectCORRECT:
// In animation loop
material.uniforms.uTime.value = performance.now(); // ALWAYS mutate .valueWhy: Three.js caches internal references to uniform objects. Replacing the object breaks the reference, so the GPU never receives the updated value.
---
Anti-Pattern 3: Declaring Built-in Uniforms in ShaderMaterial
WRONG:
// In a ShaderMaterial vertex shader
uniform mat4 modelViewMatrix; // WRONG -- already injected
uniform mat4 projectionMatrix; // WRONG -- already injected
attribute vec3 position; // WRONG -- already injectedCORRECT:
// In a ShaderMaterial vertex shader -- just use them directly
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}Why: ShaderMaterial automatically prepends built-in uniform and attribute declarations. Redeclaring them causes a GLSL compilation error ("identifier already declared"). This ONLY applies to ShaderMaterial -- RawShaderMaterial requires explicit declarations.
---
Anti-Pattern 4: Forgetting customProgramCacheKey with onBeforeCompile
WRONG:
material.onBeforeCompile = (shader) => {
shader.vertexShader = shader.vertexShader.replace(
'#include <begin_vertex>',
'#include <begin_vertex>\ntransformed.y += 1.0;'
);
};
// No customProgramCacheKey -- Three.js may reuse a cached unpatched programCORRECT:
material.onBeforeCompile = (shader) => {
shader.vertexShader = shader.vertexShader.replace(
'#include <begin_vertex>',
'#include <begin_vertex>\ntransformed.y += 1.0;'
);
};
material.customProgramCacheKey = () => 'my-displaced-material';Why: Three.js caches compiled shader programs by material type and parameters. Without a unique cache key, Two materials of the same type may share a cached program, causing your onBeforeCompile modifications to silently disappear on the second instance.
---
Anti-Pattern 5: Using GLSL1 Syntax with glslVersion: GLSL3
WRONG:
const material = new THREE.ShaderMaterial({
glslVersion: THREE.GLSL3,
fragmentShader: `
varying vec2 vUv; // WRONG -- 'varying' is not valid in GLSL3
void main() {
gl_FragColor = vec4(1.0); // WRONG -- gl_FragColor does not exist in GLSL3
}
`,
});CORRECT:
const material = new THREE.ShaderMaterial({
glslVersion: THREE.GLSL3,
fragmentShader: `
precision highp float;
in vec2 vUv; // 'varying' becomes 'in' in fragment shader
out vec4 fragColor; // Declare output explicitly
void main() {
fragColor = vec4(1.0); // Write to declared output
}
`,
});Why: GLSL 3.0 ES removes attribute, varying, gl_FragColor, and texture2D(). Using them causes compilation errors. ALWAYS use in/out, a declared output variable, and texture().
---
Anti-Pattern 6: Forgetting precision in RawShaderMaterial
WRONG:
const material = new THREE.RawShaderMaterial({
vertexShader: `
attribute vec3 position; // WRONG -- no precision declaration
void main() {
gl_Position = vec4(position, 1.0);
}
`,
fragmentShader: `
void main() { // WRONG -- no precision declaration
gl_FragColor = vec4(1.0);
}
`,
});CORRECT:
const material = new THREE.RawShaderMaterial({
vertexShader: `
precision highp float;
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
`,
fragmentShader: `
precision highp float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});Why: RawShaderMaterial injects NOTHING -- no precision qualifier, no uniforms, no attributes. The fragment shader requires an explicit precision declaration on mobile GPUs and many desktop drivers. Omitting it causes a GLSL compilation error.
---
Anti-Pattern 7: Using #include Chunks in RawShaderMaterial
WRONG:
const material = new THREE.RawShaderMaterial({
vertexShader: `
precision highp float;
#include <common> // WRONG -- not processed in RawShaderMaterial
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
`,
});CORRECT (use ShaderMaterial instead):
const material = new THREE.ShaderMaterial({
vertexShader: `
#include <common> // Works in ShaderMaterial
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
});Or manually inline the chunk:
const material = new THREE.RawShaderMaterial({
vertexShader: `
precision highp float;
${THREE.ShaderChunk.common}
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
});Why: RawShaderMaterial does NOT process #include directives. The string #include <common> is passed literally to the GLSL compiler, which does not understand it, causing a compilation error.
---
Anti-Pattern 8: Setting needsUpdate on Uniform Changes
WRONG:
material.uniforms.uTime.value = 1.0;
material.needsUpdate = true; // WRONG -- unnecessary and expensiveCORRECT:
material.uniforms.uTime.value = 1.0; // Just update the value -- no needsUpdate neededWhy: Uniform values are sent to the GPU every frame automatically. Setting material.needsUpdate = true triggers a full shader recompilation, which is extremely expensive (causes a frame stutter). ONLY set needsUpdate = true when changing defines, vertexShader, fragmentShader, lights, fog, or clipping.
---
Anti-Pattern 9: Storing onBeforeCompile Shader Reference Without Null Check
WRONG:
material.onBeforeCompile = (shader) => {
shader.uniforms.uTime = { value: 0 };
material.userData.shader = shader;
};
// In animation loop -- crashes if shader has not compiled yet
material.userData.shader.uniforms.uTime.value = clock.getElapsedTime();CORRECT:
material.onBeforeCompile = (shader) => {
shader.uniforms.uTime = { value: 0 };
material.userData.shader = shader;
};
// In animation loop -- ALWAYS check existence
if (material.userData.shader) {
material.userData.shader.uniforms.uTime.value = clock.getElapsedTime();
}Why: The onBeforeCompile callback runs lazily on first render. Before the first renderer.render() call, material.userData.shader is undefined. Additionally, setting material.needsUpdate = true can recreate the shader object, invalidating old references. ALWAYS guard access with a null check.
---
Official Sources
- https://threejs.org/docs/#api/en/materials/ShaderMaterial
- https://threejs.org/docs/#api/en/materials/RawShaderMaterial
- https://threejs.org/docs/#api/en/renderers/shaders/ShaderChunk
threejs-syntax-shaders -- Examples
Example 1: Basic Custom ShaderMaterial
A minimal ShaderMaterial with a time-based color animation.
import * as THREE from 'three';
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0.0 },
uColor: { value: new THREE.Color(0x3399ff) },
},
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() {
float pulse = sin(uTime * 3.0) * 0.5 + 0.5;
vec3 color = mix(uColor, vec3(1.0), pulse * vUv.y);
gl_FragColor = vec4(color, 1.0);
}
`,
});
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), material);
// Animation loop
const clock = new THREE.Clock();
function animate() {
material.uniforms.uTime.value = clock.getElapsedTime();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();---
Example 2: Vertex Displacement with Texture
Displaces vertices along their normals using a height map texture.
import * as THREE from 'three';
const loader = new THREE.TextureLoader();
const heightMap = loader.load('/textures/heightmap.png');
const material = new THREE.ShaderMaterial({
uniforms: {
uHeightMap: { value: heightMap },
uDisplacement: { value: 0.5 },
},
vertexShader: `
uniform sampler2D uHeightMap;
uniform float uDisplacement;
varying vec2 vUv;
varying float vHeight;
void main() {
vUv = uv;
float height = texture2D(uHeightMap, uv).r;
vHeight = height;
vec3 displaced = position + normal * height * uDisplacement;
gl_Position = projectionMatrix * modelViewMatrix * vec4(displaced, 1.0);
}
`,
fragmentShader: `
varying vec2 vUv;
varying float vHeight;
void main() {
vec3 low = vec3(0.0, 0.2, 0.8);
vec3 high = vec3(1.0, 0.9, 0.3);
vec3 color = mix(low, high, vHeight);
gl_FragColor = vec4(color, 1.0);
}
`,
});
const geometry = new THREE.PlaneGeometry(10, 10, 256, 256);
const mesh = new THREE.Mesh(geometry, material);---
Example 3: onBeforeCompile -- Patching MeshStandardMaterial
Adds a wave vertex displacement to a standard PBR material while preserving all lighting and shadow behavior.
import * as THREE from 'three';
const material = new THREE.MeshStandardMaterial({
color: 0x2194ce,
roughness: 0.4,
metalness: 0.1,
});
material.onBeforeCompile = (shader) => {
// Add custom uniforms
shader.uniforms.uTime = { value: 0.0 };
shader.uniforms.uAmplitude = { value: 0.3 };
// Inject uniform declaration at top of vertex shader
shader.vertexShader = `
uniform float uTime;
uniform float uAmplitude;
` + shader.vertexShader;
// Replace begin_vertex chunk to add displacement
shader.vertexShader = shader.vertexShader.replace(
'#include <begin_vertex>',
`
#include <begin_vertex>
float wave = sin(transformed.x * 4.0 + uTime * 2.0) *
cos(transformed.z * 4.0 + uTime * 1.5);
transformed.y += wave * uAmplitude;
`
);
// Store shader reference for uniform updates
material.userData.shader = shader;
};
// ALWAYS override customProgramCacheKey with onBeforeCompile
material.customProgramCacheKey = () => 'wavy-standard';
// Animation loop
const clock = new THREE.Clock();
function animate() {
if (material.userData.shader) {
material.userData.shader.uniforms.uTime.value = clock.getElapsedTime();
}
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();---
Example 4: RawShaderMaterial with GLSL3
A RawShaderMaterial using GLSL 3.0 ES syntax for full control.
import * as THREE from 'three';
const material = new THREE.RawShaderMaterial({
glslVersion: THREE.GLSL3,
uniforms: {
uProjectionMatrix: { value: new THREE.Matrix4() },
uModelViewMatrix: { value: new THREE.Matrix4() },
uTime: { value: 0.0 },
},
vertexShader: `
precision highp float;
in vec3 position;
in vec2 uv;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
uniform float uTime;
out vec2 vUv;
out float vWave;
void main() {
vUv = uv;
vec3 pos = position;
pos.z = sin(pos.x * 5.0 + uTime) * 0.2;
vWave = pos.z;
gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(pos, 1.0);
}
`,
fragmentShader: `
precision highp float;
in vec2 vUv;
in float vWave;
out vec4 fragColor;
void main() {
vec3 color = vec3(vUv, 0.5 + vWave);
fragColor = vec4(color, 1.0);
}
`,
});
// With RawShaderMaterial, you MUST manually update the matrix uniforms
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(4, 4, 64, 64), material);
function animate() {
mesh.updateMatrixWorld();
material.uniforms.uModelViewMatrix.value.multiplyMatrices(
camera.matrixWorldInverse,
mesh.matrixWorld
);
material.uniforms.uProjectionMatrix.value.copy(camera.projectionMatrix);
material.uniforms.uTime.value = performance.now() / 1000;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}---
Example 5: ShaderMaterial with Fog and Lights Support
Using ShaderChunk includes to integrate with Three.js fog and lighting systems.
import * as THREE from 'three';
const material = new THREE.ShaderMaterial({
uniforms: {
...THREE.UniformsLib.fog,
uColor: { value: new THREE.Color(0xff6600) },
},
vertexShader: `
#include <common>
#include <fog_pars_vertex>
varying vec3 vNormal;
void main() {
vNormal = normalize(normalMatrix * normal);
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
#include <fog_vertex>
}
`,
fragmentShader: `
#include <common>
#include <fog_pars_fragment>
uniform vec3 uColor;
varying vec3 vNormal;
void main() {
float light = dot(vNormal, normalize(vec3(1.0, 1.0, 1.0)));
light = clamp(light, 0.2, 1.0);
gl_FragColor = vec4(uColor * light, 1.0);
#include <fog_fragment>
}
`,
fog: true, // REQUIRED to enable fog uniform injection
});---
Official Sources
- https://threejs.org/docs/#api/en/materials/ShaderMaterial
- https://threejs.org/docs/#api/en/materials/RawShaderMaterial
- https://threejs.org/examples/#webgl_shader
- https://threejs.org/examples/#webgl_shader_lava
threejs-syntax-shaders -- Methods Reference
ShaderMaterial Constructor
new THREE.ShaderMaterial(parameters?: {
uniforms?: { [name: string]: { value: any } },
uniformsGroups?: THREE.UniformsGroup[],
vertexShader?: string,
fragmentShader?: string,
defines?: { [name: string]: string | number },
extensions?: {
clipCullDistance?: boolean,
multiDraw?: boolean,
},
wireframe?: boolean,
wireframeLinewidth?: number,
lights?: boolean,
fog?: boolean,
clipping?: boolean,
glslVersion?: null | typeof THREE.GLSL3,
defaultAttributeValues?: { [name: string]: number[] },
// Inherited from Material:
side?: THREE.Side,
transparent?: boolean,
opacity?: number,
depthTest?: boolean,
depthWrite?: boolean,
blending?: THREE.Blending,
})---
RawShaderMaterial Constructor
new THREE.RawShaderMaterial(parameters?: {
// Same parameters as ShaderMaterial
// Difference: NO built-in uniforms, attributes, or precision injected
uniforms?: { [name: string]: { value: any } },
vertexShader?: string,
fragmentShader?: string,
defines?: { [name: string]: string | number },
glslVersion?: null | typeof THREE.GLSL3,
// ...all Material base properties
})---
ShaderMaterial Properties
| Property | Type | Default | Description |
|---|---|---|---|
uniforms | Object | {} | Map of { name: { value: any } } |
uniformsGroups | THREE.UniformsGroup[] | [] | Uniform buffer objects |
vertexShader | string | default vertex shader | GLSL vertex shader source |
fragmentShader | string | default fragment shader | GLSL fragment shader source |
defines | Object | {} | Preprocessor defines |
extensions | Object | {} | WebGL extensions to enable |
wireframe | boolean | false | Render as wireframe |
wireframeLinewidth | number | 1 | Line width (limited to 1 on most platforms) |
lights | boolean | false | If true, passes light data as uniforms |
fog | boolean | false | If true, passes fog data as uniforms |
clipping | boolean | false | If true, enables clipping planes |
glslVersion | `string \ | null` | null |
defaultAttributeValues | Object | { color: [1,1,1], uv: [0,0], uv2: [0,0] } | Fallback values for missing geometry attributes |
isShaderMaterial | boolean | true | Read-only type flag |
---
ShaderMaterial Methods (Inherited from Material)
| Method | Signature | Returns | Description |
|---|---|---|---|
clone | (): ShaderMaterial | new instance | Deep clone the material |
copy | (source: ShaderMaterial): this | this | Copy properties from another material |
dispose | (): void | void | Free GPU resources |
toJSON | (meta?: object): object | JSON | Serialize to JSON |
onBeforeCompile | (shader: object, renderer: WebGLRenderer): void | void | Callback before shader compilation |
customProgramCacheKey | (): string | string | Return custom key for shader program caching |
---
Built-in Uniforms (Injected by ShaderMaterial)
Transform Matrices
| Uniform | GLSL Type | Description |
|---|---|---|
modelMatrix | mat4 | Object-to-world transform |
modelViewMatrix | mat4 | Object-to-camera (viewMatrix * modelMatrix) |
projectionMatrix | mat4 | Camera-to-clip projection |
viewMatrix | mat4 | World-to-camera transform |
normalMatrix | mat3 | Transpose inverse of modelViewMatrix |
Camera
| Uniform | GLSL Type | Description |
|---|---|---|
cameraPosition | vec3 | Camera position in world space |
Lighting (when lights: true)
| Uniform | GLSL Type | Description |
|---|---|---|
ambientLightColor | vec3 | Combined ambient light color |
directionalLights | struct array | Direction, color for each directional light |
pointLights | struct array | Position, color, distance, decay for each point light |
spotLights | struct array | Position, direction, color, distance, decay, angle, penumbra |
hemisphereLights | struct array | Sky color, ground color, direction |
---
Built-in Attributes (Injected by ShaderMaterial)
| Attribute | GLSL Type | Source |
|---|---|---|
position | vec3 | geometry.attributes.position |
normal | vec3 | geometry.attributes.normal |
uv | vec2 | geometry.attributes.uv |
uv2 | vec2 | geometry.attributes.uv2 |
tangent | vec4 | geometry.attributes.tangent (if present) |
color | vec3 | geometry.attributes.color (if present) |
---
ShaderChunk API
// Access any internal shader chunk by name
THREE.ShaderChunk['common'] // Returns string with source code
THREE.ShaderChunk['fog_pars_vertex'] // Returns fog vertex pars sourceUsage in GLSL (ShaderMaterial only)
#include <common>
#include <fog_pars_vertex>---
onBeforeCompile Callback Signature
material.onBeforeCompile = (shader: {
uniforms: { [name: string]: { value: any } },
vertexShader: string,
fragmentShader: string,
defines: { [name: string]: string | number },
}, renderer: THREE.WebGLRenderer) => void;customProgramCacheKey Signature
material.customProgramCacheKey = (): string => {
return 'unique-key-for-this-variant';
};---
UniformsLib
Three.js groups commonly-used uniforms into libraries:
THREE.UniformsLib.common // diffuse map, opacity, alphaMap, UV transform
THREE.UniformsLib.envmap // environment map uniforms
THREE.UniformsLib.normalmap // normal map uniforms
THREE.UniformsLib.fog // fogColor, fogNear, fogFar, fogDensity
THREE.UniformsLib.lights // all light type uniformsUniformsUtils
// Merge multiple uniform objects (deep clone)
const merged = THREE.UniformsUtils.merge([
THREE.UniformsLib.common,
THREE.UniformsLib.lights,
{ uCustom: { value: 1.0 } },
]);
// Clone uniforms (deep copy of values)
const cloned = THREE.UniformsUtils.clone(someUniforms);---
Official Sources
- https://threejs.org/docs/#api/en/materials/ShaderMaterial
- https://threejs.org/docs/#api/en/materials/RawShaderMaterial
- https://threejs.org/docs/#api/en/renderers/shaders/ShaderChunk
- https://threejs.org/docs/#api/en/renderers/shaders/UniformsLib
- https://threejs.org/docs/#api/en/renderers/shaders/UniformsUtils