Unity Shader - 水体交互
水体交互
水体交互效果在游戏中是一个很常见的需求,这里简单实现一个可交互的水体。
本篇文章主要是介绍水体交互的实现思路,水体的渲染这里就不再详细介绍,网上很多关于水体的渲染方法很多,可以自己百度、Google了解一下,这里不会过多提及。
效果图。
先放一张最终的GIF效果图!
实现思路
原理其实非常简单,就是通过粒子系统不断发射带有波纹法线贴图的面片,然后把这些法线渲染一张RenderTexture传输到Water Shader中,然后和Water Normal 叠加即可形成水波效果。
实现步骤可以简单分为:
- 简单的水体渲染
- 渲染水波法线RT
- 叠加法线
一、简单的水体渲染
这里的水体渲染采用简单的法线干扰实现,参考冯乐乐女神的《Unity Shader入门精要》里的水体渲染。
水的效果:
这里深水和潜水区的过渡是直接用场景深度值
和水面深度值
做差值
, 差值越接近0,就越接近浅滩区。
获取场景深度图需要开启 DepthModel: GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;
Shader代码:
//frag:float2 screenPos = i.screenPos.xy/i.screenPos.w;
// 获取屏幕深度
half existingDepth01 = tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos)).r;
half existingDepthLinear = LinearEyeDepth(existingDepth01);
half depthDifference = existingDepthLinear - i.screenPos.w;
// 深水和潜水颜色做插值
half waterDepthDifference01 = saturate(depthDifference / _DepthMaxDistance);
float4 waterColor = lerp(_ShallowColor, _DeepColor, waterDepthDifference01);
二、渲染水波法线的RenderTexture
1.首先在场景创建一个Camera,该Camera只渲染特定的Layer,即水波法线,Culling Mask 设置为WaterWave
,Clear Flags设置为Slid Color
,Background设置为黑色
,并且位置旋转都设置为和MainCamer一致。并且创建一个RenderTexture,拖拽到Target Texture上。
2.创建一个Shader,命名为WaterRing,该Shader用于渲染水波法线。
3.继续创建一个粒子系统,材质Shader设置为刚才创建的WaterRing Shader,并且该粒子的Layer需要修改为WaterWave
。
水波法线渲染:
水波法线的Shader可以非常简单,直接渲染一张环状的法线贴图即可。
但是这里为了可以更方便的调整水波法线的一些细节就采用动态计算的方式来渲染。
这里计算法线是通过ddx ddy的方式来计算,为了得到法线首先肯定需要知道高度差,那么我们可以先渲染一个环状的高度图,
这里就可以通过两个smoothstep相减得到一个较为平滑的环状高度。
效果如下:
Shader代码:
fixed doubleSmoothstep(float4 uv)
{float dis = distance(uv, 0.5);float halfWidth = _RingWidth * 0.5;float range = _RingRange;float smoothness = _RingSmoothness;float threshold1 = range - halfWidth;float threshold2 = range + halfWidth;float value = smoothstep(threshold1, threshold1 + smoothness, dis);float value2 = smoothstep(threshold2, threshold2 + smoothness, dis);return value - value2;
}fixed4 frag(v2f i) : SV_Target
{fixed normalCenter = doubleSmoothstep(i.uv);return fixed4(normalCenter,normalCenter,normalCenter,1);
}
有了高度差就可以计算出法线了:
Shader代码:
float normalCenter = doubleSmoothstep(i.uv);
// 波纹法线
float color0 = doubleSmoothstep(i.uv + half4(-1, 0, 0, 0) * 0.004);
float color1 = doubleSmoothstep(i.uv + half4(1, 0, 0, 0) * 0.004);
float color2 = doubleSmoothstep(i.uv + half4(0, -1, 0, 0) * 0.004);
float color3 = doubleSmoothstep(i.uv + half4(0, 1, 0, 0) * 0.004);float2 ddxy = float2(color0 - color1, color2 - color3);
float3 normal = float3((ddxy * _BumpPower), 1.0);
normal = normalize(normal);
float4 finalColor = float4((normal * 0.5 + 0.5) * normalCenter * i.color.a, normalCenter * i.color.a);
return finalColor;
这里通过ddx ddy得到了法线后,需要把法线从[-1,1]映射到[0,1]范围(normal * 0.5 + 0.5)。
此时我们就可以通过参数动态调整该环状法线的宽度、强度、范围。
最后把该材质赋值给粒子,并且通过调整粒子参数使粒子随着生命周期逐渐变大、顶点色的A通道也跟随生命周期变化来控制透明度和强度。
此时如果不出意外的话可以看到RT是这样的。
三、叠加法线
最后一步就是把之前渲染得到的RT传递到Water Shader中,通过屏幕坐标采样得到水波法线,然后把值从[0,1]映射到[-1,1]范围(normal * 2-1),然后和水的法线叠加即可。
屏幕坐标可以由ComputeGrabScreenPos
计算得到。
Shader代码:
float4 ringColor = tex2D(_RingTex, screenPos);
float3 ringNormal = UnpackNormal(ringColor).rgb;
ringNormal = mul(float3x3(i.TtoW0.xyz,i.TtoW1.xyz,i.TtoW2.xyz),ringNormal);
ringNormal = normalize(ringNormal) * ringColor.a * _RingPower;
// float3 normal = BlendNormals(ringNormal,waterNormal);
float3 normal = normalize(waterNormal+ringNormal);
效果如下:
最后再结合粒子即可实现一个动态的水波扩散的效果。
完整工程源码: https://github.com/csdjk/LearnUnityShader
Unity Shader - 水体交互相关推荐
- 【Unity Shader实例】 水体WaterEffect(一) 设计
Unity Shader 水体效果实现的设计 在设计水体效果的实现方案之前,我们先参考一下大神们写好的精彩的例子,比如DCG Water Shader的效果,这也是我们努力的目标. 好!~ 现在开始实 ...
- Unity Shader 水多种元素的实现(反射、折射、菲涅尔、深浅、浪花/泡沫、水波、可交互)
综合效果 经过各元素叠加 和 程序的审美调参 后的综合效果 交互的水波与边缘浪花的合并需要优化一下 反射 两种方案: cubeMap 以水面对称设一个摄像机 cubeMap 实现:反射探针生成Cube ...
- Unity Shader - 实现简单水体 - 浅水到深水颜色控制
文章目录 制作步骤 准备好水体网格 扰动水体网格 添加水体网格色调,纹理 放置海上放哨点(一些随便放的立方体) 添加水的深浅透视效果 添加水光效 重构水顶点法线 正交的相机的深度需要注意 改进 Pro ...
- 【Unity Shader实例】 水体WaterEffect(二) 用贴图和uv动画模拟水效
Unity Shader实现简单水体效果 效果展示 原理 用贴图和uv动画模拟水效实现"假"水. 设计 找一张水波的贴图,处理它的uv值,让贴图流动起来.这样就用静态纹理和uv动画 ...
- Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照
转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...
- Unity Shader入门
什么是Shader Shader(着色器)是一段能够针对3D对象进行操作.并被GPU所执行的程序.Shader并不是一个统一的标准,不同的图形接口的Shader并不相同.OpenGL的着色语言是GLS ...
- Unity Shader之磨砂玻璃与水雾玻璃效果
导读 玻璃效果是游戏场景中常见的效果之一,除却普通的透明玻璃外,磨砂玻璃也是较为常见的效果.玻璃与场景中的其他物体也会有交互,例如,浴室中的玻璃.雨天的窗户会在水汽的作用下带有一定差别的雾效.本文以U ...
- 【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现
笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Shader](三) ----- ...
- Unity Shader 基础教程
Unity-Shader-基础教程 在Github上看到一篇关于Unity-Shader的教程,感觉还不错,作者写的很好,很适合Unity-Shader的基础入门,我在这里翻译一下,分享给大家,英文水 ...
最新文章
- 剑指offer:对称的二叉树
- [转]深入理解 __doPostBack
- ccf报数游戏java_ccf 201712 02 (游戏)
- 在一个非套接字上尝试了一个操作。_鼠标+键盘上一个键,Excel操作效率瞬间提高一个档次,这也太神了...
- CSS3的滤镜filter属性
- java扫描指定package注解_java获取包下被指定注解的类
- 史上最全提升GPU的tricks合集
- element table滚动条占宽度_HTML table表格 固定表头 tbody加滚动条
- 图嵌入知识表征の初体验
- matlab 程序 收缩,基于MATLAB的小波收缩去噪方法研究(程序)
- 如何监控oracle的索引是否使用
- springboot项目license_license · 开源的SpringBoot前后端分离项目/framework - Gitee.com
- 基于Unity引擎的RPG3D项目开发笔录
- matlab中用xlsread()函数在Excel中读取数据
- 如何使用工具切换设备ip 电脑和手机怎么如何换ip?
- 克拉克误差网格分析程序(Performs Clarke Error Grid Analysis)
- 电子设计之国赛准备-----(前言)
- MySQL详细安装步骤
- Python - 面向对象编程 - 三大特性之继承
- 正则表达式-身份证号码验证