
three.js 中的 WebGLArrayRenderTarget 完全指南使用二维纹理数组作为分层渲染目标【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js本篇技术指南围绕 three.js 官方文档中的WebGLArrayRenderTarget类展开详细介绍这一 WebGL2 分层渲染目标的构造方式、全部配置选项、与WebGLRenderTarget/DataArrayTexture的继承关系以及逐层渲染到二维纹理数组的底层 GPU 机制。读者读完可以独立创建自己的多层渲染目标把不同相机、不同光照或不同体数据切片渲染到同一纹理的多个 layer并在着色器中以sampler2DArray采样。一、WebGLArrayRenderTarget 是什么WebGLArrayRenderTarget是 three.js 提供给WebGLRenderer使用的一类特殊渲染目标render target。它对应的 GPU 对象是 OpenGL/WebGL2 中的二维纹理数组GL_TEXTURE_2D_ARRAY/TEXTURE_2D_ARRAY因此可以把它理解为一个由多张尺寸相同的 2D 纹理按层layer堆叠的分层帧缓冲。它与常规 2D 渲染目标、3D 纹理渲染目标的关系如下表类继承链GPU 纹理类型典型用途WebGLRenderTargetRenderTarget →TEXTURE_2D常规离屏渲染 / 后处理中间缓冲WebGLArrayRenderTargetRenderTarget → WebGLRenderTarget →TEXTURE_2D_ARRAY逐层渲染到二维纹理数组体数据切片、多视图等WebGL3DRenderTargetRenderTarget → WebGLRenderTarget →TEXTURE_3D渲染到三维纹理体素写入官方文档在 WebGLArrayRenderTarget.html.md 中给出的继承关系为EventDispatcher → RenderTarget → WebGLRenderTarget → WebGLArrayRenderTarget从源码可以验证这条链WebGLArrayRenderTarget.js 中class WebGLArrayRenderTarget extends WebGLRenderTargetWebGLRenderTarget.js 中class WebGLRenderTarget extends RenderTarget而 RenderTarget.js 中class RenderTarget extends EventDispatcher。整条链路中每一层各司其职RenderTarget定义宽高、scissor/viewport、纹理数组textures、深度/模板缓冲开关、MSAA 采样数、depthTexture、尺寸变更与 dispose 等核心状态WebGLRenderTarget仅仅增加一个类型标记isWebGLRenderTarget true声明自己运行在 WebGL 渲染器环境WebGLArrayRenderTarget把默认颜色附件从普通Texture覆盖为DataArrayTexture从而把 GPU 端的 FBO 附件从单张 2D 纹理升级为二维纹理数组。二、构造函数与参数说明new WebGLArrayRenderTarget( width, height, depth, options )new WebGLArrayRenderTarget( width : number, height : number, depth : number, options : RenderTarget~Options )创建一个新的数组渲染目标array render target。对应源码实现src/renderers/WebGLArrayRenderTarget.js如下constructor( width 1, height 1, depth 1, options {} ) { super( width, height, options ); this.isWebGLArrayRenderTarget true; this.depth depth; this.texture new DataArrayTexture( null, width, height, depth ); this._setTextureOptions( options ); this.texture.isRenderTargetTexture true; }构造函数共 4 个参数参数类型默认值含义widthnumber1渲染目标每一层的宽度。heightnumber1渲染目标每一层的高度。depthnumber1纹理数组的层数layer 数量。⚠️ 官方文档页面与源码注释中此处文字误写为 The height of the render target.实际含义是层数即数组纹理第三维的大小这一点以 DataArrayTexture 的image.depth语义为准。optionsRenderTarget~Options{}配置对象控制格式、过滤、深度缓冲等见下节完整清单。构造函数内部只做四件事理解它即可理解整个类的行为调用super(width, height, options)先按普通WebGLRenderTarget初始化基础状态打上isWebGLArrayRenderTarget true类型标记记录this.depth即层数用new DataArrayTexture(null, width, height, depth)替换默认颜色附件并把传入的options应用到该纹理上_setTextureOptions。一个直观的最小创建示例import * as THREE from three; // 256x256 的 4 层数组渲染目标 const arrayTarget new THREE.WebGLArrayRenderTarget( 256, 256, 4, { format: THREE.RGBAFormat, type: THREE.UnsignedByteType, minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, depthBuffer: true } );三、options 完整配置项清单WebGLArrayRenderTarget的options与普通WebGLRenderTarget完全一致均继承自RenderTarget~Options。该 typedef 的完整定义写在 src/core/RenderTarget.js 的源码注释中。选项会在两处被消费缓冲与缓冲行为相关选项在基类RenderTarget构造函数里被Object.assign合并默认值并存储为实例属性纹理相关选项通过_setTextureOptions()src/core/RenderTarget.js应用到所有颜色附件纹理上mapping、wrapS、wrapT、wrapR、magFilter、minFilter、format、type、anisotropy、colorSpace、flipY、generateMipmaps、internalFormat。完整配置项如下选项默认值说明generateMipmapsfalse是否生成 mipmap。渲染目标纹理默认关闭逐层写入的数组纹理尤其不建议开启。magFilter视纹理类型而定放大过滤。若不指定实际由DataArrayTexture决定为NearestFilter。minFilterLinearFilter缩小过滤。基类默认LinearFilter会通过setValues覆盖数组纹理自身的NearestFilter默认值需要最近邻采样请显式传NearestFilter。formatRGBAFormat纹理颜色格式如RGBAFormat、RedFormat等。typeUnsignedByteType每个像素的数据类型UnsignedByteType、FloatType、HalfFloatType等。internalFormatnull内部格式由驱动按 formattype 推导需要精确控制如R8、RGBA16F时可显式指定。wrapS/wrapT/wrapRClampToEdgeWrappingUVW 三方向的环绕方式数组纹理默认wrapR ClampToEdgeWrapping。anisotropy1各向异性过滤等级。colorSpaceNoColorSpace纹理色彩空间如SRGBColorSpace。flipYfalse是否在上传时垂直翻转渲染目标纹理默认关闭。depthBuffertrue是否分配深度缓冲。stencilBufferfalse是否分配模板缓冲。resolveColorBuffertrue是否在渲染结束后把 MSAA 颜色解析回单采样附件仅多采样目标相关。resolveDepthBuffertrue是否解析深度缓冲仅多采样目标相关WebGPU 不支持深度解析。resolveStencilBuffertrue是否解析模板缓冲。storeMultisampled*Buffertrue三个开关分别控制多采样颜色/深度/模板数据在渲染结束后的保留策略可省显存带宽。depthTexturenull指向一张DepthTexture的引用用于把深度存进纹理以便后处理读取。samples0MSAA 采样数0表示关闭。count1颜色附件MRT数量至少为1。depth1纹理深度在WebGLArrayRenderTarget中由第三个构造参数覆盖。multiviewfalse是否用于多视图渲染WebGLOVR_multiview2扩展。useArrayDepthTexturefalse是否把深度纹理创建为数组纹理以支持逐层深度测试与 multiview 相互独立。值得一提的默认值细节DataArrayTexturesrc/textures/DataArrayTexture.js自身会把magFilter/minFilter默认设为NearestFilter、wrapR设为ClampToEdgeWrapping、generateMipmaps与flipY设为false、unpackAlignment设为1。但由于WebGLArrayRenderTarget构造末尾会调用_setTextureOptions(options)用基类默认minFilter LinearFilter覆盖一次因此实际运行时若你不显式指定minFilter是LinearFiltermagFilter仍保持NearestFilter。若要可预测的采样结果建议显式指定minFilter与magFilter。四、公开属性.isWebGLArrayRenderTarget : boolean只读用于类型测试的标记默认值为truesrc/renderers/WebGLArrayRenderTarget.js。该标记不仅是给应用层做instanceof式判断用的还直接驱动渲染器底层的纹理类型选择在 src/renderers/webgl/WebGLTextures.js 中texture.isWebGLArrayRenderTarget || texture.isCompressedArrayTexture会被映射为_gl.TEXTURE_2D_ARRAY在设置帧缓冲附件时同文件 L2185-L2187 与 L2209-L2213渲染器据此选择把颜色附件绑定为TEXTURE_2D_ARRAY而不是普通TEXTURE_2D。.texture : DataArrayTexture覆盖基类属性的默认纹理类型官方文档标注为Overrides: WebGLRenderTarget#texture。类型为 DataArrayTexture其image { data: null, width, height, depth }即三张尺寸元数据 空数据缓冲的空壳纹理实际像素内容由 GPU 渲染写入同时被标记为isRenderTargetTexture true表明这是一张渲染目标附件纹理three.js 会据此走 FBO 附件的上传与更新路径因为RenderTarget的texturegetter 实际返回textures[0]基类中用于 MRT 的多纹理机制对数组目标依然成立——如需多个颜色附件count 1每个附件都会是独立的层数组纹理。除上述两个文档明确列出的属性外从基类继承并经常用到的属性还有width、height、depth、viewport默认(0,0,width,height)、scissor、depthBuffer、stencilBuffer、samples、texturesMRT 附件数组、depthTexture、multiview等定义见 src/core/RenderTarget.js。五、核心用法把渲染结果逐层写入二维纹理数组WebGLArrayRenderTarget最大的价值在于GPU 端可以通过framebufferTextureLayer把某一帧的渲染结果只写入数组纹理的某一个 layer多次渲染即可把一整组 2D 图像如体积数据的各层切片、多视角/多相机画面累积到同一个纹理数组里之后在任意着色器中一次性采样。渲染到指定层setRenderTarget 的第二个参数即 layer在 WebGLRenderer.js 中setRenderTarget( renderTarget, activeCubeFace 0, activeMipmapLevel 0 )针对 3D/数组渲染目标做了专门处理// WebGLRenderer.js 第 2994-2999 行 if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { isRenderTarget3D true; } // 第 3071-3081 行 } else if ( isRenderTarget3D ) { const layer activeCubeFace; for ( let i 0; i renderTarget.textures.length; i ) { const textureProperties properties.get( renderTarget.textures[ i ] ); _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 i, textureProperties.__webglTexture, activeMipmapLevel, layer ); } }也就是说对WebGLArrayRenderTarget而言setRenderTarget的第二个参数名字沿用了立方体贴图的activeCubeFace被当作 layer 下标最终经gl.framebufferTextureLayer把颜色附件绑定到指定层。于是逐层渲染的标准模式是for ( let layer 0; layer arrayTarget.depth; layer ) { // 先把场景/相机切换为该层需要的内容例如把体数据切片位置对应到 layer renderer.setRenderTarget( arrayTarget, layer ); renderer.render( layerScene, layerCamera ); } // 渲染完成后切回屏幕 renderer.setRenderTarget( null );在着色器中采样数组纹理数组纹理在 GLSL 中使用sampler2DArray采样坐标是vec3( uv, layer )第三维即层下标precision highp sampler2DArray; uniform sampler2DArray uArrayTexture; varying vec2 vUv; uniform int uLayer; void main() { vec4 color texture( uArrayTexture, vec3( vUv, float( uLayer ) ) ); gl_FragColor color; }three.js 的ShaderMaterial会自动处理sampler2DArray的 uniform 注入把renderTarget.texture赋给 uniform 即可在片元着色器中按任意层采样。六、官方示例代码拆解仓库自带的官方示例 examples/webgl_rendertarget_texture2darray.html 完整演示了把二维纹理数组当作 FBO 颜色附件渲染的经典流程头骨体数据切片浏览构造数组渲染目标数据尺寸为 256×256×109宽 × 高 × 层数体数据单通道因此把格式设为RedFormatconst DIMENSIONS { width: 256, height: 256, depth: 109 }; const renderTarget new THREE.WebGLArrayRenderTarget( DIMENSIONS.width, DIMENSIONS.height, DIMENSIONS.depth ); renderTarget.texture.format THREE.RedFormat;上传输入体数据从textures/3d/head256x256x109.zip解压出Uint8Array构造一个同样为RedFormat的输入DataArrayTexture并置needsUpdate true此处即DataArrayTexture作为数据纹理的用法与渲染目标版本只是数据来源不同。后处理 pass 逐层写入数组目标一个全屏正交相机 ShaderMaterial其片元着色器用texture(uTexture, vec3( vUv, uDepth )).r从输入体数据中取出某一层切片再乘以强度系数输出。核心的逐层渲染函数为function renderTo2DArray() { const layer Math.floor( mesh.material.uniforms[ depth ].value ); postProcessMaterial.uniforms.uDepth.value layer; renderer.setRenderTarget( renderTarget, layer ); // 关键写入第 layer 层 renderer.render( postProcessScene, postProcessCamera ); renderer.setRenderTarget( null ); }采样渲染结果主场景中放置一张平面其材质把renderTarget.texture作为sampler2DArray的 diffuse uniformuniform sampler2DArray diffuse; ... texture( diffuse, vec3( vUv, depth ) )渲染到屏幕。动画动画循环里让depth在0与109之间来回摆动renderTo2DArray()每帧把对应层切片写入数组目标随后主场景平面再采样该目标渲染到屏幕形成体积数据滑动切片浏览效果。这个示例还顺带说明了两个实践要点二维纹理数组能力属于WebGL 2.0请使用WebGL2RenderingContextthree.js 的WebGLRenderer默认即要求/创建 WebGL2 上下文数组渲染目标既可以像普通目标那样整帧渲染也可以指定layer只写其中一层之后采样时用浮点/整型 layer 下标自由选取。七、底层绑定细节从类标记到 GPU 附件把WebGLArrayRenderTarget与 GPU 资源串起来的完整证据链如下构造时this.texture是DataArrayTextureimage.depth为层数这使isRenderTargetTexture truesetRenderTarget( target, layer )被调用时WebGLTextures.js 的setupRenderTarget检测到renderTarget.isWebGLArrayRenderTarget把目标类型定为_gl.TEXTURE_2D_ARRAY并对每个 MRT 附件执行setupFrameBufferTextureWebGLRenderer.js 检测到颜色附件纹理属于DataArrayTexture/Data3DTexture/CompressedArrayTexture后进入isRenderTarget3D分支对每个附件调用gl.framebufferTextureLayer绑定到activeCubeFace指定的层若某次调用未指定 layer默认为0则只向数组纹理的第 0 层写入——这与普通 2D 目标的默认行为兼容。因此对使用者而言是否逐层写入完全由setRenderTarget的第二个参数控制FBO 的创建、深度缓冲绑定与颜色附件纹理分配都在首次使用时自动完成。八、与近亲类型的对照与选型建议需求场景推荐类型说明单张离屏渲染、后处理链中间缓冲WebGLRenderTarget一层TEXTURE_2D开销最低一组同尺寸 2D 图像需要打包存取 / 逐层独立渲染WebGLArrayRenderTargetTEXTURE_2D_ARRAY支持按 layer 渲染与采样三维体素数据需要真正的三线性体素寻址WebGL3DRenderTargetTEXTURE_3D三坐标均为连续体素天空盒 / 环境贴图渲染WebGLCubeRenderTarget立方体贴图6 个 face需要特别注意的是采样上的限制数组纹理各层之间不能做 mipmap 插值混叠采样跨越 layer 的插值只有Nearest语义有意义因此默认generateMipmaps false逐层渲染时深度缓冲在各层之间不会自动隔离每个 layer 的 pass 复用同一 FBO 的深度附件若每层都需要独立深度测试请确认渲染时序或考虑useArrayDepthTexture选项上述类与机制适用于 three.js 的 WebGL 渲染路径渲染器无关的通用RenderTarget基类位于 src/core/RenderTarget.jsWebGPU/通用渲染后端对分层目标的处理在 src/renderers/common 目录下的Renderer中完成。九、注意事项与常见陷阱必须 WebGL2TEXTURE_2D_ARRAY与framebufferTextureLayer都是 WebGL2 API不要试图在 WebGL1 上下文使用。修改尺寸请用setSize(width, height, depth)基类 RenderTarget.js 的setSize在尺寸变化时会同步更新所有附件纹理的image.width/height/depth并根据image.depth 1设置isArrayTexture标记同时触发dispose()使 GPU 资源在下次使用时重建直接改.width/.height不会触发这些副作用。目标不再使用时请调用dispose()释放 GPU 资源。格式与类型要匹配不同format/type组合如RedFormatUnsignedByteType、RGBAFormatHalfFloatType的驱动支持情况不同需要精确内部布局时可显式指定internalFormat。过滤器的默认值容易踩坑正如前文分析数组纹理自身默认Nearest但渲染目标选项又默认Linear显式声明minFilter/magFilter才能保证预期行为。不要被文档的 depth 描述误导官方页面把depth写成了 The height of the render target实际指的是数组的层数第三个维度。十、延伸阅读官方 API 页面WebGLArrayRenderTarget.html、其 Markdown 源 WebGLArrayRenderTarget.html.md父类与基类WebGLRenderTarget.html、WebGLRenderer.html核心源码src/renderers/WebGLArrayRenderTarget.js、src/renderers/WebGLRenderTarget.js、src/core/RenderTarget.js、src/textures/DataArrayTexture.js渲染器底层绑定src/renderers/WebGLRenderer.jssetRenderTarget与framebufferTextureLayer分支、src/renderers/webgl/WebGLTextures.jsTEXTURE_2D_ARRAY附件设置可运行示例examples/webgl_rendertarget_texture2darray.html一句话总结当你的项目需要在同一张二维纹理数组里分门别类地渲染多个图层或者需要把体数据的若干切片渲染进一个可供后处理与着色器反复采样的 GPU 资源时WebGLArrayRenderTarget就是 three.js WebGL 路径上最直接、最贴合 GPU 特性的选择。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考