
在游戏开发中,肥皂泡作为一种常见的自然现象,其独特的光学特性对Shader实现提出了有趣的挑战。肥皂泡表面的彩虹色(iridescence)反射让肥皂泡展现五彩斑斓的效果。本文将记录在Unity中复现肥皂泡效果的完整过程,包括实现气泡的材质,表面流动效果。使用的unity版本2022.3.61f1c1,最终得到的效果还需要优化,仅供参考。
效果预览

气泡材质
气泡反射原理参考:https://developer.unity.cn/projects/62b97859edbc2a77ce95afca
气泡反射材质实现参考:https://developer.unity.cn/projects/62b97c11edbc2a7848d41dda

创建urp的shader graph,图设置如上图所示。
下图展示了实现基础肥皂泡反射的连线,这里的噪声纹理可以先用任意噪声代替,我们之后再继续实现。

整个实现的核心在于彩虹色函数,函数的设置和代码如下:

float3 bump3y(float3 x, float3 yoffset)
{
float3 y = 1 - x*x;
y = saturate(y - yoffset);
return y;
}
float3 spectral_zuccioni6_float(float w)
{
float x = saturate((w - 400.0) / 300.0);
const float3 c1 = float3(3.54585104, 2.93225262, 2.41593945);
const float3 x1 = float3(0.69549072, 0.49228336, 0.27699880);
const float3 y1 = float3(0.02312639, 0.15225084, 0.52607955);
const float3 c2 = float3(3.90307140, 3.21182957, 3.96587128);
const float3 x2 = float3(0.11748627, 0.86755042, 0.66077860);
const float3 y2 = float3(0.84897130, 0.88445281, 0.73949448);
return
bump3y(c1 * (x - x1), y1) +
bump3y(c2 * (x - x2), y2);
}
void iridescence_float(float cosThetaR, float thickness, float power, float phase_shift, out float3 color)
{
color = 0;
float value = 2.66 * cosThetaR * thickness; // 2.66 = 2 * 1.33, ior of water
for (int n = -4; n <= 4; n++)
{
float wavelength = value / (n + 0.5);
wavelength = pow(wavelength, power);
color.rgb += spectral_zuccioni6_float(wavelength + phase_shift);
}
color = saturate(color);
}
spectral_zuccioni6_float
这个函数将波长值 w
转换为对应的 RGB 颜色
使用 Zucconi 方法模拟光谱颜色(基于物理的光谱近似)
参数 w
代表波长,通过 saturate((w - 400.0) / 300.0)
将波长范围规范化到 [0,1]
使用两组参数化的凸函数( bump3y
)合成光谱颜色
六个常量向量(c1, x1, y1, c2, x2, y2)定义了光谱的参数
iridescence_float
这是主函数,计算薄膜干涉产生的虹彩颜色:
- 参数说明:
cosThetaR
: 观察角度的余弦值(影响反射光路径长度)thickness
: 薄膜厚度power
: 用于调整波长分布的幂次phase_shift
: 相位偏移,可用于调整颜色偏移color
: 输出的 RGB 颜色
- 工作原理:
- 计算
value = 2.66 * cosThetaR * thickness
(2.66 是水的折射率 1.33 的 2 倍) - 循环计算 9 个干涉级数(n = -4 到 4),模拟多级干涉
- 对每个级数,计算波长
wavelength = value / (n + 0.5)
- 应用
power
参数调整波长分布 - 累加每个波长叠加
phase_shift
过后对应的光谱颜色贡献 - 最后
saturate
确保颜色值在有效值范围内
- 计算
肥皂泡波动效果
这一部分用顶点偏移方法模拟肥皂泡的随形效果,如果要实现肥皂泡的碰撞变形,就需要对这个部分再做改动。

Flowmap实现表面流动效果

肥皂的表面具有流动的反射,之前我们用噪声纹理暂时制作了反射,现在我们要细化并制作出肥皂泡表面流动的彩虹色纹理。
FlowMap 是 Unity 中一种纹理技术,用于模拟表面材质的流动和扭曲效果。这种技术将流动方向信息存储在纹理中,通常利用 RGB 图像的红色和绿色通道分别表示 X 和 Y 方向的流动向量,蓝色通道则可用于存储流动强度或其他辅助信息。
在实际应用中,FlowMap 通过在着色器中扭曲 UV 坐标来实现纹理的动态流动。开发者首先从 FlowMap 纹理中读取方向向量,然后将这些向量应用于原始 UV 坐标,使纹理沿着指定方向偏移。为了创造连续流动的错觉,避免循环时的明显跳变,通常会采用双周期混合技术,即使用两个时间相位错开的采样并在它们之间平滑过渡。
Flowmap制作参考:https://developer.unity.cn/projects/63059542edbc2a001c44ed42
Flowmap制作工具:https://teckartist.com/?page_id=107
下图为制作中使用的Flowmap纹理:


利用两个通道实现双周期之间的时序混合,达成持续的流动效果。
材质部署
由于透明物体的渲染问题,我们需要在物体内外分别挂载材质
设置如下:



注意修改材质Surface Options中的Render Face属性,对应材质所需渲染的面。
为了实现反射周边环境物体的效果,为物体挂载反射探针(Reflection Probe)。在这里使用Custom类型,反射天空盒的图像,在使用场景中可以使用Baked或者Realtime模式反射周边物体。