找回密码
 立即注册
查看: 177|回复: 2

UE Shader学习笔记:Water Shader

[复制链接]
发表于 2023-3-24 08:36 | 显示全部楼层 |阅读模式
视频链接:

本文目标:记录所学、备忘,提供蓝图方便他人
效果:



Water Shader的组成部分:
1.波纹(Ripple)


Ripple部分比较简单,思路是基于世界坐标对法线贴图进行三次采样和叠加,效果如下:


通过调整Panner的Speed和Size可以有效减弱Tile效果。
2.交界处的渐变(Depth fade)
物体和水交界的地方需要有个渐变效果,否则会很生硬。思路是用SceneDepth(DepthOnlyPass处理后得到的场景深度值)和PixelDepth(水面上像素点到相机的深度值)的差值来表示。如果直接使用SceneDepth-PixelDepth来处理,当相机视角变化时,这个差值也在变化(当相机正视水面时此值较小,当斜视水面时较大)。这样会导致同一个点在不同的视角下渐变效果不同,视觉表现不够理想。
因此这里做个了换算处理,我们实际需要的是下图中x的值。



x的计算

蓝图如下:


直接将结果赋给BaseColor:


实际使用中是使用这个值来控制水的opacity以及水颜色的lerp


效果如下:


3.折射、反射
UE中折射可以通过设置Refraction来实现


记得将RefractionMode设置为PixelNormalOffset,这样计算折射更准确


水的折射率是1.33,为了让边缘地带过度更自然,需要根据opacity(前面DepthFade计算所得值)对refraction进行lerp


折射效果:


在Detail面板开启ScreenSpaceRefections可以实现屏幕反射:



4.水波(GerstnerWave)
Gerstner原理很多文章有讲解,这里只记录实现。
根据UE4 Water插件中对水波浪的模拟代码(GerstnerWaveFunctions.ush)进行蓝图编写:
WaveOutput GetSingleGerstnerWave(GerstnerWaveRenderer inWaveRenderer, Texture2D inWaveParamsRT, SamplerState inWaveParamsRTSampler, int inWaveIndex, int inWaterBodyIndex)
{
        WaveOutput OutWave;
               
        FWaveParams CurrentWave;
        CurrentWave = GetWaveRTData(inWaveRenderer, inWaveParamsRT, inWaveParamsRTSampler, inWaveIndex, inWaterBodyIndex);
       
        //频率 wi
        float dispersion = 2 * PI / CurrentWave.Wavelength;
        //波矢量*频率  Di * wi
        float2 wavevector = CurrentWave.Direction * dispersion;
        //波速度  φ
        float wavespeed = sqrt(dispersion * Gravity);
        //波的相位移动  φ* time
        float wavetime = wavespeed * inWaveRenderer.Time;
        // wavepos =  (x,y) * wi * Di -  φ* time
        float wavepos = dot(inWaveRenderer.WorldPos, wavevector) - wavetime;
        
        // 水平
        float wavesin = sin(wavepos);
        // 垂直
        float wavecos = cos(wavepos);
       
        // wKA 表示 振幅 和 波长 的比值 ,就是函数曲线的纵横强度
        float wKA = CurrentWave.Amplitude * dispersion;
        // 陡度  是与wKA密切相关,例如q为1时表示函数的纵横幅度相同
        float q = CurrentWave.Steepness / wKA;
       
        // 求法线       
        OutWave.Normal.xy = wavesin * wKA * CurrentWave.Direction;
               
#if SOLVE_NORMAL_Z
        OutWave.Normal.z = wavecos * CurrentWave.Steepness * saturate((CurrentWave.Amplitude * SteepnessThreshold) / CurrentWave.Wavelength);
                //OutWave.Normal.z = wavecos *  wKA * (q/MaxWaves);
#else
                OutWave.Normal.z = 0;
#endif
        // xy 偏移 =  陡度 * wavesin * 波方向 * 振幅
        OutWave.WPO.xy = -q * wavesin * CurrentWave.Direction * CurrentWave.Amplitude;
        // z 偏移 =  wavecis * 振幅
        OutWave.WPO.z = wavecos * CurrentWave.Amplitude;

        return OutWave;
               
}


Gerstner Wave效果:


GerstnerWave的Normal需要和之前Ripple产生的normal进行融合(Gerstner为Base,Ripple为Additional):


融合后效果:


5.焦散(Caustics)
焦散效果使用Unreal内置的DecalActor,DecalActor的material设置如下:


蓝图如下:


思路比较简单:就是基于世界坐标对焦散贴图以及焦散扰动贴图进行两次采样和叠加。为了让采样的UV在xyz各个平面上都能正常显示,所以采用了3平面投影的方式进行采样。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2023-3-24 08:42 | 显示全部楼层
G波参数好好调一下 不调参就只是Sin波 G波的特征是尖的
发表于 2023-3-24 08:45 | 显示全部楼层
嗯 对的
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-4-30 10:49 , Processed in 0.106836 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表