![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вывода битмапа по маске и под углом [D7, XP]
Evgnevius © (2009-12-01 18:56:00)Подскажите, пожалуйста, как это делать, а то OpenGL для меня - тёмный лес, однако нужно именно с её помощью, так как очень важна скорость. С помощью средств GDI всё у меня получается прекрасно, однако тормозит. Помогите, кто знает как.
Sapersky (2009-12-12 19:24:00) [1]Evgnevius © (09.12.09 01:22) [37]
М-да, похоже, чукча катастрофически не читатель.
Ткну носом в фастлибовский код (вариант без сглаживания). Разницу с твоим в кол-ве операций замечаешь?
for y:=0 to Dst.Height-1 do begin
dy:=cy-y;
sdx:=(ax+(isin*dy))+xd;
sdy:=(ay-(icos*dy))+yd;
for x:=0 to Dst.Width-1 do begin
dx:=sdx shr 16;
dy:=sdy shr 16;
if(dx<Src.Width)and(dy<Src.Height)then pc^:=Src.Pixels24[dy,dx];
Inc(sdx,icos);
Inc(sdy,isin);
Inc(pc);
end;
pc:=Ptr(Integer(pc)+Dst.Gap);
end;
Теория, если коротко, такова:
1) Вращение - это аффинное преобразование, и сводится к операции умножения на матрицу (уже писали). Точнее, конкретно для вращения (+ пропорционального масштабирования) достаточно иметь два коэфф-та, синус-косинус, ну и смещение (ещё два числа).
2) Для поддержки масштабирования/сглаживания удобнее считать обратное преобразование, т.е. результирующая картинка считается неповёрнутой, а из исходной пиксели выбираются с поворотом.
3) Можно упростить формулу преобразования за счёт того, что последовательно считаются соседние по горизонтали пиксели, и в результате свести всё к двум сложениям на пиксель.
4) Желательно использовать fixed point (эмуляцию дробных чисел целыми), т.к. с плавающей точкой Round тормозит.
Хотя сотни FPS на высоких разрешениях результирующей картинки этот код может не потянуть (старичок P3-1200, 800*600, 8 бит: без сглаживания - 70 FPS, со сглаживанием - 40), но по сравнению с твоим - в десятки-сотни раз быстрее.
Видеокарта, конечно, повернёт быстрее, но там свои проблемы. Передача данных в видеопамять не мгновенна, а если понадобится в обратном направлении (для доп. обработки на CPU) - наверняка растеряешь на этом всё ускорение, разве что на самых последних картах оно не очень тормозит (GF GTS, возможно GF 8000-9000 серий). Как вариант - перенести вообще всю обработку картинок на видеокарту (шейдеры, GPGPU...). Но это, прямо скажем, непросто, а для каких-то специфических алгоритмов может быть вообще невозможно.
Рамиль_ (2009-12-12 16:28:00) [2]GDI+ за глаза.
Почитайте книжку про компьютерную графику, будет намного легче.
Evgnevius (2009-12-12 00:10:00) [3]Ладно, ребят. Вижу, что все вы хотите мне помочь, однако, как я понял, специалисты по OpenGL на этот топик не заходили. Придётся исхитряться
Evgnevius (2009-12-11 23:10:00) [4]Несколько тысяч - это конечно многовато. Скорее - несколько сотен раз. А зачем - это уже зависит от поставленной задачи. Если хотите, можете поглядеть, на наше творчество 2-х летней давности, то, что мы сделали без использования OpenGL, чисто на ресурсах процессора.
www.ntlab.su
antonn (2009-12-09 16:05:00) [5]не стоит выкидывать процессор, он не так уж плох :)
если нужно выводить с последующим отображением на экране, то зачем делать это несколько тысяч раз?
Evgnevius (2009-12-09 15:59:00) [6]Рамиль, спасибо за ваше терпение. Я нажимал Ctrl и щёлкал. Кроме того, нажимал ещё и F1.
antonn, Если фастлиб не использует видеокарту, то спасибо. Процессор не хочу напрягать, так как пишу плагин, в котором на одном битмапе другой должен выводиться в разных пропорциях и с разными углами поворотов от нескольких сотен до нескольких тысяч раз. Координаты вывода для каждого битмапа должны пересчитываться динамически. Спасибо за предложенную помощь.
antonn (2009-12-09 15:48:00) [7]
> Этот перебор и есть главный тормоз не смотря на то, что
> используется ScanLine.
попробуй фастлиб
Рамиль (2009-12-09 15:28:00) [8]
> а что такое xForm?
Матрица аффинного преобразования (в виде рекорда).XFORM = record
eM11 : Single;
eM12 : Single;
eM21 : Single;
eM22 : Single;
eDx : Single;
eDy : Single;
end;
LPXFORM = ^XFORM;
_XFORM = XFORM;
TXFORM = XFORM;
PXFORM = ^XFORM;
Трудно нажать Ctrl и щелкнуть?
Evgnevius (2009-12-09 14:31:00) [9]а что такое xForm?
Рамиль (2009-12-09 13:10:00) [10]X: xForm;
Alpha, IncAlpha: double;
bm: Graphics.TBitmap;
не туда вставил, надеюсь, понятно, что это поля формы или глобальные переменные.
Рамиль (2009-12-09 13:08:00) [11]Такой скорости не хватит?
procedure TForm1.FormCreate(Sender: TObject);
X: xForm;
Alpha, IncAlpha: double;
bm: Graphics.TBitmap;
...
begin
Alpha:=0;
IncAlpha:=2*Pi/365;
bm := Graphics.TBitmap.Create;
bm.LoadFromFile('c:\lazarus\projects\test.bmp');
X.eDx:= Self.Width / 2;
X.eDy:= Self.Height / 2;
SetGraphicsMode(Self.Canvas.Handle, GM_ADVANCED);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
X.eM11:=cos(Alpha);
X.eM12:=sin(Alpha);
X.eM21:=-sin(Alpha);
X.eM22:=cos(Alpha);
SetWorldTransform(Self.Canvas.Handle, X);
Self.Canvas.Draw(-bm.Width div 2 , -bm.Height div 2, bm);
Alpha := Alpha + IncAlpha;
end;
Evgnevius (2009-12-09 01:22:00) [12]Косинусы можно не пересчитывать? А сканирование пикселей битмапа у меня что - по углам должно проходить? Я в массиве перебираю все пиксели, битмапа, узнаю фазовые координаты относительно центра вращения для каждой точки, а затем осуществляю поворот путём увеличения угла на заданный. После этого по вновь полученным фазовым координатам, я получаю декартовы. Скорость приемлема для одноразового построения битмапа, но не для моей задачи. Для меня скорость в полсекунды - с лишком много. Мне хотя бы 0.1 с. Вот и ищу помощь у видеокарты. А про матрицы поворота - спасибо, но они не помогут. Также придётся перебирать каждую точку... Этот перебор и есть главный тормоз не смотря на то, что используется ScanLine.
antonn (2009-12-02 21:04:00) [13]зато получается "бесплатный" cel-шейдинг, если спрайт на черном фоне %)
antonn (2009-12-02 21:01:00) [14]
> альфа у краевых пикселей тоже уменьшается вместе с RGB,
> но видимо недостаточно уменьшается.
дело не в альфе, каналы RGB все равно обсчитываются с "прозрачным" цветом на спрайте, а альфа отдельно. Можно, конечно, добавить в твой код умножение канала на альфу - но тогда будет зачернение. При выводе может сразу не будет заметно, но потом может помешать.
Я не разбирал работу железного поворота, но думал что они работают по тому же принципу, ведь если просто поворачивать спрайт, а потом рисовать - кайму бы завно заметили :) вообще это решается тем, что видимые каналы "протягиваются" в стороны, как вот тут: http://desksoft.ru/index.php?downloads=attachments&id=244, тогда привращении все должно быть пучком :)
Sapersky (2009-12-02 20:41:00) [15]Проверил на Фастлибе - действительно кайма получается. Хотя мне казалось, что не должна - альфа у краевых пикселей тоже уменьшается вместе с RGB, но видимо недостаточно уменьшается.
Спрайты с плавными границами (иконки Висты) рисуются нормально.
Интересно, есть ли подобные проблемы у "железных" игровиков. Мне кажется - должны быть, так что можно у них поспрашивать.
Вот, например, в текстуре с персонажем из конкурса Battle альфа по краям в основном размытая.
antonn (2009-12-02 19:38:00) [16]вот что я имел ввиду: http://desksoft.ru/index.php?downloads=attachments&id=243
antonn (2009-12-02 19:17:00) [17]понял почему оно мне казалось "не то":
я увеличиваю поворачиваемый битмап, и увеличиваю бекграунд куда он ляжет, поворачиваю битмап, рисую его на увеличенном буфере бекграунда, уменьшаю этот бутерброд, и бличу обратно. Таким образом при повороте в месте границ спрайта он смешается с фоном, у тебя в формуле нет смешений с бекграундом. И вот тут вопрос будет, про который мне лень думать :)
[B][S]
[S][S]
допустим в кубик пикселей попадет пиксель бекграунда, как выше. Тогда результирующий цвет пикселя будет ([B]+[S]+[S]+[S])/4, а в твоем примере получается ([S]+[S]+[S]+[S_clear])/4? ([S_clear] - это часть спрайта за его границей - с нулевой альфой например. Собсно из-за этого я и бличу большой увеличенный спрайт на большой бекграунд, иначе при уменьшении будет суммироваться "прозрачная" область спрайта, из-за этого будет кайма)
Sapersky (2009-12-02 19:05:00) [18]а оно точно даст такой же результат как и при повороте и уменьшении? :)
Полагаю, близкий к увеличению/уменьшению в 2 раза. Алгоритм фактически тот же самый - результирующий пиксель определяется 4-мя исходными.
Кстати, "железо" работает именно так. Ещё мипмэппинг/трилинейка используется при сильном уменьшении (анизотропка только для наклонных поверхностей).
можешь собрать примерный проект, даже через canvas.pixels[]?
Ну ты обленился... у тебя же есть свои функции вращения, всего-то дел - прикрутить к ним код интерполяции из той ветки. Хотя с т.з. производительности рекомендуется fixed point, как в фастлибе.
antonn (2009-12-02 17:34:00) [19]
> Sapersky (02.12.09 17:29) [28]
просто интересно, можешь собрать примерный проект, даже через canvas.pixels[]?
antonn (2009-12-02 17:33:00) [20]
> Sapersky (02.12.09 17:29) [28]
а оно точно даст такой же результат как и при повороте и уменьшении? :)