WGSL Shader Preprocessor that implements imports of modules
Go to file
SeanOMik 76a1c98abd
Fix parsing workgroup vars, some fn attributes, and unique blocks
2024-11-24 16:32:25 -05:00
.vscode Struct importing 2024-08-19 20:27:40 -04:00
examples Add README.md 2024-08-09 12:40:45 -04:00
src Fix parsing workgroup vars, some fn attributes, and unique blocks 2024-11-24 16:32:25 -05:00
.gitignore use rust like module names for shader imports 2024-08-09 12:40:45 -04:00
Cargo.lock Convert the crate to a library crate 2024-08-09 15:12:01 -04:00
Cargo.toml Implement importing bindings 2024-08-11 10:34:20 -04:00
LICENSE super simple includes using a pest parser 2024-08-09 12:40:45 -04:00
README.md Implement importing bindings 2024-08-11 10:34:20 -04:00

README.md

WGSL Preprocessor

This crate was created for my 3d game engine, Lyra Engine, which uses this as a preprocessor.

Features

  • Import constants, functions, and bindings from other modules More to come, check out issues in this repo.

How-To

Preprocessing modules

To process modules, they first must be parsed to find the module paths of each file:

let mut p = Processor::new();

let inner_include_src = fs::read_to_string("shaders/inner_include.wgsl").unwrap();
let inner_module_path = p.parse_module(&inner_include_src)
    .unwrap().expect("failed to find module");

let simple_include_src = fs::read_to_string("shaders/simple.wgsl").unwrap();
let simple_module_path = p.parse_module(&simple_include_src)
    .unwrap().expect("failed to find module");

let base_include_src = fs::read_to_string("shaders/base.wgsl").unwrap();
let base_module_path = p.parse_module(&base_include_src)
    .unwrap().expect("failed to find module");

Then, after all the modules are parsed, you can preprocess the module. This is where all the imported modules and items are compiled into a single output shader:

let out = p.process_file(&base_module_path, &base_include_src).unwrap();
fs::write("out.wgsl", out).unwrap();

Importing modules

To import modules, that module must have its path defined. Do to so, at the top of the file, use the preprocessor command #define_module <module_path> with module_path being the identifier of the module and how its imported:

/// ==== shadows.wgsl
#define_module engine::shadows

const PCF_SAMPLES_NUM: u32 = 32;

/// ==== pbr.wgsl
#define_module engine::pbr
#import engine::shadows::{PCF_SAMPLES_NUM}

fn fs_main(in: VertexOutput) -> vec4<f32> {
    // ...

    let samples_num = PCF_SAMPLES_NUM;

    // ...
}

The above example imports an item from the engine::shadows module. Keep in mind that you cannot have conflicted names of variables, functions, types, and other imported things. Instead of importing an item from the module, you can import the module and use items from it (still no conflicting names):

/// ==== shadows.wgsl
#define_module engine::shadows

const PCF_SAMPLES_NUM: u32 = 32;

/// ==== pbr.wgsl
#define_module engine::pbr
// not importing an item, but only a module
#import engine::shadows

fn fs_main(in: VertexOutput) -> vec4<f32> {
    // ...

    // use an item from the module here
    let samples_num = shadows::PCF_SAMPLES_NUM;

    // ...
}