Вращение с постоянной скоростью в представлении OpenGL ES с использованием CADisplayLink на iPhone - PullRequest
0 голосов
/ 06 ноября 2010

Мои классы и код OpenGL ES получены из Apple GLES2Sample пример кода . Я использую их, чтобы показать трехмерные объекты, плавно вращающиеся вокруг одной оси, с ожидаемой постоянной скоростью вращения. В настоящее время приложение использует интервал кадра 1, и каждый раз, когда рисуется представление OpenGL (в методе drawView EAGLView), я поворачиваю модель на определенный угол.

На практике это дает приличные результаты, но не идеальные: во время вращения, когда большие части объекта исчезают из виду, рендеринг становится быстрее, и вращение, таким образом, не имеет постоянной угловой скорости. У меня вопрос: как мне сделать это более плавным?

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

Ответы [ 2 ]

3 голосов
/ 08 ноября 2010

Я склонен использовать CADisplayLink для запуска новых кадров и простого вычисления времени в запросе кадров, чтобы выяснить, насколько далеко продвинется моя логика.

Предположим, у вас есть переменная-член timeOfLastDraw типа NSTimeInterval,Вы хотите, чтобы ваша логика работала, скажем, со скоростью 60 ударов в секунду.Затем (с целой кучей переменных, чтобы сделать код более понятным):

- (void)displayLinkDidTick
{
    // get the time now
    NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate];

    // work out how many quantums (rounded down to the nearest integer) of
    // time have elapsed since last we drew
    NSTimeInterval timeSinceLastDraw = timeNow - timeOfLastDraw;
    NSTimeInterval desiredBeatsPerSecond = 60.0;
    NSTimeInterval desiredTimeInterval = 1.0 / desiredBeatsPerSecond;

    NSUInteger numberOfTicks = (NSUInteger)(timeSinceLastDraw / desiredTimeInterval);

    if(numberOfTicks > 8)
    {
        // if we're more than 8 ticks behind then just do 8 and catch up
        // instantly to the correct time
        numberOfTicks = 8;
        timeOfLastDraw = timeNow;
    }
    else
    {
        // otherwise, advance timeOfLastDraw according to the number of quantums
        // we're about to apply. Don't update it all the way to now, or we'll lose
        // part quantums
        timeOfLastDraw += numberOfTicks * desiredTimeInterval;
    }

    // do the number of updates
    while(numberOfTicks--)
        [self updateLogic];

    // and draw
    [self draw];
}

В вашем случае updateLogic будет применять фиксированное количество вращения.Если постоянное вращение действительно все, что вам нужно, вы можете просто умножить постоянную вращения на numberOfTicks или даже пропустить весь этот подход и сделать что-то вроде:

glRotatef([NSDate timeIntervalSinceReferenceData] * rotationsPerSecond, 0, 0, 1);

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

1 голос
/ 08 ноября 2010

Если вы не хотите, чтобы скорость рендеринга изменялась, и ваш открытый цикл (т. Е. Полный наклон) с CADisplayLink или другим таймером анимации, вы можете сделать две вещи:

1)Оптимизируйте свой код так, чтобы он никогда не падал ниже 60 FPS - максимальной частоты кадров для устройства при любых обстоятельствах с вашей моделью.

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

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

Cheers.

...