水体渲染


简单水体

  • 贴图+UV动画
  • 使用一张噪声纹理,采样结果作为UV的偏移值,从而模拟水流动的效果

// sample the texture
fixed4 noise_col = tex2D(_NoiseTex, i.uv + fixed2(_Time.y*_XSpeed, 0));
fixed uOffset = noise_col.r;
fixed vOffset = noise_col.r;
fixed4 col = tex2D(_MainTex, i.uv +_Intensity*fixed2(uOffset, vOffset));
  • _Intensity为水流动的强度

  • _XSpeed为水流动的速度

  • 完整代码:https://github.com/kb824999404/Unity_Shader/blob/master/Shader/Test/Water/SimpleWater.shader


水波

  • 波纹内部有拉伸效果,随时间变化:用距离中心的长度和时间作为输入,通过三角函数计算拉伸值,_distanceFactor为波峰波谷数量,_totalFactor为最大拉伸强度,_timeFactor为拉伸强度变化速度

    float sinFactor = sin(dis * _distanceFactor + _Time.x * _timeFactor) * _totalFactor;
    
  • 波纹从内向外扩散:波纹半径随时间递增,不超过最大半径_maxWaveDiswaveWidth为波纹宽度,如果纹理坐标距离当前波纹运动点的距离超过该值则不拉伸
    float curWaveDis = frac(_Time.x *_waveSpeed)*_maxWaveDis;
    //距离当前波纹运动点的距离,如果小于waveWidth才予以保留,否则已经出了波纹范围,factor通过clamp设置为0
    float discardFactor = clamp(_waveWidth - abs(curWaveDis - dis), 0, 1);
    
  • 将纹理坐标进行网格细分,使水波随机出现在各个网格内,并且一个扩散周期后再次随机出现,_GridNum为细分网格数量,_RippleDensity为水波密度
    float2 st=frac(i.uv*_GridNum);     //网格内坐标
    float2 grid=floor(i.uv*_GridNum);    //网格坐标
    float2 dv=float2(st.x-0.5,st.y-0.5);
    float dis=length(dv);           //距网格中心距离//使用floor取整,一个水波扩散周期内不变
    float flag_change=floor(_Time.x *_waveSpeed);
    //用网格坐标和flag_change生成随机值,大于_RippleDensity为1,用于判断该网格是否有水波
    //这样水波随机出现在各个网格内,且一个水波扩散周期内不消失
    float flag_ripple=step(random(grid+flag_change),_RippleDensity);
    
  • 最后综合计算结果,得到偏移值
    //归一化
    float2 dv1 = normalize(dv);
    //计算每个像素uv的偏移值
    float2 offset = dv1  * sinFactor*discardFactor*flag_ripple;
    
  • 水波可能不太明显,可以加上水波的颜色(效果好像不太明显)

  • 完整代码:https://github.com/kb824999404/Unity_Shader/blob/master/Shader/Test/Water/RippleWater.shader

波浪

  • 顶点动画,这里采用线性波形叠加方法,_WaveScale为波浪数量,_WaveStrength为波浪强度
  • 需要注意的是,如果使用Unity中自带的模型,顶点数过少,会产生整个模型上下摇动的效果,而不是出现波浪,因此可以在Blender里建一个平面,细分到有足够多的顶点
    float calculateSurface(float x, float z, float scale)
    {float y = 0.0;y += (sin(x * 1.0 / scale + _Time.y * 1.0) + sin(x * 2.3 / scale + _Time.y * 1.5) + sin(x * 3.3 / scale + _Time.y * 0.4)) / 3.0;y += (sin(z * 0.2 / scale + _Time.y * 1.8) + sin(z * 1.8 / scale + _Time.y * 1.8) + sin(z * 2.8 / scale + _Time.y * 0.8)) / 3.0;return y;
    }
    v2f vert (appdata v)
    {v2f o;v.vertex.z += _WaveStrength * calculateSurface(v.vertex.x, v.vertex.y, _WaveScale);o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);UNITY_TRANSFER_FOG(o,o.vertex);return o;
    }
    

  • 完整代码:https://github.com/kb824999404/Unity_Shader/blob/master/Shader/Test/Water/WaveWater.shader

折射反射

  • 折射:使用GrabPass{}在渲染水面前获取屏幕图像,作为水下贴图,在此基础上渲染水面
  • 反射:创建一个相机捕获从水面出发捕获到的景象,建立一个RenderTextureRenderTexture赋给相机的Render Target存储获取的图像,再将RenderTexture赋给水体material_ReflectTex
  • 菲涅尔反射:使用菲涅尔等式计算反射光和折射光的比例
    Fschlick(v,n)=F0+(1−F0)(1−v⋅n)5F_{schlick}(v,n)=F_{0}+(1-F_{0})(1-v\cdot n)^{5}Fschlick​(v,n)=F0​+(1−F0​)(1−v⋅n)5
    然后按比例混合反射光和折射光

    //反射纹理采样
    fixed3 reflectColor=tex2D(_ReflectTex,coord);//水下纹理采样
    fixed3 refractColor=tex2D(_GrabTex, (i.scrPos.xy+offset)/i.scrPos.w).rgb;
    //菲涅尔等式计算反射和折射比例
    fixed fresnel=_FresnelScale+(1-_FresnelScale)*pow(1-dot(worldViewDir,worldNormal),5);//混合反射光和折射光
    fixed3 fresnelColor=lerp(refractColor, reflectColor, saturate(fresnel));
    
  • 水贴图采样,添加高光和阴影,结果:
    fixed3 color = ambient+(waterColor +specular+fresnelColor ) * atten;
    

  • 完整代码:https://github.com/kb824999404/Unity_Shader/blob/master/Shader/Test/Water/AllWater.shader

