wgsl-preprocessor

1.0.1 • Public • Published

WGSL Preprocessor

This library provides a dirt-simple way of adding simple preprocessor macros to your WGSL shaders via tagged templates. It supports:

  • #if
  • #elif
  • #else
  • #endif

Most other typical preprocessor functionality can be supported via JavaScript's template literals.

Installation

You can install from npm:

npm install wgsl-preprocessor

And then import into your code as a standard ES6 module:

import { wgsl } from './node-modules/wgsl-preprocessor/wgsl-preprocessor.js';

Or use without an install step by loading it from a CDN like jsdelivr:

import { wgsl } from 'https://cdn.jsdelivr.net/npm/wgsl-preprocessor@1.0/wgsl-preprocessor.js';

Or, you know, just copy and paste the contents of wgsl-preprocessor.js where ever is convenient for you. It's less than a 100 lines of code, we really don't need to overthink it!

Usage

Import the wgsl symbol from wherever you've installed wgsl-preprocessor.js and use it as a tag for a template literal string:

import { wgsl } from 'https://cdn.jsdelivr.net/npm/wgsl-preprocessor@1.0/wgsl-preprocessor.js';

function getDebugShader(sRGB = false) {
  return wgsl`
  @stage(fragment)
  fn main() -> @location(0) vec4<f32> {
    let color = vec4(1.0, 0.0, 0.0, 1.0);
  #if ${sRGB}
    let rgb = pow(color.rgb, vec3(1.0 / 2.2));
    return vec4(rgb, color.a);
  #else
    return color;
  #endif
  }`;
}
`

When using #if or #elif the preprocessor symbol must be followed by a substitution expression that will be evaluated as a boolean.

wgsl`
  #if ${someVar}         // Valid
  #endif

  #if ${x > 5}           // Valid
  #endif

  #if ${someFunction()}  // Valid
  #endif

  #if true               // Invalid
  #endif

  #if 1                  // Invalid
  #endif
`;

If the result of the expression is truthy then the string contents between the opening and closing tags will be returned as part of the string, otherwise it will be omitted.

const x = 1;
const source = wgsl`
#if ${x < 3}
  let a = 1;
#endif

#if ${x > 3}
  let b = 2;
#endif

#if ${x == 3}
  let c = 3;
#else
  let c = 0;
#endif

#if ${x == 4}
  let d = 4;
#elif ${x == 1}
  let d = 1;
#else
  let d = 0;
#endif
`;

// source will be:
// let a = 1
//
//
// let c = 0;
//
// let d = 1;

#if/#elif statements may be nested any number of levels deep:

wgsl`
#if ${shadowsEnabled}
  #if ${lightType == 'point'}
    let shadowAmount = computePointLightShadow();
  #elif ${lightType == 'spot'}
    let shadowAmount = computeSpotLightShadow();
  #else
    let shadowAmount = computeDirectionalShadow();
  #endif
  lightFactor = lightFactor - shadowAmount;
#endif
`;

And any number of #elifs may be chained:

wgsl`
#if ${sampleCount == 1}
  var sampleOffsets : array<vec2<f32>, 1> = array<vec2<f32>, 1>(
    vec2(0.0, 0.0)
  );
#elif ${sampleCount == 2}
  var sampleOffsets : array<vec2<f32>, 2> = array<vec2<f32>, 2>(
    vec2(-0.5, -0.5), vec2(0.5, 0.5)
  );
#elif ${sampleCount == 4}
  var sampleOffsets : array<vec2<f32>, 4> = array<vec2<f32>, 4>(
    vec2(-0.5, -0.5), vec2(-0.5, 0.5), vec2(0.5, -0.5), vec2(0.5, 0.5),
  );
#elif ${sampleCount == 8}
  // Etc...
#endif
`;

Why no #define?

If you need something to approximate a #define statement from other preprocessors, simply use JavaScript's built-in substitution expressions! You don't even need the wgsl tag!

const ambientFactor = 1.0;
const sampleCount = 2;

const source = `
  let ambientFactor = f32(${ambientFactor});

  for (var i = 0u; i < ${sampleCount}u; i = i + 1u) {
    // Etc...
  }
`;

But of course, they play nicely with the wgsl tag too:

const useApproximateSRGB = true;
const approxGamma = 2.2;

export const colorConversions = wgsl`
  fn linearTosRGB(linear : vec3<f32>) -> vec3<f32> {
    #if ${useApproximateSRGB}
      let INV_GAMMA = 1.0 / ${approxGamma};
      return pow(linear, vec3(INV_GAMMA));
    #else
      if (all(linear <= vec3(0.0031308))) {
        return linear * 12.92;
      }
      return (pow(abs(linear), vec3(1.0/2.4)) * 1.055) - vec3(0.055);
    #endif
  }
`;

Readme

Keywords

none

Package Sidebar

Install

npm i wgsl-preprocessor

Weekly Downloads

88

Version

1.0.1

License

MIT

Unpacked Size

24.4 kB

Total Files

5

Last publish

Collaborators

  • toji