寻找更好的海水的移动解决方案
发表于2018-06-28
本来已经实现了海岛奇兵的海水,但总觉得差点意思。(海岛奇兵海水地址:https://blog.csdn.net/yxriyin/article/details/78708040 )
打算进一步优化一下。
顶点着色器并不需要变化(以后打算加入波动模型,但现在暂时不考虑,因为是在很远的地方看海)
片段着色器我首先想的是增加一张法线贴图,用来模拟海浪的波纹,因为海盗奇兵是波光,而不是波纹,所以看上去稍微有点呆板。
float4变量offsetColor =(tex2D(_BumpTex,i.bumpCoord + FLOAT2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,FLOAT2(1 - i.bumpCoord .y,i.bumpCoord.x)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2;
half2 offset = UnpackNormal(offsetColor).xy * _Refract;
float4 bumpColor =(tex2D(_BumpTex,(i.bumpCoord + offset)+ float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,(float2(1 - i.bumpCoord.y,i.bumpCoord.x )+ offset)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2;
float3 Normal = UnpackNormal(bumpColor).xyz;
color = _PureColor * _Pure +(1-Pure)* color;
color.rgb = color.rgb * 1.2;
原理很简单,就是通过法线贴图的uv偏移,制造海水流动的感觉,其中_PureColor的用途后面再说。
如果只是 这样还远远不够,因为法线必须要有光照才能有更好的效果,但我的目标是移动平台的中低端机,所以肯定不会使用自带的光照,而是直接自己模拟一个最简单的光照和计算
。float3 lightDir = normalize (float3(1,1,1));
half3 halfVector = normalize(lightDir);
float diffFactor = max(0,dot(lightDir,Normal));
float addValue = min(0.2,exp2(log2(((normalMapValue.z * i.args.x *(1 - Pure * 0.8))+
(normalMapValue.w *(1.0 - i.args.x *(1 - Pure ))* i.args.y * 0.8))*((1-i.args.y)* _Pure + i.args.y))* 5.0));
颜色+ = addValue;
color.rgb + = color.rgb * diffFactor * strength;
通过法线和光线的夹角,计算出明暗的分量,加到海水颜色上。
简单处理后,效果已经有所体现:但这 还不够,海面本身的效果和海岸效果都不能少。 于是打算根据深度来计算海岸部分的变化。由于手机上对深度图的获取比较耗性能,所以还是打算使用额外的一张贴图来表示深度。越白的地方越浅,越黑的地方越深。我自己取了海岛模型的外轮廓,然后用PS做了一个简单的外发光处理,就当做深度图了。当然如果有美术帮忙,可以根据高度图得到一个完美的深度图,但作为测试,先这样子吧。 然后就是代码: float deltaDepth = tex2D(_DepthTex,i.texcoord * 10).a; color.rgb + = color.rgb * diffFactor *(1 - min(1,deltaDepth * 2)); 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;
color.rgb + =(waveColor.rgb + waveColor2.rgb)* water_A;
color.a = min(1,deltaDepth * 1.5);
原理也不难,就是根据深度,获取波浪贴图的像素,渲染到海面上,因为波浪要有运动,所以增加了一个sin函数来实现这种变化。另外为了使变化不要那么规则,增加了一个噪点来扭曲海面。
效果如下: 。然后再说一下_PureColor,主要是因为镜头拉高到一定程度之后,海面上的明暗其实是很刺眼的于是模拟了一个减弱振幅, 根据摄像机和海面的距离调整海面的变化强度。

。打算未来更多增加的特性参数状语从句:适用来风格不同游戏的
目前已经上传资产仓库上面了,地址是:
https://www.assetstore.unity3d.com/en/#!/content/120466
已向官方申请打折,不知道会不会通过,哈哈。
最后是片段着色器完整的源代码:
注意:
用'UnityObjectToClipPos(*)'
替换'mul(UNITY_MATRIX_MVP,*)'//升级注意: UnityObjectToClipPos(*)'
//升级注意:用'UnityObjectToClipPos(*)'
Shader“ Ocean2 ”
{
Properties
{
_MainTex(“Base(RGB),Alpha(A)”,2D)替换'mul(UNITY_MATRIX_MVP,*) “Black”{}
_MainTex1(“Base(RGB),Alpha(A)”,2D)=“black”{}
Map(“Base(RGB),Alpha(A)”,2D)=“black”{}
_BumpTex (” BumpTex“,2D)=”bump“{}
_DepthTex(”_ DepthTex“,2D)=”black“{}
_WaveTex(“_ WaveTex”,2D)=“white”{}
_WaterSpeed(“_ WaterSpeed”,float)= 1
_Refract(“_ Refract”,Range(0,0.1))= 0.03
strength(“strength” ))= 0.5
_Alpha(“_ Alpha”,Range(0,1))= 1
_Pure(“_ Pure”,Range(0,1))= 1
_PureColor(“_ PureColor”,Color)=(0, 0)
_Range(“Range”,vector)=( 0.13,1.53,0.37,0.78 )
}
SubShader
{
LOD 100
Tags
{
“Queue”=“ Geometry-1000“
”IgnoreProjector“=”False“
//“RenderType”=“Transparent”
}
//混合一个
//混合SrcAlpha OneMinusSrcAlpha
混合SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
//升级注意:排除DX11中的着色器; 没有语义的结构(struct v2f members v_darkColor)
#pragma exclude_renderers d3d11
#pragma vertex vert
#pragma fragment frag
#include“UnityCG.cginc”
struct appdata_t
{
float4 vertex:POSITION;
float2 texcoord:TEXCOORD0;
};
结构v2f
{
float4 pos:SV_POSITION;
float2 texcoord:TEXCOORD0;
float2 normalCoord:TEXCOORD1;
float2 bumpCoord:TEXCOORD2;
float4 color:COLOR;
float2 args:TEXCOORD4;
};
统一浮点数_Points [25];
sampler2D _MainTex;
sampler2D _MainTex1;
sampler2D Map;
sampler2D _BumpTex;
sampler2D _DepthTex;
sampler2D _GTex;
sampler2D _WaveTex;
浮动_Pure;
浮力;
float _Alpha;
float4 _PureColor;
float _WaterSpeed;
float _Refract;
float4 _Range;
fixed4 frag(v2f i):COLOR
{
fixed4 color;
float4 normalMapValue = tex2D(Map,i.normalCoord);
color = tex2D(_MainTex,i.texcoord);
color = lerp(color,tex2D(_MainTex1,i.texcoord),(normalMapValue.x * i.args.x)+(normalMapValue.y *(1.0 - i.args.x)));
float4 offsetColor =(tex2D(_BumpTex,i.bumpCoord + float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,float2(1 - i.bumpCoord.y,i.bumpCoord.x)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2;
half2 offset = UnpackNormal(offsetColor).xy * _Refract;
float4 bumpColor =(tex2D(_BumpTex,(i.bumpCoord + offset)+ float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,(float2(1 - i.bumpCoord.y,i.bumpCoord.x )+ offset)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2;
float3 Normal = UnpackNormal(bumpColor).xyz;
color = _PureColor * _Pure +(1-Pure)* color;
color.rgb = color.rgb * 1.2;
float3 lightDir = normalize(float3(1,1,1));
half3 halfVector = normalize(lightDir);
float diffFactor = max(0,dot(lightDir,Normal));
float addValue = min(0.2,exp2(log2(((normalMapValue.z * i.args.x *(1 - Pure * 0.8))+
(normalMapValue.w *(1.0 - i.args.x *(1 - _Pure))* i.args.y * 0.8))*((1 - i.args.y)* _Pure + i.args.y) )* 5.0));
颜色+ = addValue;
color.rgb + = color.rgb * diffFactor * strength;
float index = floor(i.texcoord.x * 10)* 5 + floor(i.texcoord.y * 10);
if(_Points [index]> 0)
{
float deltaDepth = tex2D(_DepthTex,i.texcoord * 10).a;
color.rgb + = color.rgb * diffFactor *(1 - min(1,deltaDepth * 2));
//color.rgb + = color.rgb * diffFactor * strength;
float _WaveRange = 0.3;
float _WaveSpeed = -12.64;
float4 noiseColor = float4(1,1,1,1);
float _NoiseRange = 6.43;
float _WaveDelta = 2.43;
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;
// color.rgb = color.rgb * pow(deltaDepth,1)+ waterColor.rgb *(1-pow(deltaDepth,1));
// color.rgb = color.rgb *(1 - waterColor.a * water_A)+ waterColor.rgb * waterColor.a * water_A;
color.rgb + =(waveColor.rgb + waveColor2.rgb)* water_A;
// color.a = min(_Range.x,deltaDepth)/ _Range.x;
color.a = min(1,deltaDepth * 1.5);
}
color.a * = _Alpha;
// color = float4(normalMapValue.z,normalMapValue.z,normalMapValue.z,1);
返回颜色;
}
ENDCG
}
}
}
打算进一步优化一下。
顶点着色器并不需要变化(以后打算加入波动模型,但现在暂时不考虑,因为是在很远的地方看海)
片段着色器我首先想的是增加一张法线贴图,用来模拟海浪的波纹,因为海盗奇兵是波光,而不是波纹,所以看上去稍微有点呆板。
float4变量offsetColor =(tex2D(_BumpTex,i.bumpCoord + FLOAT2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,FLOAT2(1 - i.bumpCoord .y,i.bumpCoord.x)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2;
half2 offset = UnpackNormal(offsetColor).xy * _Refract;
float4 bumpColor =(tex2D(_BumpTex,(i.bumpCoord + offset)+ float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,(float2(1 - i.bumpCoord.y,i.bumpCoord.x )+ offset)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2;
float3 Normal = UnpackNormal(bumpColor).xyz;
color = _PureColor * _Pure +(1-Pure)* color;
color.rgb = color.rgb * 1.2;
原理很简单,就是通过法线贴图的uv偏移,制造海水流动的感觉,其中_PureColor的用途后面再说。
如果只是 这样还远远不够,因为法线必须要有光照才能有更好的效果,但我的目标是移动平台的中低端机,所以肯定不会使用自带的光照,而是直接自己模拟一个最简单的光照和计算
。float3 lightDir = normalize (float3(1,1,1));
half3 halfVector = normalize(lightDir);
float diffFactor = max(0,dot(lightDir,Normal));
float addValue = min(0.2,exp2(log2(((normalMapValue.z * i.args.x *(1 - Pure * 0.8))+
(normalMapValue.w *(1.0 - i.args.x *(1 - Pure ))* i.args.y * 0.8))*((1-i.args.y)* _Pure + i.args.y))* 5.0));
颜色+ = addValue;
color.rgb + = color.rgb * diffFactor * strength;
通过法线和光线的夹角,计算出明暗的分量,加到海水颜色上。
简单处理后,效果已经有所体现:但这 还不够,海面本身的效果和海岸效果都不能少。 于是打算根据深度来计算海岸部分的变化。由于手机上对深度图的获取比较耗性能,所以还是打算使用额外的一张贴图来表示深度。越白的地方越浅,越黑的地方越深。我自己取了海岛模型的外轮廓,然后用PS做了一个简单的外发光处理,就当做深度图了。当然如果有美术帮忙,可以根据高度图得到一个完美的深度图,但作为测试,先这样子吧。 然后就是代码: float deltaDepth = tex2D(_DepthTex,i.texcoord * 10).a; color.rgb + = color.rgb * diffFactor *(1 - min(1,deltaDepth * 2)); 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;
color.rgb + =(waveColor.rgb + waveColor2.rgb)* water_A;
color.a = min(1,deltaDepth * 1.5);
原理也不难,就是根据深度,获取波浪贴图的像素,渲染到海面上,因为波浪要有运动,所以增加了一个sin函数来实现这种变化。另外为了使变化不要那么规则,增加了一个噪点来扭曲海面。
效果如下: 。然后再说一下_PureColor,主要是因为镜头拉高到一定程度之后,海面上的明暗其实是很刺眼的于是模拟了一个减弱振幅, 根据摄像机和海面的距离调整海面的变化强度。
。打算未来更多增加的特性参数状语从句:适用来风格不同游戏的
目前已经上传资产仓库上面了,地址是:
https://www.assetstore.unity3d.com/en/#!/content/120466
已向官方申请打折,不知道会不会通过,哈哈。
最后是片段着色器完整的源代码:
本部分设定了隐藏,以下是隐藏的内容
注意:
用'UnityObjectToClipPos(*)'
替换'mul(UNITY_MATRIX_MVP,*)'//升级注意: UnityObjectToClipPos(*)'
//升级注意:用'UnityObjectToClipPos(*)'
Shader“ Ocean2 ”
{
Properties
{
_MainTex(“Base(RGB),Alpha(A)”,2D)替换'mul(UNITY_MATRIX_MVP,*) “Black”{}
_MainTex1(“Base(RGB),Alpha(A)”,2D)=“black”{}
Map(“Base(RGB),Alpha(A)”,2D)=“black”{}
_BumpTex (” BumpTex“,2D)=”bump“{}
_DepthTex(”_ DepthTex“,2D)=”black“{}
_WaveTex(“_ WaveTex”,2D)=“white”{}
_WaterSpeed(“_ WaterSpeed”,float)= 1
_Refract(“_ Refract”,Range(0,0.1))= 0.03
strength(“strength” ))= 0.5
_Alpha(“_ Alpha”,Range(0,1))= 1
_Pure(“_ Pure”,Range(0,1))= 1
_PureColor(“_ PureColor”,Color)=(0, 0)
_Range(“Range”,vector)=( 0.13,1.53,0.37,0.78 )
}
SubShader
{
LOD 100
Tags
{
“Queue”=“ Geometry-1000“
”IgnoreProjector“=”False“
//“RenderType”=“Transparent”
}
//混合一个
//混合SrcAlpha OneMinusSrcAlpha
混合SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
//升级注意:排除DX11中的着色器; 没有语义的结构(struct v2f members v_darkColor)
#pragma exclude_renderers d3d11
#pragma vertex vert
#pragma fragment frag
#include“UnityCG.cginc”
struct appdata_t
{
float4 vertex:POSITION;
float2 texcoord:TEXCOORD0;
};
结构v2f
{
float4 pos:SV_POSITION;
float2 texcoord:TEXCOORD0;
float2 normalCoord:TEXCOORD1;
float2 bumpCoord:TEXCOORD2;
float4 color:COLOR;
float2 args:TEXCOORD4;
};
统一浮点数_Points [25];
sampler2D _MainTex;
sampler2D _MainTex1;
sampler2D Map;
sampler2D _BumpTex;
sampler2D _DepthTex;
sampler2D _GTex;
sampler2D _WaveTex;
浮动_Pure;
浮力;
float _Alpha;
float4 _PureColor;
float _WaterSpeed;
float _Refract;
float4 _Range;
fixed4 frag(v2f i):COLOR
{
fixed4 color;
float4 normalMapValue = tex2D(Map,i.normalCoord);
color = tex2D(_MainTex,i.texcoord);
color = lerp(color,tex2D(_MainTex1,i.texcoord),(normalMapValue.x * i.args.x)+(normalMapValue.y *(1.0 - i.args.x)));
float4 offsetColor =(tex2D(_BumpTex,i.bumpCoord + float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,float2(1 - i.bumpCoord.y,i.bumpCoord.x)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2;
half2 offset = UnpackNormal(offsetColor).xy * _Refract;
float4 bumpColor =(tex2D(_BumpTex,(i.bumpCoord + offset)+ float2(_WaterSpeed * _Time.x * 0.5,0))+ tex2D(_BumpTex,(float2(1 - i.bumpCoord.y,i.bumpCoord.x )+ offset)+ float2(_WaterSpeed * _Time.x * 0.3,0)))/ 2;
float3 Normal = UnpackNormal(bumpColor).xyz;
color = _PureColor * _Pure +(1-Pure)* color;
color.rgb = color.rgb * 1.2;
float3 lightDir = normalize(float3(1,1,1));
half3 halfVector = normalize(lightDir);
float diffFactor = max(0,dot(lightDir,Normal));
float addValue = min(0.2,exp2(log2(((normalMapValue.z * i.args.x *(1 - Pure * 0.8))+
(normalMapValue.w *(1.0 - i.args.x *(1 - _Pure))* i.args.y * 0.8))*((1 - i.args.y)* _Pure + i.args.y) )* 5.0));
颜色+ = addValue;
color.rgb + = color.rgb * diffFactor * strength;
float index = floor(i.texcoord.x * 10)* 5 + floor(i.texcoord.y * 10);
if(_Points [index]> 0)
{
float deltaDepth = tex2D(_DepthTex,i.texcoord * 10).a;
color.rgb + = color.rgb * diffFactor *(1 - min(1,deltaDepth * 2));
//color.rgb + = color.rgb * diffFactor * strength;
float _WaveRange = 0.3;
float _WaveSpeed = -12.64;
float4 noiseColor = float4(1,1,1,1);
float _NoiseRange = 6.43;
float _WaveDelta = 2.43;
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;
// color.rgb = color.rgb * pow(deltaDepth,1)+ waterColor.rgb *(1-pow(deltaDepth,1));
// color.rgb = color.rgb *(1 - waterColor.a * water_A)+ waterColor.rgb * waterColor.a * water_A;
color.rgb + =(waveColor.rgb + waveColor2.rgb)* water_A;
// color.a = min(_Range.x,deltaDepth)/ _Range.x;
color.a = min(1,deltaDepth * 1.5);
}
color.a * = _Alpha;
// color = float4(normalMapValue.z,normalMapValue.z,normalMapValue.z,1);
返回颜色;
}
ENDCG
}
}
}