Skip to content

Asset Flow

TeoLim edited this page Oct 16, 2026 · 20 revisions

Asset Flow

This page explains how an NWBLot asset moves from a source file to runtime rendering.

Short Version

authored file -> cook entry -> binary payload -> cooked volume -> AssetManager -> typed asset -> ECS/render system

The runtime does not treat assets as loose source files. It expects cooked data with a known asset type and a codec that can load that type.

Step 1: Author Source Content

Source content is edited under engine and project asset roots.

Shared reusable engine assets live under impl/assets. These include common graphics shader code, renderer support shaders, CSG shape assets, and scene/mesh shader ABI helpers. Material interfaces, surfaces, and BXDF policy live under the project asset root that authors them.

Project-specific authored assets live under project trees such as CoolStuff/Testbed/assets. These include Testbed materials, meshes, and project shader files.

Common source asset forms include:

  • .nwb metadata files
  • .tex raw UASTC texture sidecars
  • .slang shader source
  • .slangi shader include files
  • .bind typed shader/material interface declarations
  • .surface material surface hooks
  • .bxdf material lighting BXDF fragments
  • mesh/model/skin/skeleton source metadata
  • CSG shape metadata and evaluator shader includes

Step 2: Register Cook Entries

Asset types provide cook logic through engine modules. Cook registration connects an authored asset type to code that knows how to parse, validate, compile, and serialize it.

Concrete asset modules register codec factories and cook-entry factories through the core auto-registration helpers. The loader collects codec factories into its AssetRegistry. asset_builder collects CookEntryAutoRegistrar entries into CookEntryRegistry and graphics prepare steps through AssetVolumePrepareAutoRegistrar. Factory collection is deduplicated, so a linked module contributes each factory once.

Examples of concrete cook ownership:

  • impl/assets_shader cooks shader assets through the graphics volume-prepare path
  • impl/assets_material cooks material assets and material binding metadata
  • impl/assets_texture cooks typed UASTC texture assets
  • mesh, skeleton, model, and CSG implementation modules cook their own runtime payloads (the skin asset is cooked inside impl/assets_mesh, not a separate assets_skin module)
  • pipeline/ orchestrates discovery, selected-input building, and volume publishing

core/assets owns the generic cook plumbing: cook-entry registration, input lists, asset-bunch expansion, and staged volume publication. Implementation modules retain each asset type's parsing, validation, compilation, and serialization rules.

The pipeline is intentionally the place where expensive or fragile validation belongs.

Step 3: Parse And Validate

Cookers read authored metadata and validate the current asset contract. Authored .nwb files expose content and choices an author can control; versions, revisions, fixed payload layouts, derived transport counts, backend compiler profiles, and fixed engine transport switches remain internal. Unknown or retired fields fail validation rather than selecting a compatibility reader.

Validation examples:

  • metadata fields must match the asset schema
  • shader stages and variants must be named consistently
  • shader metadata must declare a concrete physical-stage type, such as compute_shader or pixel_shader; generic shader declarations and authored stage fields are rejected
  • material metadata must use the fields defined by the material metadata header
  • .bind files must declare typed blocks and instances correctly
  • material surface and bxdf paths must resolve through asset roots
  • material and shader interface names must match
  • authored material parameter values must match their typed layout fields
  • material texture2d and sampler fields must use material_constant storage, declare no field attributes, and receive an engine/ or project/ typed asset path through their block-scoped asset.parameters entry
  • texture metadata selects UASTC LDR or HDR, resolution, and alpha_mode for its implicit same-basename .tex sidecar; the cooker derives the complete mip layout, and a variable HDR alpha stream must mirror RGB
  • shader dependencies must resolve through stable asset roots

For material binding, the current path is typed-only at binding 6. Generated typed .bind helpers are part of the contract. Shaders that include a generated material bind receive NWB_MATERIAL_TYPED_BINDING == 1; in the generated material path this is the pixel shader, while the shared mesh shader stays interface-free.

Step 4: Compile And Pack Runtime Payloads

After validation, cookers write binary payload data.

Shader cooking compiles shader-language sources into SPIR-V bytecode and records shader archive information. Runtime graphics consumes that cooked bytecode.

Material cooking packs:

  • material metadata
  • shader and variant references
  • material interface identity
  • material shading-model id from its bxdf
  • material surface dispatch id from its surface
  • material refractive-caster classification
  • typed block layout
  • packed parameter bytes
  • typed texture and sampler asset references, their block/field identity, resource kind/source, asset-name hash, and constant-byte offset
  • stable instance identifiers

Transparent or refractive materials require a project surface hook; explicit shaders are allowed only for opaque, non-refractive materials. When a material declares surface, the cook generates a G-buffer pixel shader from the engine pixel-shader authoring header, the material .bind, and the .surface hook. It then assigns that generated pixel shader plus the shared engine mesh shader as the material's stage shaders.

For transparent surface-authored materials, the cook also generates AVBOIT occupancy, extinction, and accumulate pixel shaders from the same .bind and .surface pair. Shadow paths use the cooked surfaceDispatchId to dispatch the surface hook for transparent occluder optical parameters, and caustic paths use the refractive material flag plus .surface refraction values to identify and trace refractive casters.

Mesh/model/skinning cooking prepares renderer-usable geometry and animation data, including meshlet payloads, model hierarchy data, skin data, and skeleton pose data.

Texture cooking derives the complete mip and alpha layout from the resolution, validates the metadata/implicit-sidecar pair without conversion or re-encoding, and packs the raw linear UASTC blocks, complete mip layout, payload format, alpha mode, and dimension into the typed Texture payload. Every runtime texture uses linear RGB and linear alpha coverage. HDR payloads retain either an opaque/constant alpha declaration or a trailing matching UASTC LDR mask stream. The runtime loader can then create a 2D, cube, or 3D image from the mounted volume without rereading authoring files.

Step 5: Publish Cooked Volumes

asset_builder writes standalone .nwba artifacts. asset_gatherer then writes the graphics volume through IFilesystem. Publishing is staged so incomplete output is not promoted as a finished runtime volume. Shared volume writing, cook-cache, .nwba artifacts, and pack-manifest support live in core/assets/volume; registered prepare steps gather the per-type payloads that the builder serializes.

At runtime, the loader mounts the graphics volume from the res directory through CreateFilesystem. The mounted IFilesystem becomes the binary source for asset loading.

The handoff from authored source to runtime asset loading looks like this:

flowchart TD
    Authored["Authored asset roots<br/>impl/assets<br/>CoolStuff/Testbed/assets"]
    Discover["pipeline/launch.py discovers source assets"]
    Builder["asset_builder validates by asset type"]
    Artifacts["Standalone .nwba artifacts"]
    Volume["asset_gatherer publishes graphics volume"]
    Mount["Loader mounts res/graphics"]
    Source["IAssetBinarySource reads IFilesystem bytes"]
    Registry["AssetRegistry selects codec"]
    Runtime["AssetManager returns typed asset"]
    Systems["ECS and renderer systems consume asset"]

    Authored --> Discover --> Builder --> Artifacts --> Volume --> Mount --> Source --> Registry --> Runtime --> Systems
Loading

Step 6: Load Typed Assets

Runtime asset loading uses three main pieces:

  • AssetManager receives a virtual path and requested type.
  • IAssetBinarySource returns bytes from the mounted cooked volume.
  • AssetRegistry selects the registered codec for the asset type.

The codec deserializes the binary payload into a typed runtime asset object.

This keeps runtime loading explicit. A material request produces a material asset; a compute shader request produces ComputeShader, and a pixel shader request produces PixelShader. Concrete shader codecs share common IShader storage and one payload layout, but validate the exact SPIR-V entry point and physical stage before publishing state. A wrong-stage or malformed payload fails without replacing previously loaded storage.

Step 7: Use Assets In ECS And Renderer Systems

Project and engine systems store typed asset references in components and runtime caches.

Typical examples:

  • model components reference model assets
  • render components reference mesh/material assets
  • skinning systems reference skin and skeleton assets
  • renderer systems resolve material shader variants through the shader archive
  • material preparation resolves cached cooked 2D texture assets into global sampled-image heap slots
  • CSG systems reference shape assets and evaluator shader support

Renderer systems then upload or bind the GPU resources required for the current scene.

Why This Flow Matters

This flow makes the engine easier to reason about:

  • source validation happens before runtime
  • runtime asset loading is typed
  • shader compilation stays in cook targets
  • material layouts are deterministic
  • project content and shared engine content stay separated
  • cook determinism can be tested independently from rendering

The detailed reference pages are Asset Pipeline, Asset Types, Cooked Volumes, and Shader and Material System.

Clone this wiki locally