Конференция "Игры" » как выловить начало кадровой развертки. [D7, WinXP]
 
  • ol'ka (20.06.08 03:33) [0]
    как известно для рендерингав 3D-играх часто используется привязка начала рисования картинки к моменту импульса запуска кадровой развертки, чтобы получить картинку без наложения кадров. Существует ли компонент для обработки события типа onScreenRefresh? подобный TTimer например, который к сожалению не позволяет решить проблему.
  • DimaBr © (20.06.08 08:36) [1]
    Скорее всего существует, НО

    Внимание! Здесь обсуждаются вопросы, связанные с разработкой компонентов, редакторов свойств, редакторов компонентов и экспертов IDE.
    Вопросы по поиску и использованию готовых компонентов, редакторов или экспертов являются нарушением тематики и могут быть удалены.
  • ol'ka (20.06.08 11:08) [2]
    как раз в данном случае не снимается вопрос "разработки" ,  такого компонента или хотябы просто процедуры перехвата соответствующего прерывания от видеокарты, думаю текст займет меньше места чем это обсуждение, надеюсь найдутся профи, которым не составит труда помочь.
  • МистерТ (20.06.08 11:51) [3]
    ИМХО - не существует.

    А вообще - опиши задачу, может её можно решить другим методом ?
  • ol'ka (20.06.08 12:13) [4]
    все примитивно просто, рисую на канвасе изменяющуюся со временем картинку. Событие  onTimerEvent запускает просчет новой сцены и он же, пока, отрисовывает полученное на канвасе методом Canvas.Repaint, так вот интервал таймера 50мс в идеале равный 3м целым кадрам (60Гц) оказывается на практике не совсем точно равен, и как следствие проявляется мерцание. Понятно что .Repaint нужно привязать к началу растра чтобы убрать нежелательный эффект, вопрос - как? Тема должна быть хорошо изучена в определенных кругах так как во многих играх когда FPS приближается к Refresh Rate данный эффект проявляется в значительной степени и существует галочка в настройках включающая привязку рендеринга к началу кадра как способ борьбы с этим злом.
  • @!!ex © (20.06.08 13:07) [5]
    Мерцание никакого отношения к кадровой развертке не имеет.
    DoubleBuffer в помощь.
  • ol'ka (20.06.08 13:41) [6]

    > Мерцание никакого отношения к кадровой развертке не имеет.

    Формально вы правы, отношение как раз имеет строчная развертка, только началу рисаования 1-й строки предшествует кадровый синхроимпульс, а дальше 2-я, 3-я и т.д. строки до следующего кадра. К примеру, монитор успел отобразить 300 строк в текущем кадре, а вы рисуете начиная с 200-й, тогда все что вы нарисуете там где луч уже побывал не будет отображено до следующего кадра, а если FPS превышает кадровую частоту, то не будет отображено вообще. Зрительно это и проявляется в виде мерцаний, наложения кадров и бесит конкретно. А вот если выловить кадровый импульс и расчитать вывод на экран начиная  оттуда, где луч еще не бегал эффекта удастся избежать, нужно только прерывание от видеокарты сигнализирующее о начале кадра получить в виде события и обработать его процедурой. С процедурой справлюсь, а вот как событие выхватить - пока ступор


    > DoubleBuffer в помощь.

    ... чета не помогает, не нахожу я <property DoubleBuffered: Boolean;> у канваса ... уж потрудитесь разжевать если гдето ошибаюсь
  • ol'ka (20.06.08 13:51) [7]
    в конце концов событие onTimerEvent по сути есть тоже самое - прерывание от системного таймера!
  • Sapersky (20.06.08 14:05) [8]
    не нахожу я <property DoubleBuffered: Boolean;> у канваса

    У формы, панели есть. Или можно вручную создать битмап, рисовать в него, потом копировать битмап на экран.
    Синхронизировать обновление экрана с развёркой в принципе можно (через DirectX/OpenGL), но это, как правило, требуется в случае очень уж активной анимации, в играх, например. В большинстве приложений достаточно  буферизации.
  • @!!ex © (20.06.08 14:06) [9]
    > [6] ol'ka   (20.06.08 13:41)

    Поверьте. Вертикальная синхронизация ничего не даст.
    Возьмите любую игру. Принудительно отключите вертикальную синхронизацию... И вы не увидите мерцания. Хотя кадры и будут не синхронизированы.

    DoubleBuffer - это двойная буфферизация. Когда весь выводит идет в память, а потом одной командой(BitBlt, например) выводится в видеопамять.

    Если речь о канвасе и дельфи, то проще всего делать вывод на TBitMap, а потом через BitBlt выводить на DC формы.
  • ol'ka (20.06.08 14:43) [10]
    кхе кхе, а у формы канвас тоже есть? тоесть у меня получится сделать

    ...
    MyForm.DoubleBuffered: = True
    ...

    а потом

    ...
    with MyForm.Canvas do ......... end;
    и все у меня получится?

    а то зачем-то мною на форму TPaintBox был прикручен ради канваса...
  • @!!ex © (20.06.08 15:20) [11]
    > [10] ol'ka   (20.06.08 14:43)

    У формы тоже канвас есть.
    Лично я за 10 лет проганья на дельфе, не использовал ни разу PaintBox. ПРи том, что очень часто и много рисую на форме.
  • @!!ex © (20.06.08 15:22) [12]
    > [10] ol'ka   (20.06.08 14:43)

    Создай TbitMap. При изменении размера окна, меняй и размез битмапа. ВЕСЬ вывод делай в этот битмап. У него есть канвас. :)
    А в конце командой BitBlt копируй битмап на форму.
    BitBlt(Form.Canvas.Handle,0,0,Form.ClientWidth, Form.ClientHeight,BitMap.Canvas.Handle,0,0, SRCCOPY);
  • Sapersky (20.06.08 15:40) [13]
    Возьмите любую игру. Принудительно отключите вертикальную синхронизацию... И вы не увидите мерцания.

    Там не мерцание, а т.н. расхождение (tearing) может быть, сдвиг картинки горизонтальными полосками. У меня на этом примере на вертикальных сторонах квадратов хорошо видно:
    http://sapersky.narod.ru/files/VSync_test.rar
    (синхронизация переключается нажатием 'S').
    Конечно, это экстремальный случай, в реальных играх расхождение сложнее разглядеть.
  • @!!ex © (20.06.08 15:54) [14]
    > [13] Sapersky   (20.06.08 15:40)

    Сдвиг картинки бывает, я не спорю. Но оно мало похоже на мерцание. :)
  • ol'ka (20.06.08 15:59) [15]

    > Создай TbitMap. При изменении размера окна, меняй и размез
    > битмапа. ВЕСЬ вывод делай в этот битмап. У него есть канвас.
    >  :)
    > А в конце командой BitBlt копируй битмап на форму.
    > BitBlt(Form.Canvas.Handle,0,0,Form.ClientWidth, Form.ClientHeight,
    > BitMap.Canvas.Handle,0,0, SRCCOPY);

    методика понятна и вполне приемлема, спасибо за идею!
    Идея использовать битмап натолкнула меня на мысль оптимизировать рендеринг.
      Дело в том что TPaintBox имеел удобный для меня метод .repaint, для формы не подойдет потому как на ней кроме пэйнтбокса еще куча всяких панелек с кнопочками прикручено и перерисовывать их repaint - ом крайне криво будет. Кроме того выводимое изображение содержит статические элементы перерисовывать которые тоже бессмысленно (хотя repaint успевал перерисовывать и проблем не создавал)
     Раз уж пользоваться битмапом то рационально отделить статику от динамики и создать 2 битмапа 1-й один раз, а 2-й рендерить с заданным интервалом, потом их объединить и cгрузить на канвас формы.
     Вопрос. Как битмапы склеить чтобы второй на первый накладывался как Transparent ?
  • @!!ex © (20.06.08 16:14) [16]
    > [15] ol'ka   (20.06.08 15:59)

    TransparentBlt
    В качестве одного из параметров идет цвет, который должен быть прозрачным.
    Blendinga(насколько мне известно) у канваса можно только вручную добиться.
  • ol'ka (20.06.08 16:17) [17]

    > Сдвиг картинки бывает, я не спорю. Но оно мало похоже на
    > мерцание. :)

    по сути да, эффект мерцания в моем случае проявляется  т.к. repaint трет канвас и по новой все рисует а пока он это делает монитор ту тьму показует а картинка только в следующем кадре уже видна вот и мерцает усе! ;)
  • @!!ex © (20.06.08 16:22) [18]
    > [17] ol'ka   (20.06.08 16:17)

    Кстати, BitMap не обязательно должен быть размером с форму.
    Ничего не мешает, например, сделать БитМап размером 100х100 и рисовать его в координатах 500, 600 на форме:
    BitBlt(Form.Canvas.Handle,500,600,100,100,BitMap.Canvas.Handle,0,0, SRCCOPY);
  • @!!ex © (20.06.08 16:22) [19]
    Внимательно почитай хелп по BitBlt. Прозреешь, :)
 
Конференция "Игры" » как выловить начало кадровой развертки. [D7, WinXP]
Есть новые Нет новых   [134428   +40][b:0][p:0.001]