模仿 点点互娱《无尽冬日》并作出 优化方案 H5端高效率运行

最近再体验点点互娱游戏 《无尽冬日》,一款泛用户的数值游戏(SLG),上线很快就冲上榜单,无论是UI,还是3D都做 的非常不错,再微信端也很 流畅的运行。今天我来实现下《无尽冬日》雪地效果制作。

  老规矩,先看效果:

    

使用的素材贴图:(百度下的,断色阶,大家 有好的灰度图 效果更好)

 

  方案一:采用 法线贴图试限凹凸,并 采用 兰伯特光照或半兰伯特 光照实现;

              优点:制作 难度 小 ,比较常规,只需要重新计算光照角度。

              缺点:法线需要精度高,开销大 ,即使做平铺也是需要相对大显存空间。

  方案二(我采用的方案):采用灰度图和模型法线切线空间交叉 计算,实现 视觉上的起伏变化;

              其原理跟法线贴图类似,只是我再shader里面重新做了计算;

             优点:性能比较好,实现效果也比较OK ;

             缺点 :技术难度 还是有一些,对shader的优化也要做到极致;

先看看凹凸变化的效果:

               

核心实现:

   在顶点着色器里面对UV做重新运算,实现世界空间平铺:

  

//世界空间UV计算	
fixed2 xz = mul(unity_ObjectToWorld, v.vertex).xz; 

接下来对 模型的UV从新 计算,算法 如下:

o.uv.y *= _Graymap_TexelSize.z / _Graymap_TexelSize.w;
o.uv.x += 0.5f;
o.uv.zw = (xz - fixed2(0, _Global_Stamp_OffsetZ)) * _Global_Stamp_TexelSize.xy;
o.uv.zw.x += 0.5f;

获取灰度图 做开始和结束的深度(视觉高度计算)表达的可能不对,即开始到结束的值;

fixed getBump(fixed4 uv, fixed2 offset)
			{
				fixed stampBump = tex2D(_Global_Stamp_Texture, uv.zw + _Global_Stamp_TexelSize.zw * offset).r * 0.15;
				fixed backBump = tex2D(_Graymap, uv.xy + _Graymap_TexelSize.xy * offset).r;
				return (stampBump + (1 - stampBump) * backBump) * _BumpScale;
			}

转化城法线; 

//灰度图转法线
				fixed  bump	  = getBump(i.uv, fixed2(0, 0));
				fixed3 up	  = fixed3(0, 1, getBump(i.uv, fixed2(0, 1)) - bump);
				fixed3 right  = fixed3(1, 0, getBump(i.uv, fixed2(1, 0)) - bump);
				fixed3 normal = UnityObjectToWorldNormal(mul(cross(right, up), rotation));

实现凹凸变化完整代码如下:
 

Shader "Custom/Curved Snowfield01"
{
	Properties
	{
		_Color("Main Color", Color) = (1, 1, 1, 1)
		_Graymap("Normalmap (Gray)",2D) = "white"{}
		_Tiling("Tiling", Range(0.5, 2)) = 2
		_BumpScale("BumpScale", Range(0, 64)) = 16
	}
	SubShader
	{ 
		pass
		{
			Tags{ "LightMode" = "ForwardBase"}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fog
			#include "Lighting.cginc"
			#include "UnityCG.cginc"
			struct a2v
			{
				float4 vertex	: POSITION;
				fixed3 normal	: NORMAL;
				fixed4 tangent	: TANGENT;
			};
			struct v2f
			{
				float4 pos		: SV_POSITION;
				fixed3 normal	: NORMAL;
				fixed4 tangent	: TANGENT;
				fixed4 uv		: TEXCOORD;
				UNITY_FOG_COORDS(3)
			};
			fixed _Tiling;
			fixed _BumpScale;
			fixed4 _Color;
			sampler2D _Graymap;
			fixed4 _Graymap_TexelSize;
			fixed     _Global_Stamp_OffsetZ;
			fixed4    _Global_Stamp_TexelSize;
			sampler2D _Global_Stamp_Texture;

			v2f vert(a2v v)
			{
				v2f o;
			    o.pos = UnityObjectToClipPos(v.vertex); //转换裁剪空间
				o.normal = v.normal;
				o.tangent = v.tangent;

				//世界空间UV计算
				fixed2 xz = mul(unity_ObjectToWorld, v.vertex).xz; 
				o.uv.xy = xz * _Tiling * 0.1;   //贴图缩放
				o.uv.y *= _Graymap_TexelSize.z / _Graymap_TexelSize.w;
				o.uv.x += 0.5f;
				o.uv.zw = (xz - fixed2(0, _Global_Stamp_OffsetZ)) * _Global_Stamp_TexelSize.xy;
				o.uv.zw.x += 0.5f;
				
				UNITY_TRANSFER_FOG(o, o.pos);				
				return o;
			}

			fixed getBump(fixed4 uv, fixed2 offset)
			{
				fixed stampBump = tex2D(_Global_Stamp_Texture, uv.zw + _Global_Stamp_TexelSize.zw * offset).r * 0.15;
				fixed backBump = tex2D(_Graymap, uv.xy + _Graymap_TexelSize.xy * offset).r;
				return (stampBump + (1 - stampBump) * backBump) * _BumpScale;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				//法线
				fixed3	 binormal = cross(normalize(i.normal), normalize(i.tangent.xyz)) * i.tangent.w;
				float3x3 rotation = float3x3(i.tangent.xyz, binormal, i.normal);

				//灰度图转法线
				fixed  bump	  = getBump(i.uv, fixed2(0, 0));
				fixed3 up	  = fixed3(0, 1, getBump(i.uv, fixed2(0, 1)) - bump);
				fixed3 right  = fixed3(1, 0, getBump(i.uv, fixed2(1, 0)) - bump);
				fixed3 normal = UnityObjectToWorldNormal(mul(cross(right, up), rotation));

				//颜色+环境光
				fixed3 lightDir = _WorldSpaceLightPos0.xyz;
				fixed3 light = _LightColor0.rgb * saturate(dot(normal, lightDir));
				fixed3 ambient = ShadeSH9(fixed4(normal, 1));	
				fixed4 col = _Color;
				col.rgb *= light + ambient; //最终颜色
				UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}

	}
}

接下来咱们在这个基础上还原《无尽 冬日 》雪地 效果:

在 当前 基础上我们需要将优化光照模型为 布林效果(也是 兰伯特);

_Color("Main Color", Color) = (1, 1, 1, 1)
_Specular("Specular", Range(0, 1)) = 0
_Glass("Glass", Range(0, 1)) = 0

注意 :因为要 在web端顺利跑起来,我们需要合理 的去运用贴图:

  //雪景第二通道(绿通道)采用高光点效果
_Graymap("Normalmap (Gray)",2D) = "white"{}

为了方便,我们将 原来 的灯光库文件 #include "Lighting.cginc"修改成  #include "AutoLight.cginc"

加入光照 计算,注意:第二层高光 我是最合并在specularColor上如下:

 fixed3 specularColor = float3(_Specular,_Specular,_Specular)*_BumpTex.r*2; 

完整灯光组件:

  //灯光
                fixed attenuation = LIGHT_ATTENUATION(i);
                fixed3 attenColor = attenuation * _LightColor0.xyz;

               //光滑度
                fixed2 uv = i.uv *_SpecularTiling*0.1;
				 fixed4 _BumpTex =tex2D(_Graymap,i.uv);
                fixed4 _SpecularTex =tex2D(_Graymap,uv);
                fixed gloss = ((_SpecularTex.g)*_Glass);//贴图第二通道,
                fixed specPow = exp2( gloss *10 + 1.0 );
			    fixed3 viewDirection = normalize(_WorldSpaceCameraPos.xyz- i.posWorld.xyz-0.5);
                fixed3 lightDir = _WorldSpaceLightPos0.xyz;

                //高光强度
				//float NdotL = max(0.0,dot((viewDirection+lightDir), lightDir ));
				fixed NdotL = max(0.0,dot((viewDirection+lightDir), normal ));
                fixed3 specularColor = fixed3(_Specular,_Specular,_Specular)*_BumpTex.r*2;    
                fixed3 light = _LightColor0.rgb *pow(NdotL,specPow)*specularColor;
                fixed3 specular = light;
				fixed3 ambient = ShadeSH9(fixed4(normal, 1));	         
				fixed3 diffuse = _Color+ specular;

最终代码如下:

Shader "Custom/Curved Snowfield02"
{
	Properties
	{
		_Color("Main Color", Color) = (1, 1, 1, 1)
		_Specular("Specular", Range(0, 1)) = 0
		_Glass("Glass", Range(0, 1)) = 0
		
        //雪景第二通道(绿通道)采用高光点效果
		_Graymap("Normalmap (Gray)",2D) = "white"{}
		_Tiling("Tiling", Range(0.1, 2)) = 2
        //高光的重复度
        _SpecularTiling("Specular Tiling", float) = 2
		_BumpScale("BumpScale", Range(0, 200)) = 16
	}
	SubShader
	{ 
			 Tags {
			"RenderType" = "Opaque"
		}
		pass
		{
			Tags{

				"LightMode" = "ForwardBase"
			}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fog
		    #include "AutoLight.cginc"
			#include "UnityCG.cginc"

		     fixed4 _LightColor0;
			 fixed4 _MainColor;
			 fixed _Specular;
			 fixed _Glass;
		
			struct a2v
			{
				float4 vertex	: POSITION;
				fixed3 normal	: NORMAL;
				fixed4 tangent	: TANGENT;
                fixed4 uv : TEXCOORD0;
			};
			struct v2f
			{
				float4 pos		: SV_POSITION;
				fixed3 normal	: NORMAL;
				fixed4 tangent	: TANGENT;
				fixed4 uv		: TEXCOORD0;
                float4 posWorld : TEXCOORD1;
				UNITY_FOG_COORDS(2)
                LIGHTING_COORDS(3,4)
			};
			fixed _Tiling;
            fixed _SpecularTiling;
			fixed _BumpScale;
			fixed4 _Color;
			sampler2D _Graymap;
			fixed4 _Graymap_TexelSize;
			fixed     _Global_Stamp_OffsetZ;
			fixed4    _Global_Stamp_TexelSize;
			sampler2D _Global_Stamp_Texture;

			v2f vert(a2v v)
			{
				v2f o;
			    o.pos = UnityObjectToClipPos(v.vertex); //转换裁剪空间
                o.uv=v.uv;
				o.normal =UnityObjectToWorldNormal(v.normal);
				o.tangent = v.tangent;
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                fixed3 lightColor = _LightColor0.rgb;

				//世界空间UV计算
				fixed2 xz = mul(unity_ObjectToWorld, v.vertex).xz; 
				o.uv.xy = xz * _Tiling * 0.1;   //贴图缩放
               
				o.uv.y *= _Graymap_TexelSize.z / _Graymap_TexelSize.w;
				o.uv.x += 0.5f;
				o.uv.zw = (xz - fixed2(0, _Global_Stamp_OffsetZ)) * _Global_Stamp_TexelSize.xy;
				o.uv.zw.x += 0.5f;
				
				UNITY_TRANSFER_FOG(o, o.pos);		
                TRANSFER_VERTEX_TO_FRAGMENT(o)		
				return o;
			}

			fixed getBump(fixed4 uv, fixed2 offset)
			{
				fixed stampBump = tex2D(_Global_Stamp_Texture, uv.zw + _Global_Stamp_TexelSize.zw * offset).r * 0.15;
				fixed backBump = tex2D(_Graymap, uv.xy + _Graymap_TexelSize.xy * offset).r;
				return (stampBump + (1 - stampBump) * backBump) * _BumpScale;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				//法线
				fixed3	 binormal = cross(normalize(i.normal), normalize(i.tangent.xyz)) * i.tangent.w;
				float3x3 rotation = float3x3(i.tangent.xyz, binormal, i.normal);

				//灰度图转法线
				fixed  bump	  = getBump(i.uv, fixed2(0, 0));
				fixed3 up	  = fixed3(0, 1, getBump(i.uv, fixed2(0, 1)) - bump);
				fixed3 right  = fixed3(1, 0, getBump(i.uv, fixed2(1, 0)) - bump);
				fixed3 normal = UnityObjectToWorldNormal(mul(cross(right, up), rotation));
                //灯光
                fixed attenuation = LIGHT_ATTENUATION(i);
                fixed3 attenColor = attenuation * _LightColor0.xyz;

               //光滑度
                fixed2 uv = i.uv *_SpecularTiling*0.1;
				 fixed4 _BumpTex =tex2D(_Graymap,i.uv);
                fixed4 _SpecularTex =tex2D(_Graymap,uv);
                fixed gloss = ((_SpecularTex.g)*_Glass);//贴图第二通道,
                fixed specPow = exp2( gloss *10 + 1.0 );
			    fixed3 viewDirection = normalize(_WorldSpaceCameraPos.xyz- i.posWorld.xyz-0.5);
                fixed3 lightDir = _WorldSpaceLightPos0.xyz;

                //高光强度
				//float NdotL = max(0.0,dot((viewDirection+lightDir), lightDir ));
				fixed NdotL = max(0.0,dot((viewDirection+lightDir), normal ));
                fixed3 specularColor = fixed3(_Specular,_Specular,_Specular)*_BumpTex.r*2;    
                fixed3 light = _LightColor0.rgb *pow(NdotL,specPow)*specularColor;
                fixed3 specular = light;
				fixed3 ambient = ShadeSH9(fixed4(normal, 1));	         
				fixed3 diffuse = _Color+ specular;
               
				diffuse.rgb *= diffuse + ambient; //最终颜色
                fixed4 col = fixed4(diffuse,1);
				UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}

	}
}

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值