Unity仿海岛奇兵海洋效果

Unity仿海岛奇兵海洋效果

第一篇文章想分享一下使用Unity来制作海岛奇兵海洋效果, 最终的实现效果如下

制作这种效果,需要如下几步

1, 首先要准备一个Mesh, 我使用的是10 x 10 的Mesh, 一共100个格子,这样的Mesh顶点相对比较多,最后shader计算的时候效果比较好。

2, 然后来看看shader的具体实现

首先看一下需要传入的属性,需要传入3张贴图,一张_SeaNormal 法线图,一张亮色的海洋图_LightSea , 一张暗色的海洋图_DarkSea ,u_time 是时间变化参数,u_uvFactor 是uv缩放参数

Properties
	{
		_SeaNormal ("SeaNormal", 2D) = "white" {}
		_LightSea ("LightSea", 2D) = "white" {}
		_DarkSea ("DarkSea", 2D) = "white" {}
		u_time ("u_time", float) = 83.36153
		u_uvFactor ("u_uvFactor", float) = 0.7735959
	}

接下来看下vertshader的具体实现

struct appdata
{
	float4 vertex : POSITION0;
	float2 uv : TEXCOORD0;
};

struct v2f
{
	float4 vertex : POSITION0;
	float2 uv : TEXCOORD0;
	float2 normaluv : TEXCOORD1;
	float v_result : TEXCOORD2;
	float v_reflectionPower : TEXCOORD3;
};

v2f vert (appdata v)
{
	v2f o;

	o.vertex = UnityObjectToClipPos(v.vertex);
	o.uv = v.uv;

	float ystretch = 0.2;
	o.v_reflectionPower = clamp((1.0 - length(float2(v.vertex.x * 0.7 + (v.uv.x - 0.5) * 1.5, v.vertex.z * ystretch) - float2(0.0, ystretch))) * 3.0, 1.5, 4.0);
	
	float x = v.uv.x;
	float y = v.uv.y * u_uvFactor;
	float mov1 = y / 0.04 * 5.0 + u_time;
	float mov2 = x / 0.02 * 5.0;
	float c1 = abs((sin(mov1 + u_time) + mov2) * 0.5 - mov1 - mov2 + u_time);
	float c4 = 0.5 * sin(sqrt(x * x + y * y) * 150.0 - u_time) + 0.5;
	c1 = 0.5 * sin(c1) + 0.5;
	o.v_result = c4;

	o.normaluv = v.uv * 25.0;
	o.normaluv.x -= 0.01 * u_time * 0.5;
	o.normaluv.y += 0.02 * u_time * 0.5;

	o.normaluv = float2(o.normaluv.x + c1 * 0.01, (o.normaluv.y + c1 * 0.01) * u_uvFactor) * 1.5;

	return o;
}

vertexshader传入到pixelshader的参与有5个

a, vertex参数不传入pixelshader, 直接由引擎计算出屏幕空间的位置

b, uv就是模型的uv, 直接传入pixelshader

c, normaluv是计算出来的法线uv, 来采样法线图, 法线uv是动态的,来模拟海洋的海浪变化

d, v_reflectionPower是计算的高光强度

e, v_result参数也是用来影响法线uv的变化的


然后看下pixelshader

float4 custommix(float4 x, float4 y, float a)
{
	return (x * (1 - a) + y * a);
}

fixed4 frag (v2f i) : SV_Target
{
	float4 normalMapValue = tex2D(_SeaNormal, i.normaluv);
	float4 lightseacol = tex2D(_LightSea, i.uv);
	float4 darkseacol = tex2D(_DarkSea, i.uv);

	float4 fragcol = custommix(lightseacol, darkseacol, (normalMapValue.x * i.v_result) + (normalMapValue.y * (1.0 - i.v_result)));
	float4 fragspeccol = min(0.4, exp2(log2(((normalMapValue.z * i.v_result) + (normalMapValue.w * (1.0 - i.v_result))) * i.v_reflectionPower) * 5.0));
	fragcol += fragspeccol;

	return fragcol;
}

通过vertexshader传入的参数,采样出亮色海洋贴图,暗色海洋贴图颜色以及动态的法线图

通过函数计算得到diffuse颜色fragcol, 然后根据vertexshader传入的v_reflectionPower高光参数,计算出高光值fragspeccol, 然后计算出最终的颜色fragcol并输出

后记

这个shader的具体实现方法是通过Adreno Profiler分析得来的,具体使用方法可以参考这个大神的文章

Adreno Profiler分析任意安卓游戏特效+抓取资源 | Loading & Learningwww.qiankanglai.me图标

, Adreno Profiler是用来分析手机游戏的渲染比较好用的工具,原则上可以用来分析任意发布在手机上游戏的渲染实现

截图效果如下

项目github链接地址

xieliujian/UnityDemo_BoomBeachOceangithub.com图标

编辑于 2018-06-30

文章被以下专栏收录