本文代码: https://github.com/kb824999404/Unity_Shader/blob/master/Shader/Test/Water


参考: Unity Shader-后处理:屏幕水波效果  真实感水体渲染技术总结  Unityshader水体笔记  《Unity Shader入门精要》
【Unity Shader实例】 水体WaterEffect(二) 用贴图和uv动画模拟水效
【Unity Shader实例】 水体WaterEffect(五) 水的折射


个人博客传送门: 十七小栈

UnityShader水体渲染相关推荐

  1. UnityShader水墨渲染的尝试

    UnityShader水墨渲染的尝试 描边 混合纹理 先上一张原图,模型素材之类的可以在这里 下载 描边 使用最基本的dot(n,v)来计算边缘,根据需要给控制项,这里我使用了pow来使明暗对比更强烈 ...

  2. cocos脏话过滤_Cocos Creator 卡通水体渲染教程

    原标题:Cocos Creator 卡通水体渲染教程 本篇教程转载自 Cocos 中文社区,作者:regocxy.通过本篇教程你将学到如何做风格化水体的渲染,包含的知识点有如何使用天空立方体贴图作反射 ...

  3. [Unity/URP学习]风格化水体渲染(一)

    风格化水体的实现内容 文章目录 风格化水体的实现内容 风格化水体实现过程 1.水体颜色 1.1风格化水体颜色渐变 1.2水体深浅区域 1.2.1开启深度纹理 1.2.2深度纹理采样 1.3水体透明度 ...

  4. UnityShader RenderTypeQueue 渲染顺序

    整理自这两篇博文 https://blog.csdn.net/u013477973/article/details/80607989?depth_1-utm_source=distribute.pc_ ...

  5. UnityShader崩坏渲染解析系列(3)--高光、Dither效果、Rim、特殊状态

    身体渲染 高光 Dither效果 Rim 特殊状态 小结 高光 前面介绍了暗面的计算方式,接下来是高光的计算效果.高光计算比较简单,采用了Blinn-Phong的光照模型,明暗计算的时候采用了lamb ...

  6. UnityShader崩坏渲染解析系列(2)--明暗计算

    身体渲染 什么是明暗 处理明暗 崩坏处理 资源解析 总结 什么是明暗 与实时渲染不一样的地方在于,日式卡通渲染阴影过度有明显的分界线. 没错,左边的明暗变化有一条很明显的交界线,而右边的是有过渡效果的 ...

  7. Unity Shader - 水体交互

    水体交互 水体交互效果在游戏中是一个很常见的需求,这里简单实现一个可交互的水体. 本篇文章主要是介绍水体交互的实现思路,水体的渲染这里就不再详细介绍,网上很多关于水体的渲染方法很多,可以自己百度.Go ...

  8. 3D渲染技术分享:实时3D水面渲染(反射、折射、水深与水岸柔边)

    一.开篇 自从上次写了**<用实时反射Shader增强画面颜值>** 后,不少开发者开始尝试用它来渲染水面,但效果都差强人意. 这是因为,水面除了反射,还有许多细节需要考虑. 在此之前,也 ...

  9. 【Unity 风格化】水墨风渲染01:从总结实现方法开始

    写在前面 一直比较迷风格化的东西,之前写PBR其实也是为了后面尝试PBR+NRP做铺垫,毕竟了解写实向才能进一步学习奇奇怪怪的NPR方式!话不多说,从水墨渲染开始,正式进入风格化的世界!! 无论是什么 ...

最新文章

  1. 【硅谷牛仔】Facebook最初的CEO肖恩帕克
  2. NSArray,NSSet,NSDictionary总结 (转)
  3. 从数值、玩法、社交模块入手谈MMORPG手游设计
  4. vue 怎么样不重复往数组里插入数据_前端数据结构与算法(1) -二分查找vs二叉树...
  5. 写给小白的WordPress详细安装步骤
  6. nginx安装与项目发布
  7. 回顾之前易忘记的知识
  8. mysql一对一关系_sql-MySQL-一对一关系?
  9. 诺基亚PC套件在windows 2003安装的方法
  10. 罗技无法使用计算机上的配置文件,罗技游戏软件检测不到游戏启动,导致无法自动切换配置文件...
  11. 机器码、序列号、认证码、注册码的生成算法(四)
  12. 多标签分类问题中的评价指标:准确率,交叉熵代价函数
  13. HDMI线、DP线、DVI线、VGA线
  14. --TEXT()函数与TEXT()有什么区别
  15. 「入门运维必看」一篇让小白彻底搞懂性能调优!
  16. 《Redis设计与实现》笔记
  17. 安卓机更新系统会卡吗_安卓手机系统“越更新越卡”?或许和这4个原因有关,早看早知道...
  18. NVIDIA GeForce GTX 950M 新出驱动程序
  19. 德邦维新:如何打赢“未来之战”?
  20. 因为一句话,爱上一部电影

热门文章

  1. 抱抱脸:ChatGPT背后的算法——RLHF | 附12篇RLHF必刷论文
  2. 特斯拉Model3车主称无法开启;传高通开发首款笔记本处理器;Dfinity挑战亚马逊 | 雷锋早报...
  3. jc机制是什么_单片机中jc指令表示什么?有什么用?
  4. js获取今日,昨日,本周,上周,本月,上月,的0点及24点的时间及时间戳,
  5. seo建设者_网站优化之SEO开发标准
  6. 严打“霸座”“扒车门”!去年12月以来已有12人被行拘
  7. 克隆远程仓库#180804
  8. LC76 Minimum Window Substring
  9. 为何非得选择旧金山测试?通用Cruise讲述无人车炼成记
  10. python撤销_Python 实现还原已撤回的微信消息