首页 > 其他分享 >[UOD2021]虚幻引擎中Groom毛发系统的流程和应用 | Epic Games 孙丹璐

[UOD2021]虚幻引擎中Groom毛发系统的流程和应用 | Epic Games 孙丹璐

时间:2024-02-03 23:55:09浏览次数:34  
标签:UOD2021 HairStrands 孙丹璐 Tracing Groom 毛发 Deep Shadow

传送门:[UOD2021]虚幻引擎中Groom毛发系统的流程和应用 | Epic Games 孙丹璐_哔哩哔哩_bilibili

 


 

 

一. 资产与导入

1.1 Groom 毛发系统中常见名词

  1. Strand:生成的最终视觉上看到的毛发
    • 人类的毛发尺寸大约在 0.0017 - 0.0018 cm,建议控制在 0.008 cm
    • 发际线、鬓角、碎发的尺寸,建议控制在 0.0065 -0.007 cm
  1. Guide:引导线,用于动画和模拟
    • 人类大约有 10 万根头发,用于引擎渲染,建议控制 Guide 数量在 5 万左右
  1. Curve:曲线(毛发/引导线数量)
  2. Vertices:毛发组的顶点数量(由 DCC 软件中设置的 CV 值决定,Vertices/Curves = CV count)
    • CV 值:在 DCC 软件中制作毛发时,设置的控制顶点
    • CV 值越多,毛发表现效果越好,相应的处理时间越久,性能开销越大
    • 为了在实时领域应用 Groom 毛发,需要在 DCC 软件中控制 CV 的数量(启用 Uniform CVs 则毛发形态更平均;禁用,则利于表现如卷发等的程序化生成的毛发)
    • CV 值的设计,需要综合考虑毛发形态及应用平台,建议:
    • 影视项目,卷发不超过 80
    • 游戏项目,长直发不超过 30

 

  • 毛发资产的通用优化思路:
    • 在 DCC 软件中,控制 CV 点数量,控制最终毛发顶点的整体数量
    • 优化密度、宽度(参考真实世界中毛发尺寸,以密度减半,宽度*2为起点,根据效果进行调整)

 

 

1.2 毛发资产导入

  1. 导出为 Alembic 格式
    • 以 Maya Xgen 毛发为例,将毛发转换为可交互式毛发后,以 Alembic 格式,只导出 Strand(单帧或多帧)
    • 在 DCC 软件中制作的毛发,是根据 Guide 和修改器规则生成的,导入引擎的是最终生成好的发丝,即 Strand
    • 默认情况下,Alembic 中只有 Strand 信息,可以根据命名规则写入特定数据(如:groom_guide、groom_color、groom_root_uv、groom_closest_guide、groom_guides_weights)
    • 导入引擎后,依据 Alembic 写入的数据生成:
    • 单帧 Groom Asset
    • 多帧 Groom Cache(默认导入会生成 2 个 Cache 文件)
    • guides_cache:记录每帧每个 guide curve 的 position 数据(需打开 Groom 毛发的 Simulation 模拟,从第 0 帧开始播放)
    • strands_cache:记录每帧每个 strand curve 的 position 数据

 

  1. 转换为三角面
    • 将 Groom Cache 附着在蒙皮表面,还需提供一个绑定资产
    • 绑定资产存储了毛发发丝在目标骨骼上投射的信息,计算的是 Strand 根部与蒙皮后最近的三角面重心坐标
    • 皮肤发生形变后,默认在皮肤的 Local Space 计算毛发位置,再转换到蒙皮后的世界空间,为了防止特殊部位毛发做表情时发散(如中间图)导致表情不自然

 

    • 添加 RBF 径向基约束,以保证夸张表情下的毛发形态自然

 

    • 在 Groom 毛发资产中,启用 RBF 径向基约束

 

 

二. 裁剪与 LOD

  1. 为了高效绘制 Groom 资产,Strand 会被引擎自动划分为多个 Cluster,以在 GPU 上运行 LOD 和剔除信息
    • 渲染 Groom 时,Cluster 会根据屏幕覆盖率和可见性,进行细粒度 LOD 选择,方便以屏幕实际的显示为基础, 相应的平衡渲染与性能开销
    • 如果在 Groom Editor 中手动创建了多层 Strand LOD,每层都有自己的 Cluster 信息和 Cluster LOD 信息

 

    • 基于 Groom 毛发的物理模拟,每帧对 Cluster 生成 AABB ,获取 AABB 数据,在 GPU 上进行细粒度裁剪和 LOD 切换

 

  1. 裁剪顺序依次按:视锥裁剪 -> 距离裁剪 -> HZB 遮挡裁剪

 

  1. 对裁剪后的结果计算 LOD,在 Cluster 的 LOD 信息,减少了每个 Cluster 中的 Strand 数量,和每个 Curve 中的顶点数量,从而产生的毛发空隙感,用宽度补足

 

  1. 由于上述引擎的 Cluster LOD 切分机制,因此在创作毛发资产时,需按真实世界中的毛囊分布制作毛发,避免从一个点生成全头的毛发,避免通过毛发长度制作发型

 

  1. Cluster 默认按距离生成,详见 GroomBuilder.cpp 中的 BuildClusterData 部分

 

 

 

三. 抗锯齿与 OIT

  1. 根据 Cluster 完成了裁剪和 LOD 后,需要根据对应的数据绘制发丝,常碰到如下问题:
    1. 当像素尺寸远大于头发尺寸,产生锯齿问题
      • 头发尺寸一般引擎内设置为:0.06-0.12 毫米
      • 像素尺寸:1080P像素分辨率,在 1 米处的一个像素大小约为 1 毫米
    1. 光线照射到高散射率的头发,产生 OIT 问题
      • 头发本身不透明,但够薄且散射率高,光照效果呈透明物体状
      • 一个像素中有多根头发,需要确定多根头发的前后关系以计算散射情况

 

  1. 引擎实现了如下 3 种光栅化抗锯齿的解决方案:
    1. MSAA
      • 效果和效率综合最好
      • 原理:光栅化阶段,每个像素有多个采样点
      • 在引擎内,构成毛发的 Groom 是由一段一段四边形(两个三角面)组成,渲染处理时,四边形面向相机进行 MSAA 计算,在亚像素空间,计算并记录距相机最近的 N 个毛发片段数据,最终,通过 2 个 Pass 获取 Visibility 和 Transmittance 信息

 

      • 配置 MSAA 数据:r.HairStrands.Visibility.MSAA.SamplePerPixel 2/4/8(几倍的 MSAA 就相当于光栅化阶段要申请几倍的分辨率,显存开销大)

 

      • 在毛发资产上勾选 Use Stable Resterization,改善孤立毛发的锯齿问题

 

      • 改善毛发边缘,发梢末端形成半透效果:r.HairStrands.ViewTransmittancePass(在 4K 分辨率下,开启 4xMSAA,可以节省 1-2 ms )

 

    1. PPLL
      • 效果最好,性能最低
      • Per-Pixel Link List,链表式存储每个像素绘制到的 N 根毛发信息(N 取决于设置的最大数值),但链表式结构对 GPU 不友好
      • 配置 PPLL 数据:r.HairStrands.Visibility.PPLL 1(默认 0)r.HairStrands.Visibility.PPLL.SamplePerPixel 4/8/16

 

    1. Raster Compute
      • 低配置下效率最高,可以精确计算每段毛发渲染在哪几个像素,抗锯齿效果好
      • 利用 Compute Shader 做了光栅化,并记录毛发数量和毛发平均半径,用于计算毛发透射率
      • 开启 Raster Compute:r.HairStrands.Visibility.ComputeRaster 1
      • Raster Compute 中毛发每个片段的最大长度:r.HairStrands.Visibility.ComputeRaster.MaxPixelCount
      • Raster Compute 中毛发每个像素的采样最大数量:r.HairStrands.Visibility.ComputeRaster.SamplePerPixel 1/2/3/4

 

  1. 方案选择:
    1. 高配置方案参考

 

    1. 中配置方案参考

 

  1. 由于上面 3 种光栅化抗锯齿方案处理的毛发片段数量不一致,因此都会被写入一个线性 Buffer,记录每个像素上最近的 N 个毛发片段信息(如:Coverage、Base Color、Tangent等),方便后续用 Compute Shader 高效并行的对每个片段着色

 

  1. 总采样数量决定了效率,速度变化较快时,可以相应调整发丝宽度以减少重投影问题

 

  1. Stat GPU 或 GPU 抓帧中 HairStrandsVisibility 的开销参考:

 

 

四. 光影

4.1 光照

  1. 通过上面计算,可以初步确定哪些像素需要绘制毛发,及绘制毛发的必要信息,接下来进行光影计算

 

  1. 头发光照模型:
    1. Single Scattering - Marschner
      • 材质中的 Hair Shadering Mode
      • 主流基于物理的头发丝的光照模型 BSDF,从微观角度,抽象毛发为一节一节的圆柱体,分析毛发光照为以下 3 个主要部分:

 

      • R 光线直接反射

 

      • TT 穿过头发内部的透射

 

      • TRT 穿过头发内部的折射

 

      • 最终头发光照 = R+TT+TRT
      • 其中,R 相当于头发的第一层高光,TRT 相当于头发的第二层高光,TT 相当于头发背面看到的高光

 

      • r.HairStrands.Components.R
      • r.HairStrands.Components.TRT
      • r.HairStrands.Components.TT

 

    1. Multi Scattering - Dual Scattering
      • 浅发的吸收率低,发丝间的散射效果很重要

 

      • 采用Dual Scattering 双重散射模型:将复杂散射现象分为 2 部分:
      • Global Scattering 全局散射:宏观评估光线穿过纤维毛发的方式
      • Local Scattering 局部散射:通过简单的模型评估光线在单根毛发周围的反弹

 

      • r.HairStrands.Components.GlobalScattering
      • r.HairStrands.Components.LocalScattering

 

  1. Deep Opacity Maps(Deep Shadow)
    • 为每个光源创建专属阴影贴图,将毛发的吸收信息存储在多个 Deep Opacity Maps 中:将头发光栅化生成深度纹理,对毛发进行二次光栅,根据深度纹理距离,累加 4 层头发数量到不同 Deep Opacity Maps 的不同通道中,用 PCF/PCSS Kernel 查询毛发数量

 

    • 在灯光的细节面板上,开启 Deep Shadow

 

    • r.HairStrands.DeepShadow.DebugMode 1:查看 Deep Opacity Maps 的 4 层数据的对应情况

 

    • r.HairStrands.DebugMode 4:查看开启了 Deep Shadow 的灯光,渲染生成的 Deep Opacity Maps

 

    • r.HairStrands.DeepShadow.DebugDOMIndex:选择观察具体某盏灯光的 Deep Opacity Maps 信息

 

  1. Density Volume,Voxelization 密度体积
    • 密度体积是引擎毛发着色、环境光遮蔽、环境光照的默认机制
    • 密度体积会提供当前视口中毛发的密度/厚度信息,并迅速计算出光线在毛发密度上产生的渲染效果
    • 将毛发在密度体积中体素化( 体素化是一种将3D物体分解成小立方体(体素)的过程,以便于进行更复杂的渲染计算 ),可以复用给多个灯光,并提供天光对头发的照明

 

    • r.HairStrands.Voxelization 1:引擎默认开启密度体积
    • r.ShaderPrintEnable 1:启用着色器打印功能

 

    • r.HairStrands.Voxelization.Virtual.VoxelWorldSize: 设置头发体素化过程中使用的世界空间大小(体素大小,大体素,降低精度但提高性能;小体素,提高精度但降低性能)
    • r.HairStrands.Voxelization.Virtual.DensityScale: 调整头发体素化过程中毛发密度的比例(增加密度,毛发浓密;减少密度,毛发稀疏)
    • r.HairStrands.Voxelization.Virtual.DrawDebugPage:绘制体素化调试

 

    • r.HairStrands.DebugMode 8:查看毛发的密度体积,需要同时开启r.ShaderPrintEnable 1

 

 

