Обработка: Как я могу улучшить частоту кадров в моей программе? - PullRequest
4 голосов
/ 01 декабря 2010

Итак, я работаю в Обработка уже несколько недель, и, хотя у меня нет опыта в программировании, я перешел к более сложным проектам.Я программирую симулятор эволюции, который порождает существ со случайными свойствами.

В конце концов, я добавлю воспроизведение, но на данный момент существа просто как бы плавают по экрану и немного следуют за мышью.Он взаимодействует со звуком из линейного входа, но я прокомментировал эти части так, чтобы его можно было просматривать на холсте, это не должно действительно изменить вопрос, я просто подумал, что укажу на это.

Какна данный момент частота кадров для меня гораздо меньше идеальной, и она постепенно снижается по мере появления новых существ.Я делаю фундаментальную ошибку или просто запускаю слишком много функций на кадр?

Вот исходный код, и вы можете поиграть с ним в браузере здесь :

//import ddf.minim.*;
//import ddf.minim.signals.*;
//import ddf.minim.analysis.*;
//import ddf.minim.effects.*;

//Minim minim;
//AudioInput in;
boolean newCreature = true;
boolean matured[];
int ellipses[];
int hair[];
int maxCreatureNumber = 75;
//int volume;
//int volumeTolerance = 1;
int creatureIndex = -1;
int creatureX[];
int creatureY[];
float strokeWeightAttribute[];
float creatureSize[];
float creatureEndSize[];
float creatureXIncrement[];
float creatureYIncrement[];
float bubbleSize;
float easing = 0.05;
float angle = 0.00;
color colorAttribute[];

void setup() {
    background(0);
    size(1000,500);
    noFill();
    //minim = new Minim(this);
    //in = minim.getLineIn(Minim.STEREO, 512);
    creatureX = new int[maxCreatureNumber];
    creatureY = new int[maxCreatureNumber];
    ellipses = new int[maxCreatureNumber];
    hair = new int[maxCreatureNumber];
    strokeWeightAttribute = new float[maxCreatureNumber];
    creatureEndSize = new float[maxCreatureNumber];
    creatureSize = new float[maxCreatureNumber];
    creatureXIncrement = new float[maxCreatureNumber];
    creatureYIncrement = new float[maxCreatureNumber];
    matured = new boolean[maxCreatureNumber];
    colorAttribute = new color[maxCreatureNumber];
}

void draw() {
  angle += 0.05;
  fill(0, 50);
  rect(-1, -1, 1001, 501);
  // for(int i = 0; i < in.bufferSize() - 1; i++) {
  //     if(in.mix.get(i) * 50 > volumeTolerance) {
  //         volume++;
  //     }
  // }
  if(newCreature && creatureIndex < maxCreatureNumber - 1) {
      initSpontaneousCreature();
  }
  updateCreatures();
  // bubbleSize = volume/250;
  bubbleSize += 0.01;
  // volume = 0;
}

//void stop() {
//    minim.stop();
//    super.stop();
//}

void initSpontaneousCreature() {
    creatureIndex++;
    creatureEndSize[creatureIndex] = int(random(5, 20));
    creatureX[creatureIndex] = int(random(1000));
    if(creatureX[creatureIndex] >= 500) {
        creatureX[creatureIndex] -= creatureEndSize[creatureIndex];
    }
    else {
        creatureX[creatureIndex] += creatureEndSize[creatureIndex];
    }
    creatureY[creatureIndex] = int(random(500));
    if(creatureY[creatureIndex] >= 250) {
        creatureY[creatureIndex] -= creatureEndSize[creatureIndex];
    }
    else {
        creatureY[creatureIndex] += creatureEndSize[creatureIndex];
    }
    ellipses[creatureIndex] = int(random(4));
    hair[creatureIndex] = int(random(4));
    strokeWeightAttribute[creatureIndex] = random(1, 4);
    colorAttribute[creatureIndex] = color(int(random(20,255)), int(random(20,255)), int(random(20,255)));
    matured[creatureIndex] = false;
    newCreature = false;
    while(ellipses[creatureIndex] == 0 && hair[creatureIndex] == 0) {
        ellipses[creatureIndex] = int(random(4));
        hair[creatureIndex] = int(random(4));
    }
}

void updateCreatures() {
    for(int n = 0; n <= creatureIndex; n++) {
        if(matured[n]) {
            creatureX[n] += ((((mouseX) - creatureX[n]) * easing) / (60/*-abs(volume/5))*/)) + random(-5, 6);
            creatureY[n] += ((((mouseY) -creatureY[n]) * easing) / (60/*-abs(/*volume/5))*/)) + random(-5,6);
            drawCreature();
        }
        else {
            if(creatureEndSize[n] != creatureSize[n]) {
                creatureSize[n] += bubbleSize;
                if(creatureSize[n] > creatureEndSize[n]) {
                    creatureSize[n] -= (creatureSize[n] - creatureEndSize[n]);
                }
            }
            else {
                newCreature = true;
                matured[n] = true;
                // bubbleSize = 0;
            }
            drawCreature();
        }
    }
}

void drawCreature() {
    for(int n = 0; n <= creatureIndex; n++) {
        if(matured[n]) {
            stroke(colorAttribute[n]);
            strokeWeight(strokeWeightAttribute[n]);
            for(int i = 0; i <= 4; i++) {
                if(ellipses[n] == i) {
                    if(i == 0) {

                    }
                    else if (i == 1) {
                      pushMatrix();
                      translate(creatureX[n], creatureY[n]);
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(180));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      popMatrix();
                    }
                    else if(i == 2) {
                      pushMatrix();
                      translate(creatureX[n], creatureY[n]);
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(180));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(270));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      popMatrix();

                    }
                    else if(i == 3) {
                      pushMatrix();
                      translate(creatureX[n], creatureY[n]);
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(90));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(180));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      rotate(radians(270));
                      ellipse(creatureSize[n], creatureSize[n], creatureSize[n], creatureSize[n]);
                      popMatrix();
                    }
                }
                if(hair[n] == i) {
                    if(i == 0) {

                    }
                    else if (i == 1) {
                        pushMatrix();
                        translate(creatureX[n], creatureY[n]);
                        for(int j = 0; j <= 360; j+=70) {
                            rotate(j);
                            stroke(colorAttribute[n], random(255));
                            line(0,0, creatureSize[n] + random(10), creatureSize[n] + random(10));
                        }
                        popMatrix();
                    }
                    else if(i == 2) {
                        pushMatrix();
                        translate(creatureX[n], creatureY[n]);
                        for(int j = 0; j <= 360; j+=30) {
                            rotate(j);
                            stroke(colorAttribute[n], random(255));
                            line(0,0, creatureSize[n] + random(10), creatureSize[n] + random(10));
                        }
                        popMatrix();
                    }
                    else if(i == 3) {
                        pushMatrix();
                        translate(creatureX[n], creatureY[n]);
                        for(int j = 0; j <= 360; j+=1) {
                            rotate(j);
                            stroke(colorAttribute[n], random(255));
                            line(0,0, creatureSize[n] + random(10), creatureSize[n] + random(10));
                        }
                        popMatrix();
                    }
                }
            }
        }
        if(!matured[n]) {
            stroke(abs(sin(angle) * 255));
            //strokeWeight(5);
            ellipse(creatureX[n], creatureY[n], creatureSize[n] * 5,  creatureSize[n] * 5);
            noStroke();
        }
    }
}

Ответы [ 3 ]

12 голосов
/ 02 декабря 2010

Правильно, как я и подозревал, все ненужные вызовы pushMatrix(), popMatrix() и большое количество строк, казалось, были основными виновниками, тем не менее, было много избыточного кода.

Я просто переработал код более чистым способом, и он, кажется, работает нормально. Вот моя «улучшенная» версия:

int maxCreatures = 75;
int numCreatures = 0;
int spawnNthFrame = 50;//spawn a creature every 50 frames
Creature[] creatures;

