一、首先建立一个最基本的最简单的Shader
Shader "Customer/Water01"
{
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
Name "FORWARD"
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
// 输入结构
struct appdata
{
float4 vertex : POSITION;
};
// 输出结构
struct v2f
{
float4 pos : SV_POSITION; // 由模型顶点信息换算而来的顶点屏幕位置
};
sampler2D _MainTex;
float4 _MainTex_ST;
// 输入结构>>>顶点Shader>>>输出结构
v2f vert (appdata v)
{
v2f o = (v2f)0;// 新建一个输出结构
o.pos = UnityObjectToClipPos(v.vertex);// 变换顶点信息 并将其塞给输出结构
return o; // 将输出结构 输出
}
// 输出结构>>>像素
fixed4 frag (v2f i) : COLOR
{
return float4(0.0, 1.0, 0.0, 1.0);
}
ENDCG
}
}
}
这时候场景中shader的输出是绿色的。
二、分析做流水的思路
首先是要达到的效果:
- 可以设置水的颜色。比如河流多是浅绿色,海和池塘多事蓝色。
- 波浪效果
思路:UV顶点位置随时间做波形变化 - 水的透明效果
思路:对背景采样。 - 可以设置波浪形状。比如海浪,河浪,溪流波纹,池塘波纹等。
思路:采样波浪纹理。 - 有泡沫
思路:采样噪声 - 波纹扰动
思路:采样波纹纹理,并让波纹纹理流动起来 - 水的倒影(折射)
- 水的菲尼尔现象(反射)
- 岸边的边界线或者和物体接触的边界线
- 水的浮力(深度计算,暂时不做)
1、水的颜色这个很好做,开放一个可以设置颜色的参数即可。
2、波浪效果。
如果简单得用一个正弦波表示波形,那么波形就会显得比较单调,更好的做法就是采样一张波形纹理法线,用颜色的深度表示作为波浪的高度。然后让高度值随时间做一个波形变化即可达成。这里引出一个问题就是,波形能变动了,但是变动后的波形的光照效果如何做。这里需要用到的原理可以参照Unity自带的凹凸漫反射Shader做法。放到第二篇去做像素shader的内容。
Shader "Customer/Water01"
{
Properties
{
_Color("Color水颜色", color) = (0,0,0.8,0.5)
_WaveNormalMap("Wave Normal Map", 2D) = "bump"{}
_WaveHeight("Wave Height",Range(0,1)) = 0.1
_WaveNormalScale("Wave Scale", float) = 10.0
_WaveNormalSpeed("Wave Speed", float) = 1.0
_waveNumber("Wave Number",float) = 4
_WaveTex("Wave Tex", 2D) = "black" {}
_BigWaveSpeed("Big Wave Speed",float) = 10
_BigWaveHeight("Big Wave Height",float) = 0.5
_BigWaveNumber("Big Wave Number",float) = 10
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"RenderType" = "Transparent"
}
GrabPass{
"_GrabPassTex"
}
LOD 100
Pass
{
Name "FORWARD"
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
float4 _Color;
sampler2D _WaveNormalMap;
fixed _WaveHeight;
float _WaveNormalScale;
fixed _WaveNormalSpeed;
fixed _waveNumber;
fixed _dividHeight;
fixed _BigWaveSpeed;
fixed _BigWaveHeight;
fixed _BigWaveNumber;
// 输入结构
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal:NORMAL;//法线通常都是必须的
float4 tangent : TANGENT;
float3 color:COLOR0;
};
// 输出结构
struct v2f
{
float4 uv : TEXCOORD0;
float4 vertex : SV_POSITION; // 由模型顶点信息换算而来的顶点屏幕位置
float depth : TEXCOORD2;
float3 normal:NORMAL;//法线通常都是必须的
float4 lightDir_Tangent:TEXCOORD5;
float4 screenuv:TEXCOORD1;
float3 viewDir:TEXCOORD3;
float4 vertex_Local : TEXCOORD4;
float3 color:COLOR0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
// 输入结构>>>顶点Shader>>>输出结构
v2f vert (appdata v)
{
v2f o;
UNITY_INITIALIZE_OUTPUT(v2f, o);
//获取自身深度值
COMPUTE_EYEDEPTH(o.depth);
float2 flow = float2(_Time.x*_WaveNormalSpeed, _Time.z*1.215*_WaveNormalSpeed);
fixed3 n = UnpackNormal(tex2Dlod(_WaveNormalMap, float4(v.uv.xy*_WaveNormalScale + flow, 0, 0))).xyz;
float height = 0;
fixed wavebevel = 5;
fixed attenuation = (1.0 - v.uv.y);
fixed b = 0.8;
fixed x = v.uv.y + b * sin(v.uv.y);
if (v.vertex.y > _dividHeight)
{
height = (cos(x*_BigWaveNumber - _Time.z*_BigWaveSpeed + v.uv.x*wavebevel) + 1)*0.5*_BigWaveHeight*attenuation;
height += (cos(x*_BigWaveNumber - _Time.z*_BigWaveSpeed + (1.0 - v.uv.x)*wavebevel) + 1)*0.5*_BigWaveHeight*attenuation;
}
v.vertex.y = v.vertex.y + n * _WaveHeight + height;
if (v.vertex.y > _dividHeight)
v.vertex.z -= height * 0.1;
o.vertex = UnityObjectToClipPos(v.vertex);
_FOG(o, o.vertex);
return o;
}
// 输出结构>>>像素
fixed4 frag (v2f i) : COLOR
{
float4 finalCol = _Color;
//return finalCol;
return float4(0.0, 1.0, 0.0, 1.0);
}
ENDCG
}
}
}
其中采用噪声纹理产生高度的代码是这句。
fixed3 n = UnpackNormal(tex2Dlod(_WaveNormalMap, float4(v.uv.xy*_WaveNormalScale + flow, 0, 0))).xyz;
(注:DepthMap纹理的采样通常用tex2Dlod)
float2 flow = float2(_Time.x_WaveNormalSpeed, _Time.z1.215_WaveNormalSpeed);
是为了让采样到的纹理值能随时间变动。
另外不用UnpackNormal这个反映射方法,用下面这种写法也是可以的:
//float tempN = tex2Dlod(_WaveNormalMap, float4(v.uv.xy_WaveNormalScale + flow, 0, 0)).g;这种写法也
//v.vertex.y = v.vertex.y + tempN * _WaveHeight + height;
通过采用深度,并做随时间上的变化,已经有了波浪的效果。波形随时间变化部分参照网上其他人的经验做法。
1.gif
波形的一些控制参数
image.png
网友评论