免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

three.js UltraHDRLoader 实战指南:用 Gain Map 技术加载 Ultra HDR 全景纹理

three.js UltraHDRLoader 实战指南:用 Gain Map 技术加载 Ultra HDR 全景纹理 three.js UltraHDRLoader 实战指南用 Gain Map 技术加载 Ultra HDR 全景纹理【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsUltraHDR 是一种基于 JPEG 编码、携带 HDR Gain Map 的轻量级高动态范围图像格式。本文围绕 UltraHDRLoader 官方文档展开结合 源码实现 与仓库内置示例讲解其在 three.js 中的导入方式、API 用法、解析原理与适用范围。读完本文你将掌握如何在 Web 场景中把.hdr.jpgUltra HDR文件加载为环境贴图或普通 HDR 纹理并了解底层 SDR Gain Map 重建 HDR 的完整流程。UltraHDRLoader 是 three.js 的一个加载器扩展addon专门用于加载 Google/Android 阵营推动的 Ultra HDR 图像格式。它在内部同时解码同一文件中的SDR 基准图primary/SDR image与增益图gain map按增益元数据重建出超过普通 8-bit JPEG 动态范围的 HDR 像素最终产出可直接赋给scene.background、scene.environment或材质贴图的DataTexture。UltraHDR 图像格式速览UltraHDR 并不是一种全新的压缩算法而是把多份内容按固定结构装入一个扩展的 JPEG 容器中。根据 UltraHDRLoader 源码头注释其文件布局可以归纳为[JPEG headers] // 必需的 JPEG 标记 [MPF 容器与 SDR/gain map 的元数据] // 描述两幅子图的存储位置 - XMP metadatalegacy 格式 - ISO 21496-1 metadata现行标准格式 [可选元数据] [EXIF] [ICC Profile] [SDR image] // 普通可显示的 SDR 主图 [Gainmap image with metadata] // 增益图及其参数文件内的各个区段由0xFFXX字节标记分隔并带有描述字节0xFFE0、0xFFE1、0xFFE2而二进制图像存储区则以独特的 16 位描述符0xFFD8JPEG SOI 标记为前缀。解析器正是依据这套标记体系逐段扫描的。特性支持矩阵以 官方文档 为准当前实现状态如下能力状态JPEG headers格式信号必需已支持XMP 元数据legacy 格式已支持ISO 21496-1 元数据现行标准已支持XMP 校验未实现EXIF profile未实现ICC profile未实现SDR 与 HDR 图像的二进制存储必需已支持Gainmap 元数据必需已支持非 JPEG 图像格式未实现主图为 HDR 图像BaseRenditionIsHDR未实现也就是说UltraHDRLoader 面向的是“SDR 主图 gain map”的标准 Android Ultra HDR JPEG若文件携带主图即 HDR 的变体目前会被拒绝。快速上手加载 Ultra HDR 环境贴图官方文档的代码示例 给出了最典型的使用方式——把 Ultra HDR 图像用作球体贴图equirectangular并同时赋给场景的背景与环境光照const loader new UltraHDRLoader(); const texture await loader.loadAsync( textures/equirectangular/ice_planet_close.jpg ); texture.mapping THREE.EquirectangularReflectionMapping; scene.background texture; scene.environment texture;loadAsync是 three.js 对load()的 Promise 封装当纹理加载并解析完成后URL 中返回的就是一个可用的DataTexture。上面的ice_planet_close.jpg正是仓库内置的 Ultra HDR 样本之一位于 examples/textures/equirectangular。导入方式AddonUltraHDRLoader 与大多数纹理加载器不同它不属于核心包必须显式导入import { UltraHDRLoader } from three/addons/loaders/UltraHDRLoader.js;在仓库源码环境中对应的实际文件为 examples/jsm/loaders/UltraHDRLoader.js并已被统一收纳进 examples/jsm/Addons.js 的 addon 集合中对外导出。使用 ESM 时需要确保 import map 或打包器将three/addons/正确映射到上述 jsm 目录。完整 API 参考类继承自 three.js 的基础加载器Loader仓库核心对应 src/loaders/Loader.js文档页见 Loader。构造器new UltraHDRLoader( manager : LoadingManager )构造一个新的 Ultra HDR 加载器。manager为可选的 LoadingManager用于统一跟踪与调度加载进度。构造器内会初始化属性.type默认值为HalfFloatType源码 L78-L90。属性.type : HalfFloatType | FloatType决定最终纹理像素的数据类型默认是HalfFloatType。HalfFloatType像素存为Uint16Array半精度浮点内存占用减半适合大分辨率环境图FloatType像素存为Float32Array单精度浮点精度更高但内存翻倍。方法.setDataType( value : HalfFloatType | FloatType ) : UltraHDRLoader设置纹理类型并返回加载器自身便于链式调用。典型用法const loader new UltraHDRLoader().setDataType( THREE.FloatType );方法.load( url : string, onLoad : function, onProgress : onProgressCallback, onError : onErrorCallback ) : DataTexture从 URL 开始加载加载完成后把得到的 Ultra HDR 纹理传给onLoad()回调。url要加载的文件路径或 URL也可以传 data URIonLoad加载过程结束parse 完成后执行回调收到(texture, texData)onProgress加载过程中反复触发onError发生错误时触发。返回值一个DataTexture该方法重写了基类 Loader#load。需要说明的是load()会立即同步返回一个“空壳”纹理对象宽高为 0真正的图像数据在异步解析完成后才填充进texture.image并把texture.needsUpdate置为true见 源码 load 实现。方法.parse( buffer : ArrayBuffer, onLoad : function )解析给定的 Ultra HDR 原始数据重写 Loader#parse。buffer原始二进制数据ArrayBufferonLoad解析完成后收到{ width, height, data, format: RGBAFormat, type }形式的纹理数据对象源码 L326-L332。注意.parse()直接调用并不适合生产链路日常使用推荐走loadAsync()/load()。.parse()内部在缺少version元数据时会抛出THREE.UltraHDRLoader: Not a valid UltraHDR image而无法同时定位到 SDR 主图与 gain map 时会抛出Could not parse UltraHDR images源码 L310-L346。仓库内置实战示例仓库在 examples/webgl_loader_texture_ultrahdr.html 中提供了可运行的完整示例它在 torus knot环形结网格上把 Ultra HDR 全景图用作 PBR 环境光照import { UltraHDRLoader } from three/addons/loaders/UltraHDRLoader.js; loader new UltraHDRLoader(); loader.setDataType( THREE.FloatType ); const loadEnvironment function ( resolution 2k, type HalfFloatType ) { loader.setDataType( THREE[ type ] ); loader.load( textures/equirectangular/spruit_sunrise_${resolution}.hdr.jpg, function ( texture ) { texture.mapping THREE.EquirectangularReflectionMapping; texture.needsUpdate true; scene.background texture; scene.environment texture; } ); }; loadEnvironment( params.resolution, params.type );示例页面还通过 lil-gui 提供了resolution2k/4k与typeHalfFloatType/FloatType的动态切换用于对比两种像素精度的视觉与性能差异。渲染器侧则配合ACESFilmicToneMapping与可调的toneMappingExposure输出最终画面。仓库内置的 Ultra HDR 样本文件还包括spruit_sunrise_2k.hdr.jpg 与spruit_sunrise_4k.hdr.jpg示例主用资源moonless_golf_2k.hdr.jpg、royal_esplanade_2k.hdr.jpgice_planet_close.jpg文档示例资源现有 HDR/EXR 纹理可通过官方文档提及的 gainmap-creator 在线转换工具将.hdr文件转为携带 gain map 的.hdr.jpg得到仓库中的上述*.hdr.jpg正是此类转换产物可与同目录下的原始*.hdr文件对照理解。底层原理源码级解析管线围绕 examples/jsm/loaders/UltraHDRLoader.js其工作可拆解为 4 个阶段理解这些能帮你更好地排查兼容性问题。1. JPEG 分段扫描parse()开头会以0xFF标记为线索做逐字节的“JPEG 段感知扫描”源码 L131-L1900xFFD8SOI无长度字段直接跳过 2 字节0xFFE0APP0、0xFFE1APP1、0xFFE2APP2读取大端 16 位长度并完整入队0xC0–0xFE区间的其它带长度字段标记同样跳过0xFFD9EOI与0xD0–0xD7RST复位标记无长度字段。扫描得到的分段会被分类处理APP0 仅作头信号APP1 交给 XMP 解析APP2 交给 MPF/ISO 21496-1 解析。2. 元数据解析加载器支持两套并存的 gain map 元数据标准XMPlegacy_parseXMPMetadata()源码 L538-L590用DOMParser解析 XML读取Container:Directory仅做存在性校验或rdf:Description上的hdrgm:Version、GainMapMin、GainMapMax、Gamma、OffsetSDR、OffsetHDR、HDRCapacityMin/Max等属性ISO 21496-1现行标准_parseISOMetadata()源码 L357-L468先探测 APP2 段内的urn:iso:std:iso:ts:21496:-1\0命名空间再按 flags 位判断backwardDirection与useCommonDenominator分别走“公共分母”或“独立分子/分母”两种定点数分支读出全部 HDR 重建参数。MPF 段则解析主图SDR与 gain map 的 size/offset定位两幅 JPEG 子图在文件中的绝对偏移源码 L242-L304。3. 子图解码与对齐拿到两个二进制子图后_applyGainmapToSDR()源码 L613-L751用createImageBitmap( new Blob( [ data ], { type: image/jpeg } ) )并行解码并做两项关键处理宽高比校验SDR 主图与 gain map 的宽高比不一致时直接报错分辨率对齐借助 Canvas 2DcolorSpace: srgb上下文将 gain map 缩放到 SDR 的像素分辨率再以getImageData()读回原始 sRGB 像素。4. HDR 重建公式这是整个加载器的核心算法。重建遵循 Android HDR Image Format 规范中“用 gain map 生成适配 HDR 图像”的公式源码 L679-L740先由显示峰值推算出裁剪在[0,1]之间的权重因子weightFactor对每个像素由 gain map 值按gamma取幂得到logRecovery再映射到[gainMapMin, gainMapMax]区间得到logBoost应用hdrValue ( sdrValue offsetSDR ) * 2^( logBoost * weightFactor ) - offsetHDR最后把结果经 sRGB→linear 转换并钳制到[0, 65504]半精度上限。其中 sRGB→linear 转换使用了预计算的 1024 项查找表SRGB_TO_LINEAR源码 L33-L40线性插值以1.8的指数修正近似误差输出缓冲按.type写入Uint16Array经DataUtils.toHalfFloat转半精度或Float32Array。生成的纹理对象.load()在真正得到数据后创建/填充的DataTexture使用以下参数源码 L482-L497format: RGBAFormat重建后仍保留 alpha 通道布局type: 本实例 .type颜色空间LinearSRGBColorSpaceHDR 线性值适配 PBR 光照计算generateMipmaps true、flipY true过滤默认LinearFilterLinearMipMapLinearFilter环绕默认ClampToEdgeWrapping因此加载结果可直接作为scene.environment用于基于图像的 PBR 光照IBL配合MeshStandardMaterial等物理材质可获得镜面反射与光泽感如示例中的金属 torus knot 所示。已知限制与注意事项依据官方文档与源码以下几点在使用前需要明确仅支持 JPEG 载体非 JPEG 图像格式的 Ultra HDR 无法解析主图为 HDR 的变体未实现若BaseRenditionIsHDR标记 SDR 主图本身已是 HDR当前版本不会处理不解析 EXIF/ICC色彩管理依赖内嵌的 sRGB 假设与 three.js 的颜色空间管线依赖浏览器能力子图解码走createImageBitmapCanvas 缩放需要willReadFrequently与 sRGB 颜色空间支持内存FloatType会把每像素推到 16 字节RGBA float全景大图如 4k请按需选择HalfFloatType以平衡精度与显存。该示例同时被纳入仓库的端到端冒烟测试集合见 test/e2e/puppeteer.js#L12 中的webgl_loader_texture_ultrahdr标记为需要约 1 分钟运行的用例可作为验证加载器回归可靠性的参考。小结用途UltraHDRLoader 让 three.js 直接消费 Android/Google 生态的标准 Ultra HDR JPEG.hdr.jpg无需预处理为 EXR 或 RGBE。API 关键点Addon 显式导入、.setDataType()控制精度、loadAsync()返回可直接用作环境贴图的DataTexture。原理关键点JPEG 分段扫描 → XMP/ISO 21496-1 gain map 元数据解析 → MPF 定位 SDR 与 gain map → sRGB 线性重建 half/float 输出。局限关键点仅 JPEG、仅 SDR 主图模式、不处理 EXIF/ICC高动态场景建议使用HalfFloatType。需要继续深入时可依次阅读 UltraHDRLoader 官方文档页、源码实现、在线示例 HTML 以及 基础 Loader 文档即可串联起从 API 到像素级重建的完整知识链。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表