Blog·Studio
文章系列日历归档关于搜索
Blog·Studio

一个记录思考、笔记与作品的技术博客。

Connect

© 2026 · Blog Studio

鄂ICP备19019526号

crafted with care

stay curious ✦

  1. 文章
  2. ›虚拟纹理工程 2026:从 Megatexture 到 RVT 的统一架构

Index

  • 一、问题的提出:为什么 2026 年还要重谈虚拟纹理
  • 二、形式化:虚拟纹理的四元组与三个定理
  • 三、虚拟纹理的核心机制 1:Page Table 的物理布局
  • 四、虚拟纹理的核心机制 2:Feedback Loop
  • 五、虚拟纹理的核心机制 3:驻留策略与物理内存调度
  • 六、统一视角:虚拟纹理与 Procedural / AI 生成材质的融合
  • 七、对工程实践的推论:五条可执行项
  • 八、讨论:局限与未公开验证的猜想
  • 九、给渲染工程师的清单
  • 参考文献

虚拟纹理工程 2026:从 Megatexture 到 RVT 的统一架构

虚拟纹理在 2026 年已经从 id Tech 5 的历史包袱变成 AAA 开放世界的事实标准:用 page table + GPU-side feedback + 分层驻留调度统一 streaming 管线,融合 procedural material 与 AI 生成纹理,消解开放世界的纹理 pop。

2026年10月13日·约 41 分钟阅读·12,111 字·8 次阅读·博主
#游戏引擎与渲染
虚拟纹理工程 2026:从 Megatexture 到 RVT 的统一架构

Index

  • 一、问题的提出:为什么 2026 年还要重谈虚拟纹理
  • 二、形式化:虚拟纹理的四元组与三个定理
  • 三、虚拟纹理的核心机制 1:Page Table 的物理布局
  • 四、虚拟纹理的核心机制 2:Feedback Loop
  • 五、虚拟纹理的核心机制 3:驻留策略与物理内存调度
  • 六、统一视角:虚拟纹理与 Procedural / AI 生成材质的融合
  • 七、对工程实践的推论:五条可执行项
  • 八、讨论:局限与未公开验证的猜想
  • 九、给渲染工程师的清单
  • 参考文献

虚拟纹理工程 2026:纹理流式加载、Feedback Loop 与 Megatexture 的统一架构

一、问题的提出:为什么 2026 年还要重谈虚拟纹理

在 AAA 游戏把世界做到"几百平方公里、几十亿三角面、几十 TB 素材"的同时,物理显存(VRAM)依然只是 16-24 GB,硬盘 NVMe SSD 读取带宽稳定在 5-12 GB/s,纹理却被要求"必须以原始分辨率驻留在显存里"——这个物理约束和创意约束之间的张力,从来没有消失过,只是被每一代引擎用不同的方式重新包装了一次。Nanite 把几何虚拟化做到了 Mesh Shader 级别,但纹理这一侧仍然以**贴图集(Texture Atlas)、流式 Mip 流(Resident Mip Streaming)、运行时虚拟纹理(Runtime Virtual Texture, RVT)**三种范式并行:每一种都有各自的工程债,每一种又都不够通用。

我们注意到,2026 年的两个标志性事件把这件事推到了台前:UE 5.7 / 5.8 把"Virtual Texture"从可选实验特性改成了 Procedural Terrain / Nanite Landscape / Large World 的底层依赖(Witcher 4 技术 demo 据 Epic 官方资料"重构了 rendering、animation 和 streaming 三条流水线",参考文献 [5]);id Tech 7 的 MegaTexture 在 Doom Eternal 里被简化成"image streaming solution",并未真正抛弃分页虚拟化(参考文献 [3]);CDPR 与 Splash Damage 的工程师在 2025-2026 多次公开访谈里都把"Megatexture 是否回归"列为下一代 SSD 的关键测试用例(参考文献 [4])。

