Social & Economy

aether-asset-pipeline

Asset import, processing, compression, and bundle packaging

The aether-asset-pipeline crate handles asset conversion from source formats (glTF, FBX, OBJ) into optimized runtime bundles. It provides mesh processing, texture compression, LOD generation, content hashing, bundle packaging, and hot-reload for development workflows.

Overview

Assets pass through a multi-stage pipeline before they are ready for runtime use:

  • Import from glTF, FBX, and OBJ formats with material and texture extraction.
  • Mesh optimization including vertex deduplication and simplification.
  • LOD generation with configurable reduction policies.
  • Texture compression to GPU-native formats (BC, ASTC, ETC).
  • Content hashing for cache invalidation and deduplication.
  • Bundle packaging that groups related assets into a single archive with a manifest.
  • Hot-reload that watches source files for changes and triggers re-processing.

Key Types

GltfImporter

Imports glTF files, extracting meshes, materials, textures, and scene hierarchy.

use aether_asset_pipeline::{GltfImporter, ImportedScene, GltfImportError};

let importer = GltfImporter::new();
let scene: ImportedScene = importer.import("assets/scene.gltf")?;

MeshOptimizer

Optimizes imported meshes by removing duplicate vertices and simplifying geometry.

use aether_asset_pipeline::{SimpleMeshOptimizer, ImportedMesh, Vertex};

let optimizer = SimpleMeshOptimizer::new();
let optimized = optimizer.optimize(&mesh)?;

AutoLodPolicy

Defines how LOD levels are automatically generated from a source mesh.

use aether_asset_pipeline::{AutoLodPolicy, ProgressionRule, LodLevel};

let policy = AutoLodPolicy {
    levels: vec![
        LodLevel { distance: 0.0, reduction: 0.0 },
        LodLevel { distance: 20.0, reduction: 0.5 },
        LodLevel { distance: 50.0, reduction: 0.75 },
    ],
    rule: ProgressionRule::Geometric,
};

TextureCompressor

Compresses textures into GPU-native formats for efficient VRAM usage.

use aether_asset_pipeline::{
    TextureCompressor, PassthroughCompressor, TextureInput, CompressedTexture,
};

let compressor = PassthroughCompressor;
let compressed: CompressedTexture = compressor.compress(&texture_input)?;

ContentHasher

Computes content-addressed hashes for asset deduplication and cache keys.

use aether_asset_pipeline::{ContentHasher, HashedAsset};

let hasher = ContentHasher::new();
let hashed: HashedAsset = hasher.hash(&asset_bytes);

BundleWriter

Packages multiple processed assets into a single bundle archive with a manifest.

use aether_asset_pipeline::{BundleWriter, BundleEntry, AssetBundle};

let mut writer = BundleWriter::new();
writer.add(BundleEntry {
    path: "meshes/tree.bin".into(),
    data: mesh_bytes,
    hash: content_hash,
});
let bundle: AssetBundle = writer.finalize()?;

HotReloadWatcher

Watches asset source directories and emits reload events when files change.

use aether_asset_pipeline::{HotReloadWatcher, HotReloadConfig, ReloadEvent};

let watcher = HotReloadWatcher::new(HotReloadConfig {
    watch_paths: vec!["assets/".into()],
    debounce_ms: 200,
});
// Events are emitted when source files change

AssetBudget

Tracks asset memory usage against configurable budgets per category.

use aether_asset_pipeline::{AssetBudget, BudgetCategory, BudgetReport};

let mut budget = AssetBudget::new();
budget.set_limit(BudgetCategory::Textures, 256 * 1024 * 1024); // 256 MB
budget.record_usage(BudgetCategory::Textures, texture_size);
let report: BudgetReport = budget.report();

Usage Examples

Full Pipeline

use aether_asset_pipeline::{
    GltfImporter, SimpleMeshOptimizer, ContentHasher,
    BundleWriter, AutoLodPolicy,
};

let scene = GltfImporter::new().import("model.gltf")?;
let optimizer = SimpleMeshOptimizer::new();

let mut writer = BundleWriter::new();
for mesh in &scene.meshes {
    let optimized = optimizer.optimize(mesh)?;
    let hashed = ContentHasher::new().hash(&optimized.to_bytes());
    writer.add_mesh(hashed);
}
let bundle = writer.finalize()?;