Asset Types - limztudio/NWBLot GitHub Wiki

Asset Types

NWBLot runtime assets implement Core::Assets::IAsset. Most use TypedAsset<T>; shader types use the shared IShader/TypedShader<T> hierarchy. Each concrete asset type exposes a stable asset type name and loads from cooked binary payloads through a registered codec.

Current core engine asset types include:

  • concrete shader types, including compute_shader, pixel_shader, vertex_shader, and mesh_shader
  • material
  • texture
  • sampler
  • font
  • font_atlas
  • ui_skin
  • mesh
  • skin
  • skeleton
  • model
  • csg_shape cook metadata

Typed Asset Contract

A typed asset has:

  • a C++ asset class
  • an asset type name
  • a virtual path
  • a binary payload format
  • an asset codec

Runtime loading normally goes through:

  1. AssetRef<T> stores a virtual path.
  2. AssetManager reads cooked bytes from the mounted volume.
  3. AssetRegistry selects the codec by requested asset type.
  4. The codec constructs T and calls loadBinary.

This keeps references type-aware without embedding asset objects directly inside components.

Shader

interface IShader owns the common entry-point and bytecode storage. Final concrete types select their physical stage through static constexpr s_Stage and have separate registered codecs sharing one payload and serialization implementation. IShader is abstract and has no generic loadable asset type.

Authored type C++ asset type
vertex_shader VertexShader
hull_shader HullShader
domain_shader DomainShader
geometry_shader GeometryShader
pixel_shader PixelShader
compute_shader ComputeShader
amplification_shader AmplificationShader
mesh_shader MeshShader
ray_generation_shader RayGenerationShader
any_hit_shader AnyHitShader
closest_hit_shader ClosestHitShader
miss_shader MissShader
intersection_shader IntersectionShader
callable_shader CallableShader

Declare compute_shader asset;, pixel_shader asset;, or the required concrete type. Its declaration determines the physical stage; the generic shader declaration and authored asset.stage field are rejected. Known stage bindings use concrete references, such as AssetRef<PixelShader>; heterogeneous material stage arrays use AssetRef<IShader>. ShaderAssetLoader::Load<ComputeShader>(...) derives the stage, while LoadForStage(...) handles genuinely dynamic stage requests.

Runtime payload:

  • versioned shader header
  • authored entry-point string
  • SPIR-V bytecode bytes

The runtime shader asset does not store Slang source, include roots, or compiler state. Cook-time code validates and compiles source; runtime code validates the payload and consumes the stored bytecode through graphics shader module creation using the stored entry-point name.

SPIR-V bytecode validation checks:

  • payload magic and supported payload version
  • non-empty entry-point name
  • bytecode contains a complete SPIR-V header
  • byte size is word-aligned
  • first word matches SPIR-V magic
  • the complete instruction stream scans within bounds
  • the exact entry point exists for the concrete physical stage

The cooker asks Slang to preserve the authored entry-point spelling in SPIR-V, and the backend uses that stored spelling. The neutral nwb_shader_bytecode target owns core/graphics/spirv_entry_point.h and .cpp and declares a public nwb_common dependency, alongside the standard internal target defaults. Shader asset runtime/cook targets use it for admission, and nwb_graphics_backend uses the same parser for module validation. Payload encoding, concrete types and codecs remain in impl/assets_shader; provider-specific headers remain behind graphics selection. Concrete asset admission validates directly from a byte view, including unaligned payload offsets, without a temporary word copy. Failure preserves previously loaded entry-point and bytecode storage. Backend shader-module creation retains its independent module/stage check through the selected graphics API. A malformed instruction stream is reported as invalid SPIR-V rather than as a missing entry point.

Archive roles remain distinct from physical types: mesh_compute resolves ComputeShader payloads, while mesh_object_vertex resolves a VertexShader. Role names do not introduce additional asset classes. Concrete shader types add no per-object stage field, duplicated bytecode, or per-frame virtual stage dispatch.

Material

Material is a typed asset with type name material.

Runtime payload:

  • shader variant string
  • material interface name
  • shading-model id
  • surface dispatch id (surfaceDispatchId)
  • typed layout hash
  • typed layout blocks
  • typed layout fields
  • packed typed block bytes
  • static material resource-reference records
  • stage shader references
  • AVBOIT occupancy, extinction, and accumulate pixel shader references when and only when transparent is set
  • transparent flag
  • two-sided flag
  • refractive flag

Supported metadata fields are:

  • interface
  • surface
  • bxdf
  • shaders
  • shader_variant
  • parameters
  • transparent
  • two_sided
  • refractive