void setup() {
  background(0);
  size(1000,500);
  noFill();
  creatures = new Creature[maxCreatures];
}

void draw() {
  fill(0, 50);
  rect(-1, -1, 1001, 501);
  if(frameCount % spawnNthFrame == 0){
    println("creatures: " + numCreatures);
    if(numCreatures < maxCreatures) {
      //Creature constructor float endSize,int x, int y,int ellipses,int hair,float strokeW,color c
      creatures[numCreatures] = new Creature(random(5, 20),int(random(1000)),int(random(500)),int(random(4)),int(random(4)),random(1, 4),color(int(random(20,255)), int(random(20,255)), int(random(20,255))));
      numCreatures++;
    }
  }
  for(int i = 0; i < numCreatures; i++) creatures[i].update();
}

и класс Существа:

class Creature{
 int x,y,cXInc,cYInc;//if x,y are ints, increments would be into, right?
 float cStrokeWeight,cSize,cEndSize,cSizeInc = 0.01,easing = 0.05,angle = 0.00;
 color cColor;
 int hair,numHair,ellipses;
 boolean matured = false;

 Creature(float endSize,int x, int y,int ellipses,int hair,float strokeW,color c){
    cEndSize = endSize;
    this.x = x;
    if(x >= 500) x -= cEndSize;
    else         x += cEndSize;
    this.y = y;
    if(y >= 250) x -= cEndSize;
    else         x += cEndSize;
    this.ellipses = ellipses;
    this.hair = hair;
    if(hair == 1) numHair = 3;//~5, half that, draw through centre, etc.
    if(hair == 2) numHair = 6;
    if(hair == 3) numHair = 30;//no default value
    cStrokeWeight = strokeW;
    this.cColor = c;
 }
 void update(){
   if(matured) { 
    x += (((mouseX - x) * easing) / 60) + random(-5, 6);
    y += (((mouseY - y) * easing) / 60) + random(-5, 6);
   }else {
    if(cSize < cEndSize) cSize += cSizeInc;
    else matured = true;
    angle += 0.05;
   } 
   this.draw();
 }
 void draw(){
   if(matured){
     stroke(cColor);
     strokeWeight(cStrokeWeight);
     if(ellipses == 1){//2 ellipses diagonally
       ellipse(x,y,cSize,cSize);
       ellipse(x+cSize,y+cSize,cSize,cSize);
     }
     if(ellipses == 2){
       ellipse(x,y,cSize,cSize);
       ellipse(x,y+cSize,cSize,cSize);
       ellipse(x+cSize,y+cSize,cSize,cSize);
     }
     if(ellipses == 3){
       ellipse(x,y,cSize,cSize);
       ellipse(x+cSize,y,cSize,cSize);
       ellipse(x,y+cSize,cSize,cSize);
       ellipse(x+cSize,y+cSize,cSize,cSize);
     }
     float hairAngleInc = TWO_PI/numHair;//angle increment for each piece = 360/number of hair lines
     float hairAngle,hairLength,hairCos,hairSin;
     for(int i = 0; i < numHair; i++){
       hairAngle = hairAngleInc * i;
       hairCos = cos(hairAngle);
       hairSin = sin(hairAngle);
       hairLength = random(20);
       stroke(cColor, random(255));
       line(x + (hairCos * -hairLength),y + (hairSin * -hairLength), x + (hairCos * hairLength),y + (hairSin * hairLength)); 
     }
   }else{
     stroke(abs(sin(angle) * 255));
     ellipse(x,y, cSize * 5,  cSize * 5);
   }
 }
}

Хорошо, теперь объяснения.

Сначала я отделил все переменные, которые были связаны с одним существом, от «глобальных», которые определяют, как работает скетч (сколько порождается существ и т. Д.).

Это делает основной код длиной около 25 строк и в целом чуть меньше 100 строк, что составляет менее половины исходного.

