|
资源信息 Tutorial Information
教程名称: | Unity3D中实现常见的水面效果教程(发帖教程) |
适用引擎: | (适用引擎,为空默认为Unity) |
教程语种: | 中文 |
教程等级: | 1 |
教程格式: | 图文(请用IE9以上浏览器访问本版块) |
教程作者: | 转载自互联网 (如有问题请短消息联系作者或发表回复) |
下载地址: | 无 (兑换积分) |
一 bump
float4 temp;
temp.xyzw = v.vertex.xzxz * _WaveScale4 / unity_Scale.w + _WaveOffset;
o.bumpuv0 = temp.xy;
o.bumpuv1 = temp.wz;
首先明确unity_Scale.w的含义,个人理解为当前模型的缩放值。
w = 1 / uniform scale.
uniform float4 unity_Scale : xyz components unused; .w contains scale for uniformly scaled objects.
先排除_WaveScale4和WaveOffset因素,就是直接把plane的各点局部坐标在乘系数当成uv坐标。然后用_WaveScale4去放缩,用WaveOffset去滚动。
Vector4 waveSpeed = mat.GetVector( "WaveSpeed" );
float waveScale = mat.GetFloat( "_WaveScale" );
Vector4 waveScale4 = new Vector4(waveScale, waveScale, waveScale * 0.4f, waveScale * 0.45f);
double t = Time.timeSinceLevelLoad / 20.0;
//此帧开始的时间(只读)。这是以秒计算到最后的关卡已经加载完的时间。也就是说,从最后加载的关卡到现在所用的时间。
Vector4 offsetClamped = new Vector4(
(float)System.Math.IEEERemainder(waveSpeed.x * waveScale4.x * t, 1.0),
(float)System.Math.IEEERemainder(waveSpeed.y * waveScale4.y * t, 1.0),
(float)System.Math.IEEERemainder(waveSpeed.z * waveScale4.z * t, 1.0),
(float)System.Math.IEEERemainder(waveSpeed.w * waveScale4.w * t, 1.0)
);
//IEEERemainder返回一指定数字被另一指定数字相除的余数。
//这里这么处理好像是让生成的数据符合ieee规范还是什么,希望有懂的人能告诉我一下。
更多延伸link
mat.SetVector( "_WaveOffset", offsetClamped );
mat.SetVector( "_WaveScale4", waveScale4 );
//这样生成的波形看上去结果还不错,就先用着了。
二 fresnel
对水面来说,当观察者和水面的角度越小时,反射效果越明显,角度越大时,折射效果越明显,称为菲捏尔效果。所以需要根据观察者的角度来计算反射,折射帖图,以及水面颜色的混合方式。物理上正确的菲捏尔向计算比较复杂,通常使用近似的计算方法。
1,最高效的是假设水的颜色只与水面高度和观察者角度有关。
half fresnelTerm = saturate(dot( eyeVector,normal));
finalColor = lerp(reflectiveColor, refractiveColor,fresnelTerm);
2,在某个demo中看到的方法,也是我一直在用的。
R=normalize(eyepos-worldpos);
fastFresnel = R + ( 1.0f-R ) * pow ( 1.0 – dot ( eyeVector, normal ), 5.0);
finalColor = waterColor * lerp(reflectiveColor, refractiveColor,fastFresnel )+ sunlight;
3,u3d中的方法,大致上差不多,用了texture去模拟Fresnel,效果更多样一些。
o.viewDir.xzy = ObjSpaceViewDir(v.vertex);
//得到当前观察方向的向量
//这里用了u3d封装的函数去得到观察方向,不象我们在世界空间中,而是在观察空间中。
// Computes object space view direction
inline float3 ObjSpaceViewDir( in float4 v )
{
float3 objSpaceCameraPos = mul(_World2Object, float4
(_WorldSpaceCameraPos.xyz, 1)).xyz * unity_Scale.w;
return objSpaceCameraPos - v.xyz
;
}
//float4x4 _World2Object 为 Inverse of current world matrix
//float3 _WorldSpaceCameraPos 为 World space position of the camera
half fresnelFac = dot( i.viewDir, bump );
//水平线表示水面。指向上方的向量是像素的法线向量。另一个向量叫做eyeVector,是从相机指向像素的向量。法线向量上的绿色长度表示当前像素的反射量,红色表示折射量。
//那么我们如何找到绿色和红色线段的长度?我们需要将eyevector投影到法线向量上,这可以通过点乘做到:当你点乘eyeVector和法线后就会获得红色线段的长度。而绿色线段长度等于(1- 红色线段长度)。
//这时我们返回fresnelFac
half fresnel = tex2D( _Fresnel, float2(fresnelFac,fresnelFac) ).a;
//根据折射量去采样
//这时我们返回fresnel
uv1.xy += bump * _ReflDistort;
uv2.xy -= bump * _RefrDistort
//反射和折射的扭曲分开处理。
color = lerp( refr, refl, fresnel );
//到这一个基本的水效果就完成了。
//最后开启雾效
//这里我很倒霉,不清楚为什么u3d的fog在观察相机x 轴角度等于0时,用rtt得到的结果是错的。而我一直用0的条件在找错,浪费了大半天的时间。同时还发现个办法就是创建2个同样的cam,这样即使是0,rtt的结果也是正确的。
三 underWater
关于水下u3d自带的思路只是实现了一个blur,如果想在水下正确的看到水上,需要自己修改下refr的实现。
然后就是投影散焦图片序列,u3d自带了个组件,不用自己在写shader。GodRays效果看到也有预置,接下来准备都实际测试一下。
PS: 现在有很多插件已经支持水面效果 这里只做参考 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
评分
-
查看全部评分
|