简体   繁体   中英

How can I optimize WebGL (pixi.js) rendering in requestAnimationFrame?

I'm trying to improve performance of animation. My animation includes 3 different parts: fadein, fadeout and scale transformation effect. But they start not synchroniously. Now I use 3 requestAnimationFrame calls each of them call WebGL-renderer (I'm using pixi.js). My main question is it a good idea to improve performance to create something like buffer where I'll collect renderer calls and do rendering synchronyously? And If it is I'd like to know how to do it rightly. Thanks.

Animation:

export function animateScaling(
  timestamp,
  container,
  renderer,
  targetScale,
  currentScale,
  start,
  delta
) {
  var progress;
  if (start === null) start = timestamp;
  progress = timestamp - start;
  var lambda = progress / delta;

  if (lambda > 1) lambda = 1;
  lambda = lambda * (0.4 + lambda * (2.2 + lambda * -1.6));
  container.children.forEach(function (markerSprite) {
    markerSprite.scale.set(
      currentScale + lambda * (targetScale - currentScale)
    );
  });
  renderer.render(container);
  if (progress < delta) {
    var frame = requestAnimationFrame(() =>
      animateScaling(
        Date.now(),
        container,
        renderer,
        targetScale,
        currentScale,
        start,
        delta
      )
    );
  } else {
    cancelAnimationFrame(frame);
  }
}

export function animateFading(
  timestamp,
  container,
  fadeMarkers,
  renderer,
  start,
  delta,
  coef = 1
) {
  var progress;
  if (start === null) start = timestamp;
  progress = timestamp - start;
  var lambda = progress / delta;
  if (lambda > 1) lambda = 1;
  if (lambda < 0) lambda = 0;
  lambda = lambda * (0.4 + lambda * (2.2 + lambda * -1.6));
  fadeMarkers.forEach(function (markerSprite) {
    markerSprite.alpha = coef > 0 ? lambda : 1 - lambda;
  });
  renderer.render(container);
  if (progress < delta) {
    var frame = requestAnimationFrame(() =>
      animateFading(
        Date.now(),
        container,
        fadeMarkers,
        renderer,
        start,
        delta,
        coef
      )
    );
  } else {
    if (coef < 0) container.removeChild(...fadeMarkers);
    cancelAnimationFrame(frame);
  }
}

What I'm trying:

export class MyRendering {
  constructor(container, tick, renderer) {
    this.container = container;
    this.tick = tick;
    this.renderer = renderer;
    this.ids = [];
  }

  addId(id) {
    if (!this.ids.includes(id)) this.ids.push(id);
  }

  removeId(id) {
    if (this.ids.includes(id)) {
      var index = this.ids.indexOf(id);
      this.ids.splice(index, 1);
    }
  }

  setTick(tick) {
    this.tick = tick;
  }

  startIntervalRendering() {
    this.run = true;
    this.interval = setInterval(() => {
      console.log('render', Date.now())
      this.renderer.render(this.container);
    }, this.tick);
  }

  stopIntervalRendering(id) {
    this.removeId(id);
    if (!this.ids.length) {
      this.run = false;
      clearInterval(this.interval);
    }
  }
}

// rAF
export function animateScaling(
  timestamp,
  container,
  myRendering,
  targetScale,
  currentScale,
  start,
  delta
) {
  var progress;
  if (start === null) start = timestamp;
  progress = timestamp - start;
  var lambda = progress / delta;

  if (lambda > 1) lambda = 1;
  lambda = lambda * (0.4 + lambda * (2.2 + lambda * -1.6));
  container.children.forEach(function (markerSprite) {
    markerSprite.scale.set(
      currentScale + lambda * (targetScale - currentScale)
    );
  });

  if (!myRendering.run) {
    myRendering.startIntervalRendering();
  }
  if (progress == 0) myRendering.addId(start);

  if (progress < delta) {
    var frame = requestAnimationFrame(() =>
      animateScaling(
        Date.now(),
        container,
        myRendering,
        targetScale,
        currentScale,
        start,
        delta
      )
    );
  } else {
    cancelAnimationFrame(frame);
    myRendering.stopIntervalRendering(start);
  }
}

export function animateFading(
  timestamp,
  container,
  fadeMarkers,
  myRendering,
  start,
  delta,
  coef = 1
) {
  var progress;
  if (start === null) start = timestamp;
  progress = timestamp - start;
  var lambda = progress / delta;
  if (lambda > 1) lambda = 1;
  if (lambda < 0) lambda = 0;
  lambda = lambda * (0.4 + lambda * (2.2 + lambda * -1.6));
  fadeMarkers.forEach(function (markerSprite) {
    markerSprite.alpha = coef > 0 ? lambda : 1 - lambda;
  });

  if (!myRendering.run) {
    myRendering.startIntervalRendering();
  }
  if (progress == 0) myRendering.addId(start);

  if (progress < delta) {
    var frame = requestAnimationFrame(() =>
      animateFading(
        Date.now(),
        container,
        fadeMarkers,
        myRendering,
        start,
        delta,
        coef
      )
    );
  } else {
    if (coef < 0) container.removeChild(...fadeMarkers);
    cancelAnimationFrame(frame);
    myRendering.stopIntervalRendering(start);
  }
}

UPD : Unfortenally FPS still not stable.

Looks like I've found a solution. I will be glad to hear any comments

  constructor(container, renderer) {
    this.container = container;
    this.renderer = renderer;
    this.ids = [];
  }

  addId(id) {
    if (!this.ids.includes(id)) this.ids.push(id);
  }

  removeId(id) {
    if (this.ids.includes(id)) {
      var index = this.ids.indexOf(id);
      this.ids.splice(index, 1);
    }
  }

  startIntervalRendering() {
    this.run = true;
    this.frame = requestAnimationFrame(() => animate(this));
    // var frame =  ???
  }

  stopIntervalRendering(id) {
    this.removeId(id);
    if (!this.ids.length) {
      this.run = false;
      cancelAnimationFrame(this.frame);
      // maybe need to call cAF
    }
  }
}

function animate(ctx) {
  // console.log(ctx.run)
  ctx.renderer.render(ctx.container);
  if (ctx.run) var frame = requestAnimationFrame(() => animate(ctx));
  else {
    cancelAnimationFrame(frame);
  }
}

// transformations
export function transformScaling(
  timestamp,
  container,
  myRendering,
  targetScale,
  currentScale,
  start,
  delta
) {
  var progress;
  if (start === null) start = timestamp;
  progress = timestamp - start;
  var lambda = progress / delta;

  if (lambda > 1) lambda = 1;
  lambda = lambda * (0.4 + lambda * (2.2 + lambda * -1.6));
  container.children.forEach(function (markerSprite) {
    markerSprite.scale.set(
      currentScale + lambda * (targetScale - currentScale)
    );
  });

  if (!myRendering.run) {
    myRendering.startIntervalRendering();
  }
  if (progress == 0) myRendering.addId(start);

  if (progress < delta) {
    var frame = requestAnimationFrame(() =>
      transformScaling(
        Date.now(),
        container,
        myRendering,
        targetScale,
        currentScale,
        start,
        delta
      )
    );
  } else {
    myRendering.stopIntervalRendering(start);
    cancelAnimationFrame(frame)
  }
}

export function transformFading(
  timestamp,
  container,
  fadeMarkers,
  myRendering,
  start,
  delta,
  coef = 1
) {
  var progress;
  if (start === null) start = timestamp;
  progress = timestamp - start;
  var lambda = progress / delta;
  if (lambda > 1) lambda = 1;
  if (lambda < 0) lambda = 0;
  lambda = lambda * (0.4 + lambda * (2.2 + lambda * -1.6));
  fadeMarkers.forEach(function (markerSprite) {
    markerSprite.alpha = coef > 0 ? lambda : 1 - lambda;
  });

  if (!myRendering.run) {
    myRendering.startIntervalRendering();
  }
  if (progress == 0) myRendering.addId(start);

  if (progress < delta) {
    var frame = requestAnimationFrame(() =>
      transformFading(
        Date.now(),
        container,
        fadeMarkers,
        myRendering,
        start,
        delta,
        coef
      )
    );
  } else {
    myRendering.stopIntervalRendering(start);
    cancelAnimationFrame(frame)
    if (coef < 0) container.removeChild(...fadeMarkers);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM