Unity URP半透明服装渲染:ShaderGraph实现次表面散射与厚度控制

📅 2026/8/9 2:53:28
Unity URP半透明服装渲染:ShaderGraph实现次表面散射与厚度控制
之前在做虚拟角色渲染和服装材质模拟时经常遇到半透明材质与角色身体穿插、光照不自然的问题网上资料要么是纯理论要么是零散的代码片段很难直接应用到实际项目中。本文将以一个具体的“半透明紧身衣”材质实现为例完整拆解从Shader编写、材质参数调节到引擎内效果调试的全流程并提供可直接复用的Unity ShaderGraph和代码示例。无论你是想学习次表面散射SSS原理还是急需在项目中实现类似的半透明服装效果都能从本文中找到系统性的解决方案。1. 核心概念什么是“半透明紧身衣”效果在计算机图形学中我们常说的“半透明紧身衣”效果并非指一个单一的材质属性而是多种渲染技术的组合呈现。其核心目标是模拟光线穿透轻薄、贴身的纺织物如丝绸、薄纱、紧身运动服时所产生的一系列视觉特性。1.1 效果拆解与关键技术这种效果可以分解为几个关键的子效果每个都对应着不同的渲染技术基础透明度与折射这是最基础的一层允许光线部分穿透材质看到背后的物体如角色皮肤。简单的透明Alpha Blend/Clip会显得很“假”更像玻璃。为了模拟纺织物的质感我们通常需要结合轻微的折射扰动模拟光线穿过织物纤维网眼时的弯曲。次表面散射Subsurface Scattering, SSS这是实现“沉浸感”或“真实感”最关键的技术。当光线照射到半透明材质上时一部分光会在材质内部散射并从另一点射出。对于紧身衣来说这意味着轮廓光背光透亮在角色边缘特别是光源从背后照射时衣物会显得特别明亮仿佛被“点亮”能隐约透出皮肤的轮廓和颜色。厚度变化衣物在不同部位的厚度不同如关节处拉伸变薄布料堆积处变厚透光程度也应随之变化。较薄的地方透过的皮肤颜色更多、更亮较厚的地方则更暗、更不透。高光与纤维质感半透明纺织物尤其是含有化纤成分的会有特殊的高光反射通常不是光滑的镜面反射而是带有各向异性或拉丝质感的高光模拟纤维的走向。阴影与遮挡半透明物体投射的阴影应该是柔和的、半透明的而不是全黑的硬阴影。同时角色身体皮肤对衣物内侧应有正确的阴影遮挡避免出现“漂浮”感。1.2 与普通透明材质的区别普通透明材质如玻璃、水主要处理的是光线的折射和菲涅尔效应。而半透明纺织物材质其核心挑战在于“模拟光线在非均匀、纤维状介质内部的散射过程”并需要与下层的人体皮肤进行复杂的光照交互。这要求我们的Shader不仅要计算材质本身还要以某种方式获取并处理下层皮肤的颜色和光照信息。2. 环境准备与核心思路在开始动手前我们需要明确实现路径和所需工具。本文将以Unity URPUniversal Render Pipeline为例进行讲解因为URP提供了相对友好的ShaderGraph工具和可定制的渲染管线适合快速原型开发和移动端/PC端跨平台项目。其核心思路也适用于其他引擎如Unreal Engine的材质编辑器。2.1 所需环境与工具引擎Unity 2021.3 LTS 或更高版本确保对URP的良好支持。渲染管线Universal Render Pipeline (URP)。你需要通过Package Manager安装Universal RP包并创建一个URP Asset资源应用到项目中。核心工具Shader Graph。这是Unity的可视化着色器编辑工具我们将主要用它来构建材质。可选工具一个3D角色模型最好包含身体和一套简单的紧身衣网格。为了效果演示你可以使用任何自带人体网格的模型。2.2 实现思路总览我们的策略是“分层处理信息复用”获取皮肤信息这是最大的难点。在标准渲染流程中当前渲染的像素无法直接“看到”它背后被它遮挡的皮肤像素。我们将探讨两种主流方案方案A屏幕空间使用URP的Screen Space Shadows和自定义Buffer在皮肤渲染阶段将皮肤颜色和深度写入一张临时纹理Render Texture然后在衣物Shader中采样这张纹理。性能较好但实现稍复杂且受屏幕分辨率限制。方案B模型空间-简化版为角色身体单独设置一个只渲染到特定Layer的摄像机将皮肤渲染到一张Render Texture上。衣物Shader通过投影坐标或UV来采样这张皮肤贴图。这种方法更直观但需要额外的渲染开销和设置。方案C近似模拟-本文采用为了教程的清晰和易复现我们先采用一种高质量的近似方案——在衣物Shader中我们假设皮肤颜色是一个已知的输入例如一张皮肤贴图并专注于实现光线在衣物层内的散射模型。这能让我们先搭建出核心的SSS和折射效果。在后续的“进阶优化”章节我们再讨论如何动态获取真实皮肤信息。构建衣物材质模型在Shader Graph中我们将混合以下节点厚度图一张灰度贴图用于控制衣物不同部位的透光强度白色薄黑色厚。散射颜色与强度控制透出皮肤光的颜色和亮度。折射扰动使用法线贴图或噪声图对背后的皮肤UV进行扰动模拟纤维结构。各向异性高光模拟织物纤维方向性的高光。3. 使用ShaderGraph构建基础半透明材质让我们从零开始在Unity中创建一个最基础的、具有厚度变化的半透明材质。3.1 创建Shader Graph与材质在Project窗口中右键 - Create - Shader - Universal Render Pipeline - Shader Graph。将其命名为SG_TranslucentBodysuit。双击打开Shader Graph编辑器。在Project窗口中右键该Shader文件 - Create - Material会自动生成一个使用该Shader的材质球命名为Mat_TranslucentBodysuit。3.2 定义关键属性Properties在Shader Graph的Blackboard黑板区域添加以下属性。这些属性将作为材质球上的可调节参数Base Color(Color): 衣物本身的基底颜色。Base Map(Texture2D): 衣物基底纹理。Thickness Map(Texture2D):关键属性。一张灰度图用于控制厚度。通常我们让美术在衣服的UV上绘制关节、拉伸处为白色薄布料堆积、多层处为黑色厚。Transmission Strength(Vector1): 透光散射的整体强度。Transmission Color(Color): 透出光的颜色通常设置为皮肤色调如淡粉色/米黄色。Distortion Normal Map(Texture2D): 用于模拟折射扰动的法线贴图。Distortion Strength(Vector1): 折射扰动的强度。3.3 构建着色器网络核心逻辑以下是简化的节点逻辑描述你需要在Shader Graph中连接采样厚度图使用Sample Texture 2D节点采样Thickness Map。将其输出假设是R通道视为thickness值。注意在厚度图中我们约定“1.0白色表示薄0.0黑色表示厚”。所以thickness值越大透光应该越强。计算散射光照这是一种简化的SSS模拟。使用Lighting节点组下的Main Light节点获取主光源的方向和颜色。使用Normal Vector节点获取当前像素的世界法线。计算dot(Normal, -LightDirection)。当光线从背面照射法线与光方向点乘结果为负时这个值越大负得少表示光线穿透的路径越短散射光应该越强。我们取这个值的绝对值或进行1 - saturate(dot(...))等操作得到一个backLit因子。最终散射强度sssIntensity thickness * backLit * TransmissionStrength。散射颜色sssColor TransmissionColor * MainLightColor * sssIntensity。模拟折射扰动对基底色的影响采样Distortion Normal Map将其从切线空间转换到世界空间使用Transform节点。使用这个扰动法线去影响环境光或IBL的采样方向或者简单地用它来扰动基底纹理Base Map的UV坐标Tiling And Offset节点从而让衣物基底颜色产生细微的、波动的变化模拟光线穿过不规则纤维的效果。混合最终颜色基础颜色 Base Color * SampleTexture2D(Base Map)。将散射颜色sssColor加到基础颜色上。注意这里是加法因为散射光是额外透射出来的光能。将结果输出到Master Stack的Base Color端口。透明度设置透明度也可以由thickness和backLit因子共同控制。例如alpha thickness * 0.5 backLit * 0.5。这样越薄、背光越强的地方越透明。将计算出的alpha值连接到Master Stack的Alpha端口。关键步骤在Graph Inspector中将Graph Settings下的Surface Type设置为TransparentBlend Mode设置为Alpha或其他如Premultiply根据需求选择。一个极其简化的核心网络示意图文字描述[Thickness Map] -- (Thickness Value) [Light Direction] [Normal] -- Dot Product -- (Backlit Factor) (Thickness Value) * (Backlit Factor) * [Transmission Strength] -- (SSS Intensity) (SSS Intensity) * [Transmission Color] * [Light Color] -- (SSS Color) [Base Color/Texture] (SSS Color) -- [Final Base Color] (Thickness Value) (Backlit Factor) -- Blend -- [Final Alpha]4. 完整实战在Unity中配置与调试现在我们将把写好的Shader应用到模型上并进行效果调试。4.1 准备模型与贴图导入你的角色模型包含身体和分离的紧身衣网格。为紧身衣网格准备三张关键贴图bodysuit_albedo.png: 衣物基础颜色/花纹贴图。bodysuit_thickness.png:手绘厚度图。在PS等软件中根据衣物网格在关节肘、膝、胸部、腹部等拉伸处涂白色在腋下、裆部、布料褶皱堆积处涂黑色平滑过渡灰色。bodysuit_normal.png: 衣物法线贴图用于表现织物纹理和褶皱也可兼作折射扰动图。为身体皮肤准备一张skin_albedo.png。4.2 配置材质与场景将之前创建的Mat_TranslucentBodysuit材质拖拽到场景中的紧身衣网格上。在材质Inspector面板中将贴图分别赋值Base Map-bodysuit_albedo.pngThickness Map-bodysuit_thickness.pngDistortion Normal Map-bodysuit_normal.png设置参数初值Base Color: 浅灰色或衣物主色。Transmission Strength: 从0.5开始调节。Transmission Color: 设置为接近皮肤的颜色如 (1.0, 0.9, 0.8)。Distortion Strength: 0.1左右。在场景中放置一个方向光Directional Light调整角度使其从角色侧后方照射以便观察背光透射效果。4.3 编写一个简单的脚本进行动态测试为了更直观地测试参数我们可以创建一个控制脚本。// 文件路径Assets/Scripts/TranslucentMaterialController.cs using UnityEngine; public class TranslucentMaterialController : MonoBehaviour { public Material targetMaterial; // 拖入你的 Mat_TranslucentBodysuit 材质实例 [Header(透射参数)] [Range(0, 2)] public float transmissionStrength 1.0f; [Range(0, 1)] public float distortionStrength 0.1f; public Color transmissionColor new Color(1f, 0.9f, 0.8f); // 用于在运行时更新材质属性 void Update() { if (targetMaterial ! null) { targetMaterial.SetFloat(_TransmissionStrength, transmissionStrength); targetMaterial.SetFloat(_DistortionStrength, distortionStrength); targetMaterial.SetColor(_TransmissionColor, transmissionColor); } } // 在Inspector中点击按钮快速测试不同预设 [ContextMenu(Apply Silk Preset)] void ApplySilkPreset() { transmissionStrength 1.5f; distortionStrength 0.15f; transmissionColor new Color(1f, 0.95f, 0.9f); Update(); Debug.Log(Applied Silk Preset); } [ContextMenu(Apply Latex Preset)] void ApplyLatexPreset() { transmissionStrength 0.7f; distortionStrength 0.05f; transmissionColor new Color(0.95f, 0.85f, 0.8f); Update(); Debug.Log(Applied Latex Preset); } }将此脚本挂载到场景中任意物体上如一个空GameObject然后将你的Mat_TranslucentBodysuit材质实例拖拽到targetMaterial字段。运行游戏你可以在运行时动态调整参数或点击Inspector中的上下文菜单按钮快速切换“丝绸”或“乳胶”质感预设。4.4 运行与效果验证运行游戏并围绕角色移动视角或旋转光源你应该能看到当光源在角色正面时衣物呈现其基础颜色和纹理。当光源移动到角色背面或侧背面时衣物边缘特别是根据厚度图定义的薄区域会开始透出Transmission Color设定的光晕模拟光线穿透效果。调整Transmission Strength透光效果会增强或减弱。厚度图的效果你可以尝试临时将Thickness Map替换为一张纯白或纯黑的贴图观察透光效果是否均匀或完全消失以验证厚度图是否起作用。5. 常见问题与排查思路在实现和调试过程中你可能会遇到以下典型问题问题现象可能原因排查与解决思路完全没有透光效果1. Shader的Surface Type未设置为Transparent。2.Transmission Strength值为0。3. 厚度图采样错误UV不对或贴图未赋值。4. 光源方向计算错误backLit因子始终为0。1. 检查Shader Graph的Graph Settings。2. 检查材质参数。3. 在Shader Graph中将厚度图的采样结果直接输出到Base Color查看贴图是否正确显示。4. 将backLit因子的计算中间值输出到颜色进行可视化调试。透光颜色全黑或不正确1.Transmission Color设置为黑色。2. 未正确获取或应用主光源颜色(MainLightColor)。3. 散射强度计算结果为负或过大被截断。1. 检查Transmission Color参数。2. 确保场景中有激活的Directional Light并且Shader中使用了正确的Main Light节点。3. 使用Clamp或Saturate节点确保强度值在合理范围(0-1)。模型出现奇怪的闪烁或遮挡错误透明渲染顺序问题。Unity默认按物体到相机的距离排序透明物体但同一物体的不同部分可能顺序错乱。1. 尝试将Shader的Blend Mode从Alpha改为Premultiply有时能改善。2.更有效的方法将衣物网格拆分为不同的子网格SubMesh确保它们不会相互穿插。在建模时就让衣物的不同部分如袖子、躯干是分离的网格。性能开销大1. 使用了全屏后处理或复杂的屏幕空间采样。2. 透明物体过度绘制严重。1. 如果采用了“方案A屏幕空间”确保只在必要时采样皮肤Buffer。2. 严格控制使用此复杂材质的模型面数和数量。3. 考虑使用简化的散射公式或使用预计算的查找表(LUT)。移动设备上效果差或无效1. Shader使用了移动端不支持的复杂节点或高精度计算。2. URP设置中未开启所需特性。1. 在Shader Graph中将节点精度设置为Half或Float并检查节点兼容性。2. 确保URP Asset的配置中开启了Screen Space Shadows或任何你依赖的额外特性。6. 进阶优化与工程建议基础效果实现后为了达到项目级的“沉浸式”品质还需要考虑以下优化和最佳实践。6.1 动态皮肤信息获取进阶方案我们之前是假设皮肤颜色已知。在实际项目中皮肤是动态照明的。以下是两种更真实的方案简述方案A使用URP的Renderer Features创建一个RenderObjects类型的Renderer Feature将其Event设为Before Rendering Transparents。配置其Filters只渲染Skin层的角色身体。将其输出到一个自定义的RenderTextureRT中这个RT包含了被渲染的皮肤颜色。在你的紧身衣Shader中通过Custom Function节点或编写一个简单的HLSL代码片段采样这张皮肤RT。采样坐标需要通过当前像素的屏幕位置Screen Position节点来换算。 这种方法性能较好是主流方案。方案B预计算皮肤透射LUT如果角色皮肤颜色变化不大可以预先烘焙一张“透射查找表LUT”。这是一张2D纹理一个轴是厚度另一个轴是曲率或光线角度颜色值代表了在该厚度和角度下应透出的皮肤光颜色和强度。在运行时Shader根据当前像素的厚度和光线角度去采样这张LUT。这种方法性能极高但缺乏动态光照变化。6.2 性能优化建议精度控制在Shader Graph中非关键计算尽量使用Half精度。纹理压缩厚度图、扰动法线图可以使用低精度的压缩格式如BC4/BC5 for法线。简化模型只在主角或特写角色上使用完整效果的Shader远景或NPC可以使用简化版本例如只保留基础透明度。批处理与合批确保使用相同材质的衣物网格符合Unity的静态/动态合批条件减少Draw Call。6.3 美术协作流程厚度图绘制规范与美术师明确约定厚度图的灰度含义白薄黑厚并提供参考图。建议在建模软件如Marvelous Designer中模拟布料时可以导出厚度信息作为绘制基础。材质参数预设针对不同的服装材质丝绸、尼龙、乳胶、薄纱制作好不同的材质参数预设Transmission Strength,Color,Distortion等方便美术快速调用。分层渲染考虑将衣物的不同部分如装饰边、logo分离成不同的材质或SubMesh对不需要半透明效果的部分使用不透明Shader以优化渲染排序和性能。6.4 与后处理堆栈的兼容性确保你的半透明材质与URP的后处理效果如Bloom, Color Grading兼容。特别是Bloom泛光效果能极大地增强背光透射的“光晕”感。你可能需要调整材质的Alpha输出或使用Additive混合模式让散射光部分能更好地被Bloom捕捉。实现一个逼真的“半透明紧身衣”效果是理解现代实时渲染中次表面散射、透明渲染和光照模型的一个绝佳实践。从最基础的厚度图控制透光开始逐步引入动态皮肤信息、更精确的散射模型并与美术资源、性能优化相结合最终能在游戏中呈现出极具沉浸感的角色外观。关键在于理解“光与多层介质的交互”这一物理本质并用高效的Shader代码将其近似模拟出来。动手调节每一个参数观察其视觉变化是掌握这门技术最有效的方法。