Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Скорость отрисовки графики без DirectX, OpenGL и пр. - как поднять?

15K
30 марта 2008 года
basil-77
40 / / 17.03.2007
Все привет!
Задача: нужно написать что-то вроде 3d движка, сильно упрощенного.. т.е. должен быть отрисован какой-то ландшафт, натянута текстура, учтено освещение (Гуро или Фонг), в сцене должен присутствовать какой-либо объект (типа автомобиль, самолет.... ), который там может перемещаться... Камера также должна перемещатся, как свободно, так и в привязке к объекту... Особенность: все это должно быть сделано "ручками", никаких DirectX, OpenGL и т.п.
С математической стороны особых проблем не возникает, матрицы соответствующих преобразований сделал, тут, все относительно просто. Ландшфат и объект сделал импортом из 3d макса в массивы вершин и граней...
Проблема начинается на стадии отрисовки: рисовать приходится попиксельно; на канве ОЧЕНЬ медленно, через WinAPI заметно быстрее, но все равно недостаточно... Причем, основные затраты времени не на аглогритмы преобразований, а именно на вывод графики (прорисовка у меня реализована как построчное сканирование треугольников, задающих объекты, алгоритм из Шикина... но даже если и взять Polygon() или Polylene то оно конечно, быстрее, но недостаточно), даже и при ограничении 800х600...
Вопрос: какие еще варианты отрисовки могут быть, быстрее???
391
30 марта 2008 года
Archie
562 / / 03.02.2005
Рисуй все в битмап в памяти. А как отрисуешь всю сцену, копируй битмап в окно.
15K
30 марта 2008 года
basil-77
40 / / 17.03.2007
Цитата: Archie
Рисуй все в битмап в памяти. А как отрисуешь всю сцену, копируй битмап в окно.


Уже так

 
Код:
BitBlt(DC, 0, 0, frm_main->Width, frm_main->Height, CDC, 0, 0, SRCCOPY)
;
1.6K
31 марта 2008 года
Tdr
154 / / 13.11.2003
Без "DirectX, OpenGL и т.п." сделаеть сложно и дорого.
Работают эти апи через дрова с железом, а gdi даст только базовую функциональность и исключительно софтовую.
15K
31 марта 2008 года
basil-77
40 / / 17.03.2007
Цитата: Tdr
Без "DirectX, OpenGL и т.п." сделаеть сложно и дорого.
Работают эти апи через дрова с железом, а gdi даст только базовую функциональность и исключительно софтовую.


Но можно? Как?
зы. реализация на С++, билдер 6

1.6K
31 марта 2008 года
Vov4ick
476 / / 01.02.2007
Этот раздел тебе в помощь
http://www.wasm.ru/forum/viewtopic.php?id=20820
33K
03 апреля 2008 года
ACW-Coder
17 / / 02.01.2008
Пользуйся аппаратно-независимыми растрами (DIB). В таком случае ты имеешь дело с обычным массивом, в который записываешь значения каждой компоненты цвета (RGB). Вывод может осуществляется ф-цией SetDIBitsToDevice, которая берет в качестве источника этот массив.
Рисование осуществялется очень просто. Например, рисование точки будет выглядеть так:
 
Код:
pRastr[ddLinearAddress + 0] = B;
pRastr[ddLinearAddress + 1] = G;
pRastr[ddLinearAddress + 2] = R;

где pRastr - адрес массива, ddLinearAddress - линейный адрес точки, RGB - цвет.
Данный метод имеет массу преимуществ, взять даже заполнение экрана(растра) заданным цветом - увеличение производительности может измерятся разами, если грамотно все сделать. Если есть интерес, то могу скинуть код инициализации, вывода и рисования.
15K
03 апреля 2008 года
basil-77
40 / / 17.03.2007
Цитата: ACW-Coder
Если есть интерес, то могу скинуть код инициализации, вывода и рисования.


Есть интерес, скидывай ;)

1.9K
04 апреля 2008 года
andriano
474 / / 10.01.2008
Обычно создаю в памяти bimap с удобной мне глубиной цвета (например 8 бит), в общем случае несовпадающей с глубиной цвета текущего режма и перебрасываю его в окно функцией StretchDIBits. Если размеры в пикселях совпадают, то преобразование к нужной глубине цвета происходит практически мгновенно, думаю, железом видеокарты (судя по скорости).
33K
04 апреля 2008 года
ACW-Coder
17 / / 02.01.2008
Вот основные функции (полный код лежит в архиве, VS.NET 2002):

1. Создание растрового буфера
Код:
BOOL fnCreateRastrBuffer(DWORD ddWidth, DWORD ddHeight)
{
    //Создание буфера для информации о растре
    pBitInfo = new BITMAPINFO [sizeof(BITMAPINFO)];
    if(!pBitInfo) return FALSE;

    //Колчество байтов в строке
    ddBytesPerLine = 4 * ddWidth;
    //Размер растра в байтах
    ddBufferSize = ddBytesPerLine * ddHeight;

    //Ширина и высота растра
    ddResX = ddWidth;
    ddResY = ddHeight;

    /* Информация о растре */

    //Размер структуры
    pBitInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    pBitInfo->bmiHeader.biWidth = ddWidth;
    pBitInfo->bmiHeader.biHeight = ddHeight;
    //Кол-во плоскостей (всегда 1)
    pBitInfo->bmiHeader.biPlanes = 1;
    //Глубина цвета (24 или 32)
    pBitInfo->bmiHeader.biBitCount = 32;
    pBitInfo->bmiHeader.biClrUsed = 0;
    pBitInfo->bmiHeader.biClrImportant = 0;
    //Использование триплетов RGB
    pBitInfo->bmiHeader.biCompression = BI_RGB;

    //Создание растрового буфера
    pRastrBuffer = new BYTE[ddBufferSize];
    if(!pRastrBuffer) return FALSE;

    return TRUE;


2. Рисование точки
Код:
void fnSetPoint(DWORD X, DWORD Y, BYTE R, BYTE G, BYTE B)
{
    //Тест отсечения
    if(X < 0 || Y < 0 || X >= ddResX || Y >= ddResY) return;

    //Вычисление линейного адреса точки
    DWORD ddLinearAddress = Y * ddBytesPerLine + X * 4;
   
    //Заносим интенсивности цветовых компонент
    //  по соответствующим смещениям
    pRastrBuffer[ddLinearAddress + 2] = R;
    pRastrBuffer[ddLinearAddress + 1] = G;
    pRastrBuffer[ddLinearAddress + 0] = B;
}


3. Копирование в заданный контекст
 
Код:
void fnVisualBackScreen(HDC hDC)
{
    //Копирование растра
    SetDIBitsToDevice(hDC,
        0, 0, ddResX, ddResY,       //dst_x, dst_y, dst_w, dts_h
        0, 0, 0, ddResY,            //src_x, src_y, ..., num_of_copy_lines
        pRastrBuffer, pBitInfo, DIB_RGB_COLORS);
}


А вот еще одна функция - очистка экрана. Это самый быстрый метод, который мне удалось написать. Суть в том, что при записи не используется кеш-память, а это значительно ускоряет процесс заполнения. Требования такие: поддержка SSE (у Intel - начиная с Pentium III) и выравнивание начала растра по границе двойного слова (в VS.NET 2002 устанавливается значение 'Project' Property Pages -> C/C++ -> Code Generation -> Struct Member Alignment равное 4 Bytes).
Код:
void fnClear(BYTE R, BYTE G, BYTE B)
{
    DWORD ddColor;
    ddColor = (R << 16) + (G << 8) + B;
    __asm
    {
        movss       xmm0, ddColor   //XMM0[0] = Color
        shufps  xmm0, xmm0, 0   //XMM0 = Color Color Color Color
   
        mov     eax, pRastrBuffer   //EAX = Адрес растрового буфера
        mov     ecx, ddBufferSize   //ECX = Размер буфера в байтах
        shr     ecx, 4          //Запись будет производиться по 16 байтов
   
CLEAR:  movntps [eax], xmm0     //Запись 4 точек БЕЗ ИСПОЛЬЗОВАНИЯ КЕША
        add     eax, 16     //Корректировка указателя
        dec     ecx
        jnz     CLEAR
    }
}


Кстати, если еще будут специфические вопросы, то можешь задавать их напрямую - через e-mail (acwares@narod.ru). Просто я сам с конца 2004 года занимаюсь разработкой собственной графической библиотеки, думаю, что смогу что-нибудь подсказать.
15K
07 апреля 2008 года
basil-77
40 / / 17.03.2007
2 andriano
ACW-Coder

Огромное спасибо!

2 ACW-Coder
Отдельная благодарность за примеры кода. Будем разбираться ;)
А вопросы, скорее всего, будут, напишу :)
1.9K
07 апреля 2008 года
andriano
474 / / 10.01.2008
ACW-Coder, раз уж ты занимаешься разработкой библиотеки, то могу сделать несколько замечаний:
у тебя в тексте есть "//Глубина цвета (24 или 32)", но в самом коде поддерживается только нестандартное, хотя и поддерживаемое Windows значение 32. Для 24 правку придется вносить сразу в несколько мест, включая более хитрое вычисление длины сканлинии. Желательно бы определить ОДНУ константу, через нее определить другую и уже эти две константы использовать во всех формулах для универсальности.

Не знаю, насколько интересны 16-цветные режимы, но 256=цветные я бы рекомендовал использовать: во многих случаях, когда не требуется много цветов, режим "байт на пиксель" оказывается очень удобным.

Коль скоро используешь 32-разрядный цвет, не забывай чистить 4-й байт. Стандарта на этот счет нет, но рекомендуется заносить в него либо 0, либо 255.

Операцию чистки буфера гораздо проще записать через rep stosd. И вряд ли это будет медленнее, зато не будет проблем в случае, когда длина буфера некратна 16.
33K
07 апреля 2008 года
ACW-Coder
17 / / 02.01.2008
1. Согласен, с глубиной маленько намудрил, неуниверсально, так сказать, получилось. Все потому, что "выдергивал" куски кода из либы.

2. "Цветастость" - это уже выбирается исходя из того, что надо получить. Мне вот привычнее 32 бита. Просто в других вычислениях с 32 битами работать значительно проще. Например, при записи в растровый буфер с учетом значений точек к буфере глубины. У меня используется обработка по 4 точки через XMM-регистры. При 24 битах такой алгоритм реализовать было бы просто невозможно.

3. В жизни 4-й байт не чистил и ни разу не стопорилось.

4. Запись через rep stosd. Раньше тоже так думал (что самое быстрое). И такое заполнение даже функионирует в первой версии. Но позже (при разработке 2 версии) провел около 10 тестов на скорость. Смотрел скорость заполнения экрана 1280x1024x32. Вот некоторые результаты (frames per second):
1) REP STOSD - 230-310
2) MOVAPS [Memory], XMM0 - 269-305
3) MOVNTPS [Memory], XMM0 - 509-548
Т.е. весь выигрышь получается в том, что не используется кеш-память. Выровнять длину буфера до 16 байт вообще не проблема. Можно при резервировании памяти к итоговому размеру буфера просто прибавить 16. Еще команды movnt** требуют выравнивания по границе двойного слова. Эта тоже абсолюно не проблема. На ассемблере это выравнивание делается в пару-тройку строк (не знаю как компилятор ms vs относится к таким фокусам, но это и не важно - там есть опция компилятора для выравнивания). Да и в конечном счете это даже положительно сказывается на быстродействии. А строковой команде до фени с чем работать: будет выравнивание - хорошо, нет - и так сойдет, просто работать будет медленнее.
1.9K
08 апреля 2008 года
andriano
474 / / 10.01.2008
1. Хтя бы сделай выравнивание длины строк на 4 байта, т.к. в любом режиме кроме 32-битного может понадобиться.

2. Я, наоборот, пользуюсь этим только при глубине цвета, не превышающей 8 разрядов. И обхожуть ММХ. Для полноцветных режимов предпочитаю OpenGL. Разные задачи - разные инструменты.

3. И не будет, пока не возникнет идея записать это в файл. (хотя, кто знает, что придумают Микрософт в очередной версии Виндоуз)

4. Думаю, щдесь не то место, где надо ловить блох. Выавнивание, кстати, на ЯВУ делается одной строкой. Вот только не надо на него закладываться.
33K
09 апреля 2008 года
ACW-Coder
17 / / 02.01.2008
Цитата: andriano
Разные задачи - разные инструменты.


Абсолютно согласен. Вот у меня есть задача и я делаю все, чтобы максимально ускорить выполнение, отсюда и неуниверсальность. А OpenGL - это уже другой разговор, здесь, как я понимаю, все строится только на интересе сделать все это самому. Кстатити, про MMX я уже давно не вспоманал, т.к. кончилось ее время (! Visual Studio .NET 2005 почему-то отсутствует), в общем-то как и время жизни 3DNow! и FPU. Под 64-битной платформой (AMD64), под которую я сейчас пишу вторую версию либы, эти наборы команд уже просто не поддерживается, осталось только SSE. В принципе, меня это очень даже устраивает - нацонец-то приходим к единому стандарту.

1.9K
09 апреля 2008 года
andriano
474 / / 10.01.2008
Это кто сказал, что в ч64 не поддерживается FPU и MMX?
Первый раз такое слышу.
И уверен, что это не более, чем первоапрельская шутка.

PS. И то и другое, кстати, и есть "единый стандарт".
15K
20 апреля 2008 года
basil-77
40 / / 17.03.2007
Оживим тему :)
В общем, переписал по образцу ACW-Coder
Теперь всплыла другая проблема. Сама по себе отрисовка идет с приемлемой скоростью... Теперь главный висяк - в самом алгоритме растровой развертки треугольника, причем особо нет разницы в скорости при равномерной закрасе, по Гуро, или Фонга... Тормозит сам алгоритм...
Можно это дело какнить оптимизировать?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог