
什么是体积渲染?从云朵到爆炸,详解体积着色器
作者:Arndt von Koenigsmarck · 技术审核:Sergen Eren · 最后审阅时间:2026 年 8 月
计算机图形中的大多数物体都是中空的"外壳"。一辆渲染出的汽车、一个角色,甚至一座山,通常都只是一层包裹着空心的薄表面,因为对于实心物体而言,相机所能看到的就只有其表面。但自然界充满了完全非固体的东西:云朵、雾、烟雾、火焰、光束中的尘埃——你可以看透它们、看穿它们,且光线在每个内部点上的表现都不同。渲染这些现象正是体积渲染的职责,而描述它们外观的工具就是 体积着色器。本文将对这两者进行讲解,先介绍其中的理念与物理原理,再讲解在 Redshift.
第一部分:理解体积
什么是体积渲染?
体积渲染是一种基于三维数据网格而非表面来计算图像的技术。普通的 3D 模型由描述其外壳的多边形所定义,而一个体积则由 体素——即填充一片空间区域的微小单元,每个单元都存储密度或温度之类的数值。渲染器观察光线穿过所有这些单元时的表现,这正是为什么一个体积可以同时做到边缘稀薄、核心浓密、内部发光。
与表面渲染形成对比是最容易理解体积渲染的方式。当一束光线击中多边形表面时,渲染器只需在恰好一个点上评估材质便告完成。而当光线进入体积时,并没有"某一个点"可供评估。光线会继续行进,途中每一段都可能吸收光线、散射光线或增加光线。像素是一张 2D 图像中的彩色方块;体素则是它在 3D 世界中的对应物,是空间网格中的一个数值。这多出来的一维,正是体积渲染的全部故事——包括它为何如此好看,又为何如此昂贵。

这里创建了一个湍流、旋转的烟雾模拟。在左上角,生成的云层表面使用普通多边形进行可视化;在右上角,则使用了体积着色器进行渲染,这种方式能够实现例如烟雾的逼真背光效果,以及体积内部精细渐变的透明度和光线散射。
这里为了让计算差异更具示意性,相机被向上面完整展示的模拟场景移近了一些。绿色网格代表最终渲染的像素,按行列排布。以纯绿色区域显示的像素正是当前正在计算的像素,因此它会被一条来自相机视角的计算射线(箭头)击中,该射线穿透了场景的三维空间。就简单的多边形模型(图中左侧)而言,射线击中表面后即可在此处收集所有必要信息(见红色标记)。但对于体积而言,这种基于单点的信息是不够的,因为计算射线必须收集体积内多个位置的信息——包括密度和光线散射的数据——才能逼真地渲染出烟雾。
什么是体积着色器?
体积着色器是用于"占据空间"之物的材质。它不是描述表面,而是告诉渲染引擎体积内每一个点上的介质如何与光线交互。几乎每个现代渲染引擎都是用相同的三个要素来构建这种描述的,而 Redshift 文档 为其中每一个要素都提供了与表面材质相对应的、令人印象深刻的类比:
散射 对应体积中的漫反射颜色。它定义了介质内微观粒子会以何种颜色、反射多少光线,这正是云朵呈白色、烟雾呈灰色的原因。
吸收 对应透明度。它定义了介质会吞噬多少光线,这正是浓烟变暗、浓密体积变不透明的原因。
发射 对应白炽或自发光。它让介质能够自行发出光线,这正是火焰和爆炸从内部发光的原因。
你在电影中见过的每一团云、每一片雾或每一颗火球,都是这三种行为的某种混合,通常由模拟产生的数据驱动。在 Redshift 中,这一角色由 标准体积着色器,这是一种用于云朵、烟雾、火焰和爆炸的基于物理的体积材质。对任何从搜索引擎来到这里的人,做一个小小的澄清:网上还有一个广为人知的 GPU 压力测试工具名为 "Volume Shader BM",它借用了这个术语。那是一个基准测试工具,而非材质。本文讨论的是货真价实的那一个。
物理原理:光线如何在介质中传播
物理学家将雾、烟雾和云朵称为参与介质,因为空间本身会参与光照,而不是让光线在击中表面之前一路保持原样。当一束射线穿过这种介质时,可能发生四种情况:光线可能被吸收并转化为热量;光线可能被散射出轨道路径之外,从而使射线变暗;光线也可能从别处散射进当前路径,从而使其变亮;介质本身还可能发出新的光线。吸收与外散射的共同变暗效应被称为消光,而一段旅程后幸存下来的光线的比例被称为透过率。归根结底,体积着色器的参数正是这些物理量对艺术家友好的控制旋钮。
还有一个概念起着令人惊讶的巨大作用,那就是 相位函数,它是"表面材质如何分布反射光"的体积等价物,回答的是"光线在散射后朝哪个方向继续前进"的问题。烟雾粒子大致均匀地向各个方向散射光线,这被称为 各向同性散射。而云朵中的水滴则压倒性地将光线向前抛射,即沿其原始传播方向散射。这种 前向散射 正是当云朵位于你和太阳之间时会出现银亮边缘、背光的雾会发光的原因。渲染引擎使用 Henyey-Greenstein 相位函数来模拟这一点——这是一个可追溯到 1941 年天体物理学论文的经典模型,它使用单个各向异性值,取值范围从负一、对应后向散射,经零、对应各向同性散射,直到正一、对应前向散射。具体到云朵,Redshift 还另外提供了更新的 Jendersie-d'Eon 模型,它能逼近水滴真实的米氏散射,并捕捉到比 Henyey-Greenstein 更真实的前向峰值。

在这些渲染图中,渲染的是同一朵云,并由太阳从后方照亮。唯一的变化是体积材质的各向异性设置。从左到右使用的值分别是 -0.9、0 和 0.85。右侧渲染中的正各向异性值清晰地显示出光线如何更多地被折射向云体积的后部,从而在云朵密度较低的边缘处显现出更多的阳光。
走进标准体积着色器:开发者视角
对于想一探究竟的读者,这里介绍 Redshift 的开发者们自己是如何描述 标准体积着色器。在内部,它是 Redshift 的OpenPBR 和 标准表面材质 材质中的随机行走次表面散射的近亲。次表面散射模拟光线在皮肤或蜡这类有限、均匀的介质中漫游;标准体积着色器则将同样的思路应用于密度在每个体素上都变化的非均匀介质。两者的参数几乎是逐一对应的:次表面颜色对应体积的散射颜色,次表面半径对应透明度颜色,次表面比例则对应体积的深度控制,见下页图。

该示意图将次表面散射(左)与体积渲染(右)进行对比。次表面散射模拟的是在有多边形表面围成的体积内(例如蜡、皮肤、牛奶或大理石)的光线散射,而体积着色器模拟的则是在不由多边形定义的空间内(例如火焰、雾、烟雾或云朵)诸如密度、以及因温度而产生的光发射等属性。
在渲染时,Redshift 会进行光线步进,让射线在穿过介质时逐个体素地采样。它所采样的密度网格,本质上是对每个体素存在多少粒子(相对空虚空间而言)的一种标量化描述,与任何颜色无关。散射颜色就是这些悬浮粒子的反照率,即它们反射回来的光的颜色。各向异性控制则让散射光向前、向后或向所有方向均匀传播,默认使用 Henyey-Greenstein 模型,对于云状的水性介质则使用 Jendersie-d'Eon 模型。
透明度颜色是最有趣的部分。它是平均自由程——即每个波长的光线在被消光前于介质中传播的平均距离——的一种对艺术家友好的编码。红、绿、蓝三个值各代表其对应波长的传播距离,而深度参数将这些 0 到 1 的值放大为真实距离,以厘米计量,并会感知场景的比例。由于不同波长的光被吸收的速率不同,当其他波长被耗尽之后,在介质中传播得足够远的光最终会染上透明度颜色的补色。这正是让深水呈蓝色的物理原理,也正因如此,一丝细微的透明度色调能给体积带来自然而有生气的纵深,这是扁平的散射颜色无法做到的。
光线步进、多次散射,以及体积为何昂贵
在体素中步进回答了"渲染器如何读取体积"的问题,但真正的成本在于光线在体积内改变方向的频率。如果引擎只模拟一次反弹,即所谓的单次散射,那么轻薄的介质如淡淡的薄雾看起来还行,但浓密的云朵会被渲染成又黑又死气沉沉的样子。真实的云之所以明亮,是因为光子在逃出之前会在其中反弹数十甚至数百次:一朵厚重的积云能反射高达 90% 照射到它的光线。模拟这种多次散射,意味着要追踪每条射线经过大量额外反弹,而每增加一次反弹工作量都会倍增。这正是体积渲染落得"很慢"名声的诚实原因,也是 GPU 渲染和巧妙近似方法(第二部分会讲到)发挥价值的地方。现代引擎还用去噪进一步摊薄成本,不过体积历来比表面更难去噪,因为引导去噪器的辅助数据——例如表面法线——在云朵内部根本不存在。

这一系列图像对比了不同的体积追踪深度设置对一朵含有一个圆柱形光源的云的渲染效果。从左到右,Volume Trace Depth 分别使用了 1、5 和 31。值得注意的是,体积着色器中的散射强度必须足够高,体积内的散射光强度才能被看到。
OpenVDB:承载烟雾的文件格式
体积需要在"模拟它们的软件"与"渲染它们的引擎"之间流转,而行业多年前就通过 OpenVDB 解决了这个问题。OpenVDB 最初由梦工厂动画开发,2012 年开源,曾获得奥斯卡技术成就奖,如今由学院软件基金会维护,是存储体积数据的事实标准。Redshift 文档给出了一句完美的概括:"OpenVDB 文件之于体积渲染,正如 EXR 文件之于 HDR 图像。"EXR 存储的是像素,而 VDB 存储的是体素,并且是稀疏存储——因此一缕轻盈烟柱周围那广袤的空旷空间,在磁盘或内存中几乎不占任何成本。
在 VDB 文件内部,体素数据被组织成命名的网格,Redshift 在着色语境中将其称为通道。这些名称更多是约定而非规则,但常见的有以下几种:density——一个无单位的值,描述每个体素中填充了多少粒子,也因此决定了体积在何处具有物质实体;temperature用于驱动火焰发射的热量;velocity用于运动模糊;偶尔还会有一个color网格用于预上色的体积。在 Redshift 中,通道名称区分大小写,这一点曾让不少艺术家困惑上好一会儿。VDB 文件从哪里来?Houdini、实时流体模拟器 EmberGen、以及 Cinema 4D 内置的 Pyro 系统等模拟工具都会导出这类文件,而且还有很棒的免费素材可供练习,包括著名的Walt Disney Animation Studios 云数据集,以及来自JangaFX.
在 Redshift 中进行体积渲染
构建模块
Redshift 将体积渲染拆解为一小组工具,知道该选用哪一个,流程就成功了一半。非均匀体积,即任何密度变化的物体如云朵、烟雾、火焰和爆炸,由 Redshift 体积对象加载,它会读取一个 VDB 文件或一段动画 VDB 序列,并在视口中显示一个边界框或点云预览。该体积的外观随后由标准体积材质来定义。均匀体积,即均匀介质如大气薄雾和雾气,则完全不需要体素数据:Redshift 环境对象用散射介质填充整个场景或其中一段高度受限的层。它也是体积光照的工具——就是那些备受喜爱的、让尘埃空气中的光束变得可见的丁达尔光束。最后,还有一个专门的云朵对象可以生成整套程序化天空,它的快速模式将云层渲染成一个巧妙的背景,而全体积模式则允许一座摩天大楼或一架飞机穿透云层并被其照亮。

下面是一个例子:一扇从外部被照亮的玻璃窗。若不模拟周围环境的大气,窗户与地板之间的光束将保持不可见。借助 Redshift 环境对象,可以模拟出雾气或可见的大气——例如由高湿度或空气中的尘埃粒子所引起的大气效果。于是,即使在物体之间,光束也变成了可见的。
有一个现实约束值得直说:体积必须能完全放进 GPU 内存。它们是唯一被排除在 Redshift 超核系统之外的资产类型,因此一个巨大的 VDB 一旦超过可用显存,会直接中止渲染,而不是让渲染变慢。让模拟的分辨率只达到镜头所要求的程度,这不仅是一个速度决策,更是一份内存预算。
标准体积要点:关键设置
标准体积材质有两种"人格"。当它单独使用、在其通道字段中直接输入网格名称时,会运行一条经过特殊优化的快速路径,表现得像一个经典、易用的体积着色器,并带有针对云朵、烟雾和火焰精心调校的预设。当它连接上输入节点使用时,则会变得完全可编程,让你可以用程序化噪声驱动密度、颜色和温度,重映射网格,甚至为了额外细节而对体素进行置换。对于初次上手,内置字段就已足够,而且四组设置就完成了大部分工作:
体积通道与密度。通道字段指定定义体积形状的 VDB 网格,几乎总是 density。密度参数则对其放大,并设定介质的整体浓淡特征。请精确输入网格名称——通道是区分大小写的。
散射。散射中的颜色和比例设定体积反射什么以及反射得有多亮。各向异性模式选择相位函数:Henyey-Greenstein 及其负一到正一的滑块是全能型选手,也是各向同性烟雾的正确选择;而 Jendersie-d'Eon 则是云朵专家,专为模拟光线穿过水滴而设计。
透明度。透明度颜色与深度实现了第一部分所述的逐波长传播距离。颜色越深表示介质越浓,越亮表示越薄,而任何颜色都会在深处(阴影也不例外)以它的补色为体积着色。这里细微的饱和度就能带来很大差别;由于深度以厘米计量,请参照体积的真实世界尺寸来设置它。
发射。对于火焰和爆炸,把发射通道指向温度网格并选择黑体模式即可,这种模式会按开尔文温标把温度转换为物理上正确的颜色和强度——从约 3,000 K 的深红色,到超过 9,000 K 时的白色和蓝白色。另一种颜色模式则会给你一个渐变,也就是经典的"黑-红-黄"火焰色带,用于刻意无视物理规律、由美术主导的火焰。

