Как получить действительно плавные движущиеся объекты, используя openGL - PullRequest
0 голосов
/ 03 августа 2010

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

Это конкретный пример, но в целом мне интересно, как получить самое плавное движение даже при использовании очень простой линейной интерполяции?Когда я смотрю на движение, когда я переключаюсь между страницами на моем iphone, это просто настолько плавно, что заставляет меня задуматься, как бы я достиг этого на моем (быстром) Mac?

Спасибо
Roxlu

PhotoBoothCountdown::PhotoBoothCountdown(float fMillisDuration)
    :duration(fMillisDuration)
    ,start_time(0)
{
    setActionCommand("take_picture");
}

void PhotoBoothCountdown::update() {
    if(start_time != 0) {
        float cur = ofGetElapsedTimeMillis();
        perc = (cur-start_time)/duration;

    }
}

void PhotoBoothCountdown::draw() {
    float resolution = 150;
    int parts_filled = resolution * perc;
    int parts_unfilled = (resolution - parts_filled);
    float part_angle = TWO_PI/resolution;
    //printf("filled: %i/%i/%i\n", parts_filled, parts_unfilled, (parts_filled+parts_unfilled));
    float radius = 300.0f;
    float width = 100;
    float radius_inner = radius-width;
    float center_x = ofGetWidth()/2;
    float center_y = ofGetHeight()/2;
    float angle = 0;

    glBegin(GL_TRIANGLE_STRIP);
        glColor4f(0.2f, 0.2f, 0.2f,0.9f);   
        for(int i = 0; i <= parts_filled; ++i) {
            float cosa = cos(angle);
            float sina = sin(angle);
            glVertex2f(center_x + cosa * radius,center_y + sina * radius);
            glVertex2f(center_x + cosa * radius_inner,center_y + sina * radius_inner);
            angle += part_angle;
        }
    glEnd();
    glBegin(GL_TRIANGLE_STRIP);
        glColor4f(1.0f, 1.0f, 1.0f,0.9f);
        angle -= part_angle;
        for(int i = 0; i <= parts_unfilled; ++i) {
            float cosa = cos(angle);
            float sina = sin(angle);
            glVertex2f(center_x + cosa * radius,center_y + sina * radius);
            glVertex2f(center_x + cosa * radius_inner,center_y + sina * radius_inner);
            angle += part_angle;
        }
    glEnd();

    if(perc >= 1) { 
        printf("should fire");
        fireEvent();
        reset();
    }
}



void PhotoBoothCountdown::start() {
    start_time = ofGetElapsedTimeMillis();
    end_time = start_time + duration;
}

void PhotoBoothCountdown::reset() {
    start_time = 0;
    end_time = 0;
    perc = 0;
}

Ответы [ 3 ]

1 голос
/ 03 августа 2010
0 голосов
/ 04 августа 2010

Первое, что я хотел бы сделать, это просто нарисовать один кружок и сохранить его в списке отображения (вы можете использовать буферные объекты, но от этого не зависит ни один из оставшихся советов, и немедленный режим, поэтому мы будем придерживаться простейшего улучшения). Нарисуйте разделенный круг, поместив текстурные координаты на каждый, соответствующий проценту завершения. Примените шейдер, который в основном скучен, но имеет форму для полноты; треугольники с их текстурными координатами <= эта полнота подсвечивается. Остальные остаются серыми. Тогда ваш рисунок состоит из установки униформы и вызова списка отображения. Гораздо быстрее. </p>

0 голосов
/ 03 августа 2010

Трудно догадаться, о чем вы спрашиваете - мерцание, наложение, плавное движение или рисование артефактов.Свободные мысли после просмотра вашего кода

  • Вы предполагаете, что если float part_angle = TWO_PI/resolution;, то, суммируя (angle += part_angle) resolution раз, вы получите TWO_PI.К сожалению, это не так в арифметике с плавающей запятой.Также sin (TWO_PI), потому что (TWO_PI) не будет обязательно возвращать точные значения 0.0 и 1.0.

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

  • операции с плавающей точкой могут привести к ошибкам округления, и эти ошибки могут повлиять на целочисленные значения после преобразований.Возможно, вы никогда не получите все заполненные части, вычислив их по выражению, подобному этому int parts_filled = resolution * perc;.Вы можете преобразовать свой процентный обратный отсчет, чтобы он использовал целочисленные типы, или, по крайней мере, проверить его, распечатав процентное значение и проверить, достигнет ли он когда-либо 100%.
  • Дополнительно вы можете
    • Использовать сглаживаниечтобы сделать края более плавными
    • Увеличьте частоту кадров (это зависит от того, как вы обновляете чертеж)
    • Включите вертикальную синхронизацию, чтобы удалить разрыв страницы
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...