three.js DepthTexture 深度纹理 API 详解:将渲染深度自动写入纹理
DepthTexture 是 three.js 中一类特殊的纹理:它不保存颜色数据,而是在渲染过程中自动把片元的深度信息写入其中,供阴影映射、屏幕空间环境光遮蔽(SSAO)、延迟渲染、WebXR 深度感知等需要"可采样的深度缓冲"的场景使用。本文以官方文档 DepthTexture.html 为主体,结合仓库 v0.185.0 的源码与示例,完整讲解其构造参数、属性语义、内部实现与实战用法,读完你可以在自己的渲染管线中正确地创建并挂载深度纹理。
DepthTexture 是什么
类定义摘要写得很简洁:"This class can be used to automatically save the depth information of a rendering into a texture."(本类可用来在渲染时自动把深度信息保存进一张纹理)。
与普通 Texture 最大的差异在于:DepthTexture 不依赖来自 CPU 端的像素数据(image/Canvas/ImageBitmap),它的 image 只是一个描述符对象 { width, height, depth }。真正的深度数据来自 GPU 端深度缓冲区的回读——渲染器在把场景渲染到某个渲染目标时,如果该目标绑定了 DepthTexture,就会把深度缓冲直接写入这张纹理,供后续着色阶段采样。
其继承链为 EventDispatcher → Texture → DepthTexture,即它复用 Texture 基类 的绝大多数字段与生命周期,仅在基类之上重写了少量默认值并增加了深度相关属性。
类继承与源码定位
实现位于 src/textures/DepthTexture.js,完整类体非常精简(约 100 行)。核心构造函数(第 28 行)如下:
constructor( width, height, type = UnsignedIntType, mapping, wrapS, wrapT,
magFilter = NearestFilter, minFilter = NearestFilter, anisotropy,
format = DepthFormat, depth = 1 ) {
if ( format !== DepthFormat && format !== DepthStencilFormat ) {
throw new Error( 'THREE.DepthTexture: format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
}
const image = { width: width, height: height, depth: depth };
super( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
...
}
从源码可以读出几个关键实现事实:
- 格式白名单校验:构造函数只接受
DepthFormat与DepthStencilFormat两种格式,其余格式直接抛出THREE.DepthTexture: format must be either THREE.DepthFormat or THREE.DepthStencilFormat错误。 - 无像素数据:
image被定义为{ width, height, depth }纯描述符,而非实际像素内容。 - 参数顺序透传:除
type、magFilter、minFilter、format、depth外,mapping、wrapS、wrapT、anisotropy未在子类中给默认值,会以undefined落入基类构造函数,从而继承 Texture 构造函数 中的默认值(如Texture.DEFAULT_MAPPING、ClampToEdgeWrapping、Texture.DEFAULT_ANISOTROPY)。
在深度/立方体贴图变体上,仓库还提供了继承自 DepthTexture 的 CubeDepthTexture,它把单个 image 描述符替换为 6 个相同描述符(每个立方体面一个,见 CubeDepthTexture 构造),并默认使用 CubeReflectionMapping,专用于点光源阴影。
构造函数与全部参数
构造签名(完整 11 个参数):
new DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format, depth )
其中仅 width、height 为语义上必填,其余均有默认值。各参数官方文档说明与补充如下表:
| 参数 | 类型 | 默认值 | 含义与要点 |
|---|---|---|---|
width |
number | 必填 | 纹理宽度(像素)。 |
height |
number | 必填 | 纹理高度(像素)。 |
type |
number | UnsignedIntType |
深度数据类型。相关常量见 constants.js:UnsignedIntType(值 1014,默认)、UnsignedShortType(值 1012)、UnsignedInt248Type(值 1020,配合 DepthStencilFormat 使用)。 |
mapping |
number | Texture.DEFAULT_MAPPING |
纹理映射方式;不传则由基类默认值填充。 |
wrapS |
number | ClampToEdgeWrapping |
S 方向环绕方式。深度纹理通常不需要重复采样,保持 Clamp 即可。 |
wrapT |
number | ClampToEdgeWrapping |
T 方向环绕方式。 |
magFilter |
number | 文档标注 LinearFilter |
放大过滤。注意:当前 v0.185.0 实现(DepthTexture.js 第 28 行)实际写死默认 NearestFilter;深度纹理不生成 mipmap,配合阴影比较采样通常使用最近邻过滤,请以源码实际默认值为准。 |
minFilter |
number | 文档标注 LinearFilter |
缩小过滤。同上,当前实现默认 NearestFilter。 |
anisotropy |
number | Texture.DEFAULT_ANISOTROPY |
各向异性过滤级别;不传则由基类默认值填充。 |
format |
number | DepthFormat |
纹理格式,只允许 DepthFormat(值 1026)或 DepthStencilFormat(值 1027),见 constants.js。 |
depth |
number | 1 |
纹理层数。对普通 2D 深度纹理为 1;创建 3D/2D 阵列深度纹理时传入层数,会写入 image.depth。 |
深度数据的 type 与 format 搭配
DepthFormat:每个纹素是单个深度值。WebGL/WebGPU 侧按type决定内部格式——默认UnsignedIntType与DepthFormat组合对应 24 位/32 位整数深度。DepthStencilFormat:每个纹素是"深度 + 模板"成对数据,深度分量解释同DepthFormat,模板分量由内部格式决定;此时 type 通常配合UnsignedInt248Type(24 位深度 + 8 位模板),才能获得可用的模板存储。depth > 1:用于分层深度纹理。一个典型实现是瓦片阴影节点 TileShadowNode——它对每个阴影瓦片分配一个摄像机与 shadow map,并创建一张"深度阵列纹理":
const depthTexture = new DepthTexture( shadowWidth, shadowHeight,
undefined, undefined, undefined, undefined,
undefined, undefined, undefined, undefined, tileCount );
depthTexture.compareFunction = LessCompare;
depthTexture.name = 'ShadowDepthArrayTexture';
const shadowMap = builder.createRenderTarget( shadowWidth, shadowHeight,
{ format: RedFormat, depth: tileCount, useArrayDepthTexture: true } );
shadowMap.depthTexture = depthTexture;
这里第 11 个参数 tileCount 即用于把深度纹理声明为多层结构,并设置了 compareFunction = LessCompare,体现了 depth 参数在级联/瓦片阴影中的真实用途。
一段可直接运行的最小示例
把深度纹理挂到 WebGLRenderTarget 上,渲染场景后即可取得可采样的深度图。仓库示例 examples/webgl_materials_normalmap.html 使用相同模式:
import * as THREE from 'three';
// 1) 构造深度纹理(默认 DepthFormat + UnsignedIntType)
const depthTexture = new THREE.DepthTexture( width, height );
// 2) 将其作为渲染目标的 depthTexture 选项传入
const renderTarget = new THREE.WebGLRenderTarget( width, height, {
type: THREE.HalfFloatType,
depthTexture: depthTexture
});
// 3) 将场景渲染到该目标,深度自动写入 depthTexture
renderer.setRenderTarget( renderTarget );
renderer.render( scene, camera );
renderer.setRenderTarget( null );
// 之后便可在着色器中采样 renderTarget.depthTexture 做深度相关计算
注意:DepthTexture 的宽高应与你使用的渲染目标分辨率一致(或在 WebGPU/WebGL 双渲染器中让渲染管线按目标尺寸同步),这一点与 Texture 基类文档 中"纹理首次使用后其尺寸、格式与类型不可再更改,如需调整应调用 dispose() 后重建"的约束一致。
Properties(属性)详解
DepthTexture 在继承 Texture 大量属性之外,声明并覆写了以下 4 个关键属性。
.compareFunction
类型声明:
NeverCompare | LessCompare | EqualCompare | LessEqualCompare |
GreaterCompare | NotEqualCompare | GreaterEqualCompare | AlwaysCompare
- 默认值:
null。 - 含义:深度比较函数对应的常量码,用于阴影纹理的硬件比较采样(shadow compare)。当不为
null时,采样器会对"纹理中的存储深度"与"传入片元深度"执行指定比较,把比较结果作为采样值返回——这是 PCF 类软阴影和方向/点/聚光灯光照过滤的基础。相关的 8 个常量定义于 constants.js:
| 常量 | 数值 | 通过条件 |
|---|---|---|
NeverCompare |
512 | 永不通过 |
LessCompare |
513 | 新值 < 纹理值 |
EqualCompare |
514 | 新值 == 纹理值 |
LessEqualCompare |
515 | 新值 <= 纹理值 |
GreaterCompare |
516 | 新值 > 纹理值 |
NotEqualCompare |
517 | 新值 != 纹理值 |
GreaterEqualCompare |
518 | 新值 >= 纹理值 |
AlwaysCompare |
519 | 总是通过 |
设置示例(与 TileShadowNode 一致):
depthTexture.compareFunction = THREE.LessCompare;
未设置(null)时纹理按普通深度值采样,不做深度比较。
.flipY : boolean
- 默认值:
false(覆写基类行为,基类属性见 Texture 基类)。 - 含义:是否在上传到 GPU 时沿垂直轴翻转纹理。普通图片纹理约定原点在左上,而渲染缓冲/深度数据原点在左下,深度纹理数据直接来自帧缓冲,因此 DepthTexture 在构造时被显式覆写为
false,不要手动改为true,否则深度方向会颠倒,导致比较结果错误。
.generateMipmaps : boolean
- 默认值:
false(覆写基类行为)。 - 含义:是否为纹理生成 mipmap。DepthTexture 关闭 mipmap 有两方面原因:一是深度纹理通常不具备 mipmap 支持的内部格式;二是深度比较采样与 mipmap 过滤在语义上冲突。也因此应避免依赖 mip 层级过滤,官方实现把缩小/放大过滤默认收敛到最近邻采样(见上文 magFilter/minFilter 说明)。
.isDepthTexture : boolean(只读)
- 默认值:
true。 - 含义:类型标识。three.js 全库普遍使用这类只读标识做鸭子类型判断(避免直接
instanceof),例如在渲染器纹理上传、WebGLShadowMap、TSL 节点系统中识别深度纹理走专门的分支。单元测试 DepthTexture.tests.js 即专门验证该标识为true。
覆写的方法:copy 与 toJSON
DepthTexture 还覆写了两个生命周期方法(见 DepthTexture.js):
copy(source):调用基类复制后,将source.image拷贝进一个全新的TextureSource(源码注释标注见 #30540,用于隔离共享图像数据源),并同步compareFunction。toJSON(meta):在基类序列化结果上追加compareFunction,保证带深度比较设置的纹理在编辑器/序列化场景中可被还原。
渲染管线中如何"自动保存深度"
DepthTexture 本身不产生数据,深度写入发生在渲染流程中。仓库代码中 DepthTexture 被渲染器各子系统大量引用(源码内搜索可见于 src/renderers 下 20 余个文件),典型协同路径包括:
- 渲染目标深度附件:WebGLRenderer、Renderer(WebGPU) 及 RenderTarget 在目标绑定阶段识别
depthTexture属性,使该纹理充当渲染目标的深度附件,渲染时深度自动写入。 - 阴影映射:WebGLShadowMap 与 TSL 光照节点 ShadowNode、PointShadowNode 使用带深度纹理的渲染目标生成 shadow map。
- 屏幕空间效果:SSAO、GTAO、SAO、SSR、像素化渲染等后处理 Pass 均以
depthTexture: new DepthTexture()挂接目标深度: - TSL 深度节点:节点系统提供 ViewportDepthTextureNode 及
viewportDepthTexture()辅助函数,供着色器图(TSL)中直接读取"不透明物体深度"做软粒子、雾、描边等效果。 - WebXR 深度感知:WebXRDepthSensing 把 WebXR 设备返回的真实深度数据封装为 DepthTexture,使 AR 内容可以基于真实环境深度做遮挡与交互。
- 延迟渲染:webgpu_deferred.html 中把不透明深度纹理作为透明通道的输入,并配合
autoClearDepth: false实现两趟合一的深度复用。
常见问题与实践建议
- 格式传错会直接抛错:
format仅接受DepthFormat/DepthStencilFormat。需要同时拿模板信息(如描边/遮罩后处理)时使用DepthStencilFormat并配合UnsignedInt248Type。 - 默认过滤看源码而非注释:官方文档与 JSDoc 标注
magFilter/minFilter默认为LinearFilter,但 v0.185.0 的实际实现默认是NearestFilter(DepthTexture.js)。深度纹理无 mipmap、且常用硬件深度比较,NearestFilter是更符合渲染语义的默认,需要线性深度插值时应显式传参并按目标平台能力评估。 - 不要翻转、不要 mipmap:保持
flipY = false、generateMipmaps = false,二者在构造时已强制关闭,手动开启可能造成深度方向或采样语义错误。 - 多层深度请用
depth参数:二维阵列/三维深度纹理需把层数传给构造参数(参考 TileShadowNode 的瓦片阴影用法);立方体深度请改用 CubeDepthTexture。 - 属性不可热修改:DepthTexture 复用 Texture 基类约束——首次上传 GPU 后,尺寸/格式/类型不再可改,需要变化时调用
dispose()后新建。 - 深度图可视化需要转换:直接输出深度纹理并非线性灰度;文档没有展开说明 shader 侧写法,实际使用时通常需结合相机近远裁剪面做非线性→线性还原,再用于 AO/雾效/深度测试类效果。
- 类型判断:优先使用只读标识
isDepthTexture === true(或派生类isCubeDepthTexture)做运行时类型测试。
测试与进一步阅读
仓库针对 DepthTexture 的单元测试位于 test/unit/src/textures/DepthTexture.tests.js,覆盖三方面:继承自 Texture、可实例化、isDepthTexture 为 true——对应本文讲解的三个核心承诺。
需要继续深入时,建议按如下路径在仓库内检索:
- 官方 API 页(含继承、覆写标记):docs/pages/DepthTexture.html 与 docs/pages/DepthTexture.html.md
- 实现源码:src/textures/DepthTexture.js、基类 src/textures/Texture.js、立方体变体 src/textures/CubeDepthTexture.js
- 常量定义:src/constants.js(
DepthFormat=1026、DepthStencilFormat=1027,比较函数 512–519) - 实际使用场景:后处理 SSAOPass / SSRPass,瓦片阴影 TileShadowNode,WebXR 深度感知 WebXRDepthSensing
整体上,DepthTexture 的设计思路非常聚焦:提供一个面向"深度即纹理"场景的专用容器,把颜色纹理需要处理的翻转、mipmap、像素来源等问题全部替调用方规避掉,同时保留 compareFunction、多层 depth 等与深度采样强相关的能力,让阴影、AO、延迟渲染和 XR 深度感知等上层特性可以围绕它可靠地构建。
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