RawShaderMaterial vs ShaderMaterial in Three.js
In Three.js, creating custom WebGL shaders is typically achieved
using either ShaderMaterial or
RawShaderMaterial. This article explores the definitions of
both materials, highlights their key differences—specifically regarding
built-in uniforms, attributes, and precision qualifiers—and provides
practical guidelines to help you decide which material to use for your
3D development projects.
What is ShaderMaterial?
ShaderMaterial is a helper class in Three.js designed to
make writing custom shaders easier. When you use
ShaderMaterial, Three.js automatically prepends a set of
built-in uniforms, attributes, and precision declarations to your vertex
and fragment shader code before compiling them.
These automatic additions include essential matrices and attributes
such as: * Uniforms: projectionMatrix,
modelViewMatrix, viewMatrix,
cameraPosition * Attributes:
position, normal, uv
Because these variables are injected automatically, you can use them in your GLSL code immediately without declaring them first.
What is RawShaderMaterial?
RawShaderMaterial is a bare-bones alternative to
ShaderMaterial. When you use
RawShaderMaterial, Three.js does not prepend any variables,
attributes, or precision qualifiers to your shader code.
Your GLSL code is passed directly to the WebGL context exactly as you write it. This means you must manually declare every attribute, uniform, and precision qualifier that your shader needs to function.
Key Differences
The differences between the two materials come down to convenience, control, and boilerplate code.
1. Automatic vs. Manual Declarations
- ShaderMaterial: Automatically declares standard
Three.js attributes (like
position,uv,normal) and uniforms (likeprojectionMatrix,modelViewMatrix). - RawShaderMaterial: Requires you to write out these
declarations manually. If you forget to declare
attribute vec3 position;oruniform mat4 projectionMatrix;, the shader will fail to compile.
2. Precision Qualifiers
- ShaderMaterial: Automatically sets default
precision qualifiers (usually
precision highp float;orprecision mediump float;based on device support). - RawShaderMaterial: Does not set precision. You must
explicitly define your float and integer precision at the top of your
shader files (e.g.,
precision mediump float;).
3. GLSL Version Support
While both materials support GLSL 3.0 (WebGL 2),
RawShaderMaterial is highly favored by developers writing
modern GLSL 300 es code from scratch. It prevents Three.js from
injecting legacy GLSL 100 code, which can cause compiler conflicts in
WebGL 2 contexts.
Code Comparison
The following example demonstrates how the same vertex shader is written using both materials.
Using ShaderMaterial
In ShaderMaterial, the vertex shader is short because
Three.js handles the boilerplate in the background:
// No declarations needed for position, modelViewMatrix, or projectionMatrix
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}Using RawShaderMaterial
In RawShaderMaterial, you must explicitly define the
precision, attributes, and uniforms:
// Precision must be declared
precision mediump float;
// Attributes and Uniforms must be declared manually
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}When to Use Which?
Choose ShaderMaterial
if:
- You want to write custom shaders quickly without writing repetitive boilerplate code.
- You are heavily utilizing standard Three.js features like lighting, shadows, fog, or morph targets, which rely on built-in attributes and uniforms.
- You want to keep your shader files clean and concise.
Choose
RawShaderMaterial if:
- You are porting existing GLSL shaders from other frameworks, platforms, or Shadertoy, and want to avoid namespace collisions with Three.js.
- You want absolute control over your shader output and want to minimize overhead by only compiling the exact variables you declare.
- You are writing strict GLSL 300 es code and want to prevent Three.js from injecting automatic WebGL 1.0 structures.