如何让多个THREE.Texture实例共用同一个底层WebGL纹理
Three.js 复用WebGLRenderTarget纹理、独立配置uv参数实现方案
核心原理
Three.js中纹理的repeat、offset、rotation等uv变换参数,最终会生成独立的3x3 uv变换矩阵随材质uniform上传GPU,本身不会修改底层WebGL纹理对象的存储内容。只要多个THREE.Texture实例指向同一份底层WebGL纹理资源,就能做到不额外占用显存、不同实例的uv参数完全独立互不干扰。
具体实现步骤
- 不要使用
Texture.clone()生成新纹理实例:该方法会拷贝底层纹理数据,既浪费显存,也无法跟随WebGLRenderTarget的离屏渲染结果实时更新。 - 新建独立纹理实例时,直接复用RenderTarget纹理的底层资源引用,仅对齐和纹理格式、采样规则相关的固定参数即可,uv变换参数可独立配置。
参考代码
// 已有的离屏渲染RenderTarget实例 const offscreenRT = new THREE.WebGLRenderTarget(2048, 2048, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, wrapS: THREE.ClampToEdgeWrapping, wrapT: THREE.ClampToEdgeWrapping }) // 第一个材质使用的纹理:直接取RenderTarget自带的texture实例即可 const mat1Map = offscreenRT.texture mat1Map.repeat.set(1, 1) mat1Map.offset.set(0, 0) const mat1 = new THREE.MeshBasicMaterial({ map: mat1Map }) // 第二个材质使用的独立配置纹理:新建Texture实例,复用底层纹理资源 const mat2Map = new THREE.Texture(offscreenRT.texture.image) // 对齐底层纹理相关的固定采样参数,和原RT纹理保持一致 mat2Map.format = offscreenRT.texture.format mat2Map.type = offscreenRT.texture.type mat2Map.minFilter = offscreenRT.texture.minFilter mat2Map.magFilter = offscreenRT.texture.magFilter mat2Map.wrapS = offscreenRT.texture.wrapS mat2Map.wrapT = offscreenRT.texture.wrapT mat2Map.generateMipmaps = offscreenRT.texture.generateMipmaps // 独立配置uv参数,完全不会影响mat1Map的配置 mat2Map.repeat.set(0.5, 0.5) mat2Map.offset.set(0.25, 0.25) // 标记需要更新,首次渲染时会自动完成GPU侧绑定,不会拷贝纹理数据 mat2Map.needsUpdate = true const mat2 = new THREE.MeshBasicMaterial({ map: mat2Map })
注意事项
- 该方案下所有纹理实例共享同一份GPU纹理存储,无论创建多少个独立配置的Texture实例,都不会额外增加纹理显存占用,且所有实例都会实时拿到RenderTarget每帧的最新渲染结果。
- 如果使用自定义ShaderMaterial,直接引入Three.js内置的uv处理chunk即可自动适配独立的uv变换参数,不需要写额外逻辑。
- r150+版本的Three.js默认开启纹理矩阵自动更新,修改
repeat、offset参数后不需要手动触发needsUpdate,参数修改会实时生效。
内容的提问来源于stack exchange,提问作者Kyle
相关产品推荐
相关产品推荐

