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

2. Precision Qualifiers

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:

Choose RawShaderMaterial if: