Sign in Join
Wiki copytemporary

BGRABitmap tutorial 8/de: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11Dieses Tutorial zeigt, wie Sie Texturen verwenden können.
22
33### Erzeugen Sie ein neues Projekt
44
55Erzeugen Sie ein neues Projekt und fügen Sie eine Referenz auf [[BGRABitmap/de|BGRABitmap]] hinzu, genau so wie im [[BGRABitmap tutorial/de|ersten Tutorial]].
66
77### Verwenden des Pinsels als Textur
88
99Die einfachste Textur ist ein schraffierter Pinsel.
1010
1111Im Objektinspektor fügen Sie einen OnPaint-Handler hinzu und schreiben Sie:
1212
1313``` pascal
1414procedure TForm1.FormPaint(Sender: TObject);
1515var
1616 image,tex: TBGRABitmap;
1717 c: TBGRAPixel;
1818 x,y,rx,ry: single;
1919
2020begin
2121 image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
2222 c := ColorToBGRA(ColorToRGB(clWindowText));
2323
2424 //Ellipsenkoordinaten
2525 x := 150;
2626 y := 100;
2727 rx := 100;
2828 ry := 50;
2929
3030 //lädt einen diagonal gekreuzten Pinsel ("diagcross") mit weißem Muster und orangem Hintergrund
3131 tex := image.CreateBrushTexture(bsDiagCross,BGRAWhite,BGRA(255,192,0)) as TBGRABitmap;
3232
3333 image.FillEllipseAntialias(x,y,rx-0.5,ry-0.5,tex);
3434 image.EllipseAntialias(x,y,rx,ry,c,1); //draw outline
3535
3636 tex.Free;
3737
3838 image.Draw(Canvas,0,0,True);
3939 image.free;
4040end;
4141```
4242
4343Wie Sie sehen ist eine Textur einfach eine Bitmap. Um eine Ellipse mit einer Textur zu füllen, übergeben Sie die Textur einfach als Parameter anstelle der Farbe.
4444
4545Zwei Befehle bestimmen die Ellipse. Der erste ist die Füllung, der zweite die Rahmenlinie. Beachten Sie, dass der Radius für die Füllung um 0,5 Pixel kleiner ist. Genau genommen ist bei einer Stiftbreite von 1 der innere Radius um 0,5 kleiner und der äußere Radius um 0,5 größer. Aber sogar wenn Sie sorgfältig darauf achten, wird das Ergebnis nicht perfekt sein. Falls Sie eine Verbindung der Polygone mit Antialiasing wollen, sollten Sie 'TBGRAMultishapeFiller' aus der Unit 'BGRAPolygon' verwenden und alles zugleich zeichnen lassen.
4646
4747Mit einem Befehl für die Rahmenlinie erzielen wir eine texturierte Ellipse mit einem Rahmen. Falls die Rahmenlinienfunktion nicht verfügbar ist, können Sie auch einen Füllbefehl benutzen, zuerst mit einem größeren Radius für die Rahmenfarbe, dann mit einem kleineren Radius für das Innere.
4848
4949Fügen Sie die folgenden Zeilen ein vor 'tex.Free' :
5050
5151``` pascal
5252 image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,c,11);
5353 image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,tex,9);
5454```
5555
5656Der erste Befehl zeichnet ein breites, abgerundetes Rechteck (mit Breite 11), das den Rahmen enthält. Der zweite Befehl füllt mit einer Textur und einer geringeren Breite (9). Das klappt perfekt, solange die Textur nicht transparent ist.
5757
5858### Starten Sie das Programm
5959
6060Sie erhalten ein abgerundetes Rechteck mit einer eingeschlossenen Ellipse. Jede Figur ist mit einer orangen Textur gefüllt.
6161
62-<figure>
63-<img src="BGRATutorial8.png" title="BGRATutorial8.png" />
64-<figcaption>BGRATutorial8.png</figcaption>
65-</figure>
62+![](/wiki-images/b/b7/BGRATutorial8.png)
6663
6764### Generieren von Texturen
6865
6966#### Basic Perlin noise map
7067
7168Es ist möglich, anreihbare zufällige Texturen zu erzeugen mit der Funktion 'CreateCyclicPerlinNoiseMap', die Sie in der Unit 'BGRAGradients' finden.
7269
7370Im Objektinspektor definieren Sie einen OnPaint-Handler mit:
7471
7572``` pascal
7673procedure TForm1.FormPaint(Sender: TObject);
7774var
7875 image,tex: TBGRABitmap;
7976
8077begin
8178 image := TBGRABitmap.Create(ClientWidth,ClientHeight);
8279
8380 tex := CreateCyclicPerlinNoiseMap(100,100);
8481 image.FillRect(0,0,image.Width,image.Height, tex, dmset);
8582 tex.free;
8683
8784 image.Draw(Canvas,0,0,True);
8885 image.free;
8986end;
9087```
9188
9289Dies erzeugt eine 100x100 Textur und füllt damit das Formular. Sie erhalten etwas ähnliches wie:
9390
94-<figure>
95-<img src="BGRATutorial8b.png" title="BGRATutorial8b.png" />
96-<figcaption>BGRATutorial8b.png</figcaption>
97-</figure>
91+![](/wiki-images/3/3e/BGRATutorial8b.png)
9892
9993#### Ändern der Farben
10094
10195Dies ist zu sehr schwarz-weiß. Geben wir etwas Farbe hinein. Dazu brauchen wir eine Funktion, die die Werte interpoliert. Hier ist sie:
10296
10397``` pascal
10498 function Interp256(value1,value2,position: integer): integer; inline;
10599 begin
106100 result := (value1*(256-position) + value2*position) shr 8;
107101 end;
108102```
109103
110104Diese Funktion berechnet einen Wert, der von Wert1 bis zu Wert2 läuft. Position ist eine Zahl zwischen 0 und 256 die anzeigt, wie nahe das Ergebnis bei Wert2 liegt. Der Ausdruck "shr 8" ist das optimierte Äquivalent zu "div 256" für positive Werte. Es ist eine binäre Verschiebung um 8 Stellen.
111105
112106Wir wollen Farben interpolieren, also schreiben wir eine Funktion, die Farben interpoliert:
113107
114108``` pascal
115109 function Interp256(color1,color2: TBGRAPixel; position: integer): TBGRAPixel; inline;
116110 begin
117111 result.red := Interp256(color1.red,color2.red, position);
118112 result.green := Interp256(color1.green,color2.green, position);
119113 result.blue := Interp256(color1.blue,color2.blue, position);
120114 result.alpha := Interp256(color1.alpha,color2.alpha, position);
121115 end;
122116```
123117
124118Das ist geradlinig: jeder Farbanteil wird zwischen color1 und color2 interpoliert.
125119
126120Jetzt haben wir alles, um es uns etwas bunter zu machen. Nach 'CreatePerlinNoiseMap' fügen Sie folgende Zeilen ein:
127121
128122``` pascal
129123 p := tex.Data;
130124 for i := 0 to tex.NbPixels-1 do
131125 begin
132126 p^ := Interp256( BGRA(0,128,0), BGRA(192,255,0), p^.red );
133127 inc(p);
134128 end;
135129```
136130
137131Sie brauchen die Variablen 'p' und 'i', also klicken Sie auf eine jede und drücken Sie Strg-Umsch-C.
138132
139133Diese Schleife nimmt jedes Pixel und erzeugt eine Farbe von Dunkelgrün bis zu hellem Gelbgrün.
140134
141135Wir erhalten einen baumartigen Grünton:
142136
143-<figure>
144-<img src="BGRATutorial8c.png" title="BGRATutorial8c.png" />
145-<figcaption>BGRATutorial8c.png</figcaption>
146-</figure>
137+![](/wiki-images/9/93/BGRATutorial8c.png)
147138
148139#### Verwendung von Schwellenwerten
149140
150141Anstatt ständig zu variieren, kann die Farbänderung einen Schwellenwert berücksichtigen. Im Beispiel ergibt das ein Meer mit Inseln:
151142
152143``` pascal
153144 p := tex.Data;
154145 for i := 0 to tex.NbPixels-1 do
155146 begin
156147 if p^.red > 196 then
157148 p^ := BGRA(192,160,96) else //island
158149 p^ := BGRA(0,128,196); //sea
159150 inc(p);
160151 end;
161152```
162153
163154Wir nehmen mehrere Schwellenwerte. Fertig ist der Tarnanzug:
164155
165156``` pascal
166157 p := result.Data;
167158 for i := 0 to result.NbPixels-1 do
168159 begin
169160 v := p^.red;
170161 if v < 64 then p^:= BGRA(31,33,46) else
171162 if v < 128 then p^:= BGRA(89,71,57) else
172163 if v < 192 then p^:= BGRA(80,106,67) else
173164 p^:= BGRA(161,157,121);
174165 inc(p);
175166 end;
176167```
177168
178-<figure>
179-<img src="BGRATutorial8d.png" title="BGRATutorial8d.png" />
180-<figcaption>BGRATutorial8d.png</figcaption>
181-</figure>
169+![](/wiki-images/d/d6/BGRATutorial8d.png)
182170
183171#### Sinusfunktion
184172
185173Hier wenden wir eine Sinusfunktion für die Noise-Werte an. Erzeugen wir uns dazu eine Prozedur:
186174
187175``` pascal
188176 function CreateCustomTexture(tx,ty: integer): TBGRABitmap;
189177 var
190178 colorOscillation: integer;
191179 p: PBGRAPixel;
192180 i: Integer;
193181 begin
194182 result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1);
195183 p := result.Data;
196184 for i := 0 to result.NbPixels-1 do
197185 begin
198186 colorOscillation := round(((sin(p^.red*Pi/32)+1)/2)*256);
199187 p^ := Interp256(BGRA(181,157,105),BGRA(228,227,180),colorOscillation);
200188 inc(p);
201189 end;
202190 end;
203191```
204192
205193ColorOscillation ist ein Wert zwischen 0 und 256. Er wird aus der Intensität von (p^.red) berechnet. Hier wenden wir die Sinusfunktion mit einer halben Periode von 32 an. Dies liefert uns eine Zahl zwischen -1 und 1. Um sie auf den Bereich 0..1 abzubilden, addieren wir 1 und dividieren durch 2. Zuletzt multiplizieren wir mit 256 und haben eine Ganzzahl für Interp256.
206194
207195Die OnPaint-Prozedur wird einfacher:
208196
209197``` pascal
210198var
211199 image,tex: TBGRABitmap;
212200
213201begin
214202 image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
215203
216204 tex := CreateCustomTexture(100,100);
217205 image.FillRoundRectAntialias(20,20,300,200,20,20,tex);
218206 image.RoundRectAntialias(20,20,300,200,20,20,BGRABlack,1);
219207 tex.free;
220208
221209 image.Draw(Canvas,0,0,True);
222210 image.free;
223211end;
224212```
225213
226214Sie erhalten etwas in der Art:
227215
228-<figure>
229-<img src="BGRATutorial8e.png" title="BGRATutorial8e.png" />
230-<figcaption>BGRATutorial8e.png</figcaption>
231-</figure>
216+![](/wiki-images/8/8c/BGRATutorial8e.png)
232217
233218Jetzt wollen wir, dass es wie Marmor ausschaut, wir brauchen weniger Schwingungen. Zum Beispiel können wir eine halbe Periode von 80 nehmen. Bei Marmor sind die dunklen Stellen sehr dünn. Wir verzerren die Schwingung durch Anwendung der Potenzfunktion: ein Exponent zwischen 0 und 1 bringt die Werte näher an 1 und ein Exponent größer als 1 bringt die Werte näher an 0. So ändern wir die Schwingung in 'CreateCustomTexture':
234219
235220``` pascal
236221 colorOscillation := round(power((sin(p^.red*Pi/80)+1)/2,0.2)*256);
237222```
238223
239224Jetzt haben wir etwas marmorartiges:
240225
241-<figure>
242-<img src="BGRATutorial8f.png" title="BGRATutorial8f.png" />
243-<figcaption>BGRATutorial8f.png</figcaption>
244-</figure>
226+![](/wiki-images/9/95/BGRATutorial8f.png)
245227
246228#### Holztextur
247229
248230Auch eine Holztextur erzielen wir mit Sinusfunktionen. Holztexturen enthalten zwei Schwingungen. Eine mit hellen Farben und eine weitere mit dunklen Farben. Deshalb wenden wir eine globale Variation auf diese Schwingungen an:
249231
250232``` pascal
251233 function CreateWoodTexture(tx,ty: integer): TBGRABitmap;
252234 var
253235 colorOscillation, globalColorVariation: integer;
254236 p: PBGRAPixel;
255237 i: Integer;
256238 begin
257239 result := CreateCyclicPerlinNoiseMap(tx,ty);
258240 p := result.Data;
259241 for i := 0 to result.NbPixels-1 do
260242 begin
261243 colorOscillation := round(sqrt((sin(p^.red*Pi/16)+1)/2)*256);
262244 globalColorVariation := p^.red;
263245 p^:= Interp256( Interp256(BGRA(247,188,120),BGRA(255,218,170),colorOscillation),
264246 Interp256(BGRA(157,97,60),BGRA(202,145,112),colorOscillation), globalColorVariation);
265247 inc(p);
266248 end;
267249 end;
268250```
269251
270252Hier ist die Halbperiode 16, und die globale Variation ist einfach die Intensität. Das Ergebnis sieht etwa so aus:
271253
272-<figure>
273-<img src="BGRATutorial8g.png" title="BGRATutorial8g.png" />
274-<figcaption>BGRATutorial8g.png</figcaption>
275-</figure>
254+![](/wiki-images/d/d0/BGRATutorial8g.png)
276255
277256Meistens ist eine Holztextur entlang einer Achse ausgerichtet. Dazu müssen wir, anstatt die Intensität als globale Position zu verwenden, sie mit der x-Position kombinieren:
278257
279258``` pascal
280259 function CreateVerticalWoodTexture(tx,ty: integer): TBGRABitmap;
281260 var
282261 globalPos: single;
283262 colorOscillation, globalColorVariation: integer;
284263 p: PBGRAPixel;
285264 i: Integer;
286265 x: integer;
287266 begin
288267 result := CreateCyclicPerlinNoiseMap(tx,ty);
289268 p := result.Data;
290269 x := 0;
291270 for i := 0 to result.NbPixels-1 do
292271 begin
293272 globalPos := p^.red*Pi/32+x*2*Pi/tx*8;
294273 colorOscillation := round(sqrt((sin(globalPos)+1)/2)*256);
295274 globalColorVariation := round(sin(globalPos/8)*128+128);
296275 p^:= Interp256( Interp256(BGRA(247,188,120),BGRA(255,218,170),colorOscillation),
297276 Interp256(BGRA(157,97,60),BGRA(202,145,112),colorOscillation), globalColorVariation);
298277 inc(p);
299278 inc(x);
300279 if x = tx then x := 0;
301280 end;
302281 end;
303282```
304283
305284Wir erhalten dies:
306285
307-<figure>
308-<img src="Tutorial8h.png" title="Tutorial8h.png" />
309-<figcaption>Tutorial8h.png</figcaption>
310-</figure>
286+![](/wiki-images/3/37/Tutorial8h.png)
311287
312288[[BGRABitmap tutorial 7/de|Voriges Tutorial (Splines)]] \| [[BGRABitmap tutorial 9/de|Nächstes Tutorial (Phong-Schattierung und Texturen)]]
313289
314290---
315291*From the Free Pascal wiki, page "BGRABitmap tutorial 8/de", as it stood on 2020-02-10 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history