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()?;