温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Unity+shader如何绘制halftone动画实现星之卡比新星同盟切屏效果

发布时间:2021-11-15 16:13:40 来源:亿速云 阅读:328 作者:柒染 栏目:大数据

这篇文章将为大家详细讲解有关Unity+shader如何绘制halftone动画实现星之卡比新星同盟切屏效果,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

卡比是个好游戏,这次的切屏和loading画面也是可爱得不行。先放出这篇文章想要重现的效果:


Unity+shader如何绘制halftone动画实现星之卡比新星同盟切屏效果

卡比的进门切屏效果

接下来放出我们最终实现的效果:

Unity+shader如何绘制halftone动画实现星之卡比新星同盟切屏效果

使用起来也是十分简单的,以上效果连动画系统都可以完成。

分析一番后,我们可以将卡比的切屏特效拆分成几个部分:

1.沿一个方向移动的halftone图形
2.两张贴图/颜色的切换
3.任意形状的mask贴图以指定轴旋转缩放

那么从第一步开始,绘制一个halftone图形。
要绘制halftone dots 并让它们在画面中移动,首先需要一个property来确定图形的位置。

  Properties {
	 _MainTex ("Texture A", 2D) = "black" {} 
	 _MainTexB ("Texture B", 2D) = "black" {} 
	 [Space(10)]
	 _Position("Halftone Position", Float)=1
	 _Diameter("Diameter", Range(0,1) )=0.25
	 _Num("Length", Range(1,16)) = 3.0
 }
这里面还定义了dots的直径 _Diameter ,和halftone过渡区域的长度 _Num
struct v2f {
	float4 pos : SV_POSITION;
	half2 uvTA: TEXCOORD0;
	half2 uvTB: TEXCOORD1;
	half2 uvORI: TEXCOORD2;//original
};
 
v2f vert(appdata_img v) {
	v2f o;
	o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
	o.uvTA=(v.texcoord-_MainTex_ST.zw)*_MainTex_ST.xy ;
	o.uvTB=(v.texcoord-_MainTexB_ST.zw)*_MainTexB_ST.xy ;
	o.uvORI.xy=v.texcoord;
	return o;
}

这里两张贴图可以使用tillng和offset,而绘制halftone的uv则使用原始的值。

之后以position为基础,将uv划分为若干网格。最后以每个格子的中心点为圆心画出圆点。

    fixed4 frag(v2f i) : SV_Target {
	float _rd;
	fixed2 posCenter;
	fixed indexOfGrid=floor((i.uvORI.x-_Position)/_Diameter);//num of grids between uv and PosW
	posCenter.x=_Position+(indexOfGrid + 0.5)*_Diameter;
	posCenter.y=(floor(i.uvORI.y/_Diameter) + 0.5)*_Diameter;
	_rd=0.5*_Diameter* abs(indexOfGrid)/_Num;//radius of the current grid 
	fixed inCircle=step(distance(i.uvORI,posCenter),_rd);
	inCircle=clamp(inCircle,0,1);
 
	fixed4 texA=tex2D(_MainTex, i.uvTA).rgba;
	fixed4 texB=tex2D(_MainTexB, i.uvTB).rgba;
	fixed4 sum= lerp(texB,texA,inCircle);
	return sum;
}

看一下效果,似乎出现了一些问题呢

可以发现,position的左右两侧同时出现了对称的圆点,解决这个问题,只需要让uv大于position的部分直接显示textureB即可。

if(indexOfGrid>=1){
	return tex2D(_MainTexB, i.uvTB).rgba ;//return texture A when uv is in front (larger) of PosW
}

另一个问题是,圆点的半径根据和position的距离是一个递增的关系,在后方的格子里,圆点的半径超过了格子的尺寸时,并不会在相邻的格子里显示出来。
这个问题在格子里画方块时不会看出异常

画圆点的时候就可以发现出现了一些明显的直线(上上图的第一列圆点处),画方块的时候就满看不出来了

这时就需要在计算时将后方法格子一起考虑进去了

	float _rdNext=_rd+0.5*_Diameter/_Num; 
	fixed2 posCenterNext= posCenter-fixed2(diameterW,0); //center of up-next grid 
	//fixed inCircle=step(abs(i.uvORI.x-posCenter.x),_rd)*step(abs(i.uvORI.y-posCenter.y),_rd); //Square 
	fixed inCircle=step(distance(i.uvORI,posCenter),_rd)+step(distance(i.uvORI,posCenterNext),_rdNext); //Dot

现在,一个可以移动的halftone图形就画出来了Unity+shader如何绘制halftone动画实现星之卡比新星同盟切屏效果但是这和我们常见的半调图形还有一些不同……

是的,格子之间没有偏移,完全是横平竖直的分布,显得一点也不好看,这就需要加上一个参数来让它在y方向有一个偏移,之后为了让图形更加自然,在y方向偏移时,x方向也进行一定压缩。于是我们对frag进行以下修改
fixed4 frag(v2f i) : SV_Target {
	float _rd;
	fixed2 posCenter;
	fixed diameterW,diameterH;
	diameterW=_Diameter*(1-_rotOffset/2);//width of grid , reduce when _rotOffset is larger than zero
	diameterH=_Diameter;
	fixed indexOfGrid=floor((i.uvORI.x-_Position)/diameterW);//num of grids between uv and PosW
	if(indexOfGrid>=1){
		return tex2D(_MainTexB, i.uvTB).rgba ;//return texture A when uv is in front (larger) of PosW
	}
 
	posCenter.x=_Position+(indexOfGrid+0.5)*diameterW;
	fixed modOffset=frac(indexOfGrid*_rotOffset)*_Diameter;
	posCenter.y=(floor((i.uvORI.y-modOffset)/diameterH)+ 0.5)*diameterH+modOffset;
 
	_rd=0.5*diameterH* abs(indexOfGrid)/_Num;//radius of the current grid 
	float _rdNext=_rd+0.5*diameterH/_Num;
	fixed2 posCenterNextUp=posCenter-fixed2(diameterW,_Diameter*(_rotOffset-1));
	fixed2 posCenterNextDown=posCenter-fixed2(diameterW,_Diameter*_rotOffset); //center of down-next grid
	float _rdPrev=_rd-0.5*diameterH/_Num;
	fixed2 posCenterPrevUp=posCenter+fixed2(diameterW,_Diameter*(_rotOffset-1));
	fixed2 posCenterPrevDown=posCenter+fixed2(diameterW,_Diameter*_rotOffset); //center of down-next grid
	//fixed inCircle=step(abs(i.uvORI.x-posCenter.x),_rd)*step(abs(i.uvORI.y-posCenter.y),_rd);//Square
	fixed inCircle=step(distance(i.uvORI,posCenter),_rd);
	inCircle+=step(distance(i.uvORI,posCenterNextUp),_rdNext)+step(distance(i.uvORI,posCenterNextDown),_rdNext);
	inCircle+=step(distance(i.uvORI,posCenterPrevUp),_rdPrev)+step(distance(i.uvORI,posCenterPrevDown),_rdPrev);
	inCircle=clamp(inCircle,0,1);
 
	fixed4 texA=tex2D(_MainTex, i.uvTA).rgba;
	fixed4 texB=tex2D(_MainTexB, i.uvTB).rgba;
	fixed4 sum= lerp(texB,texA,inCircle);
	return sum;
}

因为在uv方向上都有了偏移,所以绘制一个格子里的内容时需要左上左下、右上右下四个格子。

在properties中,添加

_rotOffset("Offset Between Points",  Range(0,0.5)) = 0.0

由于圆点是对称图形,偏移量的取值范围只需要是格子尺寸的一半。
至此,一个可以移动位置的halftone切图效果就完成了。Unity+shader如何绘制halftone动画实现星之卡比新星同盟切屏效果说到这里,大家可能会想,这个跟直接使用一张贴图作为遮罩有什么不同呢?答案是,确实没什么不同,目前为止的效果是完全可以使用一张遮罩实现的。使用遮罩甚至还能达成更多花哨的效果,但遮罩也有它所不能完成的事情。接下来修改格子划分的方法,让格子的位置不再跟随position变化,再改变一下计算圆点半径的方法,作出圆点一个个弹出的效果。

修改一下格子划分的方法,让格子的位置不再跟随position变化:

fixed indexOfGrid=floor((i.uvORI.x)/diameterW);//num of grids between uv and PosW 
posCenter.x=(indexOfGrid+0.5)*diameterW;     
fixed modOffset=frac(indexOfGrid*_rotOffset)*_Diameter;
posCenter.y=(floor((i.uvORI.y-modOffset)/diameterH)+ 0.5)*diameterH+modOffset;

然后再改变一下计算圆点半径的方法,让其根据uv和position 的关系变化:

 _rd=0.5*(_Position-posCenter.x)/_Num;//radius of the current grid 
 float _rdNext=_rd+0.5*diameterW/_Num; 
 float _rdPrev=_rd-0.5*diameterW/_Num;

这里计算前后格子中的半径时,需要改用压缩过的diameter,不然就会出现不太对劲的效果。由于划分格子的方法已经发生了变化,原本的if(indexOfGrid>=1)的时候,直接输出textureB已经无效了,实际上,判断的条件应该是圆点半径小于0。

Unity+shader如何绘制halftone动画实现星之卡比新星同盟切屏效果接下来,需要一个表明角度的property,来让图形按照一个方向移动,而不是只能从左到右。

   _Rotation("Rotation", Range(0,360)) = 0.0

旋转角度的算法,在很多地方都可以找到。这里直接转换计算halftone时使用的uv坐标,而textureA和B的uv不受影响。由于各个顶点之间的uv变化是线性的,这一转化可以放在vert函数中完成。

o.uvORI.xy=v.texcoord; fixed2 offsetXY=fixed2(0.5,0.5); 
 float Rot = _Rotation * (3.1415926f/180.0f); 
 float s = sin(Rot); 
 float c = cos(Rot); 
 float2x2 rMatrix = float2x2(c, -s, s, c); 
 rMatrix *= 0.5; 
 rMatrix += 0.5; 
 rMatrix = rMatrix * 2 - 1; 
 o.uvORI.xy = mul(o.uvORI.xy-offsetXY, rMatrix)+offsetXY;

这个_Rotation换成弧度角也是完全可以的。 _Rotation("Rotation", Range(0,6.283)) = 0.0 ,到时候就不需要进行乘PI再除180的计算。

现在看一下 示例场景

SlideshowEffect: Halftone and Popup

https://sakuraplus.github.io/make-terrain-with-google-elevation/webplayershow/webplayershow.html

里面的halftone切图的效果基本完成了。

关于Unity+shader如何绘制halftone动画实现星之卡比新星同盟切屏效果就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI