http://blog.csdn.net/mobilebbki399/article/details/50493117

效果图如下(GIF因为为了把图压小所以删掉了一些帧导致后面速度突然很快,实际效果并不是这样~_~)

之前在玩很多游戏的时候,注意到里面的海水和陆地相交接的地方会产生海浪,比如《海岛奇兵》,以及水面会出现一个透明渐隐的过度,而不会在水面和陆地的交界处产生硬切边。其中海浪的效果考虑到可以使用单独的面片来制作,不过最近在试着通过深度比较的方式直接计算出水面和陆地相交接的位置来制作海边的浪花,这种方式很多效果都会用到,其中比如unity粒子shader的软粒子计算部分(当使用软粒子时粒子的面片和其它物体交叉时不会出现明显的切边,而是有一个过度),还有之前在网上看到的别人的热扭曲效果。

以下例子只讲如何实现浪花,水的反射和折射有时间另外写。另外我的水shader中从潜水处到深水处的颜色渐变也是通过深度比较来完成的。

首先来讲解一下深度比较的原理,其实很简单,就是比较水面的z深度和已写入缓存的陆地的深度(准确的说是渲染到深度图的深度值,也就是_CameraDepthTexture,若要在shader中能读到有效的深度图,摄像机的depthTextureMode要设置为DepthTextureMode.Depth),计算一个深度差,很明显,水面和陆地部分交接的深度差是0,(因为都已经交叉在一起了),而水越深的地方深度差显然越大,如下图

unity内置粒子shader中使用深度差实现软粒子的代码如下:

[plain] view plain copy
  1. #ifdef SOFTPARTICLES_ON
  2. float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
  3. float partZ = i.projPos.z;
  4. float fade = saturate (_InvFade * (sceneZ-partZ));
  5. i.color.a *= fade;
  6. #endif

其中LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)))表示对深度图_CameraDepthTexture进行纹理投射,SAMPLE_DEPTH_TEXTURE_PROJ是定义在UnityCG.cginc文件中的,相当于tex2Dproj,事实上只是多了对当前的图形api做了判断而已。

i.projPos.z的值来自顶点函数,代码如下:

[plain] view plain copy
  1. v2f o;
  2. o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
  3. #ifdef SOFTPARTICLES_ON
  4. o.projPos = ComputeScreenPos (o.vertex);
  5. COMPUTE_EYEDEPTH(o.projPos.z);
  6. #endif

而这一段就是软粒子中计算深度差的部分:

[plain] view plain copy
  1. float fade = saturate (_InvFade * (sceneZ-partZ));

我想读到这里你一定会产生一个疑问,既然深度差是计算水面深度和深度图也就是_CameraDepthTexture中的深度的差,那么为什么水的平面不会写入_CameraDepthTexture中呢,因为如果水的深度写入了_CameraDepthTexture,必然会出现水的深度和_CameraDepthTexture中自己的深度比较,此时任何一个像素位置的深度差都是0。这里我要讲一下Unity中深度图的渲染方式,如果有接触过unity中的材质替代渲染,应该知道材质替代渲染是替换掉场景中某个标签的shader,而unity中深度图的渲染方式实际上就是这样,而它替带渲染的标签就是"RenderType",其中"RenderType"="Opaque"的物体会被渲染到深度图中,而"RenderType"="Transparent"的shader则不会被渲染,而我这边的水就使用了这个标签,因此它是不会被渲染到深度图的。

接下来由于在顶点函数中我们使用了

[plain] view plain copy
  1. COMPUTE_EYEDEPTH

来计算深度,因此深度图的深度也需要转换到视空间,即使用LinearEyeDepth。

此时如果直接输出深度差应该会得到这样的效果:

注意水面和陆地交叉的地方因为深度差最小所以最暗,而水较深的地方则表现出白色。

此时我们实际上只需要在shader中输入两个值,对应潜水处的深度差和较深处的深度差,并使用插值,就能产生水边海浪泡沫的效果了:

如上。

当然这一部分还只是产生还边海浪泡沫的部分,接下来需要讲的是能像真正的海浪一样不断冲刷海滩的浪花。

一般想到浪花,其实应该很容易想到使用类似正余弦函数来模拟的方式,(当然顶点水波只靠普通的正余弦还是达不到很好的效果的,不过这里不讨论)这是一种很简单的方式,而我的浪花就使用了正弦函数。我使用了这样一张贴图:

用这张贴图来模拟反复冲刷的海浪,并通过sin函数和_Time来偏移uv来实现,那么现在的问题是如何知道海浪的方向。

其实可以回顾上面讲的,我们知道海水和陆地的交叉处深度差是0,而深水处的深度差则比较大,不妨把深度差绘制成一条轴:

那么以深度差和时间作为sin函数的参数既可以计算出海浪纹理的uv偏移量了

大致为

deltaDepth+sin(_Time.x*_WaveSpeed)

当然直接这样产生的效果,各部分海浪的相位都一致,会导致海浪效果像平滑的光圈一样放大缩小,所以我用了一张躁波贴图来扰乱海浪的相位

最后效果如下:

大致就是这样,最后附上完整代码和资源

[plain] view plain copy
  1. Shader "Water/SeaWave" {
  2. Properties {
  3. _WaterTex ("WaterTex", 2D) = "black" {}
  4. _WaveTex ("WaveTex", 2D) = "black" {} //海浪
  5. _BumpTex ("BumpTex", 2D) = "bump" {}
  6. _GTex ("Gradient", 2D) = "white" {} //海水渐变
  7. _NoiseTex ("Noise", 2D) = "white" {} //海浪躁波
  8. _WaterSpeed ("WaterSpeed", float) = 0.74  //海水速度
  9. _WaveSpeed ("WaveSpeed", float) = -12.64 //海浪速度
  10. _WaveRange ("WaveRange", float) = 0.3
  11. _NoiseRange ("NoiseRange", float) = 6.43
  12. _WaveDelta ("WaveDelta", float) = 2.43
  13. _Refract ("Refract", float) = 0.07
  14. _Specular ("Specular", float) = 1.86
  15. _Gloss ("Gloss", float) = 0.71
  16. _SpecColor ("SpecColor", color) = (1, 1, 1, 1)
  17. _Range ("Range", vector) = (0.13, 1.53, 0.37, 0.78)
  18. }
  19. CGINCLUDE
  20. fixed4 LightingWaterLight(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) {
  21. half3 halfVector = normalize(lightDir + viewDir);
  22. float diffFactor = max(0, dot(lightDir, s.Normal)) * 0.8 + 0.2;
  23. float nh = max(0, dot(halfVector, s.Normal));
  24. float spec = pow(nh, s.Specular * 128.0) * s.Gloss;
  25. fixed4 c;
  26. c.rgb = (s.Albedo * _LightColor0.rgb * diffFactor + _SpecColor.rgb * spec * _LightColor0.rgb) * (atten * 2);
  27. c.a = s.Alpha + spec * _SpecColor.a;
  28. return c;
  29. }
  30. ENDCG
  31. SubShader {
  32. Tags { "RenderType"="Transparent" "Queue"="Transparent"}
  33. LOD 200
  34. GrabPass{}
  35. zwrite off
  36. CGPROGRAM
  37. #pragma surface surf WaterLight vertex:vert alpha
  38. #pragma target 3.0
  39. sampler2D _GTex;
  40. sampler2D _WaterTex;
  41. sampler2D _BumpTex;
  42. sampler2D _CameraDepthTexture;
  43. sampler2D _GrabTexture;
  44. half4 _GrabTexture_TexelSize;
  45. sampler2D _NoiseTex;
  46. sampler2D _WaveTex;
  47. float4 _Range;
  48. half _WaterSpeed;
  49. half _WaveSpeed;
  50. fixed _WaveDelta;
  51. half _WaveRange;
  52. fixed _Refract;
  53. half _Specular;
  54. fixed _Gloss;
  55. half _NoiseRange;
  56. struct Input {
  57. float2 uv_WaterTex;
  58. float2 uv_NoiseTex;
  59. float4 proj;
  60. float3 viewDir;
  61. };
  62. void vert (inout appdata_full v, out Input i) {
  63. UNITY_INITIALIZE_OUTPUT(Input, i);
  64. i.proj = ComputeScreenPos(mul(UNITY_MATRIX_MVP, v.vertex));
  65. COMPUTE_EYEDEPTH(i.proj.z);
  66. }
  67. void surf (Input IN, inout SurfaceOutput o) {
  68. float2 uv = IN.proj.xy/IN.proj.w;
  69. #if UNITY_UV_STARTS_AT_TOP
  70. uv.y = 1 - uv.y;
  71. #endif
  72. fixed4 water = (tex2D(_WaterTex, IN.uv_WaterTex + float2(_WaterSpeed*_Time.x,0))+tex2D(_WaterTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x) + float2(_WaterSpeed*_Time.x,0)))/2;
  73. float4 offsetColor = (tex2D(_BumpTex, IN.uv_WaterTex + float2(_WaterSpeed*_Time.x,0))+tex2D(_BumpTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x) + float2(_WaterSpeed*_Time.x,0)))/2;
  74. half2 offset = UnpackNormal(offsetColor).xy * _Refract;//用于折射的uv偏移量
  75. half m_depth = LinearEyeDepth(tex2Dproj (_CameraDepthTexture, IN.proj).r);
  76. half deltaDepth = m_depth - IN.proj.z;//计算深度差
  77. fixed4 noiseColor = tex2D(_NoiseTex, IN.uv_NoiseTex);
  78. half4 bott = tex2D(_GrabTexture, uv+offset);
  79. fixed4 waterColor = tex2D(_GTex, float2(min(_Range.y, deltaDepth)/_Range.y,1));
  80. fixed4 waveColor = tex2D(_WaveTex, float2(1-min(_Range.z, deltaDepth)/_Range.z+_WaveRange*sin(_Time.x*_WaveSpeed+noiseColor.r*_NoiseRange),1)+offset);
  81. waveColor.rgb *= (1-(sin(_Time.x*_WaveSpeed+noiseColor.r*_NoiseRange)+1)/2)*noiseColor.r;
  82. fixed4 waveColor2 = tex2D(_WaveTex, float2(1-min(_Range.z, deltaDepth)/_Range.z+_WaveRange*sin(_Time.x*_WaveSpeed+_WaveDelta+noiseColor.r*_NoiseRange),1)+offset);//这里计算了两个海浪,其中第二个海浪和第一个海浪存在相位差
  83. waveColor2.rgb *= (1-(sin(_Time.x*_WaveSpeed+_WaveDelta+noiseColor.r*_NoiseRange)+1)/2)*noiseColor.r;
  84. half water_A = 1-min(_Range.z, deltaDepth)/_Range.z;
  85. half water_B = min(_Range.w, deltaDepth)/_Range.w;
  86. float4 bumpColor = (tex2D(_BumpTex, IN.uv_WaterTex+offset + float2(_WaterSpeed*_Time.x,0))+tex2D(_BumpTex, float2(1-IN.uv_WaterTex.y,IN.uv_WaterTex.x)+offset + float2(_WaterSpeed*_Time.x,0)))/2;
  87. o.Normal = UnpackNormal(bumpColor).xyz;
  88. o.Specular = _Specular;
  89. o.Gloss = _Gloss;
  90. o.Albedo = bott.rgb * (1 - water_B) + waterColor.rgb * water_B;
  91. o.Albedo = o.Albedo * (1 - water.a*water_A) + water.rgb * water.a*water_A;
  92. o.Albedo += (waveColor.rgb+waveColor2.rgb) * water_A;
  93. o.Alpha = min(_Range.x, deltaDepth)/_Range.x;
  94. }
  95. ENDCG
  96. }
  97. FallBack "Diffuse"
  98. }

资源  链接: http://pan.baidu.com/s/1qXdZSZU 密码: xkqs

【游戏渲染】unity海边波浪效果的实现相关推荐

  1. unity海边波浪效果的实现

    效果图如下(GIF因为为了把图压小所以删掉了一些帧导致后面速度突然很快,实际效果并不是这样~_~) 之前在玩很多游戏的时候,注意到里面的海水和陆地相交接的地方会产生海浪,比如<海岛奇兵>, ...

  2. 【Unity Shader】unity海边波浪效果的实现

    效果图如下(GIF因为为了把图压小所以删掉了一些帧导致后面速度突然很快,实际效果并不是这样~_~) PS.对于移动端,参考该文章:http://www.lsngo.net/2018/03/22/uni ...

  3. 【Unity Shader】渲染纹理实现镜子效果

    1 基本概念 1.1 什么是渲染到纹理? 全称是Render To Texture,<入门精要>好像又把渲染目标纹理,即Render Target Texture也叫做RTT,但我认为&l ...

  4. 学习游戏渲染(Shader)的用处

     本文在讨论的主题并不限于具体引擎或具体语言,为了说明方便可能会提到Unity的一些内容. 最近渐渐发现很多从事游戏开发的新人,对于学会写Shader似乎总是有几分神往,但一般入了门或者学了一段时间后 ...

  5. 【游戏渲染】【译】Unity3D Shader 新手教程(1/6)

    http://gad.qq.com/article/detail/7175490 该文章来自用户转载 点击阅读原文 刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散, ...

  6. 开源一个简单的RTS游戏(Unity)

    apk download : https://www.taptap.com/app/202356 Video Demo : https://www.bilibili.com/video/BV1vK4y ...

  7. 【Unity3D开发小游戏】《我的世界游戏》Unity开发教程

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 QQ群:1040082875 一.前言 这套教程涵盖了Unity Mesh编程.模拟水算法(water s ...

  8. 3D游戏场景DEMO——添加水体效果

    好久没写了,5月初就把地形弄差不多了,后来几天把天空穹改了下,弄了多重纹理云彩飘动. 之后一直在做水体的实现,发现水体太烦了.原以为比较简单没地形复杂,结果一查阅资料,天呐--比地形复杂多了.和地形也 ...

  9. 在多个游戏视图间切换实现效果

    2019独角兽企业重金招聘Python工程师标准>>> 在多个游戏视图间切换实现效果 2.2.3  实现效果 将脚本加到CameraSwitch上,并选中此游戏对象,在Inspect ...

最新文章

  1. java:this和super
  2. Struts2的声明式异常处理
  3. spring 事务案例--转账
  4. 创建AD域之后设置DNS服务访问外网
  5. idea 中文字体 自动变_提高工作效率,我推荐讯飞语记,瞬间语音秒变文字
  6. 让你博客的代码显示得更酷
  7. LOL登录后黑屏,主界面一直加载解决办法
  8. 世界地图html效果,html5 css3响应式世界地图代码
  9. SVD专题1 算子的奇异值分解——矩阵形式的推导
  10. Excel技巧:如何将数值改成以万为单位,且保留小数点两位?
  11. 奇异值分解(SVD) --- 线性变换几何意义
  12. 海信android电视直播软件,2017年,海信电视看电视必装的四大直播软件
  13. 公众号对接淘宝联盟_公众访问新联盟支持的作品
  14. 微软小冰的“体面告别”
  15. 基于bp神经网络的pid算法,神经网络pid控制器设计
  16. JAVA-乐观锁更新失败或业务异常后接口重试
  17. ftp关键技术二:nobody进程创建和使用(一)
  18. fcpx插件:Stupid Raisins Flow Pop(48个平滑和无缝过渡)
  19. probe request帧结构_WIFI探针原理
  20. java连接derby数据库

热门文章

  1. input 测试工具 3 getevent
  2. matlab程序 材料力学,基于材料力学MATLAB系统设计报告(内含).doc
  3. Mysql高级 索引优化
  4. 怎样减肚子效果最好?练这6个瑜伽动作就够了
  5. UE4 虚幻引擎 GitSourceControl源码解析
  6. c++ 单机版授权时间原理
  7. Smallest Substring
  8. FormatNumber函数
  9. 用Unity2D画节点和线段
  10. 英文文本情感分析textblob模块sentiment方法