针对之前的水面漩涡效果做了些改进。之前的漩涡效果参考:
就是爱折腾:Unity Shader实现一个水面漩涡的效果 zhuanlan.zhihu.com
主要是加了透明折射的效果,看起来更接近真实的漩涡。如图:


之前实现的漩涡效果是没有考虑这种折射效果的。所以采用了比较简单的方式,直接给水加个光照就完事了。后面想想,还是想做的更真实些。于是我开始考虑使用GrabPass这种方式,但是貌似Surface Shader中不怎么好实现这个效果(可能也是我水平有限,如果有大佬知道的话,望指出),所以我把前面的surface shader改写成了基于顶点片元的。
改完后,遇到了第一个问题便是曲面细分效果没了,毕竟之前用surface shader弄起来是so easy啊,但现在是顶点片元了,刚开始还是一脸懵逼。后面我查了些资料,摸索出了解决办法:
就是爱折腾:Unity曲面细分的原理与应用2 zhuanlan.zhihu.com
看现实当中的水,漩涡处的折射效果(扭曲)是比其它地方强的。这个效果,我直接简单的使用网格的局部空间的顶点位置来设置(这里肯定有更好的办法,不过我为了偷懒):顶点偏移越大,扭曲越厉害。

通过这些修改,上面的效果就完成了!下面是完整代码:
Shader "Water/VotexExtendPure"
{
Properties
{
_BaseColor ("BaseColor", Color) = (1,1,1,1)
[Normal]_NormalTex ("Normal", 2D) = "white" {}
_FoamTex("FoamTex",2D) = "white"{}
_FoamStrengh("FoamStrengh",Range(0,1)) = 0.2
_XSpeed("XSpeed",Range(0,1)) = 0.2
_YSpeed("YSpeed",Range(0,1)) = 0.2
_Gloss("Gloss",Range(0,0.1)) = 0.1
_SpecStrengh("SpecStrengh",Range(0,0.01)) = 1
_RefractionAmount("RefractAmount",Range(0,100)) = 5
_TessellateAmount("TessellateAmount",float) = 4
_Votex_Para("Center",vector) = (0.5,0.5,0.2,0) //x,y:漩涡中心 z:漩涡半径
_Votex_depth("Votex Depth",Range(0,4)) = 0.1 //漩涡深度
_Votex_distortAmount("Votex_distortAmount",Range(0,20)) = 2 //扭曲力度
_Shape_distortAmount("Shape_distortAmount",Range(0,1)) = 0.5//漩涡塑形
}
CGINCLUDE
#include "Assets/Shaders/1UPUtility.cginc"
#include "Assets/Shaders/1UPMath.cginc"
sampler2D _NormalTex,_FoamTex;
half4 _NormalTex_ST,_FoamTex_ST;
float _XSpeed,_YSpeed,_Gloss,_SpecStrengh,_TessellateAmount,_FoamStrengh;
fixed4 _BaseColor,_Votex_Para;
float _Votex_depth,_Votex_distortAmount,_Shape_distortAmount,_RefractionAmount;
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
struct v2f
{
float4 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
float3 normal:NORMAL;
float4 screenPos:TEXCOORD2;
float4 localPosition:TEXCOORD3;
};
v2f vert (appdata_base v)
{
v2f o;
float3 center = float3(_Votex_Para.x,0,_Votex_Para.y);
float radius = _Votex_Para.z;
float dis = distance(v.vertex.xyz,center);
float s = saturate((radius - dis)) / radius;
float ss = s * s;
//越靠近漩涡中心,顶点偏移量越大。ss = s*s,能够产生漩涡的弧形
float offsetN = _Votex_depth * ss;
//进行顶点的偏移
v.vertex.xyz = v.vertex.xyz - v.normal * offsetN;
//扭曲(三步:将漩涡中心移到零点->绕y轴旋转->将漩涡中心移回原处)
float3 tempVertex = v.vertex.xyz -center;
tempVertex += ss * _Shape_distortAmount;
tempVertex = mul(MATRIX_3_Y(ss * _Votex_distortAmount),tempVertex);
v.vertex.xyz = tempVertex+center;
o.uv.xy = v.texcoord.xy * _NormalTex_ST.xy + _NormalTex_ST.zw;
o.uv.zw = v.texcoord.xy * _FoamTex_ST.xy + _FoamTex_ST.zw;
o.localPosition = v.vertex;
o.vertex = UnityObjectToClipPos(v.vertex);
o.normal = v.normal;
o.screenPos = ComputeGrabScreenPos(o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 mainColor = _BaseColor;
float4 worldPosition = mul(unity_ObjectToWorld,i.localPosition);
float3 n1 = UnpackNormal(tex2D(_NormalTex,i.uv.xy + float2(_XSpeed,_YSpeed) * 0.1 * _Time.y));
float3 n2 = UnpackNormal(tex2D(_NormalTex,i.uv.xy - float2(_XSpeed,_YSpeed) * 0.1 * _Time.y));
float3 offset = BlendNormalRNM(n1,n2);
//泡沫
fixed4 foamColor = tex2D(_FoamTex,i.uv.zw);
mainColor += foamColor * _FoamStrengh;
//透明
i.screenPos.xy /= i.screenPos.w;
//折射(漩涡处折射加大)
i.screenPos.xy += offset.xy * (_RefractionAmount + abs(i.localPosition.y) * 400) * _GrabTexture_TexelSize.xy;
fixed4 backColor = tex2D(_GrabTexture,i.screenPos.xy);
mainColor *= backColor;
//光照(高光部分没有法线只是随便加了以下,偷懒)
half3 worldViewDir = normalize(WorldSpaceViewDir(worldPosition));
half3 worldLightDir = normalize(WorldSpaceLightDir(worldPosition));
half3 objectWorldNormal = UnityObjectToWorldNormal(i.normal);
half3 specular = Highlights(worldPosition.xyz,_Gloss,normalize(objectWorldNormal - offset),worldViewDir,worldLightDir);
mainColor.rgb += specular * _SpecStrengh * (0.05 + abs(i.localPosition.y) * 400);
// mainColor.rgb = specular;
return mainColor;
}
//曲面细分
// tessellation vertex shader
struct InternalTessInterp_appdata_base {
float4 vertex : INTERNALTESSPOS;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
InternalTessInterp_appdata_base tessvert_surf (appdata_base v) {
InternalTessInterp_appdata_base o;
o.vertex = v.vertex;
o.normal = v.normal;
o.texcoord = v.texcoord;
return o;
}
// tessellation hull constant shader
UnityTessellationFactors hsconst_surf (InputPatch<InternalTessInterp_appdata_base,3> v) {
UnityTessellationFactors o;
float4 tf;
tf = _TessellateAmount;
o.edge[0] = tf.x; o.edge[1] = tf.y; o.edge[2] = tf.z; o.inside = tf.w;
return o;
}
// tessellation hull shader
[UNITY_domain("tri")]
[UNITY_partitioning("fractional_odd")]
[UNITY_outputtopology("triangle_cw")]
[UNITY_patchconstantfunc("hsconst_surf")]
[UNITY_outputcontrolpoints(3)]
InternalTessInterp_appdata_base hs_surf (InputPatch<InternalTessInterp_appdata_base,3> v, uint id : SV_OutputControlPointID) {
return v[id];
}
// tessellation domain shader
[UNITY_domain("tri")]
v2f ds_surf (UnityTessellationFactors tessFactors, const OutputPatch<InternalTessInterp_appdata_base,3> vi, float3 bary : SV_DomainLocation) {
appdata_base v;UNITY_INITIALIZE_OUTPUT(appdata_base,v);
v.vertex = vi[0].vertex*bary.x + vi[1].vertex*bary.y + vi[2].vertex*bary.z;
v.normal = vi[0].normal*bary.x + vi[1].normal*bary.y + vi[2].normal*bary.z;
v.texcoord = vi[0].texcoord*bary.x + vi[1].texcoord*bary.y + vi[2].texcoord*bary.z;
v2f o = vert (v);
return o;
}
ENDCG
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
GrabPass{
"_GrabTexture"
}
Pass
{
CGPROGRAM
#pragma vertex tessvert_surf
#pragma fragment frag
#pragma hull hs_surf
#pragma domain ds_surf
#pragma target 5.0
// make fog work
#pragma multi_compile_fog
#pragma nodynlightmap nolightmap
#include "UnityCG.cginc"
ENDCG
}
}
}
来源:oschina
链接:https://my.oschina.net/u/4361935/blog/4280796