燃烧火把的渲染效果,火焰和烟雾以不同温度呈现(从左到右:0、3,000、6,000、9,000 和 12,000 开尔文)。这种调整可以在之后用 Redshift 标准体积材质完成,而无需重新模拟场景。
除了依据模拟温度进行物理上准确的颜色和亮度值分布之外,你也可以在体积材质内部使用自定义的颜色渐变和标准的颜色调整,例如按需定制烟雾和火焰的渲染效果。
让体积更真实:实践中的多次散射
第一部分确立了一件事:浓密的体积只有在多次散射下才会活起来。Redshift 将这一功能暴露为一个名为体积追踪深度的渲染设置,同时还附带着一条值得牢记的要求:体积多次散射需要与暴力全局光照一起配合才能工作。把追踪深度从默认值提高,会把一朵云从一团灰色物质变成发光、可信的物体,代价是渲染成本呈指数级增长。前向散射的云朵从更高的深度中获益巨大;各向同性烟雾则要早得多地出现收益递减;发射型火焰则因其光芒照亮周围烟雾,获得漂亮的内部光溢效果。
Redshift 还提供了三个有经验的艺术家在调高追踪深度之前会先上手的快捷方式。第一个是 消光衰减,它通过在每一次真实反弹时温和地减少消光,来近似成百上千次额外反弹的效果。其 0.2 的默认值是一个刻意选定的甜蜜点,在文档自己的云朵测试中,它比不含该参数的同一场景渲染得更快,同时得到更亮、更真实的结果。第二个是各向异性衰减,它是前者的天然搭档,每次反弹都会略微降低各向异性,从而使更深的射线散射得越来越接近各向同性。这模仿了辐射传输中一个名为 van de Hulst 相似性原理的经典洞见:在高多次散射的介质中,只要整体的输运性质保持不变,散射反照率与各向异性的不同组合会产生几乎无法区分的观感。由于评估各向异性散射很昂贵,随着反弹逐渐放松它,既能模拟高阶散射,又能让体积渲染得更便宜。第三个是阴影密度比例,这是一种经典的巧招,让光线能穿透到体积更深处而不改变其轮廓,以极小的成本伪装出多次散射的提亮效果。一个均衡良好的体积,通常会把适度的追踪深度与这些辅助手段结合起来,而不是单靠拉高深度。
从 Pyro 到图像:Cinema 4D 工作流程
如果你使用 Cinema 4D,就无需借助外部软件来生成体积数据,因为内置的 Pyro 系统可在本地模拟烟雾、火焰和爆炸。其工作流程简短得令人愉快。任何带有 Pyro 发射器标签的对象就会开始产生模拟,而 Pyro 输出对象会收集它的通道,通常是密度、温度和速度(Pyro 模拟的介绍可在此处找到,见 Cinema 4D 文档)。从这里你可以直接渲染,或者把模拟缓存成 VDB 序列,再通过一个 Redshift 体积对象把它加载回来——文档推荐将这条路径作为生产环境中更省内存的做法。着色这一侧几乎是全自动的:随附的 Pyro 体积预设(适用于 Redshift 标准体积着色器)出厂时就把密度网格接到散射上、把温度网格接到黑体发射上——这正是把原始模拟数据变成可视化烟雾和火焰的那两条连接。运动模糊是艺术家们往往最容易忘记的一步。由于 VDB 序列是一连串定格快照,Redshift 会从速度网格读取运动信息;把速度输入体积对象的 Velocity 字段,并调高 Velocity Scale,直到模糊程度与模拟的能量相匹配——不必害羞,远超过 1,000 的值也很常见。

