为什么现代渲染器越来越像数据库
为什么现代渲染器越来越像数据库
很多开发者第一次接触图形学时。
脑海中的渲染器通常是这样的:
scene.draw();
或者:
renderer.draw(mesh);
从软件工程角度看。
这是一种典型的对象模型。
对象拥有:
Mesh
Material
Texture
渲染器负责:
遍历对象
↓
提交 Draw Call
看起来十分自然。
但随着现代引擎不断发展。
人们开始发现一个有趣现象。
越来越多渲染器内部已经不再围绕对象运行。
而开始围绕数据运行。
它们越来越像数据库。
最初的渲染器是对象驱动的
例如:
class MeshRenderer {
public:
Mesh* mesh;
Material* material;
};
渲染时:
for(auto& renderer : renderers)
{
renderer.draw();
}
逻辑简单。
容易理解。
对象本身就是系统中心。
许多早期引擎都是这种结构。
对象数量开始爆炸
问题出现在规模增长之后。
例如:
100 个物体
时。
没有任何问题。
但当场景变成:
100000 个物体
时。
情况开始改变。
此时渲染器真正关心的往往不是:
Object #3812
而是:
哪些物体可见?
或者:
哪些物体使用同一材质?
或者:
哪些物体需要进入 Shadow Pass?
注意。
这些已经不是对象问题。
而是查询问题。
查询开始成为核心操作
观察现代渲染器会发现。
每一帧都在执行类似操作:
查找可见对象
查找透明对象
查找阴影对象
查找相同材质对象
查找相同 Mesh 对象
这些行为非常像:
SELECT *
FROM RenderObjects
WHERE Visible = true;
或者:
SELECT *
FROM RenderObjects
WHERE Material = X;
当然。
引擎不会真的运行 SQL。
但本质上。
已经开始执行:
查询
过滤
分组
这样的操作。
而这正是数据库最擅长的事情。
ECS 本质上也是一种数据表
上一篇文章讨论 Archetype 时提到。
现代 ECS 经常采用:
Position[]
Velocity[]
MeshID[]
MaterialID[]
这样的布局。
如果换一个角度观察。
这其实非常像:
Entity Table
例如:
| Entity | Mesh | Material |
|---|---|---|
| 0 | 12 | 3 |
| 1 | 4 | 8 |
| 2 | 12 | 3 |
渲染系统真正关心的是:
Material = 3
的所有实体。
或者:
Mesh = 12
的所有实体。
本质上已经变成:
数据查询
问题。
而不是:
对象调用
问题。
GPU Driven 更进一步
GPU Driven 出现后。
这种趋势更加明显。
过去:
object.draw();
现在:
Cull
LOD
Generate Draw Command
GPU 并不关心:
Object
是什么。
GPU 只关心:
数据
在哪里。
例如:
Transform[]
Bounds[]
MaterialID[]
然后执行:
过滤
排序
分组
这与数据库执行查询十分相似。
Bindless 让资源变成记录
传统资源系统:
Texture*
直接引用对象。
Bindless 出现后。
资源开始变成:
TextureIndex
例如:
Material {
uint32_t albedoTexture;
uint32_t normalTexture;
}
Shader 执行时:
textureTable[albedoTexture]
访问资源。
此时:
资源
更像数据库中的:
记录
索引开始比指针更重要。
Render Graph 像查询规划器
Render Graph 的出现。
进一步强化了这种趋势。
过去:
ShadowPass();
GBufferPass();
LightingPass();
执行顺序由程序员决定。
而 Render Graph 中:
Resource A
↓
Pass B
↓
Resource C
系统根据依赖关系自动安排执行顺序。
这与数据库中的:
Query Planner
其实有相似思想。
开发者描述:
需要什么
系统决定:
如何执行
关注点再次从过程转向数据。
为什么会发生这种变化
原因其实很简单。
对象模型更适合:
表达逻辑
而现代渲染器更关心:
处理海量数据
当规模达到:
10 万对象
100 万实例
数万资源
时。
系统真正面临的问题变成:
如何过滤
如何查询
如何批处理
这些问题与数据库面临的问题非常接近。
于是相似的设计开始出现。
现代渲染器越来越重视数据
观察过去十年的趋势会发现。
越来越多技术都在推动同一个方向:
ECS:
数据表
Archetype:
数据分区
GPU Driven:
数据查询
Bindless:
资源索引
Render Graph:
依赖规划
它们看起来完全不同。
但背后都在推动一件事:
从对象驱动转向数据驱动。
这并不意味着 OOP 失败了
看到这里。
很容易产生误解:
现代引擎已经不需要对象了。
实际上并不是。
对象仍然非常重要。
例如:
EditorWindow
AssetImporter
Project
这些系统天然适合对象模型。
变化发生在:
高频数据处理
领域。
因为当数据规模足够大时。
数据组织方式开始比对象关系更重要。
结语
很多人第一次学习渲染器时。
看到的是:
mesh.draw();
这样的代码。
但随着系统规模增长。
渲染器内部逐渐变成:
过滤
查询
排序
分组
批处理
的世界。
对象仍然存在。
但它们越来越像用户界面。
而真正驱动渲染器运行的。
是大量连续的数据。
从这个角度看。
现代渲染器并没有变成数据库。
但它们正在解决越来越多与数据库相同的问题。
而这或许也是现代引擎架构不断演化后的一个共同方向:
不再围绕对象组织系统。
而开始围绕数据组织系统。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)