
three.js WebGPUTextureUtils 详解用 decompress 将压缩纹理解压为 CanvasTexture 的完整指南【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsWebGPUTextureUtils 是 three.js 提供的一个附加addon工具模块专门用于配合WebGPURenderer将CompressedTexture压缩纹理解压为可在 CPU 侧直接读写的CanvasTexture。本文基于该模块的官方文档与仓库源码完整讲解其导入方式、decompress方法签名与参数语义、底层实现原理以及它在GLTFExporter、USDZExporter等导出流程中的实际用法帮助你正确地在 WebGPU 渲染管线中处理压缩纹理的解压与回读。模块定位与适用场景压缩纹理如 KTX2、DDS 等格式在 GPU 上以 GPU 专用格式存储内存占用低、加载快但其像素数据无法直接被 CPU 读取或用于图像导出。WebGPUTextureUtils正是为这一需求而生它把 GPU 上的压缩纹理重绘到一张离屏画布上再包装成标准的CanvasTexture返回从而让纹理数据可以用于导出、二次处理或 CPU 侧检查。从 examples/jsm/utils/WebGPUTextureUtils.js 的文件头注释可以看到它的定位/** * module WebGPUTextureUtils * three_import import * as WebGPUTextureUtils from three/addons/utils/WebGPUTextureUtils.js; */该模块只能与WebGPURenderer配合使用如果项目中使用的是WebGLRenderer则应改用同目录下的 WebGLTextureUtils对应源码 examples/jsm/utils/WebGLTextureUtils.js。两个模块在 API 上高度对称但内部实现路径完全不同。安装与导入WebGPUTextureUtils是 three.js 的附加模块addon不会打包进核心库必须显式导入。仓库的 addons 目录即 examples/jsm常规导入方式如下import * as WebGPUTextureUtils from three/addons/utils/WebGPUTextureUtils.js;这里使用命名空间导入是因为模块对外只暴露一个decompress函数导入后通过WebGPUTextureUtils.decompress()调用。若需了解 addons 的整体引入机制可参考仓库根目录的 README.md 中关于 examples/jsm 的说明。decompress 方法签名与参数详解原文档定义的唯一静态方法是decompress其完整签名如下decompress( blitTexture : CompressedTexture, maxTextureSize : number, renderer : WebGPURenderer ) : Promise.CanvasTexture这是一个async方法返回一个解析为解压后纹理的 Promise。三个参数说明如下参数类型默认值说明blitTextureCompressedTexture必填待解压的压缩纹理maxTextureSizenumberInfinity解压后纹理的最大边长像素用于限制输出尺寸rendererWebGPURenderernull渲染器实例引用为null时方法内部会自动创建并管理一个临时的WebGPURenderer返回值一个Promiseresolve 后得到解压完成的CanvasTexture。参数行为细节blitTexture任何CompressedTexture实例均可通常来自KTX2Loader、DDSLoader等压缩纹理加载器。方法会读取其image.width/image.height作为输出基准尺寸并沿用其采样与环绕设置详见下文源码实现原理。maxTextureSize默认Infinity。当传入有限值时输出尺寸为Math.min( texture.image.width, maxTextureSize )可用来控制解压后的纹理占用避免超大纹理如 8192² 以上的 HDR/环境贴图解压出过大的位图。renderer默认null。传入自己的渲染器可复用已有的 GPU 上下文不传时方法内部会new WebGPURenderer()并await renderer.init()解压完成后自动dispose()该临时渲染器并释放引用。源码实现原理一次离屏 blit 渲染阅读 examples/jsm/utils/WebGPUTextureUtils.js 的完整实现可以还原出decompress的内部执行流程export async function decompress( blitTexture, maxTextureSize Infinity, renderer null ) { if ( renderer null ) { renderer _renderer new WebGPURenderer(); await renderer.init(); } const material new NodeMaterial(); material.fragmentNode texture( blitTexture, uv().flipY() ); const width Math.min( blitTexture.image.width, maxTextureSize ); const height Math.min( blitTexture.image.height, maxTextureSize ); const currentOutputColorSpace renderer.outputColorSpace; renderer.setSize( width, height ); renderer.outputColorSpace blitTexture.colorSpace; _quadMesh.material material; _quadMesh.render( renderer ); renderer.outputColorSpace currentOutputColorSpace; const canvas document.createElement( canvas ); const context canvas.getContext( 2d ); canvas.width width; canvas.height height; context.drawImage( renderer.domElement, 0, 0, width, height ); const readableTexture new CanvasTexture( canvas ); readableTexture.minFilter blitTexture.minFilter; readableTexture.magFilter blitTexture.magFilter; readableTexture.wrapS blitTexture.wrapS; readableTexture.wrapT blitTexture.wrapT; readableTexture.colorSpace blitTexture.colorSpace; readableTexture.name blitTexture.name; if ( _renderer ! null ) { _renderer.dispose(); _renderer null; } return readableTexture; }实现可拆解为以下几个关键环节渲染器准备若未传入渲染器模块级变量_renderer会保存一个新建的WebGPURenderer并等待其init()完成保证 WebGPU 设备可用。TSL 全屏采样方法通过模块级单例QuadMesh/*__PURE__*/ new QuadMesh()配合NodeMaterial完成一次全屏 blit。材质片元节点使用 TSL 表达式texture( blitTexture, uv().flipY() )——texture与uv均来自three/tsl——其中flipY()将 UV 翻转以匹配 WebGPU 纹理坐标与 Canvas 的 Y 轴方向约定。尺寸与色彩空间处理输出尺寸取原纹理尺寸与maxTextureSize的较小值渲染前临时把renderer.outputColorSpace设为源纹理的colorSpace渲染结束后恢复原值。这一步保证解压结果的颜色空间与源纹理一致避免色彩偏差。像素回读context.drawImage( renderer.domElement, 0, 0, width, height )把渲染结果绘制到 2D Canvas 上将 GPU 侧的像素数据拷贝为 CPU 可读的位图。纹理属性继承新建的CanvasTexture会继承源纹理的minFilter、magFilter、wrapS、wrapT、colorSpace与name确保解压后的纹理在后续使用中保持与原始压缩纹理一致的采样与包裹行为。资源清理若使用了内部创建的临时渲染器方法结束时立即dispose()并置空避免 GPU 资源泄漏。从模块级缓存const _quadMesh /*__PURE__*/ new QuadMesh()可以看出全屏四边形在模块加载时只创建一次多次调用decompress会复用同一网格仅切换材质这是对性能友好的设计。与 WebGLTextureUtils 的对比WebGLTextureUtils源码 examples/jsm/utils/WebGLTextureUtils.js提供同名函数decompress但面向 WebGL 渲染管线二者的差异值得注意维度WebGPUTextureUtilsWebGLTextureUtils依赖渲染器WebGPURendererWebGLRenderer返回值PromiseCanvasTexture异步CanvasTexture同步内部实现TSLNodeMaterialQuadMeshShaderMaterial 全屏MeshPlaneGeometry(2,2,1,1)默认创建渲染器new WebGPURenderer()并await init()new WebGLRenderer({ antialias: false })清理方式dispose()forceContextLoss()后dispose()在 WebGL 版本中采样着色器还通过fullscreenQuadMaterial.defines.IS_SRGB当texture.colorSpace SRGBColorSpace时置位在片元着色器内执行 sRGB 的sRGBTransferOETF转换而 WebGPU 版本则依赖renderer.outputColorSpace的临时切换。两者的最终目标一致把压缩纹理变成可读的CanvasTexture。选择哪个模块只取决于你的渲染器类型。实战在 GLTFExporter 与 USDZExporter 中解压纹理decompress最常见的实际用途是配合导出器使用。压缩纹理无法直接被 glTF/USDZ 等格式引用导出前必须解压成普通纹理。从源码可以看到两个导出器都预留了纹理工具注入点GLTFExporter 通过setTextureUtils( utils )注入内部在导出纹理贴图如map、normalMap、metalnessMap、roughnessMap时调用this.textureUtils.decompress( texture, maxTextureSize )见 examples/jsm/exporters/GLTFExporter.js 的decompressTextureAsync方法该方法还支持options.maxTextureSize限制导出纹理尺寸。USDZExporter 同样内置textureUtils属性在需要写出纹理时执行await this.textureUtils.decompress( texture )见 examples/jsm/exporters/USDZExporter.js。两个导出器的注释均明确说明用 WebGL 渲染器就注入WebGLTextureUtils用 WebGPU 渲染器就注入WebGPUTextureUtils。典型用法示例import { WebGPURenderer } from three/webgpu; import { GLTFExporter } from three/addons/exporters/GLTFExporter.js; import * as WebGPUTextureUtils from three/addons/utils/WebGPUTextureUtils.js; const renderer new WebGPURenderer(); await renderer.init(); const exporter new GLTFExporter(); exporter.setTextureUtils( WebGPUTextureUtils ); // 注入解压工具 // 场景中若包含 KTX2/DDS 等压缩纹理导出时会自动先解压 exporter.parse( scene, ( gltf ) { // 处理导出结果... }, ( error ) { console.error( error ); }, { maxTextureSize: 2048 } );直接调用decompress的场景则相对少通常出现在需要读取压缩纹理像素的自定义逻辑中import { WebGPURenderer } from three/webgpu; import * as WebGPUTextureUtils from three/addons/utils/WebGPUTextureUtils.js; const renderer new WebGPURenderer(); await renderer.init(); // ktx2Texture 为 KTX2Loader 加载得到的 CompressedTexture const readableTexture await WebGPUTextureUtils.decompress( ktx2Texture, Infinity, renderer ); // readableTexture.image 即为可被 drawImage / getImageData 读取的 canvas注意事项与限制渲染器类型必须匹配WebGPUTextureUtils只接受WebGPURenderer。若在 WebGL 项目中使用会得到错误结果应改用 WebGLTextureUtils。依赖 TSL 与 NodeMaterialWebGPU 版本基于three/tsl的texture、uv表达式构建材质因此需要项目中已启用 WebGPU 渲染器及其 TSL 支持从three/webgpu入口导入即可。异步行为decompress是 async 函数且当未传入渲染器时内部会等待renderer.init()完成因此必须用await或.then()获取结果。性能考量解压操作涉及一次离屏渲染与像素回读drawImage属于较重操作应避免在每帧内反复调用批量导出时建议复用同一个渲染器实例传入renderer参数而不是让方法反复创建/销毁临时渲染器。尺寸限制通过maxTextureSize控制输出分辨率可显著降低大纹理解压时的内存与导出体积开销默认Infinity表示不限制。小结WebGPUTextureUtils.decompress是 three.js WebGPU 生态中连接GPU 压缩纹理与CPU 可读纹理的关键桥梁。它用一次 TSL 全屏 blit 渲染 Canvas 回读的方式将CompressedTexture转换为继承原纹理采样与色彩属性的CanvasTexture并被GLTFExporter、USDZExporter等导出工具直接依赖。掌握了它的签名、参数语义与实现原理你就可以在 WebGPU 渲染管线下自如地处理压缩纹理的读取、导出与二次处理。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考