Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
1

Виснет WM_PAINT

13.03.2010, 19:40. Показов 3535. Ответов 19
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Я долго ломал голову как мне сделать OnPaint чтобы ничего не тормозило и отрисоввывалось быстро. Сначала я навесил на onPaint перерисовку сцены, но по таймеру (иначе слишком часло получается) в 30 миллисекунд. Но тут я лдолго долбался пока приручил системные часы, так как у SetTimer() разрешение 55 мс и потом пришлось таймер этот совать в отдельный поток, вообщем не очень выход, но помогает.
Идея 2: Во-первых, когда происходит событие WM_PAINT, в него должны предаваться координаты прямоугольной области, которую нужно перерисовать. Поэтому можно прерисовывать только часть, а если ничего н поменялось - не прерисовывать сцену вообще. А во-вторых, Можно POpenGL рисовать в буфер (буфер трафарета, вроде так это называтся), а потом копировать оттуда данные о цвете в нужную область (прямоугольник из WM_PAINT). Но я не могу это реализовать.

1) Как мне заставить OpenGL рисовать все не на форме а в буфер?
2) Как мне при появлении события OnPaint узнать параметры этой прямоугольной области?
3) Как мне скопировать из буфера данные о цвете в эту область?
Помогитеэто реализовать.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
13.03.2010, 19:40
Ответы с готовыми решениями:

OpenGL + WM_PAINT
У меня нет доступа к HWND окна. Есть только доступ к событию WM_PAINT и HDC, полученного в...

CDialog::PumpMessage виснет (бесконечный WM_PAINT?)
У меня есть следующая странная проблема на компьютере заказчика (куда я не имею доступа): OS:...

Виснет программа при компиляции, степовер не работает, так же виснет
Виснет программа при компиляции, степовер не работает, так же виснет. Программа - простейший...

WM_PAINT
На главном окне- статик. По сообщению WM_PAINT и при необходимости рисую на нем. Все как описано не...

