unity海边波浪效果的实现
效果图如下(GIF因为为了把图压小所以删掉了一些帧导致后面速度突然很快,实际效果并不是这样~_~)
之前在玩很多游戏的时候,注意到里面的海水和陆地相交接的地方会产生海浪,比如《海岛奇兵》,以及水面会出现一个透明渐隐的过度,而不会在水面和陆地的交界处产生硬切边。其中海浪的效果考虑到可以使用单独的面片来制作,不过最近在试着通过深度比较的方式直接计算出水面和陆地相交接的位置来制作海边的浪花,这种方式很多效果都会用到,其中比如unity粒子shader的软粒子计算部分(当使用软粒子时粒子的面片和其它物体交叉时不会出现明显的切边,而是有一个过度),还有之前在网上看到的别人的热扭曲效果。
以下例子只讲如何实现浪花,水的反射和折射有时间另外写。另外我的水shader中从潜水处到深水处的颜色渐变也是通过深度比较来完成的。
首先来讲解一下深度比较的原理,其实很简单,就是比较水面的z深度和已写入缓存的陆地的深度(准确的说是渲染到深度图的深度值,也就是_CameraDepthTexture,若要在shader中能读到有效的深度图,摄像机的depthTextureMode要设置为DepthTextureMode.Depth),计算一个深度差,很明显,水面和陆地部分交接的深度差是0,(因为都已经交叉在一起了),而水越深的地方深度差显然越大,如下图
unity内置粒子shader中使用深度差实现软粒子的代码如下:
- #ifdef SOFTPARTICLES_ON
- float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
- float partZ = i.projPos.z;
- float fade = saturate (_InvFade * (sceneZ-partZ));
- i.color.a *= fade;
- #endif
其中LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)))表示对深度图_CameraDepthTexture进行纹理投射,SAMPLE_DEPTH_TEXTURE_PROJ是定义在UnityCG.cginc文件中的,相当于tex2Dproj,事实上只是多了对当前的图形api做了判断而已。
i.projPos.z的值来自顶点函数,代码如下:
- v2f o;
- o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
- #ifdef SOFTPARTICLES_ON
- o.projPos = ComputeScreenPos (o.vertex);
- COMPUTE_EYEDEPTH(o.projPos.z);
- #endif
而这一段就是软粒子中计算深度差的部分:
- float fade = saturate (_InvFade * (sceneZ-partZ));
我想读到这里你一定会产生一个疑问,既然深度差是计算水面深度和深度图也就是_CameraDepthTexture中的深度的差,那么为什么水的平面不会写入_CameraDepthTexture中呢,因为如果水的深度写入了_CameraDepthTexture,必然会出现水的深度和_CameraDepthTexture中自己的深度比较,此时任何一个像素位置的深度差都是0。这里我要讲一下Unity中深度图的渲染方式,如果有接触过unity中的材质替代渲染,应该知道材质替代渲染是替换掉场景中某个标签的shader,而unity中深度图的渲染方式实际上就是这样,而它替带渲染的标签就是"RenderType",其中"RenderType"="Opaque"的物体会被渲染到深度图中,而"RenderType"="Transparent"的shader则不会被渲染,而我这边的水就使用了这个标签,因此它是不会被渲染到深度图的。
接下来由于在顶点函数中我们使用了
- COMPUTE_EYEDEPTH
来计算深度,因此深度图的深度也需要转换到视空间,即使用LinearEyeDepth。
此时如果直接输出深度差应该会得到这样的效果:
注意水面和陆地交叉的地方因为深度差最小所以最暗,而水较深的地方则表现出白色。
此时我们实际上只需要在shader中输入两个值,对应潜水处的深度差和较深处的深度差,并使用插值,就能产生水边海浪泡沫的效果了:
如上。
当然这一部分还只是产生还边海浪泡沫的部分,接下来需要讲的是能像真正的海浪一样不断冲刷海滩的浪花。
一般想到浪花,其实应该很容易想到使用类似正余弦函数来模拟的方式,(当然顶点水波只靠普通的正余弦还是达不到很好的效果的,不过这里不讨论)这是一种很简单的方式,而我的浪花就使用了正弦函数。我使用了这样一张贴图:
用这张贴图来模拟反复冲刷的海浪,并通过sin函数和_Time来偏移uv来实现,那么现在的问题是如何知道海浪的方向。
其实可以回顾上面讲的,我们知道海水和陆地的交叉处深度差是0,而深水处的深度差则比较大,不妨把深度差绘制成一条轴:
那么以深度差和时间作为sin函数的参数既可以计算出海浪纹理的uv偏移量了
大致为
deltaDepth+sin(_Time.x*_WaveSpeed)
当然直接这样产生的效果,各部分海浪的相位都一致,会导致海浪效果像平滑的光圈一样放大缩小,所以我用了一张躁波贴图来扰乱海浪的相位
最后效果如下:
大致就是这样,最后附上完整代码和资源
- Shader "Water/SeaWave" {
- Properties {
- _WaterTex ("WaterTex", 2D) = "black" {}
- _WaveTex ("WaveTex", 2D) = "black" {} //海浪
- _BumpTex ("BumpTex", 2D) = "bump" {}
- _GTex ("Gradient", 2D) = "white" {} //海水渐变
- _NoiseTex ("Noise", 2D) = "white" {} //海浪躁波
- _WaterSpeed ("WaterSpeed", float) = 0.74 //海水速度
- _WaveSpeed ("WaveSpeed", float) = -12.64 //海浪速度
- _WaveRange ("WaveRange", float) = 0.3
- _NoiseRange ("NoiseRange", float) = 6.43
- _WaveDelta ("WaveDelta", float) = 2.43
- _Refract ("Refract", float) = 0.07
- _Specular ("Specular", float) = 1.86
- _Gloss ("Gloss", float) = 0.71
- _SpecColor ("SpecColor", color) = (1, 1, 1, 1)
- _Range ("Range", vector) = (0.13, 1.53, 0.37, 0.78)
- }
- CGINCLUDE
- fixed4 LightingWaterLight(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) {
- half3 halfVector = normalize(lightDir + viewDir);
- float diffFactor = max(0, dot(lightDir, s.Normal)) * 0.8 + 0.2;
- float nh = max(0, dot(halfVector, s.Normal));
- float spec = pow(nh, s.Specular * 128.0) * s.Gloss;
- fixed4 c;
- c.rgb = (s.Albedo * _LightColor0.rgb * diffFactor + _SpecColor.rgb * spec * _LightColor0.rgb) * (atten * 2);
- c.a = s.Alpha + spec * _SpecColor.a;
- return c;
- }
- ENDCG
- SubShader {
- Tags { "RenderType"="Transparent" "Queue"="Transparent"}
- LOD 200
- GrabPass{}
- zwrite off
- CGPROGRAM
- #pragma surface surf WaterLight vertex:vert alpha
- #pragma target 3.0
- sampler2D _GTex;
- sampler2D _WaterTex;
- sampler2D _BumpTex;
- sampler2D _CameraDepthTexture;
- sampler2D _GrabTexture;
- half4 _GrabTexture_TexelSize;
- sampler2D _NoiseTex;
- sampler2D _WaveTex;
- float4 _Range;
- half _WaterSpeed;
- half _WaveSpeed;
- fixed _WaveDelta;
- half _WaveRange;
- fixed _Refract;
- half _Specular;
- fixed _Gloss;
- half _NoiseRange;
- struct Input {
- float2 uv_WaterTex;
- float2 uv_NoiseTex;
- float4 proj;
- float3 viewDir;
- };
- void vert (inout appdata_full v, out Input i) {
- UNITY_INITIALIZE_OUTPUT(Input, i);
- i.proj = ComputeScreenPos(mul(UNITY_MATRIX_MVP, v.vertex));
- COMPUTE_EYEDEPTH(i.proj.z);
- }
- void surf (Input IN, inout SurfaceOutput o) {
- float2 uv = IN.proj.xy/IN.proj.w;
- #if UNITY_UV_STARTS_AT_TOP
- uv.y = 1 - uv.y;
- #endif
- 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;
- 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;
- half2 offset = UnpackNormal(offsetColor).xy * _Refract;//用于折射的uv偏移量
- half m_depth = LinearEyeDepth(tex2Dproj (_CameraDepthTexture, IN.proj).r);
- half deltaDepth = m_depth - IN.proj.z;//计算深度差
- fixed4 noiseColor = tex2D(_NoiseTex, IN.uv_NoiseTex);
- half4 bott = tex2D(_GrabTexture, uv+offset);
- fixed4 waterColor = tex2D(_GTex, float2(min(_Range.y, deltaDepth)/_Range.y,1));
- fixed4 waveColor = tex2D(_WaveTex, float2(1-min(_Range.z, deltaDepth)/_Range.z+_WaveRange*sin(_Time.x*_WaveSpeed+noiseColor.r*_NoiseRange),1)+offset);
- waveColor.rgb *= (1-(sin(_Time.x*_WaveSpeed+noiseColor.r*_NoiseRange)+1)/2)*noiseColor.r;
- fixed4 waveColor2 = tex2D(_WaveTex, float2(1-min(_Range.z, deltaDepth)/_Range.z+_WaveRange*sin(_Time.x*_WaveSpeed+_WaveDelta+noiseColor.r*_NoiseRange),1)+offset);//这里计算了两个海浪,其中第二个海浪和第一个海浪存在相位差
- waveColor2.rgb *= (1-(sin(_Time.x*_WaveSpeed+_WaveDelta+noiseColor.r*_NoiseRange)+1)/2)*noiseColor.r;
- half water_A = 1-min(_Range.z, deltaDepth)/_Range.z;
- half water_B = min(_Range.w, deltaDepth)/_Range.w;
- 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;
- o.Normal = UnpackNormal(bumpColor).xyz;
- o.Specular = _Specular;
- o.Gloss = _Gloss;
- o.Albedo = bott.rgb * (1 - water_B) + waterColor.rgb * water_B;
- o.Albedo = o.Albedo * (1 - water.a*water_A) + water.rgb * water.a*water_A;
- o.Albedo += (waveColor.rgb+waveColor2.rgb) * water_A;
- o.Alpha = min(_Range.x, deltaDepth)/_Range.x;
- }
- ENDCG
- }
- FallBack "Diffuse"
- }
unity海边波浪效果的实现相关推荐
- 【游戏渲染】unity海边波浪效果的实现
http://blog.csdn.net/mobilebbki399/article/details/50493117 效果图如下(GIF因为为了把图压小所以删掉了一些帧导致后面速度突然很快,实际效果 ...
- 【Unity Shader】unity海边波浪效果的实现
效果图如下(GIF因为为了把图压小所以删掉了一些帧导致后面速度突然很快,实际效果并不是这样~_~) PS.对于移动端,参考该文章:http://www.lsngo.net/2018/03/22/uni ...
- 纯 CSS 实现波浪效果!
一直以来,使用纯 CSS 实现波浪效果都是十分困难的. 因为实现波浪的曲线需要借助贝塞尔曲线. 而使用纯 CSS 的方式,实现贝塞尔曲线,额,暂时是没有很好的方法. 当然,借助其他力量(SVG.CAN ...
- android动态波浪效果,android贝塞尔曲线实现波浪效果
本文实例为大家分享了android贝塞尔曲线实现波浪效果的具体代码,供大家参考,具体内容如下 因为手机录制gif不知道下什么软件好,所以暂时就先忽略效果图了 我在屏幕外多画了1.5个波浪,延伸至屏幕内 ...
- 用 radial-gradient 实现波浪效果
先上效果图 codepen: https://codepen.io/linghucq1/pen/zQjqZv?editors=1100 简单画一下原理 图中的波浪线 L 就是我们要的,它是沿着上下两排 ...
- unity 条目换位效果_Unity AI主题博客条目
unity 条目换位效果 Welcome to the first of Unity's new AI-themed blog entries! We have set up this space a ...
- android波浪动画简书,Android贝塞尔曲线————波浪效果(大波浪)
Hello大家好,很高兴又一次与大家见面,今天是农历丁酉鸡年(大年初四),现在跟大家拜年有点晚,算是拜晚年,祝大家晚年幸福. 这么快大伙都到了晚年了,Android贝塞尔曲线我也准备以一个大波浪来结束 ...
- html5制作波浪,技能get:用HTML5实现波浪效果
rr Document .box{ width: 500px; height: 500px; margin:100px auto; background:hotpink; border-radius: ...
- android录音波浪动画_Android实现波浪效果 - WaveView
效果图 先上效果图 screenshot.gif 实现 WaveView的属性 WaveView的属性 Wate Level(水位) - 波浪静止时水面距离底部的高度 Amplitude(振幅) - ...
最新文章
- deeplearning 重要调参参数分析
- Datawhale编程——动态规划DP
- 如何高效学习 Kubernetes 知识图谱?
- 算法之动态规划——编辑距离问题
- 这些新技术你们都知道吗?成功收获美团,小米安卓offer
- 猜数字游戏python程序_【自学编程】python 小游戏—猜数字
- SAP学习记__物料管理(MM)模块__采购入库冲销、退货
- JAVA分页查询实现
- 你知道 FW 工程师 是做什么的吗?
- 苹果手机屏幕镜像_苹果手机还能一键投屏?点一下小屏变大屏幕,看剧是真畅快...
- java毕业设计老师评语_java教学评价管理系统毕业设计答辩PPT.ppt
- 互联网产品经理必读书目推荐
- 备战数学建模33-灰色预测模型2
- 刑侦 技侦 警种
- f2fs学习笔记 - 5. f2fs基本类图
- Python第三章总结
- CHIL-SQL-GROUP BY 语句
- 985毕业,半路出家28岁进军Java,坚持奋斗了三年现如今年薪36W+
- python学习之numpy——通用函数ufunc( sqrt() , maximun() ,modf() )
- 基于SNMP在网络监控中的应用1_OLT设备的监控
热门文章
- 风靡全网的《看漫画学Python》1、2版分享,python最佳入门教程,中学生用业余时间都能学会,北大教授看完都这样定义它
- 用H5实现四宫格切换九宫格,再切换十六宫格
- android 应用图标缓存清理,垃圾缓存清理大师
- 1254计算机组成原理试题,国家开放大学电大本科《计算机组成原理》2021期末试题及答案(1254)...
- 如何在ppt中生成柱状图_ppt中如何添加柱状图 - 卡饭网
- A - Smallest Sub-Array
- 理解Java的三大特性之多态
- Introduce·艺术学核心期刊推荐之《文艺理论研究》
- 基于CANoe的Bootloader上位机软件 下位机为飞思卡尔MC9S12G128MLL
- 校招简历书写策略与投递要点