ShaderLab:可互动水面(基于RenderTexture,实时生成动态扰动)

本篇文章是一个基于URP的可交互水面系统,实现了实时渲染水面扰动,使用了三缓冲RT交换用于实现水面波纹扩散效果。

上一篇文章实现了在无扰动理想情况下的程序化生成海面顶点数据,然而这种水面是在理想情况下,现实中水面不会平静也不会只有波浪,还有对系统施加外力情况下的水面扰动。比如,石子被投入水中、小船在水面航行等。这种情况下就不仅仅需要程序化计算顶点位置,还需要计算扰动并叠加。

代码分享:https://pan.baidu.com/s/1-VApXIrHxRjCthW2OYUMmA?pwd=9527https://pan.baidu.com/s/1-VApXIrHxRjCthW2OYUMmA?pwd=9527代码学习、参考:神奇的小阿飞https://space.bilibili.com/31839293/?spm_id_from=333.788.upinfo.detail.clickhttps://www.bilibili.com/video/BV1Xh411D7z7/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=e72728138018176c10ef41188bea0c35https://www.bilibili.com/video/BV1Xh411D7z7/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=e72728138018176c10ef41188bea0c35

效果预览

代码分析

本项目包含四个文件:

  • DrawShader.shader: 用于绘制鼠标输入点的水波扰动逻辑,以及扰动叠加逻辑
  • RippleShader.shader: 用于处理水波扩散逻辑
  • WaterShader.shader: 用于计算水质感
  • Ripple.cs: 用于处理输入相关逻辑以及shader脚本调用逻辑

DrawShader.shader

着色器功能:在一张已有纹理上绘制一个可扩散的圆形涟漪效果。在_SourceTex上叠加一个"环形渐变"的亮度ripple,位置和半径由_Pos控制。

结构体:appdata------顶点着色器输入结构,v2f------顶点输出结构。

核心公式(一个平滑的环形函数):

float ripple = pow(saturate(0.05 - abs(length(uv - _Pos.xy) - _Pos.z)), 2.0);

叠加到原图:

return SAMPLE_TEXTURE2D(_SourceTex, sampler_SourceTex, uv).r + ripple * 0.8;

SAMPLE_TEXTURE2D(_SourceTex, sampler_SourceTex, uv).r采样源图并返回r通道值。

RippleShader.shader

着色器功能:二维波动方程(水波/高度场)离散求解器。

使用经典Ping-Pong Simulation双缓冲模拟,_CurrentTex:当前帧,_PreviousTex:上一帧,输出:下一帧

cs 复制代码
half4 frag(v2f i) : SV_Target
{
    float2 e = _CurrentTex_TexelSize.xy;
    float2 uv = i.uv;

    // 这里的 up/down/left/right 是相对于当前像素的四个邻居,而 center 是当前像素在上一帧的值
    float up = SAMPLE_TEXTURE2D(_CurrentTex, sampler_CurrentTex, uv + float2(0, e.y)).r;
    float down = SAMPLE_TEXTURE2D(_CurrentTex, sampler_CurrentTex, uv - float2(0, e.y)).r;
    float left = SAMPLE_TEXTURE2D(_CurrentTex, sampler_CurrentTex, uv - float2(e.x, 0)).r;
    float right = SAMPLE_TEXTURE2D(_CurrentTex, sampler_CurrentTex, uv + float2(e.x, 0)).r;
    float center = SAMPLE_TEXTURE2D(_PreviousTex, sampler_PreviousTex, uv).r;
 
    float c = (up + down + left + right) * 0.5f - center;
    c *= 0.99f;
    return c;
}

对当前像素的当前帧进行四领域采样,以及前一帧的中心像素采样,核心更新公式:

float c = (up + down + left + right) * 0.5f - center;

因为在波的传输过程中是有能量损失的,所以计算出来的下一帧波的高度应该有一定的损失程度,这里按每次损失1%,即c *= 0.99。

WaterShader.shader

着色器功能:用高度图(_RippleTex)驱动几何+法线+反射/折射,渲染动态水面。它做了三件事情:

  • 顶点位移(水面波形):水面真实的"起伏"
  • 法线重建(光照基础):根据高度图采样计算法线
  • 光照(真实感来源):反射 + 折射 + 菲涅尔 + 高光

数据流:RippleTex(高度图) -> 顶点位移 -> 法线计算 -> 光照计算 -> 最终水面

在顶点着色器阶段不能使用函数SAMPLE_TEXTURE2D函数读取贴图,因为在这种情况下需要计算贴图的minmap,但是顶点阶段不能用自动LOD,所以会报错。这时候可以用SAMPLE_TEXTURE2D_LOD指定其minmap等级然后获取贴图。

这个shader就是普通的画面表现shader。

Ripple.cs

在Unity中实现一个基于高度场的水波模拟+鼠标交互扰动,实际上是一个在纹理上做物理模拟的系统,而不是直接操作网格。

使用三张RT做模拟,PreviousRT、CurrentRT、TempRT

包含功能:

  • 鼠标点击产生扰动
  • 每帧做波动传播
  • 把结果给水材质显示
相关推荐
摄影图18 小时前
[图片素材]国产芯片半导体 满足科技创作多场景需求
人工智能·科技·aigc·贴图·插画
郝学胜-神的一滴2 天前
中级OpenGL教程 007:解决背面光照异常高光问题
c++·unity·游戏引擎·three.js·opengl·unreal
threelab5 天前
Three.js 加载 3D Tiles 瓦片数据 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
CG_MAGIC5 天前
风格化手绘风 3D 渲染出图参数调校技巧
3d·blender·贴图·效果图·渲云渲染
threelab5 天前
Three.js 黑洞引力效果着色器 | 三维可视化 / AI 提示词
开发语言·javascript·着色器
郝学胜-神的一滴5 天前
[简化版 GAMES 101] 计算机图形学 10:反走样与深度缓冲核心解析
c++·unity·godot·图形渲染·three.js·unreal engine·opengl
threelab6 天前
Three.js 抽象艺术着色器效果 | 三维可视化 / AI 提示词
前端·javascript·人工智能·3d·着色器
♡すぎ♡6 天前
ShaderLab:PBR+IBL(ShaderToy Translation)
算法·计算机图形学·着色器·pbr·ibl
threelab7 天前
Three.js 3D 地图可视化 | 三维可视化 / AI 提示词
前端·javascript·人工智能·3d·着色器
爱怪笑的小杰杰7 天前
Leaflet 高性能大数据量图圆:彻底解决缩放/拖拽偏移问题
大数据·前端·vue.js·贴图