4.2 阴影

  1. 不透明物体对毛发的投影:Shadow Map
  2. 毛发对不透明物体的投影:Deep Shadow(Deep Opacity Maps)、Voxel Tracing 密度体积

 

  1. Deep Shadow(Deep Opacity Maps)
    • 毛发间的阴影:
    • r.HairStrands.DeepShadow.Resolution: 设置用于渲染头发深度阴影贴图的分辨率
    • r.HairStrands.DeepShadow.SuperSampling: 控制 SuperSampling 超采样设置(超采样是一种反走样技术,通过以比最终输出更高的分辨率渲染图像,然后缩小到目标分辨率来平滑边缘和减少锯齿效果)
    • r.HairStrands.DeepShadow.KernelType 0/1/2/3/4
    • 0:linear
    • 1:PCF_2*2
    • 2:PCF_6*4(默认为 2)
    • 3:PCSS
    • 4:PCF_6*6_Accurate

 

    • 当灯光据毛发过近时,开启 DeepShadow,则毛发间的阴影会过于明显,显得毛发粗糙,因此不需要每盏灯都开启 DeepShadow

 

    • 毛发对其他物体的投影:
    • r.HairStrands.DeepShadow.ShadowMaskKernelType 0/1/2/3/4
    • 0:2*2
    • 1:4*4
    • 2:Gaussian 8
    • 3:Gaussian 16
    • 4:Gaussian 8 with transmittance(默认为 4,细发丝不投影)

 

  1. Voxel Tracing 密度体积
    • 毛发间的投影:
    • r.HairStrands.Voxelization.Raymarching.SteppingScale:调整 Raymarching 光线行进过程中的步长比例(值越大,性能提高但渲染质量降低;值越小,渲染质量提高但性能消耗增加)
    • r.HairStrands.Voxelization.Virtual.Jitter: 调整体素化过程中的 Jitter 抖动效应(0 为完全关闭,1 为有规律随机抖动,2 为持续抖动)

 

    • 毛发对其他物体的投影:
    • r.HairStrands.Voxelization.DensityScale.Shadow:调整影响头发阴影密度的比例( 值越大,头发阴影越密集;值越小,阴影越空)

 

  1. Deep Shadow(Deep Opacity Maps)和 Voxel Tracing 的方案对比:
    1. 光影表现:
    • Deep Shadow 不会计算天光,因此背光面较暗

 

    • Voxel Tracing 的分辨率不足,阴影处会有噪点问题

 

    • 建议:用 Voxel Tracing 密度体积计算透射,用 Deep Shadow 计算阴影

 

    1. 性能开销:
    • Deep Shadow(Deep Opacity Maps)和 Voxel Tracing 生成的开销都较高
    • 在单个灯光的情况下(场景中包含一个平行光和一个天光),Voxel Tracing 性能持平或略优于 Deep Shadow:
    • 只使用 Deep Shadow:总耗时 25.2ms,开启时会降低 HairStrands TransmittanceMask 和 Shadow Projection 的耗时

 

    • 只使用 Voxel Tracing:总耗时 25.87ms,比 Deep Shadow 多计算一个天光

 

    • 使用 Deep Shadow + Voxel Tracing:总耗时 28.38ms

 

    • 在多个灯光的情况下(场景中包含一个平行光、一个投射光和一个天光),Voxel Tracing 的可复用的优势更明显
    • 只使用 Deep Shadow:(平行光和投射光均开启 Deep Shadow)总耗时 39.10ms
    • 只使用 Voxel Tracing:总耗时 33.74ms

 

    • 使用 Deep Shadow + Voxel Tracing:(仅主光源开启 Deep Shadow,其他使用 Voxel Tracing)总耗时 35.17ms

 

  1. Deep Shadow(Deep Opacity Maps)和 Voxel Tracing 的使用建议
    1. 用于实时渲染
    • 中远视角下,仅使用 Voxelization 密度体积的方案
    • 特写镜头中,仅主光源开启 Deep Shadow,并限制区间为 512~1024 分辨率
    1. 用于离线渲染
    • 常规使用 Voxelization 密度体积 + 主光源开启 Deep shadow (区间为 1024~2048 分辨率)
    • 特写镜头中依据 Sequencer 效果,逐个决定是否开启光源的 Deep Shadow(视角拉远时关闭)
    • 渲染输出时(酌情):
    • 提高r.HairStrands.DeepShadow.Resolution 体素分辨率
    • 开启r.HairStrandsDeepShadow.SuperSampling
    • 选择r.HairStrands.DeepShadow.KernelType

 

  1. Debug 调试:
    • r.HairStrands.StrandWidth:设置毛发宽度
    • r.HairStrands.StrandDebug:等价于 Show 视图下的分页
    • 0:NoneDebug
    • 1:SimHairStrands
    • 2:RenderHairStrands
    • 3:RenderHairRootUV
    • 4:RenderHairRootUDIM
    • 5:RenderHairUV
    • 6:RenderHairSeed
    • 7:RenderHairDimension
    • 8:RenderHairRadiusVariation
    • 9:RenderHairBaseColor
    • 10:RenderHairRoughness
    • 11:RenderVisCluster
    • 12:RenderHairTangent

 

    • r.HairStrands.DebugMode 1:查看毛发总体采样数量、修改的 MSAA 数据、鼠标对应的毛发像素采样数据等

 

    • r.HairStrands.DebugMode 4:查看绘制的 Deep Shadow(Deep Opacity Maps)

 

    • r.HairStrands.DebugMode 5:查看亚像素的采样数量(蓝色:1-2 个;黄色:3-4 个;红色:8 个)

 

    • r.HairStrands.DebugMode 7:查看 Coverage 信息(绿色:完全覆盖;红色:部分覆盖,有半透感)

 

    • r.HairStrands.DebugMode 8:查看密度体积信息,需要同时打开 r.ShaderPrintEnable 1

 

标签:UOD2021,HairStrands,孙丹璐,Tracing,Groom,毛发,Deep,Shadow
From: https://www.cnblogs.com/ZWJ-zwj/p/18005428

相关文章

  • [官方培训]07-UE材质基础 孙丹璐 Epic 笔记
    UE材质基础什么是材质定义了场景中对象的表面属性决定光源是如何与物体表面交互反射——漫反射,镜面反射折射透射本质上应用于Mesh并控制Mesh的视觉外观固体——塑料,岩石,木板,铁块...次表面——皮肤,树叶,玉石...透明——玻璃,水基于物理-PBR(PhysicallyBasedRendering......
  • 3DMax Ornatrix to UE Groom制作毛发动态效果
    Hello,大家好,今天给大家带来3DMaxOrnatrix毛发插件导入UEGroom毛发动态效果,我是沙漠骆驼-JFD。1、使用Ornatrix毛发插件生成毛发2、添加编辑器Clump和Frizz3、导出格式:OrnatrixAlembic(.abc)4、导入到虚幻引擎,注意毛发的路径不要有中文,缩放Y要-1,不然毛发是反的;5......