DrawMeshInstanced 毛发渲染
一、效果展示
1.1 静帧效果

1.2 动态效果
二、技术拆解
2.1 整体架构与数据流向
- 脚本组成:
FurSkinBody→FurManager→FurDrawInstancedFeature(数据准备驱动与执行调度)FurMaterial、EyeMaterial(材质渲染效果)
- 对应数据流向与处理:
- 单体 Mesh + VertexBuffer(Current + Previous)+ ShellCount (
FurSkinBody) - →
VertexAllBuffer(CopyBuffer Compute Shader)+InstanceDataBuffer+RigidVelocityBuffer+RigidOffsetBuffer(FurManager) - →
FurDrawInstancedFeature执行DrawMeshInstanced
- 单体 Mesh + VertexBuffer(Current + Previous)+ ShellCount (
2.2 FurShader 静态几何表现
- 毛发基础形状:通过采样 Voronoi 贴图在 Fragment Shader 阶段进行
clip操作; - 毛发长短:修改顶点色(Vertex Color)控制毛发长短:

- 整体毛发卷曲度:通过重映射
remap(shellDepth, 1, -1)模型世界空间法线的系数,配合后续 Flowmap + 毛发簇实现加强卷曲效果:
- 低频毛发流向:自制毛发流向编辑器工具:

- 中频毛发簇的实现:
- 形态参照:

- 通过 Substance Designer 获取 Voronoi 高度图 → 生成
flowmap_clump(向种子点内聚):
- 形态参照:
- 几何效果迭代展示:
- 基础形状:

- 叠加 Flowmap:

- 叠加 Flowmap + Flowmap_clump:

- 基础形状:
2.3 着色模型
- 毛发粗糙度渐变模型:
动物毛发通常内外毛粗糙度有明显变化,故根据
shellDepth进行粗糙度的 Remap 映射。 - 漫反射项:
- 直接光:半 Lambert(Half-Lambert)→ 模拟毛发多重散射导致的暗部偏亮提亮效果;
- 间接光:基础漫反射环境光(Spherical Harmonics / Ambient)。
- 镜面反射项:
- 直接光:
- Kajiya-Kay 模型:毛发的切线来源于几何部分的毛发形体(混合模型法线、Flowmap 与 Flowmap_clump);配合毛发粗糙度渐变模型,避免毛发显得油腻并具有丰富节奏变化:
(具有渐变加强)
(不具有渐变加强)
- Kajiya-Kay 模型:毛发的切线来源于几何部分的毛发形体(混合模型法线、Flowmap 与 Flowmap_clump);配合毛发粗糙度渐变模型,避免毛发显得油腻并具有丰富节奏变化:
- 间接光:
- 理想毛发法线:假设光线只打入毛发圆柱体过中轴线的一点,推导公式:
根据理想毛发法线进行镜面反射环境光(IBL Specular)计算。
- 理想毛发法线:假设光线只打入毛发圆柱体过中轴线的一点,推导公式:
- SSS(次表面散射):
通过 LightDir、-ViewDir 与模型世界空间法线进行混合与加权计算:

- 直接光:
2.4 骨骼层级毛发摆动效果(物理模拟)
来源于 RigidOffsetBuffer,根据胡克定律(弹簧-阻尼系统)进行物理模拟:

2.5 EyeShader(眼球渲染)
- 视差映射(角膜折射模拟):
通过模型空间 Y 值与 Height Property 差值确定虹膜深度,根据深度与
ViewDirOS进行 UV 偏移:
(视差映射 Off)
(视差映射 On) - 虹膜漫反射 + 风格化角膜焦散:
- 法线变换(模拟虹膜内凹结构):
float3 N_iris = reflect(-N, TransformObjectToWorldDir(float3(0, 1, 0))); - 焦散表现:在虹膜漫反射基础上做范围 Power 增强 + 焦散 Mask:

- 法线变换(模拟虹膜内凹结构):
- 整体非线性混合:
眼白镜面反射 + 角膜镜面反射 + 虹膜漫反射 + 风格化角膜焦散,使用 Sigmoid 函数对模型空间 Y 值与 Height Property 差值做 Remap():
(非线性混合 On)
(非线性混合 Off)
三、骨骼层级毛发摆动效果的具体实现
- 数据流向:
SkinMeshRenderer.VertexBuffer+SkinMeshRenderer.PreviousVertexBuffer→RigidOffsetBuffer+RigidVelocityBuffer→FurShader毛发偏移采样 - Offset + Velocity 的计算原理(胡克定律 弹簧-阻尼模型):
- 毛发外力来源(以骨骼坐标系为参考系):
- 阻尼项:空气阻力与其他损耗(数值与速度大小呈正相关);
- 弹簧力项:
- 公式递推:
- 毛发外力来源(以骨骼坐标系为参考系):
四、渲染性能优化
- 毛发几何生成技术支持:
DrawMeshInstanced:相对于传统多 Pass 绘制,已将 DrawCall 降低为 1 次;Clip指令缺陷:若ZWrite On,GPU 的 Early-Z 硬件深度剔除失效,导致大量被遮挡毛发产生冗余片元计算。
- 解决 Clip 导致的冗余片元计算方案:
DepthOnlyPass (PreDepth):共用正常 Pass 的顶点着色器,Fragment 阶段仅做clip判断,不进行复杂光照着色;NormalPass / ForwardPass:开启ZWrite Off,重新激活 Early-Z 剔除。
- 优化前后帧时间对比:
(优化前: 1.36ms)
(优化后: 1.08ms)
在近距离特写视角下,片元计算压力极大,该项优化带来的性能提升尤为显著。
五、美术与审美拆解
- 原始模型贴图来源于网络资源;
- 毛发形态的节奏差异:
- 基础 Shell 毛发(高频细节);
- 毛发簇实现(中频结构);
- 毛发整体流向(低频大势)。
- 眼球虹膜贴图设计(色彩对比):
- 虹膜最外层选取模型身体贴图颜色的低饱和互补色(兼顾整体和谐与细节差异);
- 虹膜内层设计互补色渐变过渡(在差异化前提下保持视觉舒适);
- 虹膜纹理节奏严格控制在中频与相对低频之间。
六、个人进一步思考与架构演进
- 架构演进:当前架构对场景内单体具有毛发的角色属于最优解;但对于群体同屏角色,架构仍需升级:
- 动画去重(VertexBuffer 去重) → 极大降低 VRAM 显存占用;
- 逐去重 Mesh + One Material + MaterialDataBuffer 执行 DrawInstance → 使总 DrawCall 数量仅与 Mesh 种类数正相关;
- 针对当前
Single VertexBuffer -> VertexAllBuffer架构中存在的 VRAM 内存拷贝消耗,探索更直接的 Buffer 映射优化。