对于战地风云1,场景中的积水有两种实现:一种是刷在地形表面的积水,烘培进入地形纹理,是地形材质的一种变体。用于实现简单的、浅薄的积水,随着地形一并渲染。

其二是单层面片水,用于实现场景内的大片积水,需要额外单独一趟 PASS 渲染。

地形积水

这里的积水是一种地形材质的变体:积水权重被烘培进第二张世界地形纹理(texture_virtualTextureAtlas1)的R通道中,当采样值的平方超出阈值0.01,此位置的地形将被视作水体,进入额外分支

这里对法线纹理进行两次采样,通过叠加两个不同方向、不同频率的波纹,消除平移感,让水面看起来在流动

(地形积水:地形材质变体)

作为地形材质的变体绘制,此类积水没有实际深度,中心处凸出水面的小块泥土与积水实为地形的一部分。以下是一块积水处的地形,为保持视觉上平整的水面效果,积水处的地形不启用置换纹理。

(积水处的地形 Tile 不启用置换)

单层面片水

水体的面片材质不透明,对应 UE 中的不透明 Shading Model,alpha 混合不会向水体开启。

水面之下的折射靠从地形纹理采样,投影到水面。水面之上的反射靠 SSR

同时由于(直接将下方地形的纹理投射到水体表面)的做法,无法模拟水体在深水区因折射而产生的视差,为防止穿帮,水体的深度衰减系数 external_WaterFalloff 被设置为极大。表现在视觉上:水体极其浑浊,光线在水体的穿透距离极短。仅有岸边的浅滩可以被最终折射至表面

水面需要知道水有多深来决定颜色的吸收率(深水颜色深,浅水透明),因此在计算出水深后,会结合 external_WaterFalloff 参数计算基于深度的最总衰减系数,用于控制水体的透光度和后续的散射颜色混合。

由于水体面片不透明的性质,水底折射依赖从提前烘培的世界地形大纹理上采样,投射至面片表面。因此无法折射出水面之下除地形外的一切物体,例如这棵横在水面的树干。

(作为对比,战地水体无法折射树干的水下部分)

同时这里的水体动态效果由法线纹理的流动产生,网格本身只是不经过形变的面片。

根据水体深度的从地形纹理的高度图中将程序化生成的波浪法线与虚拟纹理采样的细节法线进行混合

水体颜色与粗糙度

水体颜色的最终结果是一个基于水深的线性插值。它在虚拟纹理颜色 (浅水) 和预设的常量颜色 (深水)之间进行混合。

Result = lerp(ConstantColor, TextureColor^2, DepthFactor)

水深系数:exp2(-depth * falloff),用于在深水区域与浅水区域之间进行区分并插值

(水体颜色:硬编码常数与深度插值)

深水处的水面基色硬编码在着色器中,float3(0.13843, 0.10472, 0.07926),此为一个灰暗的棕褐色,为深处的水体提供浑浊感。

(粗糙度:硬编码常数与深度插值)

同样的,粗糙度的最终结果,也是基于水深的线性插值。同时写入粗糙度 Roughness,由于水面非常光滑,着色器中硬编码了 0.2 并受波浪影响。在浅滩的地形纹理的粗糙度与硬编码常数(0.2)之间进行混合。