图像的左侧部分展示了创建或加载体积模拟的第一步。在我们的例子中,我们使用了 Cinema 4D 中的 Pyro 模拟来生成爆炸云,并将其动画保存为 VDB 序列。这样模拟就可以随时在其它项目中复用,同时也能让渲染更省内存。右侧的图像概括了后续步骤:设置体积着色器以控制颜色和发射、为模拟布光、校正颜色,以及添加如辉光或运动模糊之类的视觉效果。这一切都可以直接在 Cinema 4D 和 Redshift 中完成,也可以放到后期制作阶段——具体取决于所期望的流程,以及是否还需要与其它渲染器或真人实拍素材进行整合。
体积故障排查清单
体积渲染成黑色或不可见:检查通道字段中是否输入了拼写和大小写完全正确的网格名称,并且至少有一盏灯的体积贡献大于零。
体积看起来噪点很多或颗粒感强:先提高灯光采样,因为灯光主导着体积噪声;以散射为主的介质比以吸收为主的介质需要更多的采样。
体积看起来块状感明显:说明模拟分辨率太低。着色器重映射可以使其柔和一些,但只有更高分辨率的缓存才能从根本上解决。
渲染因显存不足错误而中止:说明 VDB 放不进 GPU 内存。请降低模拟分辨率、从缓存中裁掉未使用的网格,或拆分该效果。
云朵看起来又平又灰:配合暴力全局光照提高体积追踪深度,让消光衰减保持 0.2 的默认值,并且在进一步加深之前,先把阴影密度比例略微调低。
雾气把整个画面洗白:大幅降低环境对象的散射值——即便是很小的值也已经很强力。
常见问题:体积渲染与体积着色器
简单来说,什么是体积着色器?
体积着色器是一种用于烟雾、雾、云朵和火焰等"填充空间"的介质的材质。它不是给表面上色,而是告诉渲染器体积内每一个点如何吸收光、散射光和发射光——这通常由存储在体素网格中的模拟数据来驱动。
体积渲染与表面渲染有什么区别?
表面渲染只在光线击中多边形外壳的那一个点上评估材质。体积渲染则让光线穿过一个体素构成的三维网格,并沿整条路径累积光线的交互,从而能够实现任何表面都无法模仿的半透明、内部发光的介质。
什么是 VDB 文件?
VDB 是用于体积数据的行业标准文件格式,它构建于源自梦工厂动画的开源 OpenVDB 库之上。它存储的是标着诸如 density、temperature 和 velocity 等名称的稀疏体素网格,可由 Houdini、EmberGen 以及 Cinema 4D 的 Pyro 系统等工具导出。
什么是体素,它和像素有什么区别?
像素是一张 2D 图像中的一个彩色方块。体素则是一个 3D 网格中的单元,在空间中的某个位置存储密度或温度之类的数值。体积渲染通过模拟光线穿过数以百万计的 3D 体素,来计算得到 2D 的像素。
为什么我的体积渲染噪点很多?
体积噪点通常来自灯光。在散射介质内部,灯光需要足够的采样才能解析它们的贡献,因此提高灯光的采样数通常比提高整体质量设置更为有效。像云朵这类以散射为主导的体积,比稀薄的吸收型烟雾需要明显更多的采样。
如何渲染逼真的火焰?
使用模拟的温度网格在黑体模式下驱动发射。黑体发射会自动把物理温度转换为正确的火焰颜色和强度,在约 3,000 开尔文时呈现红色,随温度升高逐渐向白色偏移。在 Cinema 4D 中,标准体积着色器已经为众多体积模拟系统提供了合适的预设,并会自动填入体素网格对应的名称。
如何创建God Ray?
God Ray是一种体积照明:当光线穿过稀薄的散射介质时,便会产生可见的光束。在 Redshift 中,添加一个 Redshift 环境对象,开启少量散射,并给场景一个强而部分受阻的光源,例如透过窗户的阳光。光束和体积阴影便会自然而然地出现。
为什么体积渲染这么慢,如何加快速度?
体积之所以昂贵,是因为光线在路径上的许多点被采样,并且可能在稠密介质内部散射多次。若要在 Redshift 中提速,请让模拟分辨率只达到所需程度,使用适中的体积追踪深度,让消光衰减保持默认值,降低阴影密度比例而不是增加反弹次数,剩下的交给 GPU 和降噪器即可。