Первая часть не делает ничего особенного. В функции draw () вместо создания Существа в каждом кадре я рисую по одному в каждом N-м кадре, используя переменную spawnNthFrame , что позволяет легко увидеть, какое состояние существа создало это медленно. Если вы установите небольшое значение, например 2, в эту переменную, то должно появиться много существ в кадре.

Класс Creature имеет все свойства исходного кода, хранящиеся в массивах.

Вместо того, чтобы делать

pushMatrix();
translate();
ellipse();
rotate()
ellipse()
popMatrix();

Я просто рисую эллипсы в точке x, y. Небольшой намек на повороты. Я заметил, что они были приращениями 90 градусов. Обработка имеет несколько хороших констант для 90,180,360 градусов в радианах: HALF_PI, PI, TWO_PI , что иногда бывает удобно.

Теперь о «волосатой» ситуации, вот что я прокомментировал для себя:

//if(i == 1) for(int j = 0; j <= 360; j+=70) , well 360/70 is about 5, if (i == 2) , 12 hair
//if = 3-> 360 lines ? do you really need that many lines, that thick ? how about 30 ? 5*12=60, but if you draw the lines through the centre, not from the centre, you can get away with half the lines

Таким образом, для рисования линий было 3 цикла, каждый с разным шагом. В принципе было либо 360/70 строк, 360/30 строк и 360 строк. Примерно около 5,12 и 360 строк. Примерно с 5,12 линиями я уменьшил это вдвое, нарисовав линии «диаметра» поперек центра, а не линии «радиуса» от центра.

Вот что я имею в виду, halfLines

Кроме того, я думаю, что 360 линий с этим штрихом и дрожанием, вероятно, будут выглядеть как набор линий, которые трудно сосчитать, поэтому я подумал, зачем ломать волосы? : P

Возможно, существо будет выглядеть примерно одинаково с радиусом около 60, что означает 30 диаметров.

Теперь объясним немного тригонометрических функций, используемых для этого. Главное - преобразование полярных в декартовые координаты:

Polar будет что-то вроде:

«Я двигаюсь по кругу в направлении, описанном углом (очень похоже на одну ручку часов) и радиусом (расстояние от центра)."

и декартово

«Я двигаюсь по двум осям (по горизонтали / X и по вертикали / Y), вроде улиц Манхэттена, но я обманываю и также перемещаюсь по диагонали сквозь стены".

Если это имеет смысл ... :) В любом случае, вы конвертируете пару angle и radius в пару x и y по формуле:

x = cos(angle) * radius
y = sin(angle) * radius

Для каждой строки:

angle = hairAngle
radius = hairLength

Так что line () с * x + (hairCos * -hairLength) * выглядит примерно так:

x + (hairCos * -hairLength) = 
move to x and from there move by hairLength
to the left(-) for the current angle (hairCos)

Аналогично для y, но с использованием cos, поэтому первая точка линии помещается в противоположную прямую (-hairLength) угла, движущегося от центра (который является x существа), а вторая - «диагональ». Представьте, что вы рисуете «диагонали» (от (-x, -y) до (+ x, + y)), но вы также поворачиваете их.

Обновление

Видимо, скопируйте / вставьте этот код также работает в javascript (лучше всего просматривать в Chromium / Chrome). Вы также можете запустить его прямо здесь:

var maxCreatures = 75;
var numCreatures = 0;
var spawnNthFrame = 50;//spawn a creature every 50 frames
var creatures = [];

function setup() {
  background(0);
  createCanvas(1000,500);
  noFill();
}

function draw() {
  fill(0, 50);
  rect(-1, -1, 1001, 501);
  if(frameCount % spawnNthFrame === 0){
    println("creatures: " + numCreatures);
    if(numCreatures < maxCreatures) {
      //Creature constructor float endSize,int x, int y,int ellipses,int hair,float strokeW,color c
      creatures[numCreatures] = new Creature(random(5, 20),int(random(1000)),int(random(500)),int(random(4)),int(random(4)),random(1, 4),color(int(random(20,255)), int(random(20,255)), int(random(20,255))));
      numCreatures++;
    }
  }
  for(var i = 0; i < numCreatures; i++) creatures[i].update();
}




function Creature(endSize,x,y,ellipses,hair,strokeW,c){
 this.x = x;
 this.y = y;
 this.ellipses = ellipses;
 this.hair = hair;
 this.numHair = 0;
 this.cStrokeWeight = strokeW;
 this.cColor = c;
 this.cXInc = 0;
 this.cYInc = 0.01;
 this.cSize = 0;
 this.cEndSize = endSize;
 this.easing = 0.05;
 this.angle = 0.0;
 this.matured = false;
 
    if(x >= 500) x -= this.cEndSize;
    else         x += this.cEndSize;
    if(y >= 250) x -= this.cEndSize;
    else         x += this.cEndSize;
    if(hair == 1) this.numHair = 3;//~5, half that, draw through centre, etc.
    if(hair == 2) this.numHair = 6;
    if(hair == 3) this.numHair = 30;//no default value


 this.update = function(){
   if(this.matured) { 
    this.x += (((mouseX - this.x) * this.easing) / 60) + random(-5, 6);
    this.y += (((mouseY - this.y) * this.easing) / 60) + random(-5, 6);
   }else {
    if(this.cSize < this.cEndSize) this.cSize += this.cSizeInc;
    else this.matured = true;
    this.angle += 0.05;
   } 
   this.draw();
 }
 this.draw = function(){
   if(this.matured){
     stroke(this.cColor);
     strokeWeight(this.cStrokeWeight);
     if(this.ellipses == 1){//2 ellipses diagonally
       ellipse(this.x,this.y,this.cSize,this.cSize);
       ellipse(this.x+this.cSize,this.y+this.cSize,this.cSize,this.cSize);
     }
     if(this.ellipses == 2){
       ellipse(this.x,this.y,this.cSize,this.cSize);
       ellipse(this.x,this.y+this.cSize,this.cSize,this.cSize);
       ellipse(this.x+this.cSize,this.y+this.cSize,this.cSize,this.cSize);
     }
     if(this.ellipses == 3){
       ellipse(this.x,this.y,this.cSize,this.cSize);
       ellipse(this.x+this.cSize,this.y,this.cSize,this.cSize);
       ellipse(this.x,this.y+this.cSize,this.cSize,this.cSize);
       ellipse(this.x+this.cSize,this.y+this.cSize,this.cSize,this.cSize);
     }
     var hairAngleInc = TWO_PI/this.numHair;//angle increment for each piece = 360/number of hair lines
     var hairAngle,hairLength,hairCos,hairSin;
     for(var i = 0; i < this.numHair; i++){
       hairAngle = hairAngleInc * i;
       hairCos = cos(hairAngle);
       hairSin = sin(hairAngle);
       hairLength = random(20);
       stroke(this.cColor, random(255));
       line(this.x + (hairCos * -hairLength),this.y + (hairSin * -hairLength), this.x + (hairCos * hairLength),this.y + (hairSin * hairLength)); 
     }
   }else{
     stroke(abs(sin(this.angle) * 255));
     ellipse(this.x,this.y, this.cSize * 5,  this.cSize * 5);
   }
 }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>

Creatures JS sketch preview

6 голосов
/ 01 декабря 2010

Вы можете использовать функцию frameRate(fps).Что он делает, это определяет количество кадров, которые будут отображаться каждую секунду.Однако, если процессор недостаточно быстр для поддержания заданной скорости, это не будет достигнуто.Например, вызов функции frameRate(30) попытается обновить 30 раз в секунду.Рекомендуется установить частоту кадров в пределах setup().

Помните, что при использовании draw() без указания частоты кадров, по умолчанию он будет работать на скорости 60 кадров / с

5 голосов
/ 01 декабря 2010

Ну, есть старый добрый метод случайной паузы . Это «профиль бедняка».

Просто сделайте снимок несколько раз. Это покажет вам именно то, что занимает больше всего времени. Это то, что вы должны увидеть, если вы можете сделать быстрее. Это будет отображаться в увеличенной частоте кадров.

...