Materials must explicitly author transparent, two_sided, and refractive, including zero values. There is no asset.alpha material metadata field in the current schema.

bxdf is required during cooking and selects the deferred lighting model for the material. A material declares exactly one of surface or explicit shaders: surface lets the cook generate the G-buffer pixel shader, assign the shared engine mesh shader, assign the surface dispatch id, and generate transparent occupancy/extinction/accumulate shaders when transparent is set. shaders directly maps supported stages to authored shader assets for opaque, non-refractive materials only. Transparent or refractive materials require a project surface hook.

The AVBOIT references are all-or-none: transparent materials require all three pass shaders, and opaque materials require none. That invariant is checked while building, serializing, and loading a material asset.

refractive classifies a material as a refractive caster for shadow and caustic work and, when its surface IOR is finite and above 1.0 (nwbRefractionIorEligible in impl/assets/graphics/refraction/ior.slangi), as a camera-refraction primary. It is separate from transparent; the material .surface hook supplies refraction and transmission values.

interface, surface, bxdf, and explicit stage shaders are material-authored policy paths and use the project/ virtual root. Cook-generated engine stages are assigned by the material cook, not authored through those metadata fields.

Material block classes:

  • material_constant
  • material_mutable

Typed material fields support scalar/vector families for bool, signed/unsigned integer sizes, half, and float. Half values are represented as 16-bit payload data and typed layout blocks are padded to the material word size.

The static-resource slice adds texture2d and sampler fields only to material_constant blocks. Resource fields have no .bind attributes; the material's matching block/field entry under asset.parameters supplies an engine/ or project/ path to a typed Texture or Sampler asset. The payload stores the resource kind/source, block and field identity, asset-name hash, and four-byte constant-byte offset, never a device descriptor handle. At runtime the renderer loads and caches the named asset, resolves its global-heap slot, and patches the typed-byte working copy. Resource fields cannot be overridden per instance.

Texture

Texture is a typed asset with type name texture. Its authored source is a texture asset; metadata file paired with a raw UASTC .tex sidecar. Authors select format (uastc_ldr_4x4 or uastc_hdr_4x4), dimension, base dimensions, and the data filename. Volumes require depth; 2D and cube textures infer it. LDR also declares color space and alpha presence; HDR declares an alpha mode and, only for constant alpha, its value. The cooker derives fixed block geometry, the complete mip/sidecar layout, and HDR linear color space and alpha presence, then validates and serializes one internally versioned runtime payload. Metadata contains no version/revision or derived transport fields. See Texture Conversion for the exact authoring contract.

Runtime payload data includes:

  • payload format, color space, and alpha mode
  • dimension (2d, cube, or volume) and base width, height, and depth
  • the complete mip table, including per-mip dimensions, slice count, block grid, byte offset, and byte size
  • contiguous UASTC LDR or HDR 4x4 blocks, plus a matched trailing LDR alpha stream when HDR needs variable alpha

The runtime validates the payload before creating GPU resources. TextureAssetLoader creates a matching 2D, cube, or 3D image and global sampled-image heap entry. Cached Vulkan probing selects LDR ASTC 4x4, BC7, or RGBA8; opaque HDR selects ASTC HDR 4x4, BC6H, or RGBA16_FLOAT; and HDR with alpha uses RGBA16_FLOAT so the alpha value or mask is preserved. Material texture2d references deliberately accept only the 2D descriptor class; cube and volume assets require a consumer with a matching bindless accessor.

Sampler

Sampler is a typed asset with type name sampler. Its authored source is a sampler asset; metadata file that defines the complete sampler description:

  • min_filter, mag_filter, and mip_filter: nearest or linear
  • address_u, address_v, and address_w: clamp, wrap, border, mirror, or mirror_once
  • reduction: standard or comparison
  • max_anisotropy and mip_bias

Border addressing uses the engine's fixed transparent-black border color; metadata does not expose border_color. The cooker rejects that retired field and unsupported minimum/maximum reduction modes, then validates and serializes the supported sampler choices. At runtime, SamplerAssetLoader validates the cooked payload, creates the graphics sampler, and allocates/writes a Sampler entry in the global descriptor heap. The material renderer caches sampler assets by virtual path and patches the resulting bindless sampler slot into its typed constant bytes. Engine-provided sampler assets include engine/samplers/linear_clamp and the corresponding linear/nearest clamp, mirror, and wrap variants.

Font and Font Atlas

Font authoring uses a same-stem .nwb/.font pair. The readable document declares a fieldless font face; and a font_atlas atlas;, optionally exported together by asset_bunch bunch = [face, atlas];. atlas.font = face; selects the typed relation. The prepared .font contains the authoritative SFNT and compact SDF images; both cookers derive its filename from the metadata stem.

The atlas declares bake size, spread, raster mode, editable vertical layout metrics, and one record per source glyph in source order. Empty glyphs declare only required advance_units; bitmap glyphs also declare group/channel, a positive-sized rectangle, and left/top plane origin. Cooking derives face index, units per em, glyph count, image dimensions/channels, and the fixed one-texel guard. Each glyph ID comes from its list ordinal; drawable state follows bitmap presence, and right/bottom plane bounds follow bitmap size and bake scale. Metadata rejects copied source facts, a groups list, authored glyph IDs/drawable/right/bottom fields, fixed-zero empty geometry, and version/revision fields. Runtime Font and FontAtlas payloads retain their internal binary contracts and validated IDs/layouts. See the Font guide and FontAtlas guide for exact fields and bounds.

UI Skin

UiSkin is a typed asset with type name ui_skin. Current .nwb metadata declares its typed texture reference, atlas extent, reference density, named regions, complete color palette, and default typography without a version, schema-version, or revision field.

Regions require a name and rectangle. draw_mode defaults to sprite; nine_slice requires its editable slice insets. Sprite regions omit slice, and even an authored zero array is rejected.

The optional asset.toolkit_contract = "widgets"; field validates the required stock widget regions during cooking. Generic partial skins may omit it, but the UI layer validates the same widget contract before selecting a startup or replacement skin. Internal cooked UI skin payload version 3 remains a codec contract. See the UI skin asset guide for fields, limits, and same-skin state fallbacks.

Mesh

Mesh is a typed asset with type name mesh.

Runtime geometry payload:

  • position stream
  • normal stream
  • tangent stream
  • UV0 stream
  • color stream
  • meshlet descriptors
  • meshlet bounds
  • meshlet position reference deltas
  • meshlet attribute reference deltas
  • meshlet local vertex references
  • meshlet primitive indices

Mesh payloads are built for meshlet-style rendering. The renderer selects native mesh shaders when effective support exists; otherwise it uses persistent indexed raster for eligible engine mesh programs or cooker-derived compute emulation for other draws.

Skin

Skin is a typed asset with type name skin.

Runtime payload:

  • mesh reference
  • skeleton reference
  • four-weight/four-index influences (u16 joint indices, f32 weights)
  • inverse bind matrices

The skin asset binds a mesh to a skeleton. Runtime skinning systems combine skin data, skeleton pose/palette data, and mesh resources to build renderer-visible skinned mesh buffers.

Skeleton

Skeleton is a typed asset with type name skeleton.

Runtime payload:

  • joints
  • parent indices
  • local bind poses
  • child ranges
  • child indices
  • joint name to index map

The skeleton asset rebuilds hierarchy data after loading. Runtime ECS skeleton components then hold mutable pose and palette data for scene instances.

Model

Model is a typed asset with type name model.

Model objects can be:

  • skeleton objects
  • static mesh objects
  • skinned mesh objects

Skeleton object payload:

  • object name
  • skeleton reference
  • transform

Static mesh object payload:

  • object name
  • mesh reference
  • material reference
  • optional parent object
  • optional parent joint
  • transform

Skinned mesh object payload:

  • object name
  • skin reference
  • material reference
  • skeleton object name
  • transform

Skinned metadata requires skin and a local skeleton object name, with optional material and 3x4 transform; it rejects mesh. Static objects still declare their mesh. Runtime source loading resolves and caches the skinned mesh from the authoritative Skin reference. The internal MDL2 model payload likewise omits the duplicate mesh identity; recook older model payloads.

The model ECS system expands model assets into runtime entities and components. This lets authored model structure remain asset-driven while renderer/skinning systems operate on small focused ECS components.

CSG Shape Metadata

CSG shape cook metadata uses asset type name csg_shape during cooking.

Cooked shape entries include:

  • shape name
  • shader module name
  • assigned shape type id
  • eval include path
  • generated module include path

Built-in shapes:

  • plane
  • box
  • sphere
  • capsule

The renderer's CSG shape registry uses this information to match cutter components to shader evaluation code and parameter byte layouts. At runtime the built-in shapes are registered under namespaced names (engine/csg/plane, engine/csg/box, engine/csg/sphere, engine/csg/capsule).

⚠️ **GitHub.com Fallback** ⚠️