Entwickler-Ecke

Multimedia / Grafik - Kantenglättung und Doublebuffering


AXMD - Sa 05.03.05 14:04
Titel: Kantenglättung und Doublebuffering
Moin moin :)!

Irgendwie sind mir meine Zeigerdiagramme noch zu pixelig - und unschön flackern tun sie auch, wenn sie neu gezeichnet werden. Obwohl DoubleBuffering des Panels auf dem die PaintBox liegt beim Start auf true gestellt wird. Wär nett, wenn mir jemand sagen könnte wie ich das Flackern wegbekomme ;).
Außerdem wär sowas wie leichtes Antialiasing nicht schlecht. Hab bereits im Forum gesucht, aber nur einen Link zu einem Code aus dem SDC von Horst Kniebusch gefunden, der extrem langsam ist. Jemand eine bessere Idee für's Antialising? Muss nicht weiß Gott wie aufwendig sein, soll nur nicht ganz so pixelig aussehen.

Thx
AXMD


Lossy eX - Sa 05.03.05 15:10

Also ich benutze für DoubleBuffering immer ein - zwie zusätzliches Bitmaps und unterdrücke die WM_ERASEBKGND. Damit habe ich bisher noch nie Probleme gehabt.

Und zum Thema Antialising. Also je nachdem würde dir da wohl empfehlen auf OpenGL umzusteigen. Das hat dann noch den Vorteil, dass es auch Hardwarebeschleunigt ist. Kann aber sein, dass du zu viel von Hand zeichnen musst. Dann isses natürlich eher nachteilig als vorteilhaft. Anderfalls meine ich, das die Graphics32 / G32 [http://www.g32.org/] Komponenten so etwas können. Weiß es aber nicht 100%tig.


matze.de - Sa 05.03.05 16:40

guck mal hier bei den schweizern: Antialising [http://www.swissdelphicenter.ch/de/showcode.php?id=1484]

mfg matze


AXMD - Sa 05.03.05 18:48

Bei den Schweizern hab ich schon geschaut. Daher hatte ich ja die langsame Routine ;)

AXMD


retnyg - Sa 05.03.05 18:55

guckst du hier: http://www.pgd.netstarweb.com/viewtopic.php?t=199


delfiphan - So 06.03.05 03:11

Linien zeichnen mit Kantenglättung, sowas hab ich mal gemacht. Ist mit Pixels[X,Y] programmiert, also sofern nicht top Performance gefragt ist wirds reichen :) Für deine Zeiger reicht es alle male.
Wenn du die Prozedur willst, werd ich sie posten.


AXMD - So 06.03.05 10:35

delfiphan hat folgendes geschrieben:
Linien zeichnen mit Kantenglättung, sowas hab ich mal gemacht. Ist mit Pixels[X,Y] programmiert, also sofern nicht top Performance gefragt ist wirds reichen :) Für deine Zeiger reicht es alle male.
Wenn du die Prozedur willst, werd ich sie posten.


Ja bitte :). Sieht nämlich ganz schön hässlich aus, wenn überall solche Zacken rausstehen ;)

AXMD


delfiphan - So 06.03.05 11:58

Okidoki, OpenGl ist sicher einiges schneller, aber hier ist sie: :)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
procedure SLineTo(Canvas : TCanvas; X2,Y2 : Integer);
// Zeichnet eine geglättete Linie. Berechnet eine (gute) Näherung zu einer perfekt geglätteten Linie (max 4% Fehler). 
Var
 dx, dy, X, Y, E, R, L, dT, dB, X1, Y1 : Integer;
 MainColor : TColor;
 S : Boolean;
procedure Swap(var A, B : Integer);
Var T : Integer;
begin
 T := A; A := B; B := T;
end;
function Blend(const Color : TColor; I : Integer) : TColor; // Farbe Mischen
Type
 RGB = record
  R, G, B, A : byte;
 end;
begin
 RGB(Result).R := (RGB(MainColor).R*I+RGB(Color).R*(2*L-I)) div 2 div L;
 RGB(Result).G := (RGB(MainColor).G*I+RGB(Color).G*(2*L-I)) div 2 div L;
 RGB(Result).B := (RGB(MainColor).B*I+RGB(Color).B*(2*L-I)) div 2 div L;
 RGB(Result).A := 0;
end;
begin
 with Canvas do
 begin
  X1 := PenPos.X;
  Y1 := PenPos.Y;
  dx := X2 - X1;
  dy := Y2 - Y1;
  if (dx=0or (dy=0then // horiz./vert. Linie bzw. Punkt
  begin
   LineTo(X2,Y2); // (Endpunkt selbst wird nicht mitgezeichnet)
   exit;
  end;
  MoveTo(X2,Y2); // Endpunkt
  if abs(dy) > abs(dx) then // Fallunterscheidung für alle 4 Quadranten
  begin
   Swap(dx,dy);
   Swap(X1,Y1);
   Swap(X2,Y2);
   S := True;
  end else
   S := False;
  if dx < 0 then
  begin
   Swap(X1,X2);
   Swap(Y1,Y2);
   dx := -dx;
   dy := -dy;
  end;
  if dy < 0 then
  begin
   R := -1;
   dy := -dy;
  end else
   R := 1;
  Y := Y1;
  E := 0;
  L := Round(Sqrt(dx*dx+dy*dy));
  MainColor := Pen.Color;
  For X := X1 to X2 do
  begin
   dT := L-2*E;
   dB := L+2*E;
   if dT > L then
   begin
    if S then Pixels[Y-R,X] := Blend(Pixels[Y-R,X],dT-L) else // Glättung oben bzw. links
              Pixels[X,Y-R] := Blend(Pixels[X,Y-R],dT-L);
    dT := L;
   end;
   if dB > L then
   begin
    if S then Pixels[Y+R,X] := Blend(Pixels[Y+R,X],dB-L) else // Glättung unten bzw. rechts
              Pixels[X,Y+R] := Blend(Pixels[X,Y+R],dB-L);
    dB := L;
   end;
   if (dT >= 0and (dB >= 0then
    if S then Pixels[Y,X] := Blend(Pixels[Y,X],dT+dB) else // normale Linie
              Pixels[X,Y] := Blend(Pixels[X,Y],dT+dB);
   inc(E, dy);
   if E*2 >= dx then
   begin
    Y := Y + R;
    dec(E, dx);
   end;
  end;
 end;
end;


AXMD - So 06.03.05 12:05

Danke dir vielmals :)! Sieht schon super aus :)

AXMD


wdbee - So 06.03.05 12:12
Titel: Re: Kantenglättung und Doublebuffering
AXMD hat folgendes geschrieben:
Moin moin :)!
- und unschön flackern tun sie auch


Schau mal in der Delphihilfe zu TControl.ControlStyle: csOpaque.
Wenn das Steuerelement die ganze Zeichenfläche überdeckt, werden unnötige Hintergrund-Zeichnenbefehle wohl unterdrückt. Vieleicht reicht das ja schon.


AXMD - So 06.03.05 12:18

Ich glaub heute ist nicht mein Tag :shock:


Delphi-Quelltext
1:
PaintBox1.ControlStyle := csOpaque;                    


ergibt

Zitat:
[Fehler] cmpxmain.pas(772): Inkompatible Typen: 'TControlStyle' und 'Enumeration'


:?: AXMD


delfiphan - So 06.03.05 12:23


Delphi-Quelltext
1:
... := [csOpaque];                    

;)
Gruss


AXMD - So 06.03.05 12:30

:autsch: :autsch: :autsch:

Danke dir
AXMD


AXMD - So 06.03.05 13:37

Hat vielleicht irgendjemand eine Routine, die Ellipsen glättet? Die Linien funktionieren dank delfiphans Routine super. Das Flckerproblem wurde auch behoben - nur die geglättete Ellipse wär noch das Tüpfelchen auf dem i ;)

user defined image

AXMD


delfiphan - So 06.03.05 14:26

So, hab dir was ähnliches wie Canvas.Ellipse mit Kantenglättung per PM geschickt. Also das ganze funktioniert mehr oder weniger per Brute-Force, deswegen getrau ich mich fast nicht den Code hier zu posten ;)


retnyg - So 06.03.05 14:31

brute-force ist immer gut ;)
die gemeinde wartet auf deinen code, delfiphan... :mrgreen:


delfiphan - So 06.03.05 14:48

Grml... Okay hmmm, aber ich weise explizit darauf hin, dass diese Prozedur in keiner Weise schnell ist! Ich hab das nu mal kurz auf die Beine gestellt, und mit Brute-Force programmiert, da die Geschwindigkeit nebensächlich ist.
Zur Anwendung: SEllipse(Canvas, MittelpunktX, MittelPunktY, RadiusX, RadiusY);
Die Prozedur ist also nicht gleich in der Anwendung wie Canvas.Ellipse(left,top,right,bottom)!
Flache Ellipsen (0 Pixel) können damit nicht gezeichnet werden, dann gibt es eine Division durch Null.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
Procedure SEllipse(Canvas: TCanvas; CX, CY, RX, RY : Integer);
// Rasterisiert eine Ellipse per Brute-Force
Const
 SuperSample = 16// Genauigkeit: Min = 1
Var
 X, Y : Integer;
 SX, SY : Integer;
 L : Integer;
 MainColor : TColor;
function Blend(const Color : TColor; E : Extended) : TColor; // Farbe Mischen
Type
 RGB = record
  R, G, B, A : byte;
 end;
begin
 RGB(Result).R := Trunc(RGB(MainColor).R*E+RGB(Color).R*(1-E));
 RGB(Result).G := Trunc(RGB(MainColor).G*E+RGB(Color).G*(1-E));
 RGB(Result).B := Trunc(RGB(MainColor).B*E+RGB(Color).B*(1-E));
 RGB(Result).A := 0;
end;
begin
 with Canvas do
 begin
  MainColor := Pen.Color;
  For X := 0 to RX+1 do
   For Y := 0 to RY+1 do
   begin
    L := 0;
    if ((RX<=2or (RY<=2)) or
       ((X*X/Sqr(RX-2)+Y*Y/Sqr(RY-2)>=1and // in der Nähe der Ellipse
       (X*X/Sqr(RX+2)+Y*Y/Sqr(RY+2)<=1)) then
    begin
     For SX := 0 to SuperSample-1 do
      For SY := 0 to SuperSample-1 do
      begin
       if (Sqr(X+SX/SuperSample)/Sqr(RX-0)+Sqr(Y+SY/SuperSample)/Sqr(RY-0)>1and
          (Sqr(X+SY/SuperSample)/Sqr(RX+1)+Sqr(Y+SY/SuperSample)/Sqr(RY+1)<1then
        inc(L);
      end;
      Pixels[CX+X,CY+Y] := Blend(Pixels[CX+X,CY+Y], L/SuperSample/SuperSample); // Symmetrie  
      Pixels[CX+X,CY-Y] := Blend(Pixels[CX+X,CY-Y], L/SuperSample/SuperSample);
      Pixels[CX-X,CY+Y] := Blend(Pixels[CX-X,CY+Y], L/SuperSample/SuperSample);
      Pixels[CX-X,CY-Y] := Blend(Pixels[CX-X,CY-Y], L/SuperSample/SuperSample);
    end;
   end;
 end;
end;


//Edit: kleiner Bugfix...


AXMD - So 06.03.05 14:50

Gut, ich habs jetzt eingebaut :). Sieht super aus.

Danke nochmal :)
AXMD


torud - Do 06.09.07 12:14
Titel: Ich würde dazu gern wissen
wie ich denn noch die Pen.Width mit übergeben kann, denn ich benötige Linien, die breiter als 1 Pixel sind. Ich habe schon versucht die PixelBreite vorher im Canvas zu setzen, aber das half auch nichts. Könnte man die procedure nochmals dahingehend anpassen, dass die gleich von der vorher eingestellten Canvas.Pen.Width übernommen wird?

Das wäre echt Klasse...

Danke Tom


delfiphan - Di 11.09.07 22:25

Für Kantenglättung: Schau dir GdiPlus an.


torud - Do 13.09.07 10:35

Hm, das ist doch mal ein Wort. Könntest Du mir bitte auch mitteilen, wo ich Infos dazu finde, mit denen Leute wie ich auch was anfangen können? Also möglichst ein Tutorial?

Konnte leider keins über Google finden...


BenBE - Sa 15.09.07 00:22

http://msdn2.microsoft.com/en-us/library/ms533798.aspx