Необходимо выводить каждый пиксель, координаты которого хаотичны, собственным цветом
(только GDI).
При рисовании методом CDC::SetPixel() (используя буфер) количество кадров для маленьких изображений (100х100 пикселей) падает до 15-30 в секунду, а для больших выходит за
пределы секунды.
Подскажите, пожалуйста:
Как можно для изображений 640х480 довести количество кадров хотя бы до 30?
Заранее благодарю.
Ну, можно создать текстуру (битмап), этакий Back Buffer (который Вы, я так понимаю, создали), на которую рисовать, а затем BitBlt. Еще хорошо бы использовать не SetPixel, а непосредственный доступ к битам изображения. А вообще надо использовать DirectDraw.
MC_>Здравствуйте!
MC_>Необходимо выводить каждый пиксель, координаты которого хаотичны, собственным цветом MC_> (только GDI). MC_>При рисовании методом CDC::SetPixel() (используя буфер) количество кадров для маленьких изображений (100х100 пикселей) падает до 15-30 в секунду, а для больших выходит за MC_>пределы секунды. MC_>Подскажите, пожалуйста: MC_> Как можно для изображений 640х480 довести количество кадров хотя бы до 30? MC_>Заранее благодарю.
Не все в этом мире можно выразить с помощью нулей и единиц...
Здравствуйте, MadCoder_61, Вы писали:
MC_>Здравствуйте!
MC_>Необходимо выводить каждый пиксель, координаты которого хаотичны, собственным цветом MC_> (только GDI). MC_>При рисовании методом CDC::SetPixel() (используя буфер) количество кадров для маленьких изображений (100х100 пикселей) падает до 15-30 в секунду, а для больших выходит за MC_>пределы секунды. MC_>Подскажите, пожалуйста: MC_> Как можно для изображений 640х480 довести количество кадров хотя бы до 30?
Ну если задачу надо выполнить только средствами GDI, то я бы попробовал использовать DIB секцию как back buffer.
Используя DIB секцию мы можем получить непосредственный доступ к битам изображения.
Ну а после заполнения секции делать BitBlt.
Здравствуйте, MadCoder_61, Вы писали:
MC_>Здравствуйте!
MC_>Необходимо выводить каждый пиксель, координаты которого хаотичны, собственным цветом MC_> (только GDI). MC_>При рисовании методом CDC::SetPixel() (используя буфер) количество кадров для маленьких изображений (100х100 пикселей) падает до 15-30 в секунду, а для больших выходит за MC_>пределы секунды. MC_>Подскажите, пожалуйста: MC_> Как можно для изображений 640х480 довести количество кадров хотя бы до 30?
Я полагаю, что проблема низврой производительности вовсе не в функции SetPixel (все таки сейчас видеокарты очень быстрые), я думаю проблема в алгоритме вывода на экран. Вы не могли бы привести высокоуровневое написание, иллюстрирующее как выглядит программа. Например, впишите сюда недостаяющие операторы: где Вы контекст получаете, где выводите точку на экран:
for (int i = 0; i< 100; i++)
{
for (int j = 0; j< 100; j++)
{
}
}
GUI>Я полагаю, что проблема низврой производительности вовсе не в функции SetPixel (все таки сейчас видеокарты очень быстрые), я думаю проблема в алгоритме вывода на экран. Вы не могли бы привести высокоуровневое написание, иллюстрирующее как выглядит программа. Например, впишите сюда недостаяющие операторы: где Вы контекст получаете, где выводите точку на экран:
Class Буфер Отображения
{
Инициализация ( Указатель на окно )
{
создается буфер размером с окно;
//В дальнейшем все рисование будет идти в нем
}
Рисование точки ( x, y, color )
{
// Самое часто!!! Если отключить данную функцию, то fps почти не
// падают — 10 – 15 fps на сложную сцену.
m_pDC->SetPixel(x, y, color);
}
Изменение размера окна ( новый размер )
{
пересоздаем буфер;
// происходит очень редко
}
Отчистка буфера()
{
закрашиваем буфер;
m_pDC->FillSolidRect(..) // на скорость не сильно влияет
}
Начать рисование ()
{
отчистка буфера
}
Закончить рисование
{
копирование буфера в окно;
}
};
Class Визуализатор
{
Создание проекции (Буфер Отображения )
{
Буфер Отображения->Начало рисования();
цикл по всем объектам сцены
цикл по всем полигонам объекта
Проецирование полигона ( текущий полигон, буфер ображения )
Буфер Отображения->Конец рисования();
}
Проецирование полигона
{
// используется метод заполнения треугольника
// горизонтальными линиями
// y1 – самая верхняя, y3 – самая нижняя
Определяем разницу по высоте (y3 – y1);
Пока не достигли у3
{
Определяем разницу по ширине;
Пока не достигли x2
{
Считаем освещенность ( dx , dy );
Буфер Отображения-> Рисование точки ( dx, dy, color )
// То есть m_pDC->SetPixel(x, y, color);
}
1) А где ты получаешь контекст окна? Что такое в Инициализации создается буфер, в котором все будет рисоваться, хотя ты выхываешь функцию SetPixel. Где вызывается BeginPaint / EndPaint?
2) Для оптимизации SetPixel имеет смысл применить дедовский метод: использовать CreateBitmapIndirect и работать с буфером как с обычным массивом (т.е. вместо SetPixel использовать bmBits[y<<8+x]=color; — для картинки шириной в 256 точек — ширину картинки лучше кратной степени двойки — тогда можно использовать операцию сдвига вместо умножения на ширину). Потом вызвать один раз BitBlt — и вывести весь буфер на экран сразу. Единственно, что нужно самому проверять выход за границы массива.
3) Насчет DirectX тут высказались совершенно верно — DX работает быстрее
Здравствуйте, GUID, Вы писали:
GUI>1) А где ты получаешь контекст окна? Что такое в Инициализации создается буфер, в котором все будет рисоваться, хотя ты выхываешь функцию SetPixel. Где вызывается BeginPaint / EndPaint?
В начале рендера и в конце рендера всей сцены соответственно
GUI>2) Для оптимизации SetPixel имеет смысл применить дедовский метод: использовать CreateBitmapIndirect и работать с буфером как с обычным массивом (т.е. вместо SetPixel использовать bmBits[y<<8+x]=color; — для картинки шириной в 256 точек — ширину картинки лучше кратной степени двойки — тогда можно использовать операцию сдвига вместо умножения на ширину). Потом вызвать один раз BitBlt — и вывести весь буфер на экран сразу. Единственно, что нужно самому проверять выход за границы массива.
Огромное спасибо, наврено это и есть самый оптимальный метод.
GUI>3) Насчет DirectX тут высказались совершенно верно — DX работает быстрее
Проблема в том, что вообще там где это будет использоваться еще нет DirectX или OpenGL
Здравствуйте, GUID, Вы писали:
> bmBits[y<<8+x]=color; — для картинки шириной в 256 точек — ширину картинки лучше кратной степени двойки — тогда можно > использовать операцию сдвига вместо умножения на ширину).
Ну уж, если так оgтимизировать, то можно не париться с 256 точками, а писать так:
for (int y; y<height; ++y)
for (int xy=y*width, x=0, max = (y+1)*width; xy<max; ++xy, ++x)
bmBits[xy]=color(x,y);
Не все в этом мире можно выразить с помощью нулей и единиц...
Здравствуйте, GUID, Вы писали:
GUI>2) Для оптимизации SetPixel имеет смысл применить дедовский метод: использовать CreateBitmapIndirect и работать с буфером как с обычным массивом (т.е. вместо SetPixel использовать bmBits[y<<8+x]=color;
Ошибка, кстати, тоже дедовская: y<<8+x означает y<<(8+x), что, очевидно, совсем не то, что нужно...
Здравствуйте, Evgeniy13, Вы писали:
E>Здравствуйте, GUID, Вы писали:
>> bmBits[y<<8+x]=color; — для картинки шириной в 256 точек — ширину картинки лучше кратной степени двойки — тогда можно >> использовать операцию сдвига вместо умножения на ширину).
E>Ну уж, если так оgтимизировать, то можно не париться с 256 точками, а писать так: E>
E>for (int y; y<height; ++y)
E> for (int xy=y*width, x=0, max = (y+1)*width; xy<max; ++xy, ++x)
E> bmBits[xy]=color(x,y);
E>
"Не париться" и "оптимизировать" — взаимоисключающие друг друга понятия. Если хотитите что-то соптимизировать — придется париться и идти на ограничения.
Кстати ваш алгоритм я бы изложил с следующей редакции:
Addr = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
bmBits[Addr] = color(x,y);
Addr++;
}
}
Здравствуйте, MadCoder_61, Вы писали:
MC_>Здравствуйте!
MC_>Необходимо выводить каждый пиксель, координаты которого хаотичны, собственным цветом MC_> (только GDI). MC_>При рисовании методом CDC::SetPixel() (используя буфер) количество кадров для маленьких изображений (100х100 пикселей) падает до 15-30 в секунду, а для больших выходит за MC_>пределы секунды. MC_>Подскажите, пожалуйста: MC_> Как можно для изображений 640х480 довести количество кадров хотя бы до 30? MC_>Заранее благодарю.
можно попробовать рисовать в HBITMAP юзая SetDIBits(), т.е. заполняешь попиксельно картинку(массив) в памяти, записываешь ее в HBITMAP и выводишь на экран. лучше сходу ничего не придумал, по идее должно быть быстрее.
Здравствуйте, MadCoder_61, Вы писали:
MC_>Здравствуйте!
MC_>Необходимо выводить каждый пиксель, координаты которого хаотичны, собственным цветом MC_> (только GDI). MC_>При рисовании методом CDC::SetPixel() (используя буфер) количество кадров для маленьких изображений (100х100 пикселей) падает до 15-30 в секунду, а для больших выходит за MC_>пределы секунды. MC_>Подскажите, пожалуйста: MC_> Как можно для изображений 640х480 довести количество кадров хотя бы до 30? MC_>Заранее благодарю.
It's easy!
Например так:
(Конечно, можно быстрее, но так нагляднее)
void CMyFrame::OnPaint()
{
CPaintDC dc(this);
//Создаем буфер
int CX = 400, CY = 100;
DWORD *lpbInit = new DWORD[CX * CY];
//Здесь рисуем прямо в память - так наиболее быстро
//BEGIN
//Фигню рисуем
for (int i = 0; i < CY; i++)
{
for (int j = 0; j < CX; j++)
{
BYTE color = (BYTE)(255-abs(i*255/(CY/2)-255));
lpbInit[i*CX+j] = RGB(color, color, color);
}
}
//END
//Делаем из буфера BITMAP
BITMAPINFO bmi = {
sizeof(BITMAPINFOHEADER), CX, CY, 1, 32, BI_RGB, 0,
0, 0, 0, 0
};
HBITMAP hBitmap = ::CreateDIBitmap(
dc.GetSafeHdc(), &bmi.bmiHeader, CBM_INIT,
lpbInit, &bmi, DIB_RGB_COLORS);
CBitmap bitmap;
bitmap.Attach(hBitmap); //Аттачим заготовку.
//Отрисовываем буфер в контекст
dc.DrawState(CPoint(10, 10), CSize(CX, CY),
&bitmap, DST_BITMAP);
//Чистимся
bitmap.DeleteObject();
delete lpbInit;
}
Сделать человеку приятное очень просто. Не сделайте ему гадость и ему будет приятно!
Баг — это клоп. Таpакан — это, видимо, фича.
Здравствуйте, GUID, Вы писали:
GUI>Здравствуйте, MadCoder_61, Вы писали:
MC_>>Здравствуйте!
MC_>>Необходимо выводить каждый пиксель, координаты которого хаотичны, собственным цветом MC_>> (только GDI). MC_>>При рисовании методом CDC::SetPixel() (используя буфер) количество кадров для маленьких изображений (100х100 пикселей) падает до 15-30 в секунду, а для больших выходит за MC_>>пределы секунды. MC_>>Подскажите, пожалуйста: MC_>> Как можно для изображений 640х480 довести количество кадров хотя бы до 30?
GUI>Я полагаю, что проблема низврой производительности вовсе не в функции SetPixel (все таки сейчас видеокарты очень быстрые), я думаю проблема в алгоритме вывода на экран. Вы не могли бы привести высокоуровневое написание, иллюстрирующее как выглядит программа. Например, впишите сюда недостаяющие операторы: где Вы контекст получаете, где выводите точку на экран:
Конечно, это может быть и алгоритм тоже , но SetPixel это ОЧЕНЬ узкое место в коде. MC_>>При рисовании методом CDC::SetPixel() (используя буфер) количество кадров для маленьких изображений (100х100 пикселей) падает до 15-30 в секунду, а для больших выходит за MC_>>пределы секунды.
100х100 = 10^4 вызовов SetPixel() — накладные растоды на каждый вызов + проверки каждый вызов+ собственно работа с контекстом каждый вызов
Это долгооо...
Сделать человеку приятное очень просто. Не сделайте ему гадость и ему будет приятно!
Баг — это клоп. Таpакан — это, видимо, фича.
Здравствуйте, Mr.ToNik, Вы писали:
MT>Конечно, это может быть и алгоритм тоже , но SetPixel это ОЧЕНЬ узкое место в коде.
Подтвержаю: читал, что для SetPixel создается... BITMAP единичного размера и выполняется BitBlt. Не самая дешевая операция, согласитесь.
Сам в kernel не лез, источник данных: Фень Юань, "Программирование графики".
Здравствуйте, retalik, Вы писали:
R>Здравствуйте, Mr.ToNik, Вы писали:
MT>>Конечно, это может быть и алгоритм тоже , но SetPixel это ОЧЕНЬ узкое место в коде. R>Подтвержаю: читал, что для SetPixel создается... BITMAP единичного размера и выполняется BitBlt. Не самая дешевая операция, согласитесь.
R>Сам в kernel не лез, источник данных: Фень Юань, "Программирование графики".
Очень концептуальное решение. Главное, идеология соблюдена!
Сделать человеку приятное очень просто. Не сделайте ему гадость и ему будет приятно!
Баг — это клоп. Таpакан — это, видимо, фича.