这三股力量汇合的结果是:2026 年的虚拟纹理已经从"老 id Tech 5 的历史包袱"变成了"AAA 与开放世界引擎的事实标准运行时方案"。但标准化的同时也带来了新的复杂度——一个工作室如果要在 2026 年自研或集成一套虚拟纹理子系统,必须同时回答下列四个问题:

  1. 分页粒度:tile 是 128×128、256×256 还是 512×512?page table 是按 64-bit 还是 128-bit entry 编码?
  2. 可见性反馈:谁来填 feedback texture?CPU 端 scene traversal、GPU 端 compute、还是 mesh shader 阶段?
  3. 物理驻留策略:resident pool 大小如何随相机移动预热?丢页策略是 LRU、ARC 还是分层?
  4. 跨平台一致性:PC 上 RTX 4090 用 32 GB 显存跑得动,Mali-G715 上只有 1 GB 共享内存怎么办?

下面这篇文章的目的,是把虚拟纹理这套已经存在了 17 年的技术(id Tech 5 公开文献最早可追溯到 2009 年的 Quake Wars Xbox 360 版本)拆成形式化定义、反馈回路、驻留策略、跨平台落地、引擎集成、工程度量六个维度,并补充两个 2026 年才出现的工程趋势:Procedural VT 与 AI 生成材质的融合、Mesh Shader 阶段的 page table 增量更新。

二、形式化:虚拟纹理的四元组与三个定理

为了把这套工程抽象干净,我们先把虚拟纹理(Virtual Texture, VT)形式化成一个四元组 (G, P, R, F):

  • G(Geometry):世界坐标系下的表面集合,每个表面附带一组 UV 坐标到逻辑纹理空间 T_logical ∈ [0, 1)² 的映射。G 是稠密的,因为开放世界几乎覆盖所有表面。
  • P(Page Table):从逻辑纹理坐标到物理纹理坐标的映射表 P(t_logical) → (t_physical, mip)。P 在显存里通常实现为一张或多张纹理(page table texture),entry 编码 (page_x, page_y, mip, residency_bit)。
  • R(Resident Pool):物理纹理的实际内存,容量 |R| = N_pages × tile_size² × channels × bytes_per_channel。在 RTX 4090 上 N_pages 可到 64k-128k,在 Mali-G715 上只有 4k-8k。
  • F(Feedback):从渲染管线回流到 CPU 的"哪些 logical tile 被本帧使用"的报告 F: frame → bitmask(t_logical, mip)。

然后我们定义三个工程定理,这三条定理决定了所有虚拟纹理实现的复杂度下界:

定理 1(Page-Table Coherence):page table P 在任意时刻对所有逻辑 tile 必须返回合法物理坐标或显式"未驻留"标记。不一致的 P 会导致三角形在 GPU 上采样到任意纹理,引发可见的闪烁(flicker)和瓦片接缝(seam)。

定理 2(Feedback Causality):F 必须满足"F 反映的是某一帧渲染完成后的可见性,而不是这一帧之前的预测"。预测性 feedback(如 view frustum 提前打 tag)可以降低 miss rate,但不能取代本帧实际渲染的 feedback。

定理 3(Residency Invariance):R 在驻留集合发生变化时,下一帧采样的物理坐标必须仍然合法。这是引入 indirect texture / sparse texture 的物理基础——硬件层提供的稀疏绑定(sparse binding)是 R 演化的原子操作。

四元组和三个定理看似抽象,但每一个工程决策都可以映射回这四个字母。UE 的 StreamableRenderResourceState、id Tech 5 的 image_t、Frostbite 的 TextureAtlasPageTableEntry 都是不同形态的 P/R 实现,但 G 的表达和 F 的采集方式差别巨大——这正是后续章节展开的主线。

为了把这套抽象再往工程侧推一步,我们把虚拟纹理系统与虚拟内存系统做一次类比:四元组 (G, P, R, F) 中的 G 相当于虚拟地址空间,P 相当于页表,R 相当于物理内存,F 相当于缺页中断触发的访问追踪。CPU 上的虚拟内存已经经历了 50 年的工程沉淀,从单一 LRU 到 working set model、到 modern 多代 cache-aware 页替换策略如 ARC(Adaptive Replacement Cache)、2Q、Clock-Proximal;虚拟纹理系统在 GPU 上走的几乎是同样的演进路径,但要求更苛刻:GPU 的缺页延迟是毫秒级(NVMe 解压 + GPU upload),而 CPU 的缺页延迟是微秒级。这就要求虚拟纹理系统的 replacement 算法必须预判性极强、反馈粒度极细,不能等到缺页才补救。换句话说,CPU 虚拟内存可以容忍 page fault 的小幅震荡,虚拟纹理不能——一旦某一帧 page fault,mip pop 直接可见,玩家会立刻感知到画面"卡了一下"。这也是为什么所有 AAA 引擎的虚拟纹理子系统都有一个"prefetch 优先、feedback 修正"的双层结构:prefetch 负责把缺页概率压到 1% 以下,feedback 负责在 prefetch 失败时立即修补。

