three.js WebGLCubeRenderTarget 全面指南:立方体渲染目标与动态环境贴图
【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js
WebGLCubeRenderTarget是 three.js(当前仓库GitHub_Trending/th/three.js)在 WebGL 渲染环境下用于生成立方体贴图(Cube Map)的渲染目标类型。它常与 CubeCamera 配合,把场景中某一点六个方向的视图分别渲染成立方体的六个面,从而为物体提供包含周围环境的实时反射;也可通过fromEquirectangularTexture()将一张等距柱状投影(Equirectangular)贴图一次性地烘焙为立方体贴图。读完本文,你将掌握其构造参数、纹理选项、clear()与fromEquirectangularTexture()的用法与底层实现,并能在真实示例中搭建一套“动态环境反射”的渲染管线。
概览:继承关系与定位
文档页 docs/pages/WebGLCubeRenderTarget.html 给出的继承链为:
EventDispatcher → RenderTarget → WebGLRenderTarget → WebGLCubeRenderTarget
从 src/renderers/WebGLCubeRenderTarget.js 的实现可见,它在构造时调用super( size, size, options ),即宽高始终相等(这正是立方体贴图各面必须为正方形的直接原因);随后把默认纹理替换为 6 面共享同一image对象的CubeTexture,从而真正成为一个“面向立方体六个面渲染”的特殊渲染目标。
值得强调的是它的定位边界:它专属于WebGLRenderer路径;WebGPU 渲染器使用的是等价的 src/renderers/common/CubeRenderTarget.js(CubeRenderTarget,详见文末对照小节)。
构造函数与配置选项
new WebGLCubeRenderTarget( size, options )
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256 ); // 或带上纹理选项 const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256, { generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter, type: THREE.HalfFloatType } );size:渲染目标边长(像素),默认1。由于构造实现是super( size, size, options ),它同时作为宽和高。实际项目通常取128、256或512等 2 的幂——当开启 mipmap 时 2 的幂尺寸配合LinearMipmapLinearFilter才能得到正确的完整 mipmap 链。
options:完整配置对象。与普通WebGLRenderTarget的 options 一致,字段定义于 src/core/RenderTarget.js 中的RenderTarget~Options。下表为最常用的字段及其默认值:
| 选项 | 默认值 | 说明 |
|---|---|---|
generateMipmaps | false | 是否生成 mipmap。环境贴图反射通常置true以降低采样锯齿 |
minFilter/magFilter | LinearFilter | 过滤方式;配合 mipmap 常用LinearMipmapLinearFilter |
format | RGBAFormat | 颜色纹理格式 |
type | UnsignedByteType | 纹理数据类型,如HalfFloatType(HDR 反射常用) |
wrapS/wrapT | ClampToEdgeWrapping | UV 环绕方式 |
anisotropy | 1 | 各向异性过滤等级 |
colorSpace | NoColorSpace | 色彩空间(如SRGBColorSpace) |
depthBuffer | true | 是否分配深度缓冲 |
stencilBuffer | false | 是否分配模板缓冲 |
samples | 0 | MSAA 采样数,0表示关闭 |
depthTexture | null | 可选的深度纹理 |
internalFormat | null | 内部格式覆盖项 |
构造器将这些选项通过内部的_setTextureOptions( options )(见 src/core/RenderTarget.js)写入纹理,因此凡是在WebGLRenderTarget上可用的纹理配置,在立方体渲染目标上同样生效。单元测试 test/unit/src/renderers/WebGLCubeRenderTarget.tests.js 也专门验证了“传入magFilter: NearestFilter的 options 后,object.texture.magFilter应为NearestFilter”这一行为。
属性
.isWebGLCubeRenderTarget : boolean(只读)
类型判定标志,默认true。构造器中直接写入,用于运行时区分该对象是否为立方体渲染目标,等价于其它对象的isXXX惯例标志。
.texture : CubeTexture
文档页标注为 “Overwritten with a different texture type”,源码中确实将基类的Texture覆写为CubeTexture:
const image = { width: size, height: size, depth: 1 }; const images = [ image, image, image, image, image, image ]; this.texture = new CubeTexture( images ); this._setTextureOptions( options ); this.texture.isRenderTargetTexture = true;需要注意:CubeTexture本身在 src/textures/CubeTexture.js 中默认flipY = false,这与普通纹理不同。正是这个texture.isRenderTargetTexture标志,帮助渲染器识别“这是渲染目标的输出纹理”,从而避免对坐标方向做多余的翻转(源码注释详细解释了 WebGL 立方体贴图历史上遵循左手坐标系、而 three.js 世界为右手坐标系,环境贴图因此表现为 px/nx 交换的约定)。渲染时把该纹理赋给材质即可作为环境映射使用:
material.envMap = cubeRenderTarget.texture;继承自基类的属性
立方体渲染目标同样继承RenderTarget的公开属性,例如width、height、depth、viewport、scissor、samples、depthBuffer、stencilBuffer等(详见 src/core/RenderTarget.js),其中depth默认1、viewport/scissor初始化为整个目标区域。由于继承自EventDispatcher,还可在其上监听dispose事件。
方法
.clear( renderer, color = true, depth = true, stencil = true )
清除立方体渲染目标中六个面的缓冲。源码实现是依次将渲染器绑定到第 0~5 个面并执行renderer.clear():
clear( renderer, color = true, depth = true, stencil = true ) { const currentRenderTarget = renderer.getRenderTarget(); for ( let i = 0; i < 6; i ++ ) { renderer.setRenderTarget( this, i ); renderer.clear( color, depth, stencil ); } renderer.setRenderTarget( currentRenderTarget ); }注意它先把当前渲染目标保存下来、清理完成后恢复,因此调用前后不会破坏你正在进行的渲染状态。三个布尔参数分别控制颜色、深度、模板缓冲是否被清除,默认均true。
.fromEquirectangularTexture( renderer, texture ) : WebGLCubeRenderTarget
把一张等距柱状投影贴图(panorama 全景图)转换为立方体贴图并写入本渲染目标。这是一个同步完成的烘焙操作,完成即可直接用本目标作为环境贴图。转换结果保存了源纹理的类型、色彩空间、mipmap 开关及过滤方式:
fromEquirectangularTexture( renderer, texture ) { this.texture.type = texture.type; this.texture.colorSpace = texture.colorSpace; this.texture.generateMipmaps = texture.generateMipmaps; this.texture.minFilter = texture.minFilter; this.texture.magFilter = texture.magFilter; // ... 渲染 6 面 return this; }典型用法:
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 512, { generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter } ); // 例如从 RGBELoader 加载的 HDR 全景图 texture cubeRenderTarget.fromEquirectangularTexture( renderer, equirectTexture ); scene.environment = cubeRenderTarget.texture;从源码结构看,该方法的底层原理值得展开:
- 它构造一个 5×5×5 的
BoxGeometry,配合side: BackSide、blending: NoBlending的ShaderMaterial,把立方体作为被采样对象; - 顶点着色器中用
transformDirection( position, modelMatrix )把顶点位置变换为世界方向vWorldDirection; - 片元着色器调用 three.js 着色器库中
equirectUv( direction )完成“世界方向 → 等距柱状 UV”的映射,再采样sampler2D tEquirect得到颜色; - 随后创建
new CubeCamera( 1, 10, this )并调用camera.update( renderer, mesh ),一次调用即把立方体的六个面渲染进本目标的六个面; - 两个值得注意的细节:若源纹理
minFilter为LinearMipmapLinearFilter,转换期间会临时退化为LinearFilter(源码注释 “Avoid blurred poles”),结束后恢复;所有临时 geometry / material 在结束后均被dispose()。
该流程的完整参数与行为可在 src/renderers/WebGLCubeRenderTarget.js 中核对。
实战:用 CubeCamera 打造动态实时环境反射
WebGLCubeRenderTarget最常见的动态场景是与 CubeCamera(源码 src/cameras/CubeCamera.js)配合:在运动物体所在位置,用六个PerspectiveCamera(fov 为 -90、aspect 为 1)分别向六个方向渲染一次场景,输出即该点周围的实时环境。文档 docs/pages/CubeCamera.html.md 给出的经典工作流:
// 1. 创建立方体渲染目标 const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256, { generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter } ); // 2. 创建 CubeCamera(near、far、渲染目标),并加入场景 const cubeCamera = new THREE.CubeCamera( 1, 100000, cubeRenderTarget ); scene.add( cubeCamera ); // 3. 把渲染目标纹理作为材质 envMap const chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: cubeRenderTarget.texture } ); const car = new THREE.Mesh( carGeometry, chromeMaterial ); scene.add( car ); // 4. 更新环境:让目标物体暂时不可见,避免其“自我遮挡” car.visible = false; cubeCamera.position.copy( car.position ); cubeCamera.update( renderer, scene ); // 5. 渲染主场景 car.visible = true; renderer.render( scene, camera );从 src/cameras/CubeCamera.js 的实现看,CubeCamera.update()会依次以renderer.setRenderTarget( renderTarget, 0..5, activeMipmapLevel )切换六个面并分别渲染;其中第 6 面(NZ)渲染完成时所有面均已定义,随即恢复texture.generateMipmaps让 mipmap 在最后一次render()中一并生成,最后把texture.needsPMREMUpdate置为true。此外它还会临时关闭renderer.xr.enabled、并缓存与恢复当前的渲染目标与立方体面索引,避免污染外部渲染状态。调用者需要自行处理“目标物体自遮挡”问题(上面的car.visible = false即是官方推荐的规避手段)。
仓库内可运行的真实示例
仓库在 examples/webgl_materials_cubemap_dynamic.html 中提供了完整的动态反射示例,其关键片段:
// HDR 全景作为背景与全局环境 new HDRLoader().setPath( 'textures/equirectangular/' ).load( 'quarry_01_1k.hdr', function ( texture ) { texture.mapping = THREE.EquirectangularReflectionMapping; scene.background = texture; scene.environment = texture; } ); // 256 大小的立方体渲染目标,半浮点精度(适合 HDR 反射) cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256 ); cubeRenderTarget.texture.type = THREE.HalfFloatType; cubeCamera = new THREE.CubeCamera( 1, 1000, cubeRenderTarget ); // 金属球材质的 envMap 指向立方体渲染目标纹理 material = new THREE.MeshStandardMaterial( { envMap: cubeRenderTarget.texture, roughness: 0.05, metalness: 1 } );动画循环中每一帧都执行cubeCamera.update( renderer, scene ),使金属球始终反射到移动的立方体与环面结物体——这就是“动态环境贴图”最直观的呈现。该示例还演示了两个关键实践:HDR 反射应把texture.type设为THREE.HalfFloatType,以及半浮点纹理下对采样滤波的要求。仓库中另见examples/webgl_materials_cubemap_render_to_mipmaps.html与examples/webgl_lightprobe_cubecamera.html等基于WebGLCubeRenderTarget的衍生用法。
源码级要点补充
- 坐标约定:构造器中有一段详细注释——WebGL 立方体贴图按历史上 RenderMan 规范的左手坐标系约定存储(沿 +z 看时 +x 朝右),而 three.js 世界为右手坐标系;普通环境贴图因此常出现 px/nx 交换的观感,而
isRenderTargetTexture标志让渲染器自动跳过该翻转。阅读 src/renderers/WebGLCubeRenderTarget.js 顶部注释可完整理解这一约定。 - 内存/尺寸:六面共享同一份
image对象,单面尺寸为size,因此总内存约为普通同尺寸纹理的 6 倍,创建时应权衡分辨率。 - 测试证据:单元测试 test/unit/src/renderers/WebGLCubeRenderTarget.tests.js 确认了继承关系(
instanceof WebGLRenderTarget)、无参实例化、以及 options 能传导至纹理三个事实。 - 资源释放:不再使用时应调用
dispose(),该方法自基类RenderTarget继承并派发dispose事件,便于渲染器释放对应 GPU 资源。
WebGPU 时代的对应物:CubeRenderTarget
仓库在渲染架构演进中,为 WebGPU 渲染路径提供了功能对等的 src/renderers/common/CubeRenderTarget.js(CubeRenderTarget)。两者 API 高度一致:同样new CubeRenderTarget( size, options )、覆写CubeTexture、提供fromEquirectangularTexture()与clear();区别在于前者基于WebGLRenderer与ShaderMaterial驱动立方体转换,而后者直接继承RenderTarget、内部用NodeMaterial与 TSL 节点(equirectUV、positionWorldDirection)实现,由文档 docs/pages/CubeRenderTarget.html.md 收录。选用哪个类型,取决于你的渲染器是WebGLRenderer还是WebGPURenderer——fromEquirectangularTexture的用法在两条渲染路径上保持一致。
【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考