假云阴影模拟
云阴影效果简介
这里说的云阴影,是使用噪声图或者特定规律的随机图模拟的假云阴影。效果类似于大片云投影在大地上,同时阴影按照一定速度移动和随机流动变化,并且支持双层阴影叠加。
全局参数
全局云阴影开关
可以看到,有一个是否启用(Enable)的全局开关控制是否开启全局云阴影。这可以使用全局变体实现,由于全局变体无法剔除,容易引入变体爆炸问题。因此,最好使用材质局部变体替代。
云阴影颜色
有一个全局的云阴影颜色用于调整整体的云阴影颜色,比如可以调出红色等特殊颜色的云阴影,默认是黑色。
云阴影参数
从参数设置可以看到,云阴影分为两层。每层有大小、强度、方向、速度以及噪声的强度、速度、tiling。噪声是为了模拟云阴影边缘的快速变化抖动效果。同时,需要一张云阴影贴图来控制这两层的参数;规定贴图的R、G通道是第一层阴影的强度和噪声的强度,B、A通道是第二层阴影的强度和噪声的强度。
Shader或者材质参数
材质云阴影开关
Shader上有专门的变体开关控制是否激活云阴影。这里针对的是当前材质的开关,使用local变体即可满足据要求。
材质云阴影强度
同时,有一个强度滑块控制该材质的云阴影强度。这样,可以定制不同材质接收到云阴影强度。
实现原理
修改albedo
#if _GLOBAL_CLOUD_SHADOWsurfaceData.albedo = ApplyGlobalCloudShadow修改(surfaceData.albedo, input.positionWS, _CloudShadowIntensity);
#endif
从上述代码可以看到,在开启变体_GLOBAL_CLOUD_SHADOW时候,使用函数ApplyGlobalCloudShadow修改albedo。
计算CloudShadow
inline half3 ApplyGlobalCloudShadow(half3 albedo, float3 positionWS, half intensity = 1.0f)
{half firstCloudShadowIntensity = GetFirstGlobalCloudShadowIntensity(positionWS);half secondCloudShadowIntensity = GetSecondGlobalCloudShadowIntensity(positionWS);albedo *= lerp(half3(1, 1, 1), _CloudShadowColor, intensity * max(firstCloudShadowIntensity, secondCloudShadowIntensity));return albedo;
}
- 函数ApplyGlobalCloudShadow首先计算两层云阴影强度,再使用max获得两层的最大强度(两层阴影叠加的位置取最大值)作为云阴影强度。
- 然后使用这个云阴影强度在白色与云阴影颜色之间进行插值获得最终的云阴影颜色。
- 最终,将该云阴影颜色乘到albedo上。
计算单层CloudShadow强度
该函数代码比较关键,不再直接提供源码,有需要的可以理解后再自行实现。
- 使用传入的positionWS计算出worldUV。
- 使用worldUV结合云阴影的大小、速度计算出云阴影的位置(cloudUV),然后使用cloudUV采用贴图的R通道获得云阴影强度。
- 使用worldUV结合云阴影噪声的速度、tiling计算出云阴影噪声的位置(cloudNoiseUV),然后使用cloudNoiseUV采用贴图的B通道获得云阴影噪声强度。
- 将云阴影强度和云阴影噪声强度进行叠加获得整体的云阴影强度。注意:叠加算法很关键,需要使用PS的线性加深模式。
整体效果
更精细的效果可以参考文章:假云阴影模拟