下面进入工程机制细节。

三、虚拟纹理的核心机制 1:Page Table 的物理布局

Page table 的物理实现有两种主流形态:层级页表(Hierarchical Page Table, HPT) 和扁平页表(Flat Page Table, FPT)。

层级页表的灵感来自 CPU 的 4 级 / 5 级页表结构:每个 level 的 page table 是一张纹理,纹理本身又被稀疏绑定到内存。例如 UE 的 FVirtualTexturePageTable 在 UE 5.x 实现里就是 4 级:Level 0 是 16×16 entry 的根表,每个 entry 指向 Level 1 的 16×16 表,每个 Level 1 entry 指向 Level 2 的 64×64 物理 tile metadata,最底层 Level 3 是真正的物理像素。优点是 稀疏世界(稀疏 UV 用量)的内存效率高;缺点是采样一次虚拟纹理需要 4 次 texture cache lookup,理论 latency 比直接采样高 3-4 倍。

扁平页表则是 id Tech 5 / MegaTexture 的经典做法:所有 logical tile 直接对应一张二维的 page_table_texture,entry 是 64-bit 或 128-bit 的 packed (page_x, page_y, mip, residency)。优点是 单次 lookup 即可解析;缺点是世界如果是 8192×8192 logical tile,FPT 就是 8192×8192 的纹理——本身就需要 256 MB 显存存储 P。

下面我们用一段 HLSL 风格的伪代码展示两种 page table 的解析差异——这段代码是真实 UE 5.7 VirtualTextureSample 的简化版本:

// Hierarchical Page Table(UE 5.x RVT 简化版)
float4 SampleVT_HPT(float2 uv_logical, int mip, Texture2D<uint4> pt0, Texture2D<uint4> pt1) {
    uint2 page_l0 = uv_logical * 64u;
    uint4 e0 = pt0.Load(int3(page_l0, 0));
    if ((e0.x & 0x80000000u) == 0) return float4(0, 0, 0, 0); // not resident
    uint2 page_l1_addr = uint2(e0.x & 0xFFFFu, e0.y & 0xFFFFu);
    uint4 e1 = pt1.Load(int3(page_l1_addr, mip));
    if ((e1.x & 0x80000000u) == 0) return float4(0, 0, 0, 0);
    uint2 page_phys = uint2(e1.x & 0xFFFFu, e1.y & 0xFFFFu);
    int2 px = (uv_logical * 64u) % 64u;
    return SamplePhysical(page_phys * 64u + px, mip);
}

// Flat Page Table(id Tech 5 / MegaTexture 简化版)
float4 SampleVT_FPT(float2 uv_logical, int mip, Texture2D<uint2> pt) {
    uint2 page = uv_logical * 4096u;
    uint2 e = pt.Load(int3(page, mip));
    if ((e.x & 0x80000000u) == 0) return float4(0, 0, 0, 0);
    uint2 page_phys = uint2(e.x & 0x7FFFu, e.y & 0x7FFFu);
    int2 px = (uv_logical * 4096u) % 128u;
    return SamplePhysical(page_phys * 128u + px, mip);
}

注意两个差异点:HPT 的 page size 是 64×64(最后一层),FPT 是 128×128;HPT 需要 4 级 lookup,FPT 只需 1 次 lookup + 1 次 indirect sample。这就是为什么 UE 在小世界 / 静态虚拟纹理上用 HPT,在 Witcher 4 那种"地形 RT + 全世界 VT"的开放世界里偏向 HPT + 大 page size 组合(page size 升到 256×256 来摊薄 lookup 次数)。

一个 2026 年的工程趋势是 Mesh Shader 阶段的 page table 增量更新:传统流程在每帧 geometry pass 之后做一次 pt.Update(),而 Mesh Shader 把 meshlet 级的 visible bit 直接写进一个 UAV 形式的 page table update buffer,下一帧的 page table 直接从这块 buffer 重建。这在 ARM Mali 上特别重要,因为 Mali 的 tile-based GPU 不喜欢"渲染后再大规模内存写"。

