DEMO.DESIGN
Frequently Asked Questions
 
оглавление | demo party в ex-СССР | infused bytes e-mag | новости от ib/news | другие проекты | письмо | win koi lat

следующий фpагмент (2)
- [89] Computer Graphics (2:5030/84) ----------------------------- SU.GRAPHICS - Msg : 10 of 11 From : Maxim Shemanaryov 2:5015/18.7 01 Mar 96 14:54:00 To : Ilya Nakvasin Subj : Re: Anti-aliasing algorithm -------------------------------------------------------------------------------- Hello Ilya! Tuesday February 27 1996 13:19, Ilya Nakvasin wrote to All: IN> Подскажите пожалуйста алгоритм рисования линии с анти-алиазингом IN> или где можно почитать об этом. Возможно это жуткий faq - сильно IN> не ругайте. Hикогда не занимался этим, но вот понадобилось. Делал я такой самодельный - есть реализация на C (для демонстрации метода) для линий и для эллипсов. Вот накопал двухуровневый (двухцветный) анти-алиасинг для линий. Может чем поможет. В принципе несложно сделать и многоуровневый, но это сложней - надо придумывать критерии (м.б. даже эмпирически). С уважением McSeem =============================CUT================================= #define LEFT_SIDE 0 #define RIGHT_SIDE 1 static int sign(int i) { if(i == 0) return 0; if(i > 0) return 1; return -1; } void AntiAliasedLine(int x1, int y1, int x2, int y2, int MainColor, /* Основной колор */ int AntiColor, /* Сглаживающий колор */ int Side /* С какой стороны вектора сглаживать: LEFT_SIDE или RIGHT_SIDE */ ) { int x, y, dx, dy, sx, sy, i, swap, temp1; int E, E0, dx2, dy2; /* Определение коэффициентов для классического алгоритма Брезенхема */ dx = abs(x2 - x1); dy = abs(y2 - y1); sx = sign(x2 - x1); sy = sign(y2 - y1); x=x1; y=y1; swap = 0; if(dy > dx) { temp1 = dx; dx = dy; dy = temp1; swap = 1; } dx2 = dx << 1; dy2 = dy << 1; E = dy2-dx; if(sy < 0) E--; /* Это мое изобретение - при таком декременте отрезок x1,y1 -> x2,y2 всегда будет с точностью до пиксела совпадать с отрезком x2,y2 -> x1,y1 */ /* Запомним начальное значение оценочной функции */ E0 = E; /* Эту строчку понять невозможно, ее надо запомнить ;-) смысл сглаживания сводится к тому, что если текущее значение оценочной функции E больше (или меньше) начального E0, то рисуем пиксел MainColor, иначе AntiColor. А этот хитрый XOR как раз и определяет критерий - больше или меньше. */ temp1 = (sx < 0) ^ (sy < 0) ^ swap ^ Side; for(i = 0; i <= dx; i++) { if( (E <= E0) == temp1 ) { /* Рисуем основным цветом */ putpixel(x, y, MainColor); } else { putpixel(x, y, AntiColor); /* Рисуем сглаживающим цветом */ } /* Это тоже из классического Брезенхема */ if(E >= 0) { if(swap) x += sx; else y += sy; E -= dx2; } if(swap) y += sy; else x += sx; E += dy2; } } ====================================CUT============================ Код для проверки: int maxx = 640-1; int maxy = 480-1; int dx = 15; int dy = 15; for(i = 0; i < maxx; i += dx) AntiAliasedLine(maxx/2, maxy/2, i, 0, 15,7, LEFT_SIDE); for(i = 0; i < maxy; i += dy) AntiAliasedLine(maxx/2, maxy/2, maxx, i, 15,7, LEFT_SIDE); for(i = maxx; i >= 0; i -= dx) AntiAliasedLine(maxx/2, maxy/2, i, maxy, 15,7, LEFT_SIDE); for(i = maxy; i >= 0; i -= dy) AntiAliasedLine(maxx/2, maxy/2, 0, i, 15,7, LEFT_SIDE); getch(); for(i = 0; i < maxx; i += dx) AntiAliasedLine(maxx/2, maxy/2, i, 0, 15,7, RIGHT_SIDE); for(i = 0; i < maxy; i += dy) AntiAliasedLine(maxx/2, maxy/2, maxx, i, 15,7, RIGHT_SIDE); for(i = maxx; i >= 0; i -= dx) AntiAliasedLine(maxx/2, maxy/2, i, maxy, 15,7, RIGHT_SIDE); for(i = maxy; i >= 0; i -= dy) AntiAliasedLine(maxx/2, maxy/2, 0, i, 15,7, RIGHT_SIDE); getch();
следующий фpагмент (3)|пpедыдущий фpагмент (1)
- Demo/intro making and discussion (2:5030/84) ------------------ DEMO.DESIGN - Msg : 10126 of 12629 From : Akzhan Abdulin 2:5040/55 20 Sep 99 15:36:24 To : Andrew Aksyonoff 06 Oct 99 23:41:12 Subj : рисование отрезков, включая антиалиасинг ------------------------------------------------------------------------------- Здравствуй, Andrew! Помнится, когда-то Вы затронули тему рисования линий с антиалиасингом. Hиже представлены полностью неоптимизированные исходники генерации отрезков на Object Pascal (под рукой только Delphi был). Можете добавить в Ваш FAQ. Есть также исходники рисования простых и произвольных эллипсов с антиалиасингом методом Руа. Алгоритм Брезенхема - рисование отрезка DrawLineBresenham; Алгоритм Люка - рисование отрезка DrawLineLucas (imho, быстрее, чем Bresenham); Алгоритм Руа - модификация алгоритма Брезенхема, выполняет антиалиасинг. В алгоритме учитывается только интенсивность точки. AAPointDrawer должен учитывать её как альфа-канал. Конечно, в оптимуме легко можно полностью избавиться от вещественной арифметики, но так легче для восприятия. Специфика VCL вынесена в отдельное место. === Cut === unit MainFormUnit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls; type TPointDrawer = procedure(X, Y: Integer) of object; TAAPointDrawer = procedure(X, Y: Integer; Intensity: Integer) of object; TMainForm = class(TForm) Panel1: TPanel; Panel2: TPanel; Button1: TButton; Button2: TButton; Label1: TLabel; Label2: TLabel; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private declarations } FPanelCanvas: TControlCanvas; procedure DrawPointAtPanel2(X, Y: Integer; Intensity: Integer); procedure DrawLineLucas(Xd, Yd: Integer; Xf, Yf: Integer; PointDrawer: TPointDrawer); procedure DrawLineBresenham(Xd, Yd: Integer; Xf, Yf: Integer; PointDrawer: TPointDrawer); procedure DrawLineBresenhamAA(Xd, Yd: Integer; Xf, Yf: Integer; Imax: Integer; AAPointDrawer: TAAPointDrawer); public { Public declarations } end; var MainForm: TMainForm; implementation {$R *.DFM} function AbsInt(Value: Integer): Integer; begin if Value >= 0 then Result := Value else Result := - Value; end; { TForm1 } procedure TMainForm.Button1Click(Sender: TObject); var i: Integer; tmLucas, tmBresenham: TTime; begin tmLucas := Time; for i := 0 to 60000 do begin DrawLineLucas( 1, 1, 120, i, nil ); end; tmLucas := Time - tmLucas; Label1.Caption := TimeToStr(tmLucas); tmBresenham := Time; for i := 0 to 60000 do begin DrawLineBresenham( 1, 1, 120, i, nil ); end; tmBresenham := Time - tmBresenham; Label2.Caption := TimeToStr(tmBresenham); end; procedure TMainForm.Button2Click(Sender: TObject); var i: Integer; begin FPanelCanvas := TControlCanvas.Create; FPanelCanvas.Control := Panel2; for i := 1 to 45 do begin DrawLineBresenhamAA( i*2, 1, 90, i, 255, DrawPointAtPanel2 ); end; FPanelCanvas.Free; FPanelCanvas := nil; end; procedure TMainForm.Button3Click(Sender: TObject); begin FPanelCanvas := TControlCanvas.Create; FPanelCanvas.Control := Panel2; DrawLineBresenhamAA( 1, 1, 90, 90, 255, DrawPointAtPanel2 ); FPanelCanvas.Free; FPanelCanvas := nil; end; procedure TMainForm.DrawLineBresenham(Xd, Yd, Xf, Yf: Integer; PointDrawer: TPointDrawer); var dX, dY: Integer; XInc, YInc: Integer; S: Integer; dX2, dY2, dXY: Integer; X, Y: Integer; i: Integer; procedure DrawPoint; begin if Assigned(PointDrawer) then begin PointDrawer(X, Y); end; end; begin { метод Брезенхема } dX := AbsInt(Xd - Xf); dY := AbsInt(Yd - Yf); dX2 := dX + dX; dY2 := dY + dY; if Xd < Xf then XInc := +1 else XInc := -1; if Yd < Yf then YInc := +1 else YInc := -1; X := Xd; Y := Yd; DrawPoint; if dX > dY then begin { x изменяется быстрее, чем y } S := dY2 - dX; dXY := dY2 - dX2; for i := 1 to dX do begin if S >= 0 then begin Inc(Y, YInc); Inc(S, dXY); end else begin Inc(S, dY2); end; Inc(X, XInc); DrawPoint; end; end else begin { y изменяется быстрее, чем x } S := dX2 - dY; dXY := dX2 - dY2; for i := 1 to dY do begin if S >= 0 then begin Inc(X, XInc); Inc(S, dXY); end else begin Inc(S, dX2); end; Inc(Y, YInc); DrawPoint; end; end; end; procedure TMainForm.DrawLineBresenhamAA(Xd, Yd, Xf, Yf, Imax: Integer; AAPointDrawer: TAAPointDrawer); procedure DrawPoint(X, Y: Integer; Intensity: Integer); begin if Assigned(AAPointDrawer) then begin AAPointDrawer(X, Y, Intensity); end; end; var dX, dY: Integer; Xinc, Yinc: Integer; X, Y: Integer; DeltaX, DeltaY: Integer; i: Integer; D: Integer; Xs, Ys: Integer; Cp: Double; I_p: Integer; { яркость вспомогательной точки } I_s: Integer; { яркость основной точки } begin { метод Руа } dX := Xf - Xd; dY := Yf - Yd; DeltaX := AbsInt(dX); DeltaY := AbsInt(dY); if dX > 0 then Xinc := +1 else Xinc := -1; if dY > 0 then Yinc := +1 else Yinc := -1; X := Xd; Y := Yd; DrawPoint(X, Y, Imax); if DeltaX >= DeltaY then begin { x изменяется быстрее, чем y } D := 0; for i := 1 to DeltaX do begin Inc(X, Xinc); Inc(D, DeltaY); if D <= 0 then begin Ys := Y - Yinc; end else begin if D - DeltaX < 0 then begin if 2 * D - DeltaX <= 0 then begin Ys := Y + Yinc; end else begin Ys := Y; Inc(Y, Yinc); Dec(D, DeltaX); end; end else begin Inc(Y, Yinc); Ys := Y + Yinc; Dec(D, DeltaX); end; end; Cp := Abs( D / DeltaX ); I_s := Round(Cp * Imax); I_p := Imax - I_s; DrawPoint(X, Y, I_p); DrawPoint(X, Ys, I_s); end; end else begin { y изменяется быстрее, чем x } D := 0; for i := 1 to DeltaY do begin Inc(Y, Yinc); Inc(D, DeltaX); if D <= 0 then begin Xs := X - Xinc; end else begin if D - DeltaY < 0 then begin if 2 * D - DeltaY <= 0 then begin Xs := X + Xinc; end else begin Xs := X; Inc(X, Xinc); Dec(D, DeltaY); end; end else begin Inc(X, Xinc); Xs := X + Xinc; Dec(D, DeltaY); end; end; Cp := Abs( D / DeltaY ); I_s := Round(Cp * Imax); I_p := Imax - I_s; DrawPoint(X, Y, I_p); DrawPoint(Xs, Y, I_s); end; end; end; procedure TMainForm.DrawLineLucas(Xd, Yd, Xf, Yf: Integer; PointDrawer: TPointDrawer); var dX, dY: Integer; XIncr, YIncr: Integer; X, Y: Integer; Cumul: Integer; i: Integer; procedure DrawPoint; begin if Assigned(PointDrawer) then begin PointDrawer(X, Y); end; end; begin { метод Люка } X := Xd; Y := Yd; DrawPoint; if Xd < Xf then XIncr := +1 else XIncr := -1; if Yd < Yf then YIncr := +1 else YIncr := -1; dX := AbsInt(Xd - Xf); dY := AbsInt(Yd - Yf); if dX > dY then begin { x изменяется быстрее, чем y } Cumul := X div 2; for i := 1 to dX do begin Inc(X, XIncr); Inc(Cumul, dY); if Cumul >= dX then begin Dec(Cumul, dX); Inc(Y, YIncr); end; DrawPoint; end; end else begin { y изменяется быстрее, чем x } Cumul := Y div 2; for i := 1 to dY do begin Inc(Y, YIncr); Inc(Cumul, dX); if Cumul >= dY then begin Dec(Cumul, dY); Inc(X, XIncr); end; DrawPoint; end; end; end; procedure TMainForm.DrawPointAtPanel2(X, Y: Integer; Intensity: Integer); var Color: TColor; Coeff, PastCoeff: Double; R, G, B: Double; Ri, Gi, Bi: Byte; Temp: Integer; begin Color := FPanelCanvas.Pixels[X, Y]; R := GetRValue( Color ); G := GetGValue( Color ); B := GetBValue( Color ); if Intensity < 0 then begin Intensity := 0; end; if Intensity > 255 then begin Intensity := 255; end; Coeff := Intensity / 255; PastCoeff := 1 - Coeff; Temp := Trunc(PastCoeff * R) + Trunc(Coeff * 255); if Temp > 255 then Ri := 255 else Ri := Temp; Temp := Trunc(PastCoeff * G) + Trunc(Coeff * 255); if Temp > 255 then Gi := 255 else Gi := Temp; Temp := Trunc(PastCoeff * B) + Trunc(Coeff * 255); if Temp > 255 then Bi := 255 else Bi := Temp; FPanelCanvas.Pixels[X, Y] := RGB(Ri, Gi, Bi); end; end. === Cut === С уважением, Akzhan http://www.akzhan.midi.ru/devcorner/ - мой уголок разработчика

Всего 2 фpагмент(а/ов) |пpедыдущий фpагмент (2)

Если вы хотите дополнить FAQ - пожалуйста пишите.

design/collection/some content by Frog,
DEMO DESIGN FAQ (C) Realm Of Illusion 1994-2000,
При перепечатке материалов этой страницы пожалуйста ссылайтесь на источник: "DEMO.DESIGN FAQ, http://www.enlight.ru/demo/faq".