Улучшение производительности частиц в холсте - PullRequest
0 голосов
/ 22 ноября 2018

Я пытался воссоздать этот проект в canvas и Javascript.Я не смог расшифровать оригинальный код, поэтому я сделал это с нуля.Разница в том, что мои проекты начинают отставать примерно от 2500 частиц, в то время как проект выше работает с 30 000.

Я вставлю весь свой код ниже, но это соответствующие части:

var particleContainer = []
var distance = 10


for(let i = 0; i< square.height/distance; i++){
    for(let j = 0; j< square.height/distance; j++){
    particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
}  
}

if(  c < 90  ){
            i.xVelocity = a/c * -20
            i.yVelocity = b/c * -20
        }else if(90 < c && c < 95){
            i.xVelocity = a/c * -1
            i.yVelocity = b/c * -1
        }else if(c2 !== 0){
            i.xVelocity =( a2/c2 )
            i.yVelocity = (b2/c2 )
        }
  • (c -> расстояние между мышью и частицей)

Я создаю новую Частицу через каждые «расстояния» пикселей моего квадрата и помещаю их все в массив.когда моя мышь приблизится к одному из них, частица начнет отходить от мыши, пока она не окажется на расстоянии 90-95 пикселей от мыши.

30 000 пикселей, похоже, работает аналогичным образом, судя по этой строке

  for ( i = 0; i < NUM_PARTICLES; i++ ) {

    p = Object.create( particle );
    p.x = p.ox = MARGIN + SPACING * ( i % COLS );
    p.y = p.oy = MARGIN + SPACING * Math.floor( i / COLS );

    list[i] = p;
  }

но этот проект не сталкивается с тем же случаем проблем с производительностью, что и я.

мой полный код для справки (html - это просто холст):

var canvas = document.querySelector("canvas")
var c = canvas.getContext('2d')




function getMousePos(canvas, evt) {
    // var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX,
      y: evt.clientY
    };
  }

  document.addEventListener('mousemove', function(evt) {
    var mousePos = getMousePos(canvas, evt);
    mouse.x= mousePos.x; 
    mouse.y= mousePos.y;
  }, false);

  var mouse = {
    x:0,
    y:0
  }

function Particle(x,y){
    this.x = x;
    this.y = y;
    this.xFixed = x;
    this.yFixed = y;
    this.radius = 1
    this.xVelocity = 0
    this.yVelocity = 0
    this.color = 'white'
}

Particle.prototype.draw = function(){
    c.save()
    c.beginPath()
    c.arc(this.x, this.y, this.radius,0,Math.PI*2,false)
    c.fillStyle = this.color
    c.fill()
}

Particle.prototype.update = function(){
    this.draw()
    this.x += this.xVelocity
    this.y += this.yVelocity
}

var square = {
    x: 500,
    y: 150,
    height: 500,
    width: 500,
    color: 'white'
}

var particleContainer = []
var distance = 10


for(let i = 0; i< square.height/distance; i++){
    for(let j = 0; j< square.height/distance; j++){
    particleContainer.push( new Particle(square.x + i*distance,square.y + j*distance) )
}

}





function animate(){
    requestAnimationFrame(animate);
    c.clearRect(0,0,window.innerWidth,window.innerHeight)

  canvas.width = window.innerWidth
canvas.height = window.innerHeight

    for(i of particleContainer){
        let a = mouse.x - i.x
        let b = mouse.y - i.y
        let c = Math.sqrt(Math.pow(b,2) + Math.pow(a,2))

        let a2 = i.xFixed - i.x
        let b2 = i.yFixed - i.y
        let c2 = Math.sqrt(Math.pow(b2,2) + Math.pow(a2,2))

        if(  c < 90  ){
            i.xVelocity = a/c * -20
            i.yVelocity = b/c * -20
        }else if(90 < c && c < 95){
            i.xVelocity = a/c * -1
            i.yVelocity = b/c * -1
        }else if(c2 !== 0){
            i.xVelocity =( a2/c2 )
            i.yVelocity = (b2/c2 )
        }


    }

   for(i of particleContainer){
       i.update()
   }
}

animate()

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Чтобы улучшить рендеринг, вам нужно добавить объекты рендеринга по тому же пути.После создания пути вы можете нарисовать их за один вызов ctx.fill

Попробуйте ограничить доступ к innerWidth и innerHeight, поскольку они являются очень медленными объектами DOM, которые могут вызывать перекомпоновки, просто обращаясь к ним.

Дальнейшие улучшения могут быть сделаны с использованием пулов объектов и предварительного распределения, но это выходит за рамки одного ответа.

Внесите следующие изменения в вашу функцию анимации.

var W = 1, H = 1;
function animate() {
    requestAnimationFrame(animate);
    c.clearRect(0 ,0, W, H)
    if (H !== innerHeight || W !== innerWidth) {
        W = canvas.width = innerWidth;
        H = canvas.height = innerHeight;
    }
    c.beginPath(); // start a new path
    c.fillStyle = "white";
    for (i of particleContainer) {  // update and draw all particles in one pass
        const a = mouse.x - i.x, b = mouse.y - i.y
        const c = (b * b + a * a) ** 0.5;
        const a2 = i.xFixed - i.x, b2 = i.yFixed - i.y
        const c2 = (b2 * b2 + a2 * a2) ** 0.5; 
        if(  c < 90  ){
            i.x += a/c * -20
            i.y += b/c * -20
        }else if(90 < c && c < 95){
            i.x += a/c * -1
            i.y += b/c * -1
        }else if(c2 !== 0){
            i.x +=( a2/c2 )
            i.y += (b2/c2 )
        }
        c.rect(i.x, i.y, 1,1);
    }
    c.fill();  // path complete render it.
   //for(i of particleContainer){  // no longer needed
   //    i.update()
   //}
}
0 голосов
/ 22 ноября 2018

Узнайте, как использовать вкладку «Быстродействие» в инструментах разработчика, и вы сможете увидеть, какие функции занимают больше всего времени.В этом случае я думаю, вы увидите, что это ctx.fill.Пример, который вы разместили, - это запись пикселей в буфер ImageData, который будет намного быстрее, чем рисование и заполнение дуг.В этом примере есть много других небольших оптимизаций, но это будет самым важным, рисование обычно намного медленнее, чем обновление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...