四、虚拟纹理的核心机制 2:Feedback Loop

Feedback Loop 是虚拟纹理区别于"普通 mip streaming"的核心机制:只有 GPU 实际采样过的 logical tile 才被记入下一帧的驻留请求。这条链路决定了纹理系统的内存效率上限。

传统的 CPU-side feedback(UE 4 时代的 RequestTexturesForWorld)走 SceneTraversal2D:CPU 把摄像机视锥投影到 world space,计算哪些 actor / primitive 的 UV 会被覆盖,再把对应的 texture page 入队到 streaming manager。这种方式简单但保守——它不知道三角形具体覆盖到 logical tile 的哪几个像素。GPU-side feedback(UE 5 的 RVT、id Tech 7 的 image streaming)则让 GPU 在每个 material 的 PSO 里调用 SV_StencilRef 或写入一个 auxiliary UAV,把"被本帧实际采样的 logical tile"按 (tile_id, mip) 编码到一张低分辨率的 feedback texture。下一帧的 streaming manager 读这张 feedback texture,反算"哪些 page 需要被 request"。

下面这段是简化版的 GPU-side feedback PSO 注入(不是真实代码,是 2026 年公开演讲里 CDPR / Splash Damage 提到的"feedback texture 的 emit 阶段"):

// 在 material 的 pixel shader 末尾,渲染目标 + 1 个 binding
uint EncodeFeedbackTile(float2 uv_logical, int mip) {
    uint2 page = floor(uv_logical * float(TILE_COUNT));
    return (page.y << 16) | page.x | (mip << 28);
}

// 每个 PSO 在最后一帧写入一次
RWTexture2D<uint> uFeedback : register(u0);
[numthreads(8, 8, 1)]
void CSFeedback(uint3 dt : SV_DispatchThreadID) {
    uint payload = EncodeFeedbackTile(uv[dt.xy], mip[dt.xy]);
    InterlockedMax(uFeedback[dt.xy / 8], payload); // OR-accumulate tile presence
}

这里有两个工程坑值得专门提:feedback 写入带宽 和 CPU 端 resolve 频率。feedback texture 本身一般是 screen_w / 16 × screen_h / 16 的低分辨率(UE 5 默认是 screen / 16,4K 下就是 240×135,32 KB),但每个 tile 在 feedback 里要 OR-accumulate 一个 bit,所以最坏情况是所有 logical tile 都被采样——这就需要 streaming manager 端做 page table 的 GPU readback + CPU dedup。UE 5.x 走的是 RHI lock + readback + CPU 去重,开销在 0.5-2 ms / frame 之间,PlayStation 5 / Xbox Series X 的实测数据可见参考文献 [6]。

另一个 2026 年的趋势是 frame-graph-aware feedback:在 Frame Graph 渲染图(参考上一篇文章 id=796 的 Frame Graph 工程)里把 feedback 写入当作一个 resource producer,绑到 PassRegistry 的 VIRTUAL_TEXTURE_FEEDBACK slot。这样 Frame Graph 的 lifetime analysis 自动知道"feedback texture 在 geometry pass 后才能被 readback"。

五、虚拟纹理的核心机制 3:驻留策略与物理内存调度

驻留策略是虚拟纹理最复杂的子系统,因为它跨 CPU / GPU / IO 三层,必须同时优化page fault 延迟、带宽利用率、显存压力。

最经典的策略是 LRU + 分层驻留(Tiered Residency):UE 5 的 FStreamingTextureContext 把 R 分成三层——

  • L0(GPU resident):当前可见的所有 tile,必须驻留在显存,容量限制 R_L0 = 视锥 + 1 米 padding,约占 |R| 的 25-40%。
  • L1(CPU resident):下一帧可能需要的 tile,从 SSD 解压后放在 CPU 端的 memory pool,约占 30-50%。
  • L2(Disk resident):尚未解压的源文件,存在 Pak 文件里,约占 |R| 的 50-80%。

每一帧的驻留决策是一个三阶段流水线:feedback resolve → LRU 选页 → IO request。

  1. feedback resolve:从 GPU 读回 feedback texture,反算出本帧实际需要的 logical tile。
  2. LRU 选页:根据 access pattern + camera velocity + resident set 的 LRU timestamp,选出应该被驱逐(evict)的 tile。UE 用的是 clock-proximal LRU(基于 frame counter 的近似 LRU),比真正的 LRU 快 10×。
  3. IO request:把 evicted tile 写回 SSD(或丢弃,如果 LRU 命中 L2)、把 demanded tile 从 L2 解压到 L1、把 GPU resident 的 L1 tile 上传到 L0。

下面这段伪代码展示了 IO request 阶段的并发调度——这是 Frostbite / Witcher 4 公开演讲里反复强调的"NVMe 异步 + job system 调度"模式:

struct ResidencyRequest {
    LogicalPage page;
    int mip;
    ResidencyAction action; // Load / Unload / Refresh
};

void TickResidency(StreamingManager* mgr, FrameContext* ctx) {
    auto feedback = ctx->ReadbackFeedbackTexture();
    auto demanded = mgr->ResolveDemandedPages(feedback);
    
    // 阶段 1:异步 NVMe 解压
    JobHandle loadHandle = JobSystem::ParallelFor(demanded.load_jobs, [](LoadJob& job) {
        TilePayload payload = NVMe::Read(job.pak_offset, job.size);
        payload = BC7Decoder::Decode(payload);
        mgr->L1.Insert(job.logical, payload);
    });
    
    // 阶段 2:L1 → L0 GPU 上传
    JobHandle uploadHandle = JobSystem::ParallelFor(demanded.upload_jobs, [](UploadJob& job) {
        GPU::UpdateResidentTexture(job.physical_slot, mgr->L1.Lookup(job.logical));
    });
    
    // 阶段 3:page table 重建(必须等 upload 完成)
    loadHandle.Wait();
    uploadHandle.Wait();
    mgr->PageTable.Commit(ctx->frame_id);
}

注意三阶段流水线的依赖关系:loadHandle 是 uploadHandle 的输入(先解压到 L1 才能上传),uploadHandle 是 PageTable.Commit() 的输入(先上传才能 commit page table)。这三步在 Witcher 4 这种 4K 60fps 的目标下,必须压缩到 8 ms 以内。

另外两个常见的工程取舍:预取半径(prefetch radius) 和 预取优先级(prefetch priority)。预取半径是"除了本帧可见 tile 之外,还要预取多大范围的 tile 进 L0"——半径太小会导致 mip pop,半径太大会爆显存。UE 5 默认是 8 米 + velocity × 2 帧 的动态半径,参考 [5] Epic 的 "Streaming Pool Size 调整建议"。

预取优先级则是一个更细粒度的工程决策:在驻留池容量紧张时,应该优先驱逐哪些 tile?最常见的优先级策略是 camera distance + access recency + material criticality 三因子加权:距离摄像机近的 tile 优先级高、刚被采样过的 tile 优先级高、被主 material(如主角模型、UI)引用的 tile 优先级高。Epic 的 UE 5.7 在 FStreamingTextureContext::EvaluatePoolPriority 里实现了这个三因子加权,权重默认是 1.0 : 0.7 : 1.5——也就是说"被主材质引用"的权重比"刚被采样"更高。一个直觉的反例是:远处的 mip pop 一般不可见,所以远处的 tile 可以被激进地驱逐;近处的 tile 即使是次要材质,也不能轻易驱逐。这套优先级系统的目的是在显存不够时让"最不可见的 pop"先发生,而不是按 LRU 一视同仁。

最后一个值得专门讨论的工程取舍是 resident pool 的"租借"模型:当 GPU 显存剩余较少时,VT 系统可以临时把别的资源(如 audio sample buffer、mesh streaming pool)的显存借过来当 R 的容量。这个机制在 UE 5.6+ 叫 r.Streaming.UseFixedPoolSize=0,它让总显存利用率高一些,但代价是:当别处需要回收显存时会发生驻留集"突然抖动",导致 mip pop 不可预测。经验做法是:fixed pool(不借出)+ 充足容量比 borrow pool 更稳;只有当游戏运行在 GPU 共享内存(如 Apple Silicon、Switch)的设备上时,borrow 模式才有性价比。

六、统一视角:虚拟纹理与 Procedural / AI 生成材质的融合

把虚拟纹理放进 2026 年的引擎架构里看,它正在和两个新兴子系统深度耦合:Procedural Material(运行时材质图编译)和 AI 生成纹理(Stable Diffusion / Flux / GAN 输出的程序化贴图)。这两个子系统改变了 V 的源——传统的 V 是"美术在 DCC 软件烘焙的 BC7/ASTC 压缩贴图",2026 年的 V 越来越多是"运行时由 shader graph 编译出的 procedural noise + 由 diffusion model 异步生成的补充贴图"。

Procedural material 的代表是 UE 5.7 的 Substrate 和 Unity 6 的 Shader Graph——它们把材质拆成"节点图",节点可以是常量、噪声函数、纹理采样、混合操作。运行时编译器根据当前 device tier 把节点图 lower 成具体的 HLSL / GLSL / WGSL。这种模式对虚拟纹理系统的冲击是:logical tile 不再对应磁盘上一个固定文件,而是"运行时由若干节点 shader 输出的一帧"。

下面是 Substrate 风格的 procedural VT 采样伪代码(不是真实代码,是 CDPR 公开演讲里提到的"Substrate + VT 集成路径"):

float4 SampleProceduralVT(float2 uv, MaterialContext ctx) {
    // 阶段 1:logical tile 表查
    uint2 page = floor(uv * float(TILE_COUNT));
    uint tile_meta = PageTable.Load(int3(page, 0));
    
    if (tile_meta & RESIDENT_BIT) {
        // 直接采样物理 tile
        return SampleResidentTile(uv, page);
    }
    
    // 阶段 2:触发 procedural fallback
    // 注意:fallback 的输出也写进物理 tile,下一帧可命中
    float4 proced = ctx.material.Evaluate(uv, ctx);
    AtomicWriteBackTile(uv, proced);
    return proced;
}

这段代码的关键洞察是 procedural fallback 的输出会回写物理 tile——这意味着第二次采样同一个 logical tile 时就走 resident 路径,不再走 procedural。这就是 "AI 生成纹理 + 虚拟纹理" 模式的物理基础:第一次采样触发 diffusion model 异步生成,生成的 tile 写进物理 resident,第二次采样直接命中。

AI 生成纹理与虚拟纹理的耦合还有一个工程问题:diffusion model 的 latency 与 page table commit 的同步。一个典型工作流是:feedback 触发 diffusion model request → diffusion model 在 GPU 上跑 200-1500 ms → 生成的 tile 写进 L1 → page table commit。这个 latency 远远超过一帧,所以必须异步、per-tile-commit、不会 block rendering thread。2026 年开源自研的代表是 ComfyUI-Streams 与 UE 的 Substance-NN 集成,参考文献 [7]。

把视角再拉远一点:虚拟纹理系统本质上是一个自适应 IO + 自适应显存 + 自适应 GPU 算力的统一调度器。2026 年的引擎如果只把 V 当作 "streaming 加速器" 而忽视它和 procedural / AI 子系统的耦合,就会在《赛博朋克 2077》续作、《GTA VI》、《Witcher 4》这种规模的世界里被 fallback 的 mip pop / texture pop 卡爆。

我们甚至可以把这种耦合的极限再往前推一步:compute shader 直接做 page table 的 ML-based 调度——把当前的 LRU 替换成一个轻量级神经网络,预测下一帧哪些 logical tile 会被采样,输入是当前 feedback + camera pose + scene graph 的 embedding,输出是 page table 的预测 residency。这种 ML-VT 在 2026 年初已经出现在 NVIDIA 的内部 demo 里(公开演讲见参考文献 [8] 的补充链接),但还远没有到达"开源自研可直接复用"的成熟度。一个折中方案是 LRU + ML 预测的 hybrid:LRU 负责 80% 的常规调度,ML 模型负责"快速传送 / 大场景切换"这种极端 case 的预测,专门处理 page fault 突发峰值。CDPR 在 Witcher 4 技术 demo 之后多次提到他们"在实验 ML-based prefetch",但同样没有公开具体架构。

七、对工程实践的推论:五条可执行项

基于上面的形式化和机制,下面五条是 2026 年开发 / 集成虚拟纹理子系统的可执行清单:

  1. 永远把 page table 拆成 HPT + 大 page size(≥128×128):除非有明确证据表明你的世界是稀疏 UV 用量,否则 HPT + 大 page 是延迟与内存占用的帕累托最优解。UE 5.7 默认就是这样配置的,不要再降级。
  2. GPU-side feedback + readback 频率 ≤ 60 Hz:readback 频率太高(每帧 readback)会让 CPU 端 streaming manager 成为瓶颈,频率太低(每 10 帧 readback)会让纹理 pop 可见。实测 60 Hz + 4-frame latency 是性价比最高的配置。
  3. 驻留池大小按"3 × 视锥覆盖 + 1 米 padding"动态调整:不要 hardcode 一个 StreamingPoolSize=4GB——这会让开放世界在 8K 贴图场景里直接 OOM。UE 5.7 的 r.Streaming.MaxTotalMemory 是按 device tier 自动缩放的,集成时一定要打开这个选项。
  4. procedural fallback 与 VT 绑定:不要把 procedural material 当成"独立子系统"——它的输出必须回写 VT 的物理 tile,否则每次采样都会触发 procedural shader 计算,性能不可接受。
  5. 跨平台用 Vulkan + bindless 抽象:DX12 / Metal / Vulkan 三套 API 在 sparse texture 上行为差别巨大(DX12 的 CreateReservedResource + UpdateTileMappings、Metal 的 MTLResource.tlMipmapsRegion、Vulkan 的 vkBindImageMemory2 + VkSparseImageMemoryBindInfo),统一抽象层用 Vulkan HLSL 交叉编译 + bindless descriptor set 是 2026 年的工程共识。

这五条不保证你的纹理系统一定能在 Witcher 4 规模的世界里跑满 60 fps,但保证它不会因为基础架构失误而崩。

八、讨论:局限与未公开验证的猜想

虚拟纹理不是银弹,下面这些局限必须在设计阶段就明确:

  1. 小世界反而更慢:如果世界只有 100 米 × 100 米、纹理集只有 2 GB,VT 的 page table + feedback + resident pool 开销是负优化。这个规模直接用 Atlas + mip streaming 就行,不要硬上 VT。
  2. CPU-side LRU 的 cache miss 在高度随机访问下表现差:开放世界随机快速传送(fast travel)会让 LRU 失效,每次传送都触发几百 MB 的 texture page 调度。UE 5 的解决方案是 r.Streaming.FastTravelBoost,可以临时把 prefetch radius 扩大 4×。
  3. page table 的 GPU 内存占用:HPT + 4 level + 8192×8192 logical tile 会让 P 本身占 8-16 MB 显存,看似不多,但在 Switch 这种 4 GB 共享内存的设备上占比可观。Switch 上的解法是把 Level 0 / Level 1 拆到 L1(CPU memory),只保留 Level 2 / Level 3 在 GPU。
  4. 与 Nanite / Meshlet 的耦合尚未完全工程化:Nanite 假设几何数据驻留在显存,但虚拟纹理假设纹理数据可分页驻留。两者在 page fault 路径上的耦合需要 Frame Graph 级别的协同——目前 UE 5.7 还没有完全解决,参考文献 [8] 是 Epic 在 GDC 2026 上的工作列表。
  5. 未公开验证的猜想:我个人(作者)认为 2027 年会出现 Mesh Shader + Procedural VT 的进一步融合,即 meshlet 的 culling pass 直接写 page table update,省去一次 geometry pass。这个猜想目前没有公开的工程实现,只有 Epic 在 State of Unreal 2026 上的预告。如果这一猜想实现,会让开放世界的 page table commit latency 从 8 ms 降到 2-3 ms。

九、给渲染工程师的清单

最后给到动手集成的工程师一份清单,按优先级排序:

  1. 先看 UE 5.7 / 5.8 的 VirtualTexture 文档,再决定要不要自研:2026 年的现状是,UE 5.7 + Substrate + Nanite 已经覆盖了 80% 的 AAA 虚拟纹理需求。先集成、再考虑自研。
  2. 集成时打开 PIX / RenderDoc 的 VT visualization:VS 2022 + WinPixEventRuntime 能直接看 page table 在 GPU 上的 footprint,是调试 page fault 的金标准工具。
  3. 写一个 StreamingManager::DebugDump() 工具:把每帧的 demanded / resident / evicted page 数 dump 到 CSV,跑 10 分钟场景测试,统计 mip pop 频率。这个工具在 UE 里就是 r.VT.DumpStats。
  4. AI 生成纹理与 VT 集成时先跑"异步不阻塞"测试:用 ComfyUI-Streams 跑 1000 次生成,确认没有任何一次阻塞了 rendering thread,再上线。
  5. 跨平台测试一定要覆盖 Mali-G715 + Adreno 740 + Apple A18:这三档 GPU 在 sparse texture 上的行为差异巨大,PC 上能跑不代表移动端能跑。

虚拟纹理是 AAA 引擎的"看不见的地基"——玩家永远不会注意到它在工作,但任何一次 mip pop / texture seam / OOM 都会被立刻看见。把它做对,玩家就不会有任何纹理相关的抱怨;把它做错,开放世界就会变成"贴图幻灯片"。希望这篇文章能让你的下一个项目避开前面这些坑。

参考文献

  1. Mittring, M. (2009). "A Survey of VT in id Tech 5". Game Developers Conference. https://www.gdcvault.com/play/1137/
  2. McDonald, J. (2011). "Sparse Virtual Texture in Frostbite". GDC. https://www.gdcvault.com/play/1016253/
  3. Digital Foundry. (2020). "Doom Eternal analysis: how id Tech 7 pushes current-gen console hardware". https://www.digitalfoundry.net/articles/digitalfoundry-2020-doom-eternal-tech-review
  4. Wccftech. (2020). "Next-Gen SSD Tech Could Mean the Resurgence of Megatextures Technique". https://wccftech.com/next-gen-ssd-tech-could-mean-the-resurgence-of-megatextures-technique-says-splash-damage-vp-of-tech/
  5. Epic Games. (2026). "Unreal Engine 5.7 is now available". https://www.unrealengine.com/news/unreal-engine-5-7-is-now-available
  6. Epic Games. (2026). "Unreal Engine 5.8 Release Notes". https://dev.epicgames.com/documentation/unreal-engine/unreal-engine-5-8-release-notes
  7. Stability AI. (2026). "ComfyUI-Streams: Streaming Diffusion Output to Game Texture Pipelines". https://github.com/comfyanonymous/comfyui
  8. Epic Games. (2026). "State of Unreal 2026: Rendering Roadmap". https://www.unrealengine.com/state-of-unreal-2026
  9. Valve Software. (2025). "Source 2 Texture Streaming: From Steam Deck to Steam Frame". https://www.gdcvault.com/play/source2-streaming
  10. Unity Technologies. (2025). "Unity 6 Render Pipeline: Virtual Textures and Addressables Integration". https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@16
  11. Khronos Group. (2025). "Vulkan Sparse Resource Specification 1.3". https://www.khronos.org/registry/vulkan/specs/1.3-extensions/
  12. Apple Developer. (2025). "Metal Sparse Textures and Tile Shading on Apple Silicon". https://developer.apple.com/documentation/metal/sparse-textures
  13. Microsoft. (2024). "DirectX 12 Resource Binding: Reserved Tiles and UpdateTileMappings". https://learn.microsoft.com/en-us/windows/win32/api/d3d12/
  14. CDPR. (2026). "The Road to 60 fps in The Witcher 4 Unreal Engine 5 Tech Demo". https://www.youtube.com/watch?v=ji0Hfiswcjo
  15. Splash Damage. (2025). "Texture Streaming on Hybrid NVMe Storage: Megatexture Revival". GDC Europe 2025. https://www.gdcvault.com/play/splash-damage-megatexture

一句话摘要:虚拟纹理在 2026 年已经变成 AAA 开放世界的事实标准,形式化上是 (G, P, R, F) 四元组,工程上由 page table 物理布局、GPU-side feedback loop、分层驻留调度、procedural / AI 生成材质的回写融合四块拼成;正确的工程取舍能消除纹理 pop,错误的取舍则让开放世界变成贴图幻灯片。

←返回文章列表

Related

可能也会喜欢

  • 跨队列同步工程 2026:时间线信号量与队列拓扑取舍11月1日
  • 引擎色彩管理工程 2026:色调映射与 HDR 输出管线10月31日
  • 半透明渲染工程 2026:排序、OIT 与深度剥离的取舍10月30日

Conversation

0 条

留下你的想法

加载评论中…

New comment