three.js 中 CompressedCubeTexture 详解:压缩立方体贴图的构造、参数与加载流程
本文以 three.js 官方 API 文档中的 CompressedCubeTexture 页面为主体,结合 src/ 源码与示例工程,系统讲解这个类的作用、继承关系、构造参数与属性、压缩纹理在 three.js 中的通用约束(flipY、mipmap 生成),以及它如何经由 CompressedTextureLoader / DDSLoader 从 DDS 文件加载为立方体环境贴图。读完本文,你将能够正确手动构造一个压缩立方体贴图、理解其六面数据结构,并复现仓库中 webgl_loader_texture_dds 示例的加载流程。
一、什么是 CompressedCubeTexture
CompressedCubeTexture 用于创建基于压缩格式数据的立方体(cube)纹理。文档页面(docs/pages/CompressedCubeTexture.html.md)给出的原始定义为:
Creates a cube texture based on data in compressed form. These textures are usually loaded with CompressedTextureLoader.
它的典型使用场景是把 DXT1/DXT3/DXT5/BC 系列等 GPU 压缩块纹理(通常存放在 .dds 文件中)作为环境反射、天空盒或法线贴图使用。相比普通 CubeTexture(接收 6 张 Image/Canvas),CompressedCubeTexture 的每一面都是 CompressedTexture 数据,可直接被 GPU 以压缩块格式采样,显存占用与带宽显著低于未压缩 RGBA 数据。
二、继承关系与源码结构
文档明确标注了继承链:
EventDispatcher → Texture → CompressedTexture → CompressedCubeTexture
这一链条可在源码中逐层印证:
- src/textures/CompressedCubeTexture.js 中
class CompressedCubeTexture extends CompressedTexture; - src/textures/CompressedTexture.js 中
class CompressedTexture extends Texture,而Texture自身继承自EventDispatcher。
该类的公共导出入口在 src/Three.Core.js(export { CompressedCubeTexture } from './textures/CompressedCubeTexture.js';),因此通过标准 three 包即可直接使用,无需从 examples 附加模块导入。
2.1 构造函数逐行解读
文档给出的构造函数签名为:
new CompressedCubeTexture( images : Array.<CompressedTexture>, format : number, type : number )
对应 src/textures/CompressedCubeTexture.js 的实现:
constructor( images, format, type ) {
super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping );
this.isCompressedCubeTexture = true;
this.isCubeTexture = true;
this.image = images;
}
从源码结构看,有三个值得注意的细节:
- 尺寸取自第一张图:父类
CompressedTexture的构造函数会把image置为{ width, height }占位对象(压缩纹理没有可直接显示的位图,image仅用于描述尺寸),因此CompressedCubeTexture用images[0].width/images[0].height作为基准尺寸传入super(...); - 映射方式硬编码为立方体反射:
super调用的最后一个参数是CubeReflectionMapping(来自 src/constants.js),意味着该纹理天然按立方体贴图方式参与材质反射计算,无需再手动设置mapping; image被覆盖为六面数组:构造末尾this.image = images,把 6 个面的压缩纹理数组挂回image属性。渲染端(如 src/renderers/common/SampledTexture.js 中(CubeTexture | CompressedCubeTexture)的绑定分支)正是依赖这一约定来识别并绑定立方体纹理。
2.2 参数说明
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
images |
Array<CompressedTexture> |
6 张压缩纹理的数组,每个元素对应立方体的一个面,需包含 width、height 及压缩块 mipmaps 数据 |
必填 |
format |
number |
纹理格式(如 RGBAFormat 或具体压缩格式常量) |
RGBAFormat |
type |
number |
纹理数据类型 | UnsignedByteType |
手动构造示例(假设 6 个面数据来自已解析的压缩块):
import * as THREE from 'three';
// faces[i] 形如 { width, height, format, mipmaps: [ { data, width, height }, ... ] }
const texture = new THREE.CompressedCubeTexture(
faces,
THREE.RGBAFormat, // format
THREE.UnsignedByteType // type
);
// texture.mapping 已自动为 CubeReflectionMapping
material.map = texture;
2.3 属性说明
文档列出两个只读布尔属性,均用于类型判断(type testing):
.isCompressedCubeTexture : boolean (readonly),默认true;.isCubeTexture : boolean (readonly),默认true。
两者在 src/textures/CompressedCubeTexture.js 中分别赋值为 true。isCubeTexture 与父类 CompressedTexture 上的 isCompressedTexture(见 src/textures/CompressedTexture.js)叠加后,可以用 texture.isCompressedTexture && texture.isCubeTexture 这类组合判断精确区分“压缩 + 立方体”纹理。
三、压缩纹理的通用约束:flipY 与 mipmap
理解 CompressedCubeTexture 必须理解其父类 CompressedTexture 强加的两条限制(src/textures/CompressedTexture.js):
flipY恒为false:注释写明“压缩纹理无法在上传 GPU 时沿垂直轴翻转”,因此在CompressedTexture中被强制覆盖为false。这意味着数据朝向完全由压缩文件本身决定;generateMipmaps恒为false:GPU 无法对压缩块数据现场生成 mipmap,mip 链必须内嵌在压缩纹理文件中。如果文件只带基础 mip(mipmapCount === 1),加载流程会相应调整最小过滤方式(见下一节)。
这两条约束解释了为什么 CompressedCubeTexture 的 images 参数里每个面都必须自带完整的 mipmaps 数组,而不是像普通 CubeTexture 那样传入图像后由 three.js 代为生成。
四、加载流程:CompressedCubeTexture 与 CompressedTextureLoader 的协作
文档提示“这些纹理通常用 CompressedTextureLoader 加载”。基类 src/loaders/CompressedTextureLoader.js 是一个抽象类,负责统一的加载骨架,并把格式解析交给派生类(如 examples/jsm 下的 DDSLoader、KTXLoader 等)实现的 parse() 方法。
load() 方法(src/loaders/CompressedTextureLoader.js)支持两种 URL 形式:
- URL 数组(6 个面文件):循环调用
loadTexture(i),每解析出一个面就填入images[i] = { width, height, format, mipmaps };当 6 个面全部完成(loaded === 6)时,把texture.image = images、设置format并置needsUpdate = true,触发回调; - 单个 DDS 文件内含完整立方体:
parse()返回isCubemap === true时,按mipmaps.length / mipmapCount算出面数,把扁平的 mipmap 数组按面重组为 6 个images[f] = { mipmaps, format, width, height }子对象,同样写回texture.image。
两种路径都有一条关键分支:
if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;
即无 mip 链的压缩纹理会自动退化为 LinearFilter,避免使用依赖 mipmap 的过滤模式导致采样异常——这正是第三节 generateMipmaps = false 约束在加载端的落地体现。
DDS 格式的立方体判定在 examples/jsm/loaders/DDSLoader.js 中实现:解析 DDS 头部的 DDSCAPS2 标志位(dds.isCubemap = caps2 & DDSCAPS2_CUBEMAP),并在后续按 faces = 6 展开各面的数据(约 L319-L339)。
五、仓库内实操示例:webgl_loader_texture_dds
仓库自带完整可运行的示例 examples/webgl_loader_texture_dds.html,演示了单张纹理与立方体贴图两条加载路径:
import { DDSLoader } from 'three/addons/loaders/DDSLoader.js';
const loader = new DDSLoader();
// 普通压缩纹理(2D)
const map = loader.load( 'textures/compressed/disturb_dxt1_mip.dds' );
// 压缩立方体(单文件内含 6 面)
const cubemap = loader.load( 'textures/compressed/Mountains.dds', function ( texture ) {
// texture.image 为 6 个面的数组,可直接用作 envMap 等
} );
示例中同时覆盖了 disturb_dxt1_*、hepatica_dxt3_mip.dds、explosion_dxt5_mip.dds、disturb_dx10_bc6h_* 等多种压缩格式,以及带 mip 与不带 mip(nomip)的两类文件;测试素材位于 examples/textures/compressed/ 目录。该示例展示了从加载到赋给材质的完整闭环,是验证 CompressedCubeTexture 相关行为(过滤方式、六面结构)最直接的参照。
六、小结与使用要点
CompressedCubeTexture是Texture → CompressedTexture继承链上专门承载“6 面压缩数据”的节点,image属性即 6 个面的数组,mapping自动为CubeReflectionMapping(见 src/textures/CompressedCubeTexture.js);- 构造参数为
images(必填的 6 面CompressedTexture数组)、format(默认RGBAFormat)、type(默认UnsignedByteType);类型判断属性为isCompressedCubeTexture与isCubeTexture,均默认true; - 压缩纹理不可
flipY、不可现场生成 mipmap,mip 链必须内嵌于文件;单 mip 文件加载时minFilter会自动回退为LinearFilter(见 src/loaders/CompressedTextureLoader.js); - 实际项目中优先通过
CompressedTextureLoader派生类(如DDSLoader)加载,再按 examples/webgl_loader_texture_dds.html 的方式将纹理交给材质使用。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00