Chapter 64: Hair, Fur, Cloth Rendering
毛发、皮毛和布料经常出现在同一类角色镜头里:头发随骨骼和风场摆动,皮毛在衣领或动物表面形成密集细节,布料在大面积轮廓上折叠、透光、产生绒面高光。读完本章后,读者应能把这类画面拆回几何表达、光照模型、遮挡数据、动态模拟、LOD 和工具证据,并判断一帧里的主要成本来自哪条资源路径。
本章使用一个贯穿帧作为分析对象:近景角色转头,角色包含长发、短皮毛衣领和带绒面的外套。这个画面的难点集中在三个方向。第一,毛发和皮毛由大量细几何组成,很多片段小于一个像素,需要 coverage、透明合成和时间稳定性共同支撑。第二,头发高光沿发丝切线拉长,布料高光受纤维方向和绒面反射影响,普通粗糙金属度材质很难单独覆盖。第三,这些对象会运动,会遮挡自身,还会和骨骼、碰撞体、风场、阴影 pass、后处理抗锯齿发生耦合。
本章的核心结论是:Hair、Fur、Cloth 的渲染质量取决于“表达模型与预算等级是否匹配”。近景英雄角色可以使用 strand、deep opacity、Marschner 类光照和高质量模拟;中远景角色更适合 cards、shells、简化各向异性高光、低频遮挡和较低模拟频率;远景群众、装饰毛边和快速运动目标应把成本压到 impostor、baked normal、材质分级和 cluster culling 上。
工程上不要把这类效果归类成一个 shader 任务。正确排查顺序是先看几何数量和屏幕覆盖,再看透明/coverage pass,再看 shadow 和 transmittance,再看 lighting sample,再看 simulation 和 buffer update。每一步都要落到 draw、buffer、texture、pipeline state 或 profiler counter 上。
64.1 毛发/皮毛/布料渲染的挑战与特点
毛发、皮毛和布料的共同点是微结构会直接改变可见结果。头发由成束的细纤维形成轮廓和高光,皮毛由表面外伸的短纤维形成柔软边界,布料由编织纤维、法线纹理、绒面反射和折叠轮廓形成材质识别。它们进入管线后,常规 opaque mesh 的“一个三角形覆盖一块稳定表面”的假设会变弱,因为屏幕上同时存在大量细边界、半透明覆盖、自遮挡和高速形变。
在贯穿帧里,长发的根部绑定到头部骨骼,发束中段和发尾跟随模拟。它的输入包括 guide curves、render strands、根部 UV、宽度、切线、颜色、粗糙度和分组信息。皮毛衣领通常更短,可以由 shell、fin、strand 或 card 表达。外套主体仍然是布料 mesh,但绒面、缝线、毛边和半透光需要额外的材质层。一个角色 draw 可能因此拆成 body opaque pass、cloth material pass、hair visibility pass、hair shadow/transmittance pass、hair lighting pass 和 composition pass。
这类对象的第一类成本来自细几何。发丝和皮毛的顶点数量、曲线控制点数量、card 数量、shell 层数会影响 vertex processing、compute update、raster coverage 和后续 lighting sample 数量。近景头发看起来柔顺,通常意味着更多曲线、更高段数、更细的 width、更密的 coverage。屏幕距离拉远后,如果几何数量保持不变,GPU 仍然会处理大量对子像素贡献很小的片段,帧耗时会快速被可见性和透明合成占据。
第二类成本来自各向异性高光。各向异性高光指反射随方向变化,头发的主方向通常是发丝切线,布料的主方向可能来自织物方向或法线贴图。普通 Lambert 漫反射只依赖法线和光照方向,无法表现头发沿发束滑动的亮带,也无法表现天鹅绒在掠射角出现的柔亮边缘。shader 需要读取切线、视线、光线、粗糙度、颜色吸收、fiber 参数,并把结果写入透明或半透明合成路径。
第三类成本来自透明排序和 coverage。发丝、毛边、薄布料经常使用 alpha 或 coverage 表达边界。Alpha test 可以减少排序压力,但边缘容易闪烁;alpha blend 可以保留柔边,但顺序依赖会让背后发束贡献不稳定;per-pixel linked list、weighted blended OIT、MSAA alpha-to-coverage 和 stochastic transparency 都能处理一部分问题,同时会增加内存、带宽或噪声。Unreal 的 Groom 性能文档把 strand 管线拆为 simulation、interpolation、voxelization、primary visibility、lighting、composition,这个拆分适合作为观察成本的基线:Unreal Engine Groom Scalability and Performance。
第四类成本来自自遮挡。头发内部的深色层次来自发束之间互相遮挡,也来自光在纤维间穿过时的衰减。皮毛如果缺少自阴影,会贴在表面上像噪声贴图;布料褶皱如果缺少接触阴影和微表面层次,会失去厚度。实时渲染中常见做法是使用 voxelized density、deep opacity map、屏幕空间遮挡、预计算 AO 或每灯光的低分辨率遮挡贴图。这里的关键取舍是遮挡数据的分辨率、更新频率和参与灯光数量。
第五类成本来自动态模拟。Hair 和 cloth 的运动需要在动画系统、物理约束、碰撞体、风场和渲染 buffer 之间同步。模拟过弱会让头发和衣料贴在骨骼上,模拟过强会带来发束穿插、布料抖动、缓存不同步和时间抗锯齿拖影。性能上,模拟成本受 guide 数量、segment 数量、约束迭代次数、碰撞体数量和更新频率影响;视觉上,错误通常表现为根部漂移、发尾穿透、衣角抖动、阴影滞后或 LOD 切换跳变。
下面的图只描述本章贯穿帧的一条典型路径。不同引擎会拆分 pass 名称,但资源关系保持相似。
这条路径说明一个工程事实:画面里看到的是最终合成结果,性能和稳定性问题经常出现在更早的资源更新或中间贴图。发丝发黑,可能来自 light/transmittance;边缘闪烁,可能来自 visibility/coverage;阴影滞后,可能来自 shadow density 更新频率;头发穿过肩膀,可能来自 simulation 和 collision。
64.2 几何模型与特定细分策略
Hair、Fur、Cloth 的几何表达要先回答一个问题:画面需要表达单根纤维、纤维簇、柔边轮廓,还是大面积布料形变。表达目标不同,输入数据、shader 参数、pass 成本和 LOD 方案都会改变。
Strand 是最直接的毛发表达。它把发丝存为曲线或折线,每根发丝带有根部位置、控制点、宽度、切线、颜色、粗糙度和 group id。Guide strand 负责模拟,render strand 负责显示,二者通过插值关系连接。近景长发、眉毛、睫毛和高质量动物毛适合 strand,因为它能保持发束的方向、层次和动态连续性。代价是 buffer 规模大,visibility pass 复杂,shadow/transmittance 数据昂贵,LOD 切换需要额外设计。
Ribbon 是把一根曲线扩展成面向相机或按切线构造的窄带。它比直接 rasterize 细曲线更容易进入传统三角形管线,也能让 fragment shader 读取沿发丝的 UV 和宽度。Ribbon 适合中等距离的发束、粗毛、风格化发丝和需要稳定 alpha coverage 的场景。它的风险在于朝向相机的方式会影响高光方向,强侧光下容易暴露带状几何。
Shells and fins 常用于短皮毛和草状覆盖。Shell 是沿表面法线挤出多层薄壳,每层使用 alpha 或噪声遮罩形成毛体积;fin 是在轮廓附近增加竖向片面,增强侧面毛边。这个方案对短毛、绒毛、地毯、动物身体和衣领装饰很实用,因为底层 mesh 提供稳定表面,shell 层数提供厚度。代价集中在 overdraw、alpha test、shell 层数和材质采样。
Card-based 表达把一簇头发烘焙到带 alpha 的面片上。每张 card 通常包含发束颜色、alpha、flow/tangent、depth 或 normal 信息。它适合中距离角色、远景发型、移动平台和大量 NPC。它的优势是顶点和模拟成本低,资源易压缩;主要问题是视角变化时体积感下降,透明排序和背面照明需要特殊处理。Epic 的 Groom Asset Editor 文档也把 strands、cards、meshes 放在同一个 groom asset 中管理,说明生产管线通常会同时准备多种几何等级:Groom Asset Editor。
Cloth mesh 是布料主体的常规表达。它由三角形网格、骨骼权重、模拟顶点、法线、切线、UV 和材质参数组成。布料需要更关注轮廓、褶皱、厚度、纤维方向和碰撞。细分策略可以来自 DCC 预细分、运行时 tessellation、mesh shader 细分、法线/位移贴图或局部 wrinkle map。近景衣袖边缘和裙摆需要足够几何表达轮廓;平整大面可以用 normal、roughness、sheen 和微阴影表达纤维质感。
| 表达模型 | 主要输入 | 适合距离 | 主要成本 | 典型风险 |
|---|---|---|---|---|
| Strand | curve、guide、width、tangent、root data | 近景到中景 | simulation、visibility、lighting、shadow | buffer 大、透明合成贵、LOD 难平滑 |
| Ribbon | curve 扩展面、UV、宽度 | 中景 | raster、alpha、材质采样 | 侧面带状感、高光方向偏差 |
| Shells and fins | base mesh、shell layers、noise alpha | 近景短毛到中景 | overdraw、alpha test、层数 | 轮廓穿帮、阴影过粗 |
| Cards | alpha texture、flow map、normal/depth | 中景到远景 | alpha sorting、texture bandwidth | 体积感弱、视角依赖明显 |
| Cloth mesh | triangle mesh、skin/sim buffer、material | 全距离 | vertex/simulation、材质、阴影 | 褶皱不足、碰撞抖动、材质平 |
细分策略应跟屏幕误差绑定。对 strand 来说,段数控制弯曲精度,根数控制密度,width 控制覆盖。近景可以保留更多 render strands 和更细 width;中景可以减少根数并增加单根宽度;远景可以切到 card 或 impostor。对 fur 来说,shell 层数和噪声频率应随屏幕占比下降;对 cloth 来说,轮廓区域、关节附近和褶皱高频区域优先保留几何,平整区域交给 normal 和 material。
一个稳定的 LOD 设计应把几何、材质、阴影和模拟一起降级。只减少发丝数量会让头发变稀;只降低阴影分辨率会让发束漂浮;只关闭模拟会让发尾突然贴住骨骼。工程上常用的顺序是:先按 screen size 选择几何表达,再为对应几何绑定材质等级,然后匹配 shadow/transmittance 质量,最后匹配 simulation update rate 和 collision 复杂度。
64.3 光照模型与遮挡处理实践
Hair 和 cloth 的光照模型要先确定微结构方向。头发的微结构方向是发丝切线,皮毛的方向通常接近表面法线外伸并带局部弯曲,布料的方向来自编织纤维、法线贴图、anisotropy map 或 artist-authored flow map。shader 的输入如果缺少这些方向,高光只能跟表面法线走,发束会失去亮带,绒面会失去掠射角层次。
Kajiya-Kay 模型是实时头发渲染中的经典低成本近似。它把发丝看作沿切线延伸的圆柱,使用切线、光线和视线计算沿发丝方向拉长的高光。工程上可以把它理解为“用 tangent 替代 normal 主导高光方向”。它适合中低预算角色、cards、ribbons 和风格化发型。它的优点是输入少、计算稳定、容易调参;边界是多重散射、发色穿透和复杂自遮挡需要额外近似。
Marschner 类模型更接近真实发丝光学。它把光在发丝中的反射、穿透和内部反射分成多个 lobe,常见命名包括 R、TT、TRT 等路径。R 表示表面反射,TT 表示透过发丝后的前向散射,TRT 表示进入发丝、内部反射再射出。这个模型能解释金发和浅色毛发的彩色透光、背光边缘和多层高光,但需要更多参数、更多采样和更复杂的阴影/透射数据。AMD 的 TressFX 页面把 hair/fur rendering and simulation 放在 GPU 路径中,并在 5.0 相关说明里提到 Marschner shading、deep shadow approximation 和 continuous LOD,这些关键词正好对应本节的光照、遮挡和成本控制方向。
Self-shadow 是毛发可信度的主要来源。头发内部有大量遮挡路径,单纯依赖角色头部 depth buffer 会把发束之间的暗部丢掉。实时方案通常会生成一种密度表示:voxel density 把发丝写入三维或分层结构,deep opacity map 沿光照方向记录透明度累积,screen-space occlusion 用当前视角近似局部暗部。选择哪种方案取决于灯光数量、角色距离、目标平台和发型重要性。
Deep opacity map 的工作方式可以按“光源视角的透明度累积”理解。对一束光来说,系统从光源方向观察头发,把沿深度方向遇到的 alpha 或 density 累积成多层数据。主视角 lighting pass 采样这张数据,估计某个发丝样本被前方发丝遮住多少。它比普通 shadow map 更适合半透明纤维,因为它保留了光穿过多层发丝后的衰减信息。代价是每个重要光源需要额外数据和更新。
Voxel density 更适合统一支持阴影、环境光遮挡和 transmittance。它把发丝写入体素空间,lighting pass 通过 ray marching 估计遮挡和透射。优点是可复用,能支持多种照明路径;代价是体素分辨率、步进次数、mip 选择和更新范围会直接进入性能预算。低分辨率会让阴影块状化,高步进会增加 lighting cost,过多灯光会扩大采样成本。
Cloth BRDF 的核心是把纤维层放到材质模型里。普通布料往往有高 roughness、明显 diffuse、局部 weave normal;天鹅绒、麂皮、羊毛和部分厚织物会在掠射角出现 sheen。glTF 的 KHR_materials_sheen 扩展把 sheen 作为叠加在基础 PBR 材质上的层,用 sheenColorFactor 和 sheenRoughnessFactor 控制绒面反射,这可以作为跨工具资产表达的参考。引擎内部实现可以更复杂,但参数意义要保持可追踪:颜色控制绒面强度,粗糙度控制边缘高光宽度,normal/anisotropy 控制方向。
布料透光要按厚度和材质等级分层处理。薄丝绸、窗帘、裙摆和斗篷边缘可以使用 subsurface 或 transmission 近似,让背光进入材质;厚毛呢、牛仔和皮革更依赖 roughness、normal、fiber AO 和边缘磨损。一个实用规则是:薄布料用透光解释亮边,厚布料用微表面和接触阴影解释层次。材质 authoring 中应把 base color、roughness、sheen、normal、thickness 和 opacity 的来源分开管理,便于在 LOD 时独立降级。
在贯穿帧中,排查光照应按固定顺序进行。先以 debug view 查看 hair tangent 或 cloth anisotropy 是否正确;再关闭阴影观察基础高光是否沿发束或纤维方向移动;再打开 shadow/transmittance 检查暗部是否来自发束密度;再观察透明 composition 是否让背后发束过亮或过暗;最后比较 TAA 前后边缘稳定性。这个顺序能把 shader 公式、资源状态和最终画面分开定位。
64.4 动力学模拟与渲染结合技巧
Hair 和 cloth 的动态问题要从 frame order 入手。角色动画先更新骨骼矩阵,发根和布料固定点根据骨骼得到新位置,模拟系统再基于约束、碰撞和外力更新 guide 或 cloth vertices,渲染系统把模拟结果写入 GPU buffer,随后 visibility、shadow 和 lighting pass 使用同一帧的数据。如果 shadow pass 使用上一帧 buffer,或者 lighting pass 使用不同 LOD 的 buffer,画面会出现阴影滞后、边缘漂移或抖动。
Hair simulation 通常只模拟 guides。Guide 是少量代表性发丝,render strands 通过插值跟随 guides。这个设计把模拟成本从几十万根发丝压到可控规模,同时保留渲染密度。关键输入包括 guide root、rest shape、segment length、stiffness、damping、gravity、wind、collision 和 interpolation weights。渲染阶段需要保证 render strands 的根部仍然贴合皮肤或头皮,发尾可以响应模拟。
约束决定运动风格。Length constraint 保证发丝或布料边不被拉长;bend constraint 控制弯曲程度;shape constraint 让发型或衣褶接近美术设定;damping 抑制高频振荡;collision constraint 处理头部、肩膀、身体和衣物之间的穿插。游戏中常用 capsule、sphere、SDF 或简化碰撞 mesh。SDF 适合复杂角色表面,capsule 适合骨骼附近的快速碰撞,二者可以按距离和预算组合。
Cloth simulation 更关注面片之间的约束和碰撞。常见做法包括 mass-spring、position based dynamics、extended position based dynamics 和骨骼驱动的局部模拟。衣物一般有 pinned vertices 或 skin weights,让领口、腰带、袖口跟随身体;自由区域根据重力、风场和碰撞移动。渲染 buffer 可以存储当前顶点位置、上一帧位置、法线和切线,lighting pass 依赖这些数据保持法线和 motion vector 一致。
风场和角色事件要在同一坐标空间中表达。风可以来自全局方向、局部 volume、角色速度、武器挥动或爆炸事件。输入模拟前,需要把风场采样位置和碰撞体位置放到相同的 world space 或 component space。坐标空间错误会导致风向跟角色旋转绑定,或在角色移动时出现不合理的反向摆动。debug 方法是把风向、collision capsule、guide root 和 simulated point 画成可见线段,观察它们是否跟动画同步。
Simulation LOD 和 render LOD 应分开设计。近景可以使用较多 guides、较高约束迭代、精确碰撞和 strand render;中景可以减少 guides 和碰撞体,render 仍保留部分 strands 或 ribbons;远景可以停止逐帧模拟,改用骨骼摆动、风动画、card vertex shader offset 或 baked animation。分离这两个 LOD 能保留视觉连续性:渲染密度可以按屏幕尺寸下降,模拟频率可以按运动重要性下降。
缓存用于解决帧间一致性。动态 hair/cloth 通常需要上一帧位置、上一帧速度、上一帧 LOD、上一帧 bounding volume 和 motion vector。TAA、motion blur、temporal denoise 和 GPU culling 都依赖这些历史数据。LOD 切换时,系统应让新旧表达在一小段距离或时间内混合,或者使用同一组 guide 驱动不同 render 表达。这样可以减少 card 与 strand 切换时的形状断裂。
下面是一个简化的帧内顺序。它可以帮助定位“模拟正确但画面错误”的情况。
| 顺序 | 阶段 | 写入资源 | 后续消费者 | 典型错误 |
|---|---|---|---|---|
| 1 | Skeleton update | bone matrices | root skinning、cloth pin | 根部漂移 |
| 2 | Collision update | capsule/SDF buffer | simulation | 穿肩、穿身体 |
| 3 | Simulation | guide/cloth positions | interpolation、render buffer | 抖动、拉伸 |
| 4 | Interpolation/Skinning | render strand/vertex buffer | visibility、shadow | 发束断裂 |
| 5 | Visibility/Shadow | coverage、density、opacity | lighting | 边缘闪、阴影滞后 |
| 6 | Lighting/Composition | scene color | post-processing | 高光错位、透明过亮 |
贯穿帧中,如果角色快速转头后头发位置正确但阴影仍停留在旧位置,优先检查 shadow density 使用的 buffer 和更新频率。如果头发根部离开头皮,优先检查 root skinning 和 interpolation weights。如果布料边缘在 TAA 后拖影,优先检查 motion vector 是否使用模拟后位置。这些判断都依赖具体资源,而非只看最终截图。
64.5 Hair Fur Cloth Cost Control and Approximation Model
Hair、Fur、Cloth 的成本控制可以用一个近似模型描述:frame cost = simulation + buffer update + visibility + shadow/transmittance + lighting + composition。这个公式用于定位,不用于精确预测毫秒数。每一项都对应可观察资源:simulation 对应 guide/vertex 数量和约束迭代;buffer update 对应上传、compute skinning 和写入带宽;visibility 对应 coverage sample 和 overdraw;shadow/transmittance 对应 voxel/deep opacity 数据;lighting 对应 hair sample 与灯光数量;composition 对应透明合成和目标格式带宽。
Card impostor 是远景控制成本的主要工具。它把复杂发型或毛团预烘焙到少量带 alpha、normal、depth、flow 的面片或 billboard 上。近景角色转头时,impostor 会暴露视角依赖;远景角色只占几十像素时,impostor 能把 simulation、shadow 和 visibility 成本压到固定范围。使用 impostor 的关键是让颜色、宽度、暗部和轮廓与上一层 LOD 接近,并让切换发生在屏幕误差足够小的位置。
LOD 应同时作用于数量、宽度、材质和阴影。对头发,LOD0 可以使用完整 strands、较细 width、deep opacity 和多 lobe 光照;LOD1 减少 strands,略增 width,使用 voxel 或简化 shadow;LOD2 使用 cards,改用 Kajiya-Kay 或 flow map 高光;LOD3 使用 impostor 或 baked hair volume。对 fur,LOD 可以减少 shell 层数、降低噪声频率、关闭部分 self-shadow。对 cloth,LOD 可以减少模拟顶点、降低 wrinkle 更新、切换到 normal map 和简化 sheen。
Cluster culling 用于降低不可见发束和毛团成本。系统可以按 groom group、hair cluster、cloth patch 或 fur tile 建立 bounding volume,然后在 CPU 或 GPU 上按 frustum、occlusion、screen size 和 backface 进行剔除。Cluster 粒度过粗会留下很多不可见工作,粒度过细会增加 culling 和索引管理成本。实用粒度应跟资产 authoring 单位匹配,例如刘海、侧发、后发、衣领毛区、披风上半区和下摆。
Compute skinning 能把骨骼驱动、guide interpolation、cloth vertex update 和 LOD 数据写入 GPU buffer,减少 CPU 到 GPU 的逐顶点传输。它适合大量动态角色和高密度 hair/cloth,但会增加 GPU compute pass、barrier 和 buffer lifetime 管理。使用显式 API 时,需要让 compute 写入后的 buffer 状态正确过渡到 vertex/structured buffer 读取状态;使用隐式 API 时,也要关注 driver 同步和 readback 触发。
材质分级要和视觉重要性绑定。近景头发可以启用多 lobe、transmission、deep shadow 和高质量 environment integration;中景发型使用单高光 lobe、低分辨率 shadow density 和较少 sample;远景只保留 base color、flow highlight 和预计算暗部。布料同理,近景保留 sheen、anisotropy、normal detail 和 thickness;远景保留 roughness 与 base color,少量法线即可支撑识别。
| 观察症状 | 可能成本项 | 首要证据 | 稳定处理 |
|---|---|---|---|
| 头发近景帧耗时高 | visibility、lighting、shadow | hair samples、voxel pass、transparent pass 时间 | 降低 strand 数量,增大 width,减少重要灯光,降低 shadow density 分辨率 |
| 远景 NPC 仍然昂贵 | simulation、buffer update | guide 数量、compute dispatch、角色数量 | 切到 cards/impostor,降低模拟频率,合并 cluster culling |
| 皮毛边缘闪烁 | alpha coverage、TAA | alpha mask、MSAA sample、历史权重 | 调整 alpha-to-coverage,降低高频噪声,匹配 motion vector |
| 布料抖动 | simulation、collision | 约束迭代、碰撞体、上一帧位置 | 增加 damping,降低碰撞复杂度,固定 pin 区域和时间步 |
| 发丝阴影滞后 | shadow/transmittance update | shadow density buffer 帧号、pass 顺序 | 让 shadow pass 读取模拟后 buffer,按可见性控制更新频率 |
| 绒面高光过亮 | cloth BRDF、tone mapping | sheen 参数、roughness、exposure | 限制 sheen 强度,匹配 base roughness,检查 HDR 到 LDR 的压缩 |
工具观察顺序应从 frame breakdown 开始。先确认 CPU 是否被 draw/dispatch 提交占用,再确认 GPU 里哪个 pass 超预算。发现 hair voxelization、primary visibility、transparent composition、cloth simulation 或 material lighting 其中一项异常后,再进入 draw 或 dispatch 查看资源规模。RenderDoc 可以检查 draw state、resource binding、纹理和 buffer;Nsight 或 Radeon GPU Profiler 更适合看 GPU pass 时间、occupancy、bandwidth 和 cache 行为;Xcode GPU tools 适合 Metal 项目观察 encoder、resource 和 tile memory 相关问题。工具名称不决定结论,结论来自 pass 时间和资源路径。
贯穿帧的近似决策可以按四档执行。Hero close-up 使用 strands、guide simulation、deep opacity 或 voxel density、多 lobe hair shading、cloth sheen 和稳定 motion vector。Medium character 使用减少后的 strands 或 ribbons,简化 self-shadow,布料保留 normal 与 sheen。Background character 使用 hair cards、骨骼摆动、baked shadow 和低频材质。Crowd or reflection 使用 impostor、prebaked color/normal/depth 和粗略 alpha。
这个模型也适用于上线前的预算分配。先为角色效果设定帧预算,例如 hair 1.5 ms、cloth 0.8 ms、fur 0.5 ms;再把预算拆成 simulation、visibility、shadow、lighting、composition;最后为每个 LOD 写明启用的几何、材质、阴影和模拟等级。预算写成资源路径后,美术、引擎和技术美术可以围绕同一组开关沟通,而非围绕“更真实”或“更省”这类模糊目标争论。
最小自检任务
给定一个近景角色帧:角色有 120k 根 render hair strands、短皮毛衣领和一件带绒面外套。目标平台超出预算 4 ms。一次 GPU 捕获显示,hair voxelization 和 primary visibility 占用最高,PPLL 透明合成也明显变贵;cloth simulation 占用较低,外套绒面高光稳定。请设计一个第一轮降级方案,并说明每一步对应的管线阶段、资源状态和可观察结果。
答案要点
第一步应把问题定位到 hair 几何可见性、hair shadow/transmittance 和透明 composition,cloth simulation 暂时保持原等级。证据是 voxelization、primary visibility 和 PPLL 时间最高,说明主要成本来自发丝密度、coverage sample、density 数据和透明链表存储。
第二步降低 hair strands 数量或启用较近的 strand LOD,同时适当增大发丝 width,保持整体覆盖面积接近原画面。这个动作改变 render strand buffer、visibility pass 和 lighting sample 数量。预期结果是 primary visibility 时间下降,发量观感保持相近,局部细节减少。
第三步降低 voxel density 分辨率或减少参与 deep opacity 的灯光数量,把 shadow/transmittance 成本限制在关键主光上。这个动作改变 shadow density texture 或 per-light opacity map 的写入与采样。预期结果是 voxelization 和 lighting 中的遮挡采样下降,发束内部暗部略粗。
第四步把 PPLL 切到较低 sample 数、weighted blended OIT 或 alpha-to-coverage 等等级,具体选择取决于当前引擎的透明路径。这个动作改变透明 composition 的存储和合成策略。预期结果是透明 pass 内存和带宽下降,边缘精度或排序准确性降低。
第五步为中景和远景补充 card 或 impostor LOD,使后续帧在角色离开近景时自动切换。这个动作改变几何表达和材质等级。预期结果是远景 hair 的 simulation、visibility、shadow 和 composition 同时下降,LOD 切换区需要检查轮廓、暗部和高光连续性。
本章知识点总结
- 细几何成本:Hair 和 fur 的主要压力来自大量子像素纤维对 visibility、shadow、lighting 和 composition 的连续影响。
- 各向异性:Hair 高光依赖发丝切线,cloth sheen 依赖纤维方向和粗糙度,shader 输入必须能追踪方向来源。
- 透明覆盖:Alpha、coverage、PPLL、OIT 和 alpha-to-coverage 控制柔边质量,同时影响带宽、内存和时间稳定性。
- 自遮挡数据:Voxel density 和 deep opacity map 用于表达发束、皮毛和薄层之间的遮挡与透射。
- Strand 表达:Strand 适合近景高质量毛发,代价集中在模拟、buffer、visibility、shadow 和 lighting。
- Card 表达:Cards 和 impostors 适合中远景,以较低几何和模拟成本保留整体发型轮廓。
- Shells fins:Shells and fins 适合短皮毛,通过层数和轮廓片表达厚度,主要受 overdraw 和 alpha 控制。
- 布料材质:Cloth mesh 负责形变和轮廓,sheen、normal、roughness、thickness 负责纤维层次。
- 模拟顺序:Skeleton、collision、simulation、interpolation、visibility、shadow、lighting 必须在同一帧资源链中闭合。
- LOD 分离:Simulation LOD 和 render LOD 可以独立降级,但要让几何、材质、阴影和 motion vector 保持连续。
- Cluster culling:按 hair group、fur tile 或 cloth patch 剔除不可见工作,可以减少远景和遮挡区域的无效成本。
- 成本公式:Hair/Fur/Cloth 的预算可拆为 simulation、buffer update、visibility、shadow/transmittance、lighting 和 composition。
- 工具证据:性能结论应来自 pass 时间、resource binding、buffer/texture 规模、coverage sample 和 pipeline state。
- 分级策略:Hero close-up 使用高质量 strand 与遮挡,中景使用简化 strands/ribbons,远景使用 cards 或 impostors。