From 514114892dd6090e0df256d6a8d5dca852e44de6 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Tue, 31 Mar 2026 23:04:28 +0200 Subject: [PATCH] Add HDR texture support and metadata extraction --- src/assets/image-assets.ts | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/assets/image-assets.ts b/src/assets/image-assets.ts index 7700db96..0a83454d 100644 --- a/src/assets/image-assets.ts +++ b/src/assets/image-assets.ts @@ -184,6 +184,18 @@ function extractImageAssetMetadata(image: HTMLImageElement): ImageAssetMetadata }; } +function extractHdrTextureMetadata(texture: DataTexture): ImageAssetMetadata { + const width = texture.image.width as number; + const height = texture.image.height as number; + const warnings: string[] = []; + + if (Math.abs(width / height - 2) > 0.15) { + warnings.push("Background images work best as a 2:1 equirectangular panorama."); + } + + return { kind: "image", width, height, hasAlpha: false, warnings }; +} + function createImageTexture(image: HTMLImageElement): Texture { const texture = new Texture(image); texture.colorSpace = SRGBColorSpace; @@ -192,6 +204,28 @@ function createImageTexture(image: HTMLImageElement): Texture { return texture; } +function configureHdrTexture(texture: DataTexture): DataTexture { + // HDR/EXR data is linear — do not apply sRGB color space + texture.colorSpace = LinearSRGBColorSpace; + texture.mapping = EquirectangularReflectionMapping; + texture.needsUpdate = true; + return texture; +} + +function loadHdrTexture(url: string, sourceName: string): Promise { + return new Promise((resolve, reject) => { + if (getFileExtension(sourceName) === "exr") { + new EXRLoader().load(url, resolve, undefined, () => { + reject(new Error(`EXR file could not be loaded: ${sourceName}.`)); + }); + } else { + new RGBELoader().load(url, resolve, undefined, () => { + reject(new Error(`HDR file could not be loaded: ${sourceName}.`)); + }); + } + }); +} + function createLoadedImageAsset( asset: ImageAssetRecord, image: HTMLImageElement, @@ -208,6 +242,22 @@ function createLoadedImageAsset( }; } +function createLoadedHdrImageAsset( + asset: ImageAssetRecord, + texture: DataTexture, + sourceUrl: string, + revokeSourceUrl: () => void +): LoadedImageAsset { + return { + assetId: asset.id, + storageKey: asset.storageKey, + metadata: asset.metadata, + texture: configureHdrTexture(texture), + sourceUrl, + revokeSourceUrl + }; +} + function createImageAssetRecord( sourceName: string, mimeType: string,