2010-12-31 3 views
0

Я написал небольшую систему частиц для моего 2d-приложения. Вот код дождя:Помогите с оптимизацией кода

// HPP ----------------------------------- 
struct Data 
{ 
    float x, y, x_speed, y_speed; 
    int timeout; 
    Data(); 
};   
std::vector<Data> mData; 
bool mFirstTime; 
void processDrops(float windPower, int i); 

// CPP ----------------------------------- 
Data::Data() 
    : x(rand()%ScreenResolutionX), y(0) 
    , x_speed(0), y_speed(0), timeout(rand()%130) 
{ } 

void Rain::processDrops(float windPower, int i) 
{ 
    int posX = rand() % mWindowWidth; 

    mData[i].x = posX; 

    mData[i].x_speed = WindPower*0.1; // WindPower is float 
    mData[i].y_speed = Gravity*0.1; // Gravity is 9.8 * 19.2 

    // If that is first time, process drops randomly with window height 
    if (mFirstTime) 
    { 
     mData[i].timeout = 0; 
     mData[i].y = rand() % mWindowHeight; 
    } 
    else 
    { 
     mData[i].timeout = rand() % 130; 
     mData[i].y = 0; 
    } 
} 

void update(float windPower, float elapsed) 
{ 
    // If this is first time - create array with new Data structure objects 
    if (mFirstTime) 
    { 
     for (int i=0; i < mMaxObjects; ++i) 
     { 
      mData.push_back(Data()); 
      processDrops(windPower, i); 
     } 
     mFirstTime = false; 
    } 

    for (int i=0; i < mMaxObjects; i++) 
    { 
     // Sleep until uptime > 0 (To make drops fall with randomly timeout) 
     if (mData[i].timeout > 0) 
     { 
      mData[i].timeout--; 
     } 
     else 
     { 
      // Find new x/y positions 
      mData[i].x += mData[i].x_speed * elapsed; 
      mData[i].y += mData[i].y_speed * elapsed; 

      // Find new speeds 
      mData[i].x_speed += windPower * elapsed; 
      mData[i].y_speed += Gravity * elapsed; 

      // Drawing here ... 

      // If drop has been falled out of the screen 
      if (mData[i].y > mWindowHeight) processDrops(windPower, i); 
     } 
    } 
} 

Итак, основная идея: у меня есть структура, состоящая из положения падения, скорости. У меня есть функция обработки капель по некоторому индексу в векторном массиве. Теперь, если это первый запуск, я делаю массив с максимальным размером и обрабатываю его в цикле.

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

Я пытался заменить все Int с uint16_t, но я думаю, что это не имеет значения.

+0

Возможно, что тайм-аут не так эффективен, но я не знаю, как называется функция «update()» – Cristy

+0

@Cristy У меня нет других идей о том, как сделать капли движутся с разным временем. – Ockonal

+0

@Cristy, функция обновления вызывает обновление каждого кадра (например, ~ 17 мс) – Ockonal

ответ

0

В цикле ввести ссылку Data& current = mData[i] и использовать его вместо mData[i]. И используйте эту ссылку вместо индекса также в procesDrops.

BTW Я думаю, что консультации mFirstTime в processDrops нецелесообразны, потому что это никогда не будет правдой. Хмм, я пропустил processDrops в цикле инициализации. Не обращайте на это внимания.

+0

Измените компилятор, если это действительно изменилось! :/ – T33C

+0

В отладочной сборке некоторые другие вещи важнее производительности – Dialecticus

1

Замена int на uint16_t не должна иметь никакого значения (это займет меньше памяти, но не должно влиять на время работы на большинстве машин).

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

Если это медленно, это из-за чего-то другого. Возможно, у вас слишком много капель, или остальная часть вашего кода настолько медленная, что update получает мало раз в секунду.
Я бы посоветовал вам профайл вашей программы и посмотреть, сколько времени тратится.


EDIT:
одна вещь, которая может ускорить такой алгоритм, особенно если ваша система не получила FPU (! Это не тот случай персонального компьютера ...), будет замените значения с плавающей запятой целыми числами.

Просто умножьте переменную elapsed (и ваши константы, такие как 0.1) на 1000, чтобы они отображали миллисекунды и использовали только целые числа во всем мире.

0

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

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

+0

~ 150 элементов в векторе. – Ockonal

1

Несколько точек:

  1. Физика неверности: энергия ветра должна быть изменена скорость делает закрыта для скорости ветра, а также для простоты я бы предположить, что начальное значение x_speed является скорость ветра.
  2. Вы не заботитесь о фракции с ветром, поэтому капли становятся все быстрее и быстрее. но это зависит от вашего желания моделировать.
  3. Я бы просто предположил, что падение падает с постоянной скоростью в постоянном направлении, потому что это действительно то, что происходит очень быстро.

Также вы можете оптимизировать все это очень просто, как вам не нужно решить уравнение движения с помощью интегрирования, как это может быть решена достаточно просто прямо как:

x(t):= x_0 + wind_speed * t 
y(t):= y_0 - fall_speed * t 

Это случай устойчивого падения когда сила тяжести равна трению.

x(t):= x_0 + wind_speed * t; 
y(t):= y_0 - 0.5 * g * t^2; 

Если вы хотите моделировать капли, которые падают быстрее и быстрее.

+0

Спасибо за идею, я рассмотрю ее. – Ockonal

1

Несколько вещей, чтобы рассмотреть следующие вопросы:

В вашей processDrops функции, вы передаете в windPower, но использовать какое-то член класса или глобального называется WindPower, что опечатка? Если значение Gravity не изменяется, сохраните расчет (т. Е. Мульти на 0,1) и используйте это напрямую.

В вашей функции update, вместо вычисления windPower * elapsed и Gravity * elapsed для каждой итерации, вычислите и сохраните это перед циклом, затем добавьте. Кроме того, реорганизуйте цикл, нет необходимости делать расчет скорости и рендеринг, если выпад из экрана, сначала выполните проверку, и если падение все еще находится на экране, обновите скорость и визуализируйте!

Интересно, что вы никогда не проверяете, не выпадает ли капля из интервала между координатами x, вы проверяете высоту, но не ширину, вы можете сэкономить себе некоторые вычисления и время рендеринга, если вы сделали это проверьте также!

+0

О, очень хорошие идеи. Благодаря! – Ockonal

0

Похоже, что все ваше время идет в ... Drawing Here.
Довольно легко find out for sure, где время идет.