19
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
14.03.2010, 04:28 2
Цитата Сообщение от galileopro Посмотреть сообщение
пришлось таймер этот совать в отдельный поток, вообщем не очень выход, но помогает.
Зачем таймер в поток? Лучше сам рендеринг ОГЛа в отдельном потоке сделать. Или я чего-то не пойму?
Цитата Сообщение от galileopro Посмотреть сообщение
Как мне заставить OpenGL рисовать все не на форме а в буфер?
Это конечно можно сделать. Называется внеэкранный буфер или pixel buffer (Pbuffer). Только для его инициализации нужно пересоздавать окно на винде =(. Если интересно загугли расширениеWGL_ARB_pbuffer. Кстати, есть ещё альтернатива - фреймбуфер, тоже как расширение идёт.
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
14.03.2010, 12:17  [ТС] 3
О. Вы мне очень помогли. Смотрите какая у мееня идея:
1) Пускай OpenGL использует 2 буфера, но ни первый ни второй на экран само не выводит.
2) По событию таймера (не очень часто, думаю 25 раз в секунду хватит. Все равно чловеческий глаз не различает слишком частую смену кадров) делать SwapBuffer() с отключенной вертикальной синхронизацией (а то 25 раз за секунду можт и н успеть). Таким образом изображение, которо е нужно выводит должно будет поместиться в первый буфер (FRONT buffer). После этого этот првый буфер нужно полностью скопировать в видимую видеопамять, чтобы у нас частота обновлния не упала ниже 25 fps. А то ведь пользоватль может вообще наше окно не трогать и тогда WM_PAINT просто не будет происходить.
2) По событию OnPaint просто выводить содержимое првого буфера на экран. Сцну не пеерерисовывать, буферы местами НЕ менять, а просто скопировать в нужную область видеопамяти содержимое 1 - го буфера. Причем тут можно прерисовывать только облать, которая требует этой перерисовки (которая прекрывалась другими приложениями или просто пользователь затер как-то)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
PAINTSTRUCT myPS;  //В myPaintStruct будут все парамтры перерисовки
RECT myRect;  //Прямоугольную облать, требующая перерисовки
BITMAPINFO* bm_info = new BITMAPINFO;
byte* wrk = new byte[4*400*500];
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)        
{
    switch (uMsg) 
    {
    case WM_CREATE:
        {
        bm_info->bmiHeader.biSize = 40;
        bm_info->bmiHeader.biSizeImage = 0;
        bm_info->bmiHeader.biWidth = 500;
        bm_info->bmiHeader.biHeight = -400;
        bm_info->bmiHeader.biPlanes = 1;
        bm_info->bmiHeader.biBitCount = 32;
        bm_info->bmiHeader.biCompression = BI_RGB;
        for (int i = 0; i < 400*500; i++){
                wrk[i*4] = 0;
                wrk[i*4+1] = 0;
                wrk[i*4+2] = 0xFF;
            }
        return 0;
        }
case WM_PAINT:
    {
        BeginPaint(hWnd, &myPS);
        myRect = myPS.rcPaint; 
        SetDIBitsToDevice(hDC, 0, 0, myRect.right - myRect.left, myRect.bottom - myRect.top, 0, 0, 0, myRect.bottom - myRect.top, (void*)wrk, bm_info, DIB_RGB_COLORS);
        EndPaint(hWnd, &myPS);
        return 0;
    }
Здесь я скопировал данные о цвете из массива расположнного в хипе (HEAP) в прямоугольную область, требующую перерисовки. Вот как мне вместо этого массива копировать прямо из буфера OpenGL????? И еще, я хочу написать тут ассемблерную вставку, которая вообще напрямую скопирует из этого буфера посредстрвом
Assembler
1
rep movsw
байты в видимую часть видеопамяти. Но для этого мне надо получить указатель на этот Frame Buffer OpenGL.
И ЕЩЕ: даже если я напишу копирование напрямую, то выполнять его будет ЦП, а мне бы неплох как-то так исхитриться, чтобы из одного бужера в другой копировала сама видеокарта. Вдь ей это лгче сделать. Там память более быстрая (чаще всего, если только польователь не уникум и н поставил себе навороченную DDR3 - 1600 с плохой видеокартой), и не андо по главной шине данные гонять. Вдь OpenGL, как я понимаю, вс свои буферы делает в видеопамяти, так что там просто нужно из одной области в другую скопировать.

Добавлено через 13 минут
Цитата Сообщение от snake32 Посмотреть сообщение
пересоздавать окно на винде =(
Это не проблема я ведь все равно пишу все на WinApi. Просто другой стиль поставить.
Цитата Сообщение от snake32 Посмотреть сообщение
WGL_ARB_pbuffer. Кстати, есть ещё альтернатива - фреймбуфер
А какой из них быстрее?

Добавлено через 12 минут
Вот еще: можно вообще ничего никуда не копировать. Просто найти функцию, которая скажет видеокарте "Выводи то, что находится в видеопамяти по вот-такому адресу" (я еще в себе), тогда там достаточно скопировать указатель на буфер OpenGL. Вот только проблема: когда после такого копирования видеокарта начнет формировать следующий кадр, то она затрет буфер OpenGL. Как с эти бороться? Неужели кроме SwapBuffers ничго пристойного нет?
0
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
14.03.2010, 15:25 4
Цитата Сообщение от galileopro Посмотреть сообщение
А то ведь пользоватль может вообще наше окно не трогать и тогда WM_PAINT просто не будет происходить.
Окно с ОГЛом юзер может и не трогать, но это не означает что WM_PAINT не будет вызываться. Например, такой случай, когда юзер начинает перемещать левое окно поверх нашего.
Цитата Сообщение от galileopro Посмотреть сообщение
А какой из них быстрее?
На сколько я знаю PBuffer появился раньше, чем FBO(Frame Buffer Object). PBuffer сложнее инициализоравать и обладает некоторыми недостатками:
Цитата Сообщение от Разработка и отладка шейдеров
Каждый р-буфер имеет свой контекст рендеринга. Это приводит к тому, что операции переключения между буферам оказываются весьма дорогостоящими в плане быстродействия.

Каждый р-буфер имеет свой набор внутренних буферов(цвета, глубины, трафарета....), но возможность совместного использования одного и того же внутреннего буфера несколькими р-буферами отсутствует.
Кроче FBO - рулит. С ним тоже не всё так просто и прозрачно:
http://www.gamedev.ru/communit... es/caveats
Хотя возможно уже всё это исправили в последних дровах.
Цитата Сообщение от galileopro Посмотреть сообщение
Вот еще: можно вообще ничего никуда не копировать. Просто найти функцию, которая скажет видеокарте "Выводи то, что находится в видеопамяти по вот-такому адресу" (я еще в себе), тогда там достаточно скопировать указатель на буфер OpenGL. Вот только проблема: когда после такого копирования видеокарта начнет формировать следующий кадр, то она затрет буфер OpenGL. Как с эти бороться? Неужели кроме SwapBuffers ничго пристойного нет?
FBO, думаю, как раз подойдёт для этого. Только необходимо научится правильно реализовать механизм. Расширение называется EXT_framebuffer_object.

galileopro, если не секрет, выложите хотябы принтскрин, чего Вы там рисуете такое мегатормозное?
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
14.03.2010, 16:30  [ТС] 5
Цитата Сообщение от snake32 Посмотреть сообщение
galileopro, если не секрет, выложите хотябы принтскрин, чего Вы там рисуете такое мегатормозное?
Обычный Кубик-рубика Я еще мало сделал там смысла нету выкладывать. Тупо закрашеный кубик. Просто мои преподаватели очень любят тестить мои программы на слабых машинах и смеяться громко, когда оно тормозит на первом пне с 32 метра видеокартой (правда nVidia)), А еще это будет не полноэкранное приложение, поэтому на аппаратно ускорение расчитывать не выйдет, а кроме этого окно с нарисованной сцено должно уметь перерисовываться, когда его пытаются вытянуть за предлы экрана. Вот я нашл примр на pBuffer, но он мало того, что грузит процессор, так еще если его вытянуть за пределы экрана мышко, то изображение испортится, и обновится, только когда его отпустить. Вот мне поставили условие: обновлять избражение при каждом событии OnPaint, причем учитывать InvalidateRect, чтобы не отрисовывать все полностью. Но так как я даже сли несложная сцена, её отрисовать в промежутке между двумя вызовами WM_PAINT сложно (я могу взять кошко за панель и начать тягать по рабочему стролу с диким множеством открытых других окон) и тогда этот WM_PAINT возникает раз 200 в секунду. Ну учитывая, что этот рубик еще должен собираться и по довольно не простому алгоритму, то за 5 миллисекунд полностью все прсчитать, отрисовать сцену, и выполнить Swapbuffers() не выходит. оэтому я хочу рисовать виртуальный буфр, а картинку в том виртуальном буффере менять 25 раз в секунду по таймру.
Вот пример на pBuffer. думаю его недостатки заметить несложно. OpenGL Ext Part 3.rar Толко там файлы из папки "Библиотеки" нужно скопировать в папку с проектом.
Как было бы легко жить на свете, если бы Windows сохраняла информацию, помещенную в HDC и сама, когда возникает WM_PAINT отрисовавыла испортившийся участок. Тогда мне бы всего-навсего нужно было менять картинку в HDC 25 раз в секунду.
0
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
14.03.2010, 18:01 6
Цитата Сообщение от galileopro Посмотреть сообщение
Просто мои преподаватели очень любят тестить мои программы на слабых машинах и смеяться громко
Вот ... нехорошие люди
Цитата Сообщение от galileopro Посмотреть сообщение
когда оно тормозит на первом пне с 32 метра видеокартой (правда nVidia))
Думаю, буфер тут не поможет. Тем более врядли на таком железе есть данная фича. Всё дело в прорисвке. Предлагаю забыть о WM_PAINT и попытаться делать всё в отдельном потоке. Но необходимо предусматреть средства синхранизации с каллбэком окна. Хотя ещё проще можно сделать без потоков:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    switch( message )
    {
    case WM_SIZE:
        GLResize( LOWORD(lParam), HIWORD(lParam) );
        break;
    case WM_CREATE:
        GLinit( hWnd );
        SetTimer( hWnd, 1, 7000, NULL );// ставишь нужный тебе таймер
        
        break;
    case WM_DESTROY:
        GLFree;
        KillTimer( hWnd, 1 );
        PostQuitMessage( 0 );
        break;
    case WM_TIMER:
        // здесь что-то происходит по таймеру
        break;
    case WM_KEYDOWN: 
    case WM_LBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_RBUTTONDOWN:
        // здесь обрабатываешь нажатия
        // и если необходимо выход
        PostMessage( g_hMainWnd, WM_CLOSE, 0,0 );
        break;
    case WM_MOUSEMOVE:
        // здесь изменеия положения камеры например
        break;
    default:
        return ( DefWindowProc( hWnd, message, wParam, lParam ) );
    };
    return 0L;
}
// собственно сама точка входа
int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
{
    hInst = GetModuleHandle( NULL );
    DWORD dwWSflag = WS_VISIBLE | WS_CLIPCHILDREN 
                | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW;
    UINT style =  CS_VREDRAW | CS_HREDRAW |CS_OWNDC;
 
    
    WNDCLASSEX wc;
    MSG msg;
    ZeroMemory( &wc, sizeof( wc ) );
    ZeroMemory( &msg, sizeof( msg ));
    wc.cbSize = sizeof( wc );
    wc.style = style;
    wc.lpszClassName = szClassName;
    wc.hInstance = hInst;
    wc.lpfnWndProc = (WNDPROC)WndProc;
    wc.hCursor = LoadCursor( NULL, IDC_ARROW );
 
    if( ! RegisterClassEx( &wc ) )
        return FALSE;
    timeBeginPeriod( 1 );
    DWORD dwLastTick = timeGetTime();
 
    g_hMainWnd = CreateWindowEx( /*WS_EX_TOPMOST*/NULL, szClassName, szWindowName, dwWSflag, //WS_OVERLAPPEDWINDOW,
        0, 0, 640 ,480,
        hParent, NULL, hInst, NULL );
 
    if( ! g_hMainWnd )  
        return FALSE;
 
    ShowWindow( g_hMainWnd, SW_SHOW );
    UpdateWindow( g_hMainWnd );
 
 
    while ( msg.message != WM_QUIT )
    {
        if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }else
        {
            // здесь идёт постоянные обновления и прорисовка пока нет никаких сообщений
// а также вычисляется дельта анимации.
            DWORD dwCurrentTick = timeGetTime();
            GLUpdateAndRender( (float)(dwCurrentTick - dwLastTick) );
            dwLastTick = dwCurrentTick;
        }
    };
    timeEndPeriod( 1 );
    UnregisterClass( szClassName, hInst );
    return msg.wParam;
}
Это вырезки из моего скринсейвера поэтому естественно сразу всё не откомилится
так чисто для общего понимая куда что вставлять. (могу скинуть на мыло весь проект. я до сих пор не знаю как тут аттачить )
Вообще у меня там оформлено как класс это я для упрощения вверху показал как обычные ф-ии
вот как ~ выглядят ф-ии огла: GLinit( hWnd );
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
int mainGL::InitGL( HWND hWnd )
{
    m_hDC = GetDC( hWnd );
    if( m_hDC == NULL )
        return 0x01;
    SetDCPixelFormat();
    m_hRC = wglCreateContext( m_hDC );
    if( m_hRC == NULL )
        return 0x02;
    wglMakeCurrent( m_hDC, m_hRC );
    glClearColor( pfClearColor[0], pfClearColor[1], pfClearColor[2], pfClearColor[3] );
    glEnable( GL_COLOR_MATERIAL );
    glDepthFunc( GL_ALWAYS );
    glEnable( GL_DEPTH_TEST );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    glEnable( GL_BLEND );
    glFogi ( GL_FOG_MODE, GL_EXP2 );
    glFogfv( GL_FOG_COLOR, pfClearColor);
    glFogf ( GL_FOG_DENSITY, 0.02f );
    glEnable( GL_FOG );
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );
    glEnableClientState( GL_COLOR_ARRAY );
    glEnableClientState( GL_VERTEX_ARRAY );
    LoadTexture();
    return 0x00;
}
// он же GLResize
void mainGL::Resize( int x, int y )
{   
    glViewport( 0, 0, x, y );
    if( y <= 0 )
        y = 1;
    float aspect = (float)x/(float)y;
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 45.0f, aspect, 1.0f, 101.0f );
    
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    if( !g_flCameraRot )
    {
        glTranslatef( 0.0f, 0.0f, -(float)nAbsRangeZ-35.0f );
        CalcFrustum();
    }
    fLoadNotReady = false;
}
// он же GLUpdateAndRender
void mainGL::UpdateAndRender( float delta )
{
    if( fLoadNotReady )
        return;
    // тут у меня идёт оптимизация - что именно нужно рисовать(что попало в обзор камеры)
    glPushMatrix();
 
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
    CGLChain::Render();
    glPopMatrix();
    SwapBuffers( m_hDC );
}
Добавлено через 9 минут
Про GLFree забыл
C++
1
2
3
4
5
6
7
8
9
10
11
12
mainGL::~mainGL(void)
{
    //CGLChain::Free();
    glDeleteTextures( 1, &g_uiTextureName );
    if( m_hDC )
    {
        wglMakeCurrent( m_hDC, NULL );
        if( m_hRC )
            wglDeleteContext( m_hRC );
        ReleaseDC( g_hMainWnd, m_hDC );
    };
}
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
14.03.2010, 18:34  [ТС] 7
Ух спасибо. Скиньте на galileo7777@gmail.com ПОЖАЛУЙТА А то я не разберусь с этим всем)
Кстати чтобы файл приаттачить нажмите "Расширенный режим" когда пишете сообщение. И в появившемся окне выбрите скрепку.

Добавлено через 5 минут
Кстати. Я что-то не замтил где тут FBO. И почему всетки нельзя в WM_PAINT это окошко подрисовать?

Добавлено через 11 минут
Эта фишка появилась немного раньше, чем GeForce 2MX. Так что я думаю её можно смело использовать. Даже если комп 2000 года, то та она будет.
1
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
14.03.2010, 18:46 8
Цитата Сообщение от galileopro Посмотреть сообщение
Кстати. Я что-то не замтил где тут FBO.
Там его и нет =)
Цитата Сообщение от galileopro Посмотреть сообщение
И почему всетки нельзя в WM_PAINT это окошко подрисовать?
Почему нельзя? Можно. Только походу винда ещё что-то делает, кроме того что действительно необходимо - вывод огла. Вот и получается что заметно медленее это происходит. Например, при изменении размеров окна, где вызывают обычно InvalidateRect который в свою очередь вызывает весь WM_PAINT я заметил неприятное мерцание, независимо от того двойная буферизация или нет. Винда всё время сначала рисует фон окна, где есть Огл(обычно серного цвета), а потом сообственно вызов ОГЛ команд, которые перерисовывают этот левый фон. Вот я и подумал, что нефиг мне рисовать то что не надо и перестал вызывать InvalidateRect, сразу рисую то что мне надо. Глюков нигде не заметил. Специально тестил на разных системах.
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
14.03.2010, 19:10  [ТС] 9
Я понял. Да глюков там нт. Я кусками скопировал себе. А нельзя винду обойти? опустим найти адрс буфера OpenGL (буфера кадра, т. е. буфера цвета, вообщем указатль на облать память, куда OpenGL отрисовала кадр) и найти в Device Context указатель на область, в которую надо рисовать и прорисовать с помощью ассемблерной вставки тупо напрямую. Конечно тут явный недостаток: даже если перерисовывать не все окно а только изменяющуюся часть, все равно схма такая:
ЦП по 4 байта будт копировать из видопамяти к себе в кеш, а потом копировать это в другую область видеопамяти. Это нагрузит шину. Хорошо бы чтоб такую операцию сделать видокартой. Нельзя посмотреть исходный код SwapBuffers?
0
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
14.03.2010, 19:24 10
Цитата Сообщение от galileopro Посмотреть сообщение
Цитата:Сообщение от snake32
пересоздавать окно на винде =(
Это не проблема я ведь все равно пишу все на WinApi. Просто другой стиль поставить.
Какой стиль? Я таких не знаю. Дело в том чтобы подключить дополнительный буфер необходимо установить подходящий режим вызовом ОГЛовой команды wglChoosePixelFormatARB а для вызова этой команды необходимо уже обладать контекстом рендера OpenGL. Иначе ни одна команда огла не выполнится. А контекст рендера OpenGL( тот который HGLRC ) создаётся после установки формата пикселя SetPixelFormat, которая может быть вызвана только ОДИН раз для текущего окна!
Цитата Сообщение от http://msdn.microsoft.com/en-us/library/dd369049(VS.85).aspx
If hdc references a window, calling the SetPixelFormat function also changes the pixel format of the window. Setting the pixel format of a window more than once can lead to significant complications for the Window Manager and for multithread applications, so it is not allowed. An application can only set the pixel format of a window one time. Once a window's pixel format is set, it cannot be changed.
Вот почему во многих играх при изменении antialiasing'a в настройках окно заново пересоздаётся. (Antialiasing тоже ставится через wglChoosePixelFormatARB)
Так что без уничтожения и повторного создания окна не обойтись =(
Если кто знает другой способ установки нужного формата пикселя буду рад выслушать.

Добавлено через 1 минуту
Цитата Сообщение от galileopro Посмотреть сообщение
Я понял. Да глюков там нт. Я кусками скопировал себе. А нельзя винду обойти? опустим найти адрс буфера OpenGL (буфера кадра, т. е. буфера цвета, вообщем указатль на облать память, куда OpenGL отрисовала кадр) и найти в Device Context указатель на область, в которую надо рисовать и прорисовать с помощью ассемблерной вставки тупо напрямую. Конечно тут явный недостаток: даже если перерисовывать не все окно а только изменяющуюся часть, все равно схма такая:
ЦП по 4 байта будт копировать из видопамяти к себе в кеш, а потом копировать это в другую область видеопамяти. Это нагрузит шину. Хорошо бы чтоб такую операцию сделать видокартой. Нельзя посмотреть исходный код SwapBuffers?
Чего не знаю того не знаю
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
14.03.2010, 19:43  [ТС] 11
Спасибо. Я вот сколько читаю, выходит что FBO как раз то, что нужно. Никак не выходит склепать пример нормальный. Я нашел это http://www.gamedev.net/referen... efault.asp (там нужно клацнуть Source code) и http://www.gamedev.ru/communit... ect?page=5 Но в перво источнике оно требует freeglut.lib и если ей копируешь просто glut32.lib и применовать, то выскакивает несколько ошибок такого рода:
Error 2 error LNK2019: unresolved external symbol __imp__wglGetProcAddress@4 referenced in function ___GLeeGetProcAddress GLee.obj Multiple texture with single FBO
Error 6 error LNK2019: unresolved external symbol __imp__glTexImage2D@36 referenced in function "void __cdecl init(void)" (?init@@YAXXZ) Multiple texture with single FBO.obj Multiple texture with single FBO
А в русскоязычной статье много всего, поэтому еще не разобрал. Мне же текстуры н нужны, мне просто нужен Frame Buffer. А там уже более сложные примеры его применения.
1
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
14.03.2010, 21:06 12
galileopro, а как собственно вы выводите грани кубика-рубика? Случайно не так:
C++
1
2
3
4
5
6
7
8
glBegin( GL_QUADS );
glColor3f( cr1, cg1, cb1 );
glNormal3f( nx1, ny1, nz1 );
glVertex3f( x1, y1, z1 );
glVertex3f( x2, y2, z2 );
glVertex3f( x3, y3, z3 );
glVertex3f( x4, y4, z4 );
glEnd();
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
14.03.2010, 21:33  [ТС] 13
Да. Так.
Кстати я наконец скомпилил прокт с FBO. Жаль не пойму для чего там половина кода используется. Там, похоже, кроме FBO еще шейдеры вершинные используются.

Добавлено через 1 минуту
Ну я для начала решил вообщ простой примитив нарисовать. треугольник
C++
1
2
3
4
5
6
7
8
9
10
11
int DrawGLScene( GLvoid ){          
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Очистить экран и буфер глубины
    glLoadIdentity();                               // Сброс просмотра
    glTranslatef(-1.5f,0.0f,-6.0f);
    glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f, 1.0f, 0.0f);  // Вверх
    glVertex3f(-1.0f,-1.0f, 0.0f);  // Слева снизу
    glVertex3f( 1.0f,-1.0f, 0.0f);  // Справа снизу
    glEnd();
    return true;        // Прорисовка прошла успешно
}
Добавлено через 5 минут
Вот кстати что нам предлагает почитать nVidia http://http.download.nvidia.co... Object.pdf
0
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
14.03.2010, 21:42 14
Цитата Сообщение от galileopro Посмотреть сообщение
Да. Так.
Вообще в дальнейшем откажитесь от такой вывода примитива. Лучше сразу пачками посылать на видеокарту через массивы вершин. У меня кстати в том проекте что Вам отослал так делается. Проверено что таким способом намного быстрее получается. До этого делал по отдельности - каждую вершину передавал в результате на слабых ПК да ещё со встроеной видеокартой или на ноутах тормозило просто жуть!
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
14.03.2010, 22:20  [ТС] 15
хорошо. Я понимаю, что все идет к тому, чтобы оптимизировать построение примитивов грамотно сделать таймер, но мне хочется все таки н идти лгким путем,а сделать через FBO. Сейчас все видеокарты это поддерживают, и это все равно будет быстрее, чем всякие навороты типа списков вывода или рендеринга текстуры.

Добавлено через 9 минут
Вот есть пример FBO но на Delphi. http://zdogl.narod.ru/enZGLine.html
Плохо, что я не могу найти с поставкой OpenGL SDK пример на FBO. Вробе все в examples просмотрел, но нету ничго. Хотя SDK 10.0...

Добавлено через 21 минуту
Нашел наконец несложный туториал по FBO http://steps3d.narod.ru/tutori... orial.html
На компиляции пишет
Error 4 error C2146: syntax error : missing ';' before identifier 'wglReleaseTexImageARB' e:\кубик\fbo\fbo\libext.h 118 fbo
Error 5 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int e:\кубик\fbo\fbo\libext.h 118 fbo
Вот проект. fbo.rar Как исправлять пока не знаю.
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
15.03.2010, 00:29  [ТС] 16
Не могу понять. Этот буфер виртуальный, к чему его привязывать надо? Всмысле как его выводить на экран, а как записывать в него?
Вот тут например он привязывается к текстуре http://gamedev32.narod.ru/stat... x_fbo.html
А если мне не надо ни к чму его привязывать? Мне просто надо, чтобы OpenGL всю свою сцену рисовал в этот буфер. А когда мне надо, я выведу его на экран.
Вообще уже не пойму как с ним работать. Зачем нужно выполнять все это, чтобы создать какой-то нсчастный буфер (память грубо говоря выделить)
1) Создаётся объект буфера кадра (framebuffer object). Это буфер кадра не зависит от оконной системы и является скорее неким «контейнером» установок OpenGL. Буфер кадра является гибкой (а не фиксированной, как оконный контекст вывода) структурой.
2) К буферу кадра подсоединяются логические буферы - созданные пользователем текстуры и буферы вывода (renderbuffers). Для подсоединения используются т. н. attachment points. Можно подсоединять три вида логических буферов – цвета, глубины и трафарета.
3) Проверяется, поддерживает ли аппаратура желаемую конфигурацию буфера кадра. По аппаратно-зависимым причинам некоторые комбинации логических буферов могут не поддерживаться, тогда на пользователя ложится задача по поиску поддерживаемой комбинации.
4) Буфер кадра делается текущим. Такая операция не является бесплатной, но тем не менее, она намного более быстрая, чем смена оконного контекста вывода.
5) Осуществляется рисование изображения в заданные логические буферы.
6) Происходит возврат к буферу кадра основного окна программы.
0
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
15.03.2010, 00:31 17
Цитата Сообщение от galileopro Посмотреть сообщение
Нашел наконец несложный туториал по FBO
Это просто класс-обёртка для работы с FBO. Здесь нет точки входа. То есть в своём приложении нужно подключить FrameBuffer.h и сможешь заюзать FBO как класс.
1
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
15.03.2010, 01:00  [ТС] 18
Может с Delphi код на C++ перписать? Просто я так и не разобрал полностью пока-что этот буфер. Можно преписать готовое, а потом доработать. Может понятне станет.
0
Пробующий
185 / 98 / 10
Регистрация: 28.04.2009
Сообщений: 1,101
15.03.2010, 03:37  [ТС] 19
Получилось, но с glut. Никак не могу въехать как мне это на WinApi переписать чтобы без glut было.
snake32, как Вы считаете тот проект на Delphi из поста 16 можно пределать? он же без всяких сторонних библиотек (только сам opengl).
А еще мне не нравиться в этом glu, что он открывает консольное окно, а еще: он НЕ ПОСЫЛАЕТ СОБЫТИЕ WM_PAINT, когда мое окно прекрывается другими. Если его вытащить за пределы экрана, сразу изображение стирается. FBO_2.rar
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <windows.h>        // Заголовочные файлы для Windows
#include "glee.h"
#include "glut.h"
#include <stdlib.h>
#include <gl\gl.h>          // Заголовочные файлы для библиотеки OpenGL32
 
#define FBO_WIDTH  640
#define FBO_HEIGHT 480
 
GLuint frameBuffer;
GLuint fbTexture;
GLuint fbDepth;
 
GLsizei window_w, window_h;
HWND hWnd;
 
void initGL()
{
    //glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    glFrontFace(GL_CCW);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
 
void createFBO()
{
    glGenFramebuffersEXT(1, &frameBuffer); // создаем FBO
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer); // делаем его текущим
 
    glGenTextures(1, &fbTexture);  // создаем текстуру
    glBindTexture(GL_TEXTURE_2D, fbTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, FBO_WIDTH, FBO_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
    glGenRenderbuffersEXT(1, &fbDepth);   // создаем буфер глубины для FBO
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbDepth);
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, FBO_WIDTH, FBO_HEIGHT);
 
    // присобачиваем к FBO текстуру
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbTexture, 0);
    
    // присобачиваем к FBO буфер глубины
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbDepth);
 
    if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
    {
        MessageBox(NULL, "Cannot create FrameBuffer object", "Error", MB_OK | MB_ICONERROR);
        exit(1);
    }
    glClearColor(0.0, 0.0, 0.0, 0.0);
}
 
void renderToFBO()
{
    // включаем рисование в наш FBO
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer);
    glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
    glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
 
    glViewport(0, 0, FBO_WIDTH, FBO_HEIGHT);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    // Устанавливаем матрицы
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
 
    // рисуем...
    glColor3f(1.0f, 1.0f, 1.0f);
 
    glBegin(GL_TRIANGLES);
        glVertex3f(-0.5, -0.5, 0.0);
        glVertex3f(0.5, -0.5, 0.0);
        glVertex3f(0.0, 0.5, 0.0);
    glEnd();
 
    // переключаем рисование обратно в буфер кадра
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 
    glDrawBuffer(GL_BACK);
    glReadBuffer(GL_BACK);
}
 
void render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    // рисуем в FBO
    renderToFBO();
 
    glViewport(0, 0, window_w, window_h);
 
    // включаем FBO-текстуру
    glBindTexture(GL_TEXTURE_2D, fbTexture);
    glEnable(GL_TEXTURE_2D);
 
    // Устанавливаем единичные матрицы для того, чтобы было
    // удобно рисовать квадратик на весь экран
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
 
    // рисуем квадратик на весь экран
    glColor3f(1.0, 1.0, 1.0);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0, 0.0);
        glVertex3f(-1.0, -1.0, 0.0);
 
        glTexCoord2f(1.0, 0.0);
        glVertex3f(1.0, -1.0, 0.0);
 
        glTexCoord2f(1.0, 1.0);
        glVertex3f(1.0, 1.0, 0.0);
 
        glTexCoord2f(0.0, 1.0);
        glVertex3f(-1.0, 1.0, 0.0);
    glEnd();
    
    // выключаем текстурирование (или выбираем другие текстуры и т.д.)
    glDisable(GL_TEXTURE_2D);
    
    // устанавливаем матрицы для рисования нашего объекта
    // (в данном случае единичные)
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
 
    // рисуем объект
    glColor3f(1.0f, 0.0f, 0.0f);
    glBegin(GL_TRIANGLES);
        glVertex3f(-0.3, -0.3, 0.0);
        glVertex3f( 0.3, -0.3, 0.0);
        glVertex3f( 0.0,  0.3, 0.0);
    glEnd();
    glutSwapBuffers();
}
 
void onSize(GLsizei w, GLsizei h)
{
    window_w = w;
    window_h = h;
    render();
}
 
int main(int argc, char *argv[])
{
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    hWnd = (HWND)glutCreateWindow("FBO");
    glutDisplayFunc(render);
    glutReshapeFunc(onSize);
    initGL();
    createFBO();
    glutMainLoop();
    return 0;
}
0
3408 / 1595 / 236
Регистрация: 26.02.2009
Сообщений: 7,838
Записей в блоге: 5
15.03.2010, 14:07 20
Цитата Сообщение от galileopro Посмотреть сообщение
snake32, как Вы считаете тот проект на Delphi из поста 16 можно пределать?
Конечно, можно. Там как раз без глута на чистом винапи.

Лично я с FBO ничего не кодил поэтому подсказать как вместо текстуры использовать что-то другое не могу =(
Цитата Сообщение от galileopro Посмотреть сообщение
Я понимаю, что все идет к тому, чтобы оптимизировать построение примитивов грамотно сделать таймер, но мне хочется все таки н идти лгким путем,а сделать через FBO. Сейчас все видеокарты это поддерживают, и это все равно будет быстрее, чем всякие навороты типа списков вывода или рендеринга текстуры.
Какие бы новые, умные, навороченные, современные технологии не использовали при рендере - всё равно придётся программить таймеры. На них базируется вся анимация! Я понимаю, что Вам намного интереснее реализовать FBO, чем ковырятся в виндовых таймерах. Сам такой же =). Но реально качественного приложения всё равно не получите при таком подходе.
1
15.03.2010, 14:07
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
15.03.2010, 14:07
Помогаю со студенческими работами здесь

WM_PAINT и tpanel
Как отслеживать в 2007 сообщение WM_Paint для tpanel Пишу код procedure WMPAINT(var Msg:...

WM_PAINT зацикливается
Подскажите, пожалуйста, с обработкой сообщения перерисовки. Вот так нормально работает без...

В WM_PAINT не обновляется
В событиях WM_KEYDOWN и классе, где изменяется переменная, переменная изменяется. Т.е код на вывод...

Перерисовка окна WM_PAINT
Добрый вечер. Кто подскажет как в нужный момент перерисовать окно? Как я понимаю нужно вызвать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru