Skip to main content

Shader Modules

luma.gl provides a shader module system through @luma.gl/shadertools that lets you build modular shaders. The system is built around a shader "assembler", and addresses the lack of a module/import system in GLSL and WGSL. The shader assembler allows you to import chunks of reusable shader code from separately defined shader fragments into your shader program source code, which lets you organize shader code into reusable modules.

  • Enables you to import and "inject" prepackaged modules of shader code into your shaders.
  • Allows you to package up reusable GLSL and/or WGSL code as shader modules.
  • Adds GPU detection and a measure of portability your shaders.

Usage

To add/inject existing modules into your shaders, just add the modules parameter to your assembleShaders call:

import {shaderModule} from 'library-of-shader-modules';
const {vs, fs, getUniforms, moduleMap} = assembleShaders(device, {
fs: '...',
vs: '...',
modules: [shaderModule],
...
})

To create a new shader module, you need to create a descriptor object.

const MY_SHADER_MODULE = {
name: 'my-shader-module',
vs: ....
fs: null,
inject: {},
dependencies: [],
deprecations: [],
getUniforms
};

This object can be used as shader module directly:

assembleShaders(device, {..., modules: [MY_SHADER_MODULE]});

Structure of a Shader Module

The simplest shader modules just contain one or more reusable generic global GLSL or WGSL functions that can be included either in fragment or vertex shaders, or both. The shader assembler simply adds the functions to the top of the assembled shader. The fp64 module is an example of this type of module.

More complex shader modules contain specific vertex and/or fragment shader "chunks". In this case the shader module defines vertex shader inputs and outputs requiring more sophisticated shader generation to wire up the inputs and outputs between shader stages.

Shader Module Descriptors

To define a new shader module, you create a descriptor object that brings together all the necessary pieces:

import type {ShaderModule} from '@luma.gl/shadertools';

export const myShaderModule = {
name: 'my-shader-module',
vs: '...',
fs: '...',
inject: {},
dependencies: [],
deprecations: [],
getUniforms
} as const satisfies ShaderModule;

For details see the ShaderModule type reference page.

For the uniform descriptor syntax used by uniformTypes, including structs, fixed-size arrays, and TypeScript inference, see Core Shader Types.

Several functions are also available to initialize and use shader modules.

For the current WGSL-specific assembly and binding-relocation rules used by shadertools, see WGSL Support.