slang-pbr

June 7, 2026 ยท View on GitHub

Slang implementations of:

  • Enterprise PBR
  • OpenPBR
  • sampled glTF PBR parameter mapping
  • homogeneous volume helpers
  • analytic and LUT-backed energy compensation

OpenPBR is implemented as its own lobe stack and is analytical-parity tested against cases derived from Adobe's openpbr-bsdf reference implementation.

Model Status

ModelImplemented material featuresKnown material-feature gaps
Enterprise PBRCore metallic/dielectric BSDF, opaque and transparent dielectric transmission, diffuse transmission/translucency, thin film, dispersion, clearcoat, sheen, emission, homogeneous volume preparation, and LUT data/hooks for energy compensation.Metallic flakes and photometric emission parameterization are not implemented.
OpenPBRSeparate OpenPBR implementation with base, coating, fuzz, thin-wall transmission, homogeneous volume preparation, thin film, dispersion hooks, emission, and LUT data/hooks for energy compensation. Analytical eval/pdf parity is tested against Adobe-reference-derived cases.Thick subsurface parameters are currently mapped to homogeneous volume parameterization, no separate BSSRDF/random-walk subsurface transport.

Cut-out/geometry opacity and displacement are treated as geometry/visibility features for the renderer to handle before BSDF evaluation.

Contents

Quick Start

Install from npm:

npm install slang-pbr

Pick one entrypoint:

EntrypointUse it when
gltf_pbr.slanginputs are sampled glTF PBR parameters
models/enterprise/enterprise_pbr.slanginputs are native Enterprise PBR parameters
models/openpbr/openpbr.slanginputs are native OpenPBR parameters

Sampled glTF Parameters

For sampled glTF PBR parameters:

#define SLANG_PBR_MODEL SLANG_PBR_MODEL_ENTERPRISE
#include "gltf_pbr.slang"

GltfPbrMaterial gltf = defaultGltfPbrMaterial();
PbrSurfaceMaterial surface = buildPbrSurfaceFromGltf(gltf);
PbrClosure closure = buildPbrSurfaceClosure(surface, normals, normals.anisotropyTangent);
PbrBsdfState state = preparePbrBsdfState(surface, closure, transport);

float3 value = evalPbrBsdf(state, directions, normalContext);
float pdf = pdfPbrBsdf(state, directions, normalContext);
PbrBsdfSample sample = samplePbrBsdf(state, directions, normalContext, randoms);

Switch the selected backend by changing the define:

#define SLANG_PBR_MODEL SLANG_PBR_MODEL_OPENPBR
#include "gltf_pbr.slang"

The glTF adapter uses Khronos property names. It does not perform texture lookup, UV transforms, packed-layout decoding, or resource binding.

Native Enterprise PBR Parameters

For native model parameters, include the model entrypoint directly:

#include "models/enterprise/enterprise_pbr.slang"

SurfaceMaterial surface = /* native Enterprise PBR parameters */;
SurfaceClosure closure = buildSurfaceClosure(surface, normals, normals.anisotropyTangent);
MaterialBsdfState state = prepareMaterialBsdfState(surface, closure, transport);

float3 value = evalMaterialBsdf(state, directions, normalContext);

Native OpenPBR Parameters

#include "models/openpbr/openpbr.slang"

OpenPbrSurfaceMaterial surface = defaultOpenPbrSurfaceMaterial();
SurfaceClosure closure = buildOpenPbrSurfaceClosure(surface, normals, normals.anisotropyTangent);
OpenPbrBsdfState state = prepareOpenPbrBsdfState(surface, closure, transport);

float3 value = evalOpenPbrBsdf(state, directions, normalContext);

Generated Shader Includes

Renderers that consume generated shader text can emit include-safe output:

npx slang-pbr-generate --target wgsl --kind include --out-dir ./generated/slang-pbr

Call the stable Pbr* facade symbols listed in slang-pbr.codegen.json, not backend-generated Slang names.

Package Exports

ExportPurpose
slang-pbrEnterprise PBR source entrypoint
slang-pbr/pbr.slangselected-model API
slang-pbr/gltf_pbr.slangsampled glTF adapter
slang-pbr/openpbr.slangOpenPBR source entrypoint
slang-pbr/manifeststable API manifest
slang-pbr/models/enterprise/lut/dataEnterprise LUT data JSON
slang-pbr/models/openpbr/lut/dataOpenPBR LUT data JSON
slang-pbr/tools/generategenerator module

Non-JavaScript consumers can use the same files from a git tag, source archive, CMake FetchContent, Rust build.rs, Python build step, or any build system that can invoke slangc.

Project Layout

src/
  pbr/                  selected-model interface and wrappers
  adapters/gltf/        sampled glTF parameter adapter
  models/enterprise/    Enterprise PBR model, lobes, volume prep, LUT hooks
  models/openpbr/       OpenPBR model, lobes, volume prep, LUT hooks
  core/                 shared math, frames, Fresnel, GGX, thin film
  shared/               common surface, direction, normal, and sample types
  volume/               homogeneous medium helpers
  api.manifest.json     stable adapter-facing API manifest

tools/
  generate.mjs          WGSL/HLSL/GLSL/SPIR-V generator
  include_facade.mjs    stable facade builder for text includes
  measure_openpbr_metrics.mjs

tests/
  openpbr/              analytical OpenPBR parity checks

Documentation

Validation

npm test
npm run test:openpbr

npm test checks generator structure and runs the OpenPBR analytical parity suite.

Current validation coverage:

  • OpenPBR eval/pdf behavior is compared against analytical cases derived from Adobe's openpbr-bsdf reference implementation. Strict OpenPBR sampling parity is not covered yet; sampling quality is validated through renderer-level visual/MIS tests for now.
  • Enterprise PBR is checked against the official Enterprise PBR validation suite in downstream renderer integration tests. Those scene-level checks live outside this package because they require a complete renderer.

AI Collaboration

slang-pbr is being developed with heavy use of AI coding assistants. AI is used for implementation work: code generation, boilerplate, refactoring, test scaffolding, and unfamiliar glue. Technical direction, material-model decisions, validation targets, and review remain human-led.

Acknowledgements

This project builds on public specification and open source work:

License

Apache-2.0.