luma.gl/docs/developer-guide/shader-modules.md
2019-11-08 14:52:00 -05:00

6.9 KiB

Shader Modules

Overview

shadertools is a GLSL shader module system built around a GLSL "assembler" that allows you build modular shaders. It addresses the lack of a module/import system in the GLSL language and allows you to import chunks of reusable shader code from modules into your shader source code, and organize your shader code in reusable modules.

  • Enables you to import and "inject" prepackaged modules of shader code into your shaders.
  • Allows you to package up reusable GLSL 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(gl, {
  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,
  dependencies: [],
  deprecations: [],
  getUniforms
};

This object can be used as shader module directly:

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

Structure of a Shader Module

Shader Module Type

A shader module is either:

  • Generic - a set of generic GLSL functions that can be included either in a fragment shader or a vertex shader (or both). The fp64 module is a good example of this type of module.
  • Functional - Contains specific vertex and/or fragment shader "chunks", often set up so that the vertex shader part sets up a varying used by the fragment shader part.

Shader Module Descriptor

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

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

Descriptor objects can define the following fields:

  • name (String, Required) - The name of the shader module.
  • vs - (String | null)
  • fs - (String | null)
  • getUniforms JavaScript function that maps JavaScript parameter keys to uniforms used by this module
  • uniforms (Object) - a light alternative to getUniforms, see below
  • dependencies (Array) - a list of other shader modules that this module is dependent on
  • deprecations (Array) - a list of deprecated APIs.

If deprecations is supplied, assembleShaders will scan GLSL source code for the deprecated constructs and issue a console warning if found. Each API is described in the following format:

  • type: uniform <type> or function
  • old: name of the deprecated uniform/function
  • new: name of the new uniform/function
  • deprecated: whether the old API is still supported.

GLSL Code

The GLSL code for a shader module typically contains:

  • a mix of uniform and varying declarations
  • one or more GLSL function definitions

getUniforms

Each shader module provides a method to get a map of uniforms for the shader. This function will be called with two arguments:

  • opts - the module settings to update. This argument may not be provided when getUniforms is called to generate a set of default uniform values.
  • context - the uniforms generated by this module's dependencies.

The function should return a JavaScript object with keys representing uniform names and values representing uniform values.

The function should expect the shape of the dependency uniforms to vary based on what's passed in opts. This behavior is intended because we only want to recalculate a uniform if the uniforms that it depends on are changed. An example is the project and project64 modules in deck.gl. When opts.viewport is provided, project64 will receive the updated projection matrix generated by the project module. If opts.viewport is empty, then the project module generates nothing and so should project64.

uniforms

If the uniforms of this module can be directly pulled from user settings, they may declaratively defined by a uniforms object:

{
  name: 'my-shader-module',
  uniforms: {
    strength: {type: 'number', value: 1, min: 0, max: 1},
    center: [0.5, 0.5]
  }
}

At runtime, this map will be used to generate the uniforms needed by the shaders. If either strength or center is present in the user's module settings, then the user's value will be used; otherwise, the default value in the original definition will be used.

Each uniform definition may contain the following fields:

  • type (String) - one of number, boolean, array or object
  • value - the default value of this uniform

With type: 'number', the following additional fields may be added for validation:

  • min (Number)
  • max (Number)

Note: uniforms is ignored if getUniforms is provided.

GLSL Syntax Conversion Reference

Where possible, the shader assembler replaces keywords based on the version of the shader into which a module is inserted. While not all GLSL ES 3.0 features can be emulated, this allows many modules to be used across versions.

Syntax replacement tables are provided below:

Vertex Shaders

3.00 ES 1.00 ES Comment
in attribute
out varying

Fragment Shaders

3.00 ES 1.00 ES Comment
in varying
out gl_FragColor
out gl_FragData
texture texture2D texture will be replaced with texture2D to ensure 1.00 code is correct. See note on textureCube below.
textureCube * textureCube textureCube is not valid 3.00 syntax, but must be used to ensure 1.00 code is correct, because texture will be substituted with texture2D when transpiled to 100. Also textureCube will be replaced with correct texture syntax when transpiled to 300.
gl_FragDepth gl_FragDepthEXT WebGL1: EXT_frag_depth
3.00 ES 1.00 ES Comment
texture2DLod texture2DLodEXT WebGL1: EXT_shader_texture_lod
texture2DProjLod texture2DProjLodEXT WebGL1: EXT_shader_texture_lod
texture2DProjLod texture2DProjLodEXT WebGL1: EXT_shader_texture_lod
textureCubeLod textureCubeLodEXT WebGL1: EXT_shader_texture_lod
texture2DGrad texture2DGradEXT WebGL1: EXT_shader_texture_lod
texture2DProjGrad texture2DProjGradEXT WebGL1: EXT_shader_texture_lod
texture2DProjGrad texture2DProjGradEXT WebGL1: EXT_shader_texture_lod
textureCubeGrad textureCubeGradEXT WebGL1: EXT_shader_texture_lod