首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PIXI.js性能优化

PIXI.js性能优化
EN

Stack Overflow用户
提问于 2021-05-14 17:14:27
回答 1查看 255关注 0票数 0

我使用canvas 2dContext构建了一个fractal clock,但当层数增加到6层以上时,我发现出现了性能问题。为了提高性能和增加层限制,我重新构建了the same clock using PIXI.js

我遇到的问题是性能提升很小--在我的桌面上,从2dContext的最多6层到PIXI的7层。

我处理PIXI解决方案的方式有没有明显的错误,可能会限制它的性能?

我怀疑最好的解决方案是将所有的计算转移到着色器中,并从样板webgl开始。

保存点击链接的代码:

代码语言:javascript
复制
const config = {
  numLevels: 7, // bottleneck here, higher means poor performance
  levelAngleOffset: 0,
  levelScale: .7,
  levelOpacityMultiplier: .7,
  levelHueRotation: 40,

  initialRadius: .4,
  initialOpacity: 1,
  initialHue: 0,

  dialOpacity: .1,
  handOpacity: 1,

  secondHandLength: .9,
  secondHandWidth: .015,
  minuteHandLength: .8,
  minuteHandWidth: .03,
  hourHandLength: .6,
  hourHandWidth: .05,

  // set by code
  width: 0,
  height: 0,
};

// https://stackoverflow.com/a/44134328/3282374
function hslToHex(h, s, l) {
  l /= 100;
  const a = s * Math.min(l, 1 - l) / 100;
  const f = n => {
    const k = (n + h / 30) % 12;
    const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
    return Math.round(255 * color).toString(16).padStart(2, '0');   // convert to Hex and prefix "0" if needed
  };
  return `0x${f(0)}${f(8)}${f(4)}`;
}

class Hand extends PIXI.Graphics {
  constructor(x,y,length, rotation, width, opacity) {
    super();
    
    this.length = length;
    
    this.lineStyle({
      width: width, 
      color: 0xFFFFFF,
      alpha: config.handOpacity * opacity,
      cap: PIXI.LINE_CAP.ROUND
    });
    this.moveTo(0, 0);
    this.lineTo(0, -length);
    this.rotation = rotation;
    this.x = x;
    this.y = y;
    this.endFill();
  }
  
  setClock(clock) {
    this.hasClock = true;
    this.clock = clock;
    
    clock.x = 0;
    clock.y = this.length;

    this.addChild(clock);
  }

  update(rotation, angles) {
    this.rotation = rotation;
    
    if (this.hasClock) {
      this.clock.update(angles, 0, -this.length, rotation);
    }
  }
}

class Clock extends PIXI.Graphics {
  constructor(cx, cy, radius, rotation, hue, opacity) {
    super();

    this.lineStyle(0);     
    this.beginFill(hslToHex(hue, 100, 50), opacity * config.dialOpacity);
    this.drawCircle(0, 0, radius);
    this.endFill();
    this.x = cx;
    this.y = cy;
    this.rotation = rotation;

    this.hourHand = new Hand(0, 0, config.hourHandLength * radius, 0, config.hourHandWidth * radius, opacity);
    this.minuteHand = new Hand(0, 0, config.minuteHandLength * radius, 0, config.minuteHandWidth * radius, opacity);
    this.secondHand = new Hand(0, 0, config.secondHandLength * radius, 0, config.secondHandWidth * radius, opacity);

    this.addChild(this.hourHand, this.minuteHand, this.secondHand);
  }
  
  setChildClocks(hour, minute, second) {
    this.hourHand.setClock(hour);
    this.minuteHand.setClock(minute);
    this.secondHand.setClock(second);
  }

  update(angles, cx, cy, rotation) {
    this.x = cx;
    this.y = cy;
    this.rotation = rotation;

    this.hourHand.update(angles.hour, angles);
    this.minuteHand.update(angles.minute, angles);
    this.secondHand.update(angles.second, angles);
  }
}

function getTimeAngles() {
  const time = new Date();

  const millisecond = time.getMilliseconds();
  const second = time.getSeconds() + millisecond / 1000;
  const minute = time.getMinutes() + second / 60;
  const hour = time.getHours() % 12 + minute / 60;

  const hourAngle = Math.PI * 2 * hour / 12;
  const minuteAngle = Math.PI * 2 * minute / 60;
  const secondAngle = Math.PI * 2 * second / 60;

  return {
    hour: hourAngle,
    minute: minuteAngle,
    second: secondAngle
  };
}

let clock;

function initClock() {
  const center = Math.min(config.width, config.height) / 2;
  clock = new Clock(
    center, 
    center, 
    center * config.initialRadius, 
    Math.PI / 2,     
    config.initialHue, 
    config.initialOpacity);

  let level = 0;
  let clocks = [clock];
  while (level < config.numLevels) {
    level++;
    const nextClocks = [];
    for (const parent of clocks) {
      const children = [];
      for (var i  = 0; i < 3; i++) {
        const child = new Clock(
          center, 
          center, 
          center * config.initialRadius * config.levelScale**level, 
          0, 
          config.initialHue + config.levelHueRotation * level, 
          config.initialOpacity * config.levelOpacityMultiplier ** level);
        
        children.push(child);
      }
      parent.setChildClocks(...children);
      nextClocks.push(...children);
    }
    clocks = nextClocks;
  }
}

function step() {
  const angles = getTimeAngles();
  clock.update(angles, config.width/2, config.height/2, 0);
}

function init() {
  PIXI.utils.skipHello();
  
  const app = new PIXI.Application({ antialias: true, transparent: true });
  document.body.appendChild(app.view);

  const canvas = document.querySelector('canvas');

  const resize = () => {
    const {width, height } = canvas.getBoundingClientRect();
    config.width = width;
    config.height = height;
    app.renderer.resize(width, height);
  }

  window.addEventListener('resize', resize);
  resize();

  initClock();

  app.stage.addChild(clock);
  app.ticker.add(step);
}

init();
代码语言:javascript
复制
html, body {
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100%;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #222;
}

canvas {
  width: 99vw;
  height: 99vh;
}
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.3.9/pixi.min.js"></script>

EN

回答 1

Stack Overflow用户

发布于 2021-05-14 17:27:08

我处理PIXI解决方案的方式有没有明显的错误,可能会限制它的性能?

您的性能问题来自CPU,而不是GPU。对于深度8,在我的PC (英特尔酷睿i7-10700F)上绘制单个帧需要60毫秒,因为CPU必须做大量的工作(在深度上遍历不断扩展的树)。

切换到Pixi不会有帮助,因为您在CPU上执行相同数量的工作。为了让你的分形时钟在更大的深度下很好地工作,你必须在GPU上进行编程。WebGL允许您通过编写着色器来执行此操作。

您需要重新考虑您的程序顺序算法,并将其转换为片段着色器,该着色器的指令一次对多个像素(片段)并行执行。这不是一项微不足道的任务,需要一些实践。

但是,根据您希望分形看起来的方式,您可能会仍然使用画布。您可以只绘制一层,然后将此图像数据复制到其他位置,以及平移/旋转/缩放,而不是从头开始重新绘制每个分支。详情请参见getImageData

但是,如果您的分形较深的节点需要使用仿射变换或简单的基于像素的操作无法实现的操作,则必须使用我所描述的自定义片段着色器解决方案。

有关在WebGL中可以对着色器执行的操作的灵感,请参见ShaderToy。那是a section for fractals as well。这是一个clock similar to yours (如下图所示)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67531861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档