实现动态渐变相册

478 阅读2分钟

大多数相册采用传统的跑马灯式轮播, 而通过使用Shader,我们可以为相册创建独特而富有动感的渐变过渡效果,使图片的切换变得更为流畅和自然。在游戏中,这可以用于两个场景间的过渡效果。

效果展示

photo.gif

直接用SD生成了几张游戏背景图,由于mac的显卡不够给力,生成的图片高清度不够,勉强凑合着用。

实现思路

本实例的实现思路主要分为两个核心功能点:

  1. 图片的渐变:实现图片的平滑过渡。
  2. 图片的切换:保持图片在队列中循环切换。
图片渐变

图片的渐变是通过控制图片上每个像素点的透明度来实现的。这里采用了水平滚轴式的切换,这需要用到一个关于时间变化的垂直直线x = time。每个像素点的x坐标与此直线比较,左边的像素点透明度设为0,右边的透明度设为1。通过平滑取样的方法,就能够实现渐变过渡的效果:

void main () {
  vec4 color = vec4(1, 1, 1, 1);
  color *= texture(texture, v_uv0);
  color *= v_color;

  #if USE_TRAMSFORM
    color.a = smoothstep(0.0, u_fade_radius, u_fade_radius + v_uv0.x - u_time);
  #endif

  gl_FragColor = color;
}
图片切换

对于图片的切换,所有的图片都在一个队列中。当渐变完成后,我们只需要将最上面的那张图片放到队列的最下面。这样,相册就能够持续循环播放。在此过程中,加入一些图片的状态处理,从而实现本文中所展示的渐变相册效果。

代码实现

下面是一段核心的代码实现,主要使用了Shader实现图片的渐变过渡,并通过定时器控制图片的切换:

isTransforming: boolean = false;
bgTramsform() {
  if (this.isTransforming) return;
  this.isTransforming = true;

  let time = 0.0;
  let node = this.switchNodeList[0];
  let material = node.getComponent(cc.Sprite).getMaterial(0);
  material.setProperty('u_fade_radius', this.fadeRadius);
  material.setProperty('u_time', time);
  material.define('USE_TRAMSFORM', true, 0, true);

  let timer = setInterval(() => {
    time += 0.06;
    material.setProperty('u_time', time);
    if (time > 1.0 + this.fadeRadius) {
      this.switchNodeList.shift();
      this.switchNodeList.push(node);
      this.switchNodeList.forEach((node, idx) => node.zIndex = this.switchNodeList.length - idx)
      material.define('USE_TRAMSFORM', false, 0, true);
      this.isTransforming = false;
      timer && clearInterval(timer);
    }
  }, 30);
}