按计划继续,目前为止写了三篇对工程已有shader的分析解读,当然实际上我读的shader远不止这三个啦,比如这周就把乐乐同学的blog里的几十篇文章泛泛通读了一遍,主要也是为自己开始构思写一些简单的shader作准备,所谓“思而不学则殆”,不多看些别人的东西自己就想搞创作明显是要吃亏的。
所谓“黑幕扩散”,就是一开始屏幕全黑,然后从中心向外逐渐展示出游戏画面。
为什么我要做这么一个东西呢?一是它想来比较简单。二是去年这个时候,一个UI妹子提出了这个需求,我那时哪懂什么shader咯,只好想了个笨办法,找她要了张中间挖了一个圆孔的黑图,贴面片上,放摄像机前面,然后用扩大面片尺寸的方法,好歹也给实现了,哈哈,这当然很蠢。
现在我是具备这个能力了,可惜妹子也早已离职。
废话不多说,开工。
shader是能利用内置的time变量通过取模方式在时间跨度上做一些动画效果的,比如那些UV动画、滚动的波浪、跳动的心之类的。
但是也都只能循环播放,假如想做一些一次性的变化,比如内置一个bool IsAlreadyRunning标志量,第一次运行时执行某些代码,然后将此标志量改变,第二次运行时,就不再执行某些代码,这种功能我估计是必须借助外部脚本控制的,假如哪位大神能不借助外力神奇的只让shader动画播放一次,请赐教。
我的想法是在之前黑屏shader的基础上加个半径属性,使半径圆内不黑掉即可。
试了下是可行的,HLSL有个内置函数distance,然后屏幕中心点借用Unity提供的内置参数_ScreenParams即可。代码如下:
Shader "MyShader/BlackScreenSpread"
{
Properties
{
_Color("Main Color", Color) = (0.5,0.5,0.5,0.5)
_MainTex ("Base (RGB)", 2D) = "white" {}
_Radius("ViewRadius", float) = 0.0
}
SubShader
{
Pass
{
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert_img
#pragma fragment frag
fixed4 _Color;
sampler2D _MainTex;
float _Radius;
float4 frag (v2f_img i) : COLOR
{
float2 centerPoint = float2(_ScreenParams.x / 2, _ScreenParams.y / 2);
if ( distance(i.pos.xy, centerPoint) > _Radius)
{
return tex2D(_MainTex, i.uv) * _Color;
}
else
{
return tex2D(_MainTex, i.uv);
}
}
ENDCG
}
}
Fallback off
}
注意这里用了if else这种流程控制语句,因为我查了下Cg/HLSL是支持这些流程控制关键字的,所以就试了下。
但我们会发现别人的shader中基本看不到if,传说这种写法效率极低,具体怎么回事去网上可以搜到相关解释。
不使用if的计算方法肯定是有的,不过我就暂时偷个懒不深究了。
另外在Unity Editor中圆的中心往往和画面中心有偏差,具体原因我也不深究了,反正发布了一个Android包实机测试画面是正确的。
效果如下:
外部控制脚本加个radius变量更新下就好了,这里也略过。
另外通过这次实验我发现顶点经过MVP变换后,pos的xy确实已经是屏幕的像素坐标了,而且坐标原点在左上角,往右是x轴正向,往下是y轴正向。
最后扯点别的,因为我Unity重新安装过,这次为了用UnityRemote看实际效果,又装了次JDK和Android SDK,好像Unity5.0后就要多设置一个JDK路径了,我设了好久都说路径无效,后来把JDK重新装在C盘而不是原来的D盘就没问题了,真是坑。
UnityRemote最终还是不能使用,有谁还在用的可以告诉我一声。