Форум: "Начинающим";
Текущий архив: 2010.02.07;
Скачать: [xml.tar.bz2];
ВнизВывода битмапа по маске и под углом Найти похожие ветки
← →
Evgnevius © (2009-12-01 18:56) [0]Подскажите, пожалуйста, как это делать, а то OpenGL для меня - тёмный лес, однако нужно именно с её помощью, так как очень важна скорость. С помощью средств GDI всё у меня получается прекрасно, однако тормозит. Помогите, кто знает как.
← →
Evgnevius © (2009-12-01 20:39) [1]Само наличие маски не обязательно, хотя создать чёрно-белую маску с градиентом для меня не проблема - главное, чтобы часть точек битмапа выводилась с заданной прозрачностью по отношению к фону.
← →
antonn © (2009-12-01 21:29) [2]
> С помощью средств GDI всё у меня получается прекрасно, однако
> тормозит.
покажи код
← →
Evgnevius © (2009-12-01 22:28) [3]
procedure DrawBar(Bmp: PBmp; Cols: CL_TColConstruction; XC, YC, Side: Integer; Angle: Extended); stdcall;
var
I, J, W2, X, Y, K, L, XI, YJ: Integer;
Poz, Len: Int64;
Tmp: TBmp;
begin
Tmp := TBmp.Create;
Tmp.Assign(Bmp^);
with Bmp^ do
begin
K := 2;
Side := Side * K;
XC := XC * K;
YC := YC * K;
Len := Side * K * 10;
W2 := Side div 2;
L := Length(Cols) - 1;
for I := 0 to Side do
for J := 0 to Side do
begin
CL_RotateXY(X, Y, I + XC - W2, J + YC - W2, XC, YC, Angle);
case CL_GetSector(Pi / 4, W2, W2, I, J, 4) of
2, 4: Poz := 40 * Abs(W2 - I);
1, 3: Poz := 40 * Abs(W2 - J);
end;
XI := X div K;
YJ := Y div K;
Cols[L].Color := PComp_GetPixel(@Tmp, XI, YJ);
PComp_PutPixel(Bmp, XI, YJ, SimpleLinear(Cols, Len, Poz));
end;
end;
Tmp.Free;
end;
← →
Andy BitOff © (2009-12-01 22:28) [4]> antonn © (01.12.09 21:29) [2]
=)
> Evgnevius © (01.12.09 18:56) [0]
Ага, покажи.
← →
Evgnevius © (2009-12-01 22:34) [5]А вот ниже я привёл специфические функции, использованные в приведённой выше процедуре
type
CL_TColStructure = record
Color: TColor;
ColPart, GradPart: Real;
end;
CL_TColConstruction = array of CL_TColStructure;
procedure CL_RotateXY(var NewX, NewY: Integer; X, Y, X0, Y0: Integer; Angle: Real; R: Real = -1); stdcall;
var
A: Real;
begin
if R = -1 then R := Sqrt(Sqr(X - X0) + Sqr(Y - Y0));
if R <> 0 then
begin
A := ArcCos((X - X0) / R);
if Y > Y0 then
A := 2 * Pi - A;
A := A + Angle;
NewX := Round(X0 + R * Cos(A));
NewY := Round(Y0 + R * Sin(A));
end;
end;
var
A, A1, R: Extended;
function CL_GetSector(A0, CX, CY, X, Y: Extended; S: Word): Integer; stdcall;
begin
CL_DecartToPhase_E(A, R, CX, CY, X, Y);
A1 := A - A0;
if A1 >= 0 then A1 := A1 - Trunc(A1 / TwoPi) * TwoPi else A1 := A1 - (Trunc(A1 / TwoPi) - 1) * TwoPi;
Result := Trunc(A1 * S / TwoPi) + 1;
end;
function SimpleLinear(Cols: CL_TColConstruction; Len, Poz: Int64): TColor; stdcall;
var
L, N, P, TS: Integer;
S: Extended;
begin
L := Length(Cols);
S := Len / (L - 1);
if Poz > Len then Poz := Len;
N := Trunc(Poz / S);
P := Round(Poz - N * S);
TS := Trunc(S);
if P > TS then P := TS;
Result := Linear(Cols[N].Color, Cols[N + 1].Color, TS, P);
end;
function Linear(BC, EC: TColor; Len, Poz: Int64): TColor; stdcall;
begin
if Len = 0 then
begin
Result := BC;
Exit;
end;
if Poz < 0 then
begin
Result := BC;
Exit;
end else
if Poz > Len then
begin
Result := EC;
Exit;
end;
CL_GetRGB(BC, R1, G1, B1);
CL_GetRGB(EC, R2, G2, B2);
Rh := ((R2 - R1) * Poz) div Len;
Gh := ((G2 - G1) * Poz) div Len;
Bh := ((B2 - B1) * Poz) div Len;
R := R1 + Rh;
B := B1 + Bh;
G := G1 + Gh;
Result := RGB(R, G, B);
end;
← →
Evgnevius © (2009-12-01 22:36) [6]а, и вот ещё:
procedure CL_DecartToPhase_E(var Angle, Radius: Extended; X0, Y0, X, Y: Extended); stdcall;
begin
Radius := Sqrt(Sqr(X - X0) + Sqr(Y - Y0));
if Radius <> 0 then Angle := ArcCos((X - X0) / Radius) else
begin
Angle := 0;
Exit;
end;
if Y <= Y0 then Angle := 2 * Pi - Angle;
end;
← →
Andy BitOff © (2009-12-01 22:37) [7]А это - PComp_GetPixel, PComp_PutPixel
← →
Evgnevius © (2009-12-01 22:39) [8]вместо них используйте
Bmp.Canvas.Pixels[X, Y]
← →
Evgnevius © (2009-12-01 22:40) [9]procedure CL_GetRGB(C: TColor; var R, G, B: Integer); stdcall;
begin
if C > $FFFFFF then C := $FFFFFF;
if C < 0 then C := 0;
R := GetRValue(C);
G := GetGValue(C);
B := GetBValue(C);
end;
← →
Andy BitOff © (2009-12-01 22:43) [10]> Evgnevius © (01.12.09 22:39) [8]
Вот в этом и проблема. Сейчас тебе antonn © расскажет как надо работать с пикселями. От себя могу посоветовать http://www.delphimaster.ru/articles/pixels/
← →
Andy BitOff © (2009-12-01 22:44) [11]А в целом для задачи я бы взял GDI+
← →
Evgnevius © (2009-12-01 22:45) [12]не спасибо, с пикселями у нас всё впорядке -
PComp_GetPixel
иPComp_PutPixel
написаны на основеScanLine
А мне нужно именно на OpenGL
← →
Evgnevius © (2009-12-01 22:51) [13]Скорость очень важна - доли секунды - это много
Прорисовка вообще не имеет значения, самое медленное здесь - это математические операции, выполняемые с помощью ЦП, а не ГП
← →
Sapersky (2009-12-01 23:04) [14]Потенциально на софтвере можно получить такую скорость:
http://sapersky.narod.ru/files/FastLIBv389i.rar (пример Rotozoom)
Там, правда, 8 бит, 24 (есть в FastFX.Rotate) будет раза в 2-3 медленнее. Ещё на скорость влияет использование сглаживания и размер результирующей (исходной в меньшей степени) картинки.
Насчёт "маски" не вполне понял, то ли фиксированная альфа нужна, то ли альфа-канал. Ну это тоже можно прикрутить.
← →
antonn © (2009-12-01 23:40) [15]Ниче не покажу, если надо на ОГЛ :) сбило с толку "битмап". ОГЛ ведь в окно рендерит (хоть и можно снять с dc скриншот).
можно попробывать софтваре сообразить, но было бы лучше скинуть тестовый проект с уже наработанным, дабы посравнивать - а есть ли смысл.
← →
Evgnevius © (2009-12-02 00:02) [16]Я мне нужно на контекст OpenGL выводить битмап с использованиаем маски прозрачности и под углом
← →
Sapersky (2009-12-02 00:36) [17]Книга Краснова по OGL:
http://d3dengine.narod.ru/books.html
← →
Evgnevius © (2009-12-02 13:26) [18]Sapersky, спасибо. У меня есть эта книга... Но толку от этого мало.
← →
RWolf © (2009-12-02 14:25) [19]Приемлемый FPS для случая вращения картинки умеренного размера можно получить и без применения OpenGL.
Если, конечно, не считать синусы с косинусами для каждой точки, как в приведённом коде.
← →
Evgnevius © (2009-12-02 15:02) [20]Попробую поянить подробнее. В общем, мне нужно создать битмап и вывести его так, чтобы его края не были в виде лесенки при поворотах. Поэтому нужно просто сглаживать края, а это можно сделать, если использовать маску вывода (хоть альфа-канал, хоть как его назови). Картинка должна меняться в реальном времени, поэтому важна скорость.
← →
Evgnevius © (2009-12-02 15:07) [21]RWolf, Синусы и арксинусы нужны для поворота каждой точки. Так что, изходя из написанного мной и, вообще, поставленной задачей, выход один - это увеличение скорости построения изображения, а для этого есть только один способ: использовать возможности видеокарты. А то, что я тут выложил - это просто жёсткий напряг для центрального процессора.
← →
RWolf © (2009-12-02 15:12) [22]
> Синусы и арксинусы нужны для поворота каждой точки.
если речь о повороте изображения на заданный угол, то они одинаковые для всех точек.
← →
Evgnevius © (2009-12-02 15:43) [23]Углы одинаковые, а координаты разные, поэтому, изходя из заданного угла разсчитываются координаты для каждой точки выводимого изображения
← →
RWolf © (2009-12-02 16:21) [24]но синусы-то зачем при этом пересчитывать?
угол поворота изображения — константа.
← →
Рамиль © (2009-12-02 16:33) [25]Если уж на то пошло, угол можно выставить API SetWorldTransform, зачем изобретать велосипед?
> Углы одинаковые, а координаты разные, поэтому, изходя из
> заданного угла разсчитываются координаты для каждой точки
> выводимого изображения
Поворот выполняется умножением вектора на заранее просчитанную матрицу.
http://www.compgraphics.info/2D/affine_transform.php
P. S. Непоколебима тяга людей к изобретению велосипедов :)
← →
Sapersky (2009-12-02 17:23) [26]А то, что я тут выложил - это просто жёсткий напряг для центрального процессора.
Это крайне нерациональное использование мощностей ЦП.
Я [14] для кого писал?
У меня есть эта книга... Но толку от этого мало.
То, что тебе нужно, называется "наложение текстуры". В разделе "спецэффекты", вроде.
← →
antonn © (2009-12-02 17:24) [27]
> Попробую поянить подробнее. В общем, мне нужно создать битмап
> и вывести его так, чтобы его края не были в виде лесенки
> при поворотах. Поэтому нужно просто сглаживать края, а это
> можно сделать, если использовать маску вывода (хоть альфа-
> канал, хоть как его назови). Картинка должна меняться в
> реальном времени, поэтому важна скорость.
Маска тут не совсем нужна. Я увеличиваю изображение в 2/3/4 раза, поворачиваю его, а потом уменьшаю в 2/3/4 раза (выбирая средний цвет из "кубиков" 2*2 пикселей (3*3/4*4)), получается с антиалиасингом (суперсемплинг типа :)), в том числе и альфаканал "плавно" уменьшается, и по нему уже рисую.
в ОГЛ ведь есть свои инструменты для поворотов.
← →
Sapersky (2009-12-02 17:29) [28]Можно без увеличения/уменьшения. Я уже объяснял здесь:
http://delphimaster.net/view/18-1231614795/
← →
antonn © (2009-12-02 17:33) [29]
> Sapersky (02.12.09 17:29) [28]
а оно точно даст такой же результат как и при повороте и уменьшении? :)
← →
antonn © (2009-12-02 17:34) [30]
> Sapersky (02.12.09 17:29) [28]
просто интересно, можешь собрать примерный проект, даже через canvas.pixels[]?
← →
Sapersky (2009-12-02 19:05) [31]а оно точно даст такой же результат как и при повороте и уменьшении? :)
Полагаю, близкий к увеличению/уменьшению в 2 раза. Алгоритм фактически тот же самый - результирующий пиксель определяется 4-мя исходными.
Кстати, "железо" работает именно так. Ещё мипмэппинг/трилинейка используется при сильном уменьшении (анизотропка только для наклонных поверхностей).
можешь собрать примерный проект, даже через canvas.pixels[]?
Ну ты обленился... у тебя же есть свои функции вращения, всего-то дел - прикрутить к ним код интерполяции из той ветки. Хотя с т.з. производительности рекомендуется fixed point, как в фастлибе.
← →
antonn © (2009-12-02 19:17) [32]понял почему оно мне казалось "не то":
я увеличиваю поворачиваемый битмап, и увеличиваю бекграунд куда он ляжет, поворачиваю битмап, рисую его на увеличенном буфере бекграунда, уменьшаю этот бутерброд, и бличу обратно. Таким образом при повороте в месте границ спрайта он смешается с фоном, у тебя в формуле нет смешений с бекграундом. И вот тут вопрос будет, про который мне лень думать :)[B][S]
[S][S]
допустим в кубик пикселей попадет пиксель бекграунда, как выше. Тогда результирующий цвет пикселя будет ([B]+[S]+[S]+[S])/4, а в твоем примере получается ([S]+[S]+[S]+[S_clear])/4? ([S_clear] - это часть спрайта за его границей - с нулевой альфой например. Собсно из-за этого я и бличу большой увеличенный спрайт на большой бекграунд, иначе при уменьшении будет суммироваться "прозрачная" область спрайта, из-за этого будет кайма)
← →
antonn © (2009-12-02 19:38) [33]вот что я имел ввиду: http://desksoft.ru/index.php?downloads=attachments&id=243
← →
Sapersky (2009-12-02 20:41) [34]Проверил на Фастлибе - действительно кайма получается. Хотя мне казалось, что не должна - альфа у краевых пикселей тоже уменьшается вместе с RGB, но видимо недостаточно уменьшается.
Спрайты с плавными границами (иконки Висты) рисуются нормально.
Интересно, есть ли подобные проблемы у "железных" игровиков. Мне кажется - должны быть, так что можно у них поспрашивать.
Вот, например, в текстуре с персонажем из конкурса Battle альфа по краям в основном размытая.
← →
antonn © (2009-12-02 21:01) [35]
> альфа у краевых пикселей тоже уменьшается вместе с RGB,
> но видимо недостаточно уменьшается.
дело не в альфе, каналы RGB все равно обсчитываются с "прозрачным" цветом на спрайте, а альфа отдельно. Можно, конечно, добавить в твой код умножение канала на альфу - но тогда будет зачернение. При выводе может сразу не будет заметно, но потом может помешать.
Я не разбирал работу железного поворота, но думал что они работают по тому же принципу, ведь если просто поворачивать спрайт, а потом рисовать - кайму бы завно заметили :) вообще это решается тем, что видимые каналы "протягиваются" в стороны, как вот тут: http://desksoft.ru/index.php?downloads=attachments&id=244 , тогда привращении все должно быть пучком :)
← →
antonn © (2009-12-02 21:04) [36]зато получается "бесплатный" cel-шейдинг, если спрайт на черном фоне %)
← →
Evgnevius © (2009-12-09 01:22) [37]Косинусы можно не пересчитывать? А сканирование пикселей битмапа у меня что - по углам должно проходить? Я в массиве перебираю все пиксели, битмапа, узнаю фазовые координаты относительно центра вращения для каждой точки, а затем осуществляю поворот путём увеличения угла на заданный. После этого по вновь полученным фазовым координатам, я получаю декартовы. Скорость приемлема для одноразового построения битмапа, но не для моей задачи. Для меня скорость в полсекунды - с лишком много. Мне хотя бы 0.1 с. Вот и ищу помощь у видеокарты. А про матрицы поворота - спасибо, но они не помогут. Также придётся перебирать каждую точку... Этот перебор и есть главный тормоз не смотря на то, что используется ScanLine.
← →
Рамиль © (2009-12-09 13:08) [38]Такой скорости не хватит?
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;
← →
Рамиль © (2009-12-09 13:10) [39]X: xForm;
Alpha, IncAlpha: double;
bm: Graphics.TBitmap;
не туда вставил, надеюсь, понятно, что это поля формы или глобальные переменные.
← →
Evgnevius © (2009-12-09 14:31) [40]а что такое xForm?
← →
Рамиль © (2009-12-09 15:28) [41]
> а что такое 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 и щелкнуть?
← →
antonn © (2009-12-09 15:48) [42]
> Этот перебор и есть главный тормоз не смотря на то, что
> используется ScanLine.
попробуй фастлиб
← →
Evgnevius © (2009-12-09 15:59) [43]Рамиль, спасибо за ваше терпение. Я нажимал Ctrl и щёлкал. Кроме того, нажимал ещё и F1.
antonn, Если фастлиб не использует видеокарту, то спасибо. Процессор не хочу напрягать, так как пишу плагин, в котором на одном битмапе другой должен выводиться в разных пропорциях и с разными углами поворотов от нескольких сотен до нескольких тысяч раз. Координаты вывода для каждого битмапа должны пересчитываться динамически. Спасибо за предложенную помощь.
← →
antonn © (2009-12-09 16:05) [44]не стоит выкидывать процессор, он не так уж плох :)
если нужно выводить с последующим отображением на экране, то зачем делать это несколько тысяч раз?
← →
Evgnevius © (2009-12-11 23:10) [45]Несколько тысяч - это конечно многовато. Скорее - несколько сотен раз. А зачем - это уже зависит от поставленной задачи. Если хотите, можете поглядеть, на наше творчество 2-х летней давности, то, что мы сделали без использования OpenGL, чисто на ресурсах процессора.
www.ntlab.su
← →
Evgnevius © (2009-12-12 00:10) [46]Ладно, ребят. Вижу, что все вы хотите мне помочь, однако, как я понял, специалисты по OpenGL на этот топик не заходили. Придётся исхитряться
← →
Рамиль_ (2009-12-12 16:28) [47]GDI+ за глаза.
Почитайте книжку про компьютерную графику, будет намного легче.
← →
Sapersky (2009-12-12 19:24) [48]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...). Но это, прямо скажем, непросто, а для каких-то специфических алгоритмов может быть вообще невозможно.
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2010.02.07;
Скачать: [xml.tar.bz2];
Память: 0.62 MB
Время: 0.005 c