Sign in Join
Wiki copytemporary

BGRABitmap tutorial 9/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 mit der Phong-Schattierung Texturen erzeugen 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### Phong-Schattierung und Beleuchtung
88
99Um die Phong-Schattierung zu benutzen, müssen Sie eine TPhongShading-Klasse instantiieren. Diese befindet sich in der Unit 'BGRAGradients'.
1010
1111Fügen wir eine Variable in der Formulardefinition hinzu:
1212
1313``` pascal
1414TForm1 = class(TForm)
1515 ...
1616 phong: TPhongShading;
1717```
1818
1919Wenn das Formular erzeugt wird, erzeugen wir auch die Klasse:
2020
2121``` pascal
2222procedure TForm1.FormCreate(Sender: TObject);
2323begin
2424 phong := TPhongShading.Create;
2525 phong.LightPositionZ := 150;
2626 phong.SpecularIndex := 20;
2727 phong.AmbientFactor := 0.4;
2828 phong.LightSourceIntensity := 250;
2929 phong.LightSourceDistanceTerm := 200;
3030end;
3131```
3232
3333Der Specularindex zeigt an, wie konzentriert das reflektierte Licht ist.
3434
3535Wenn das Formular zerstört wird:
3636
3737``` pascal
3838procedure TForm1.FormDestroy(Sender: TObject);
3939begin
4040 phong.Free;
4141end;
4242```
4343
4444Wenn das Formular gezeichnet wird, fügen wir ein phong-schattiertes Objekt ein:
4545
4646``` pascal
4747var
4848 image: TBGRABitmap;
4949
5050begin
5151 image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
5252
5353 phong.DrawSphere(image,rect(20,20,120,120),50,BGRA(255,0,0));
5454
5555 image.Draw(Canvas,0,0,True);
5656 image.free;
5757end;
5858```
5959
6060Die Parameter von DrawSphere sind das Zielbild, die Abmessungen des Objektes, die maximale Höhe und die Farbe. Der Durchmesser der Kugelist 100, also ist die maximale Höhe der Halbkugel 50.
6161
6262Zuletzt wäre es nett, wenn die Lichtquelle den Mauszeigerbewegungen folgen würde:
6363
6464``` pascal
6565procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
6666 Y: Integer);
6767begin
6868 phong.LightPosition := point(X,Y);
6969 FormPaint(Sender);
7070end;
7171```
7272
7373### Starten Sie das Programm
7474
7575Sie sollten mit dem Licht auf der Kugel spielen können:
7676
77-<figure>
78-<img src="BGRATutorial9a.png" title="BGRATutorial9a.png" />
79-<figcaption>BGRATutorial9a.png</figcaption>
80-</figure>
77+![](/wiki-images/f/fd/BGRATutorial9a.png)
8178
8279### Verwenden Sie die Phong-Schattierung, um Texturen zu erzeugen
8380
8481Die folgende Prozedur erzeugt ein Stück Schokolade:
8582
8683``` pascal
8784function CreateChocolateTexture(tx,ty: integer): TBGRABitmap;
8885var
8986 square,map: TBGRABitmap;
9087 phong: TPhongShading;
9188 margin: integer;
9289begin
9390 margin := tx div 20; //empty space around the square
9491 square := CreateRectangleMap(tx-2*margin,ty-2*margin,tx div 8);
9592
9693 //erzeugt eine Bitmap mit einem Quadrat in der Mitte
9794 map := TBGRABitmap.Create(tx,ty,BGRABlack);
9895 map.PutImage(margin,margin,square,dmDrawWithTransparency);
9996
10097 //durch Verwischen erscheint es weicher
10198 BGRAReplace(map,map.FilterBlurRadial(tx div 40,rbFast));
10299 square.free;
103100
104101 //erzeugt die resultierende Bitmap
105102 result := TBGRABitmap.Create(tx,ty);
106103
107104 //benutzt die Phong-Schattierung
108105 phong := TPhongShading.Create;
109106 phong.LightSourceDistanceFactor := 0;
110107 phong.LightDestFactor := 0;
111108 phong.LightSourceIntensity := 200;
112109 phong.AmbientFactor := 0.5;
113110 phong.LightPosition := Point(-50,-100);
114111 phong.LightPositionZ := 80;
115112
116113 //zeichnet ein Stück Schokolade mit maximaler Höhe 20
117114 phong.Draw(result,map,20,0,0,BGRA(86,41,38));
118115 map.Free;
119116 phong.Free;
120117end;
121118```
122119
123120Der Phong-Shader benutzt eine Höhenkarte zum Darstellen der Lichteffekte. Hier enthält die Karte ein Quadrat.
124121
125122Unter den Eigenschaften des Phong-Shaders gibt es 'LightSourceDistanceFactor' und 'LightDestFactor'. Setzt man diese Werte auf 0 wird das Ergebnis anreihbar. Genau genommen: Wenn der DistanceFactor 0 ist, bleibt die Distanz zwischen der Lichtquelle und dem Objekt unberücksichtigt. Und wenn der LightDestinationFactor 0 ist, dann bleibt die Position des Objektes beim Berechnen des Lichteinfallswinkels unberücksichtigt.
126123
127124Wenn jetzt das Formular erzeugt wird, dann erzeugen wir auch die Schokoladentextur:
128125
129126``` pascal
130127 chocolate := CreateChocolateTexture(80,80);
131128```
132129
133130Und wenn das Formular zerstört wird:
134131
135132``` pascal
136133 chocolate.Free;
137134```
138135
139136Fügen Sie im OnPaint-Ereignis vor 'phong.DrawSphere' folgende Zeile ein:
140137
141138``` pascal
142139 image.FillRect(0,0,80*7,80*4,chocolate,dmSet);
143140```
144141
145142### Resultierender Code
146143
147144``` pascal
148145unit UMain;
149146
150147{$mode objfpc}{$H+}
151148
152149interface
153150
154151uses
155152 Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
156153 ExtCtrls, Buttons, BGRABitmap, BGRABitmapTypes, BGRAGradients;
157154
158155type
159156 { TForm1 }
160157
161158 TForm1 = class(TForm)
162159 Timer1: TTimer;
163160 procedure FormCreate(Sender: TObject);
164161 procedure FormDestroy(Sender: TObject);
165162 procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
166163 procedure FormPaint(Sender: TObject);
167164 private
168165 { private declarations }
169166 public
170167 { public declarations }
171168 phong: TPhongShading;
172169 chocolate: TBGRABitmap;
173170 end;
174171
175172var
176173 Form1: TForm1;
177174
178175implementation
179176
180177function CreateChocolateTexture(tx,ty: integer): TBGRABitmap;
181178var
182179 square,map: TBGRABitmap;
183180 phong: TPhongShading;
184181 margin: integer;
185182begin
186183 margin := tx div 20;
187184 square := CreateRectangleMap(tx-2*margin,ty-2*margin,tx div 8);
188185 map := TBGRABitmap.Create(tx,ty,BGRABlack);
189186 map.PutImage(margin,margin,square,dmDrawWithTransparency);
190187 BGRAReplace(map,map.FilterBlurRadial(tx div 40,rbFast));
191188 square.free;
192189
193190 result := TBGRABitmap.Create(tx,ty);
194191 phong := TPhongShading.Create;
195192 phong.LightSourceDistanceFactor := 0;
196193 phong.LightDestFactor := 0;
197194 phong.LightSourceIntensity := 200;
198195 phong.AmbientFactor := 0.5;
199196 phong.LightPosition := Point(-50,-100);
200197 phong.LightPositionZ := 80;
201198 phong.Draw(result,map,20,0,0,BGRA(86,41,38));
202199 map.Free;
203200 phong.Free;
204201end;
205202
206203{ TForm1 }
207204
208205procedure TForm1.FormCreate(Sender: TObject);
209206begin
210207 phong := TPhongShading.Create;
211208 phong.LightPositionZ := 150;
212209 phong.SpecularIndex := 20;
213210 phong.AmbientFactor := 0.4;
214211 phong.LightSourceIntensity := 250;
215212 phong.LightSourceDistanceTerm := 200;
216213
217214 chocolate := CreateChocolateTexture(80,80);
218215end;
219216
220217procedure TForm1.FormDestroy(Sender: TObject);
221218begin
222219 phong.Free;
223220 chocolate.Free;
224221end;
225222
226223procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
227224 Y: Integer);
228225begin
229226 phong.LightPosition := point(X,Y);
230227 FormPaint(Sender);
231228end;
232229
233230procedure TForm1.FormPaint(Sender: TObject);
234231var
235232 image: TBGRABitmap;
236233begin
237234 image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
238235
239236 image.FillRect(0,0,80*7,80*4,chocolate,dmSet);
240237 phong.DrawSphere(image,rect(20,20,120,120),50,BGRA(255,0,0));
241238
242239 image.Draw(Canvas,0,0,True);
243240 image.free;
244241end;
245242
246243initialization
247244 {$I UMain.lrs}
248245
249246end.
250247```
251248
252249### Starten Sie das Programm
253250
254251Sie sehen hoffentlich eine leckere Tafel Schokolade mit einer großen Kirsche:
255252
256-<figure>
257-<img src="BGRATutorial9b.png" title="BGRATutorial9b.png" />
258-<figcaption>BGRATutorial9b.png</figcaption>
259-</figure>
253+![](/wiki-images/6/6f/BGRATutorial9b.png)
260254
261255### Gemeinsame Nutzung von Perlin noise und Phong-Schattierung
262256
263257Die Idee dahinter ist, eine Höhenkarte mit dem Perlinrauschen zu erzeugen und dann zur Darstellung die Phong-Schattierung anzuwenden. Damit erzeugen wir hier eine Steintextur:
264258
265259``` pascal
266260 function CreateStoneTexture(tx,ty: integer): TBGRABitmap;
267261 var
268262 temp: TBGRABitmap;
269263 phong: TPhongShading;
270264 begin
271265 result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,0.6);
272266 temp:= result.GetPart(rect(-2,-2,tx+2,ty+2)) as TBGRABitmap;
273267
274268 phong := TPhongShading.Create;
275269 phong.LightSourceDistanceFactor := 0;
276270 phong.LightDestFactor := 0;
277271 phong.LightSourceIntensity := 100;
278272 phong.LightPositionZ := 100;
279273 phong.NegativeDiffusionFactor := 0.3;
280274 phong.AmbientFactor := 0.5;
281275 phong.Draw(result,temp,30,-2,-2,BGRA(170,170,170));
282276
283277 phong.Free;
284278 temp.Free;
285279 end;
286280```
287281
288282Zuerst erzeugen wir eine zyklische Karte. Zyklisch ist wichtig für eine anreihbare Textur. Aber wenn wir die Phong-Schattierung anwenden wollen, müssen wir dem Shader diesen Zyklus bekanntgeben. Also extrahieren wir mittels Getpart die erzeugte Karte mit 2 zusätzlichen Pixels zu jeder Seite, sodass der Shader zyklisch auf die Karte angewendet werden kann.
289283
290284Der Aufruf von 'phong.Draw' mit einem Offset (-2,-2) stellt die Karte am rechten Ort dar und berücksichtigt auch unsere zwei zusätzlichen Pixel.
291285
292286Jetzt lautet das OnPaint-Ereignis:
293287
294288``` pascal
295289procedure TForm1.FormPaint(Sender: TObject);
296290var
297291 image: TBGRABitmap;
298292 stone: TBGRABitmap;
299293begin
300294 image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
301295
302296 stone := CreateStoneTexture(100,100);
303297 image.FillEllipseAntialias(200,100,150,50,stone);
304298 stone.free;
305299
306300 image.Draw(Canvas,0,0,True);
307301 image.free;
308302end;
309303```
310304
311305### Starten Sie das Programm
312306
313307Sie sehen ein Formular mit einem steinartigen Hintergrund.
314308
315-<figure>
316-<img src="BGRATutorial9c.png" title="BGRATutorial9c.png" />
317-<figcaption>BGRATutorial9c.png</figcaption>
318-</figure>
309+![](/wiki-images/a/af/BGRATutorial9c.png)
319310
320311### Darstellung von Wasser
321312
322313Fast die gleiche Prozedur erzeugt uns eine Wassertextur:
323314
324315``` pascal
325316function CreateWaterTexture(tx,ty: integer): TBGRABitmap;
326317const blurSize = 5;
327318var
328319 temp: TBGRABitmap;
329320 phong: TPhongShading;
330321begin
331322 result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1.2);
332323 temp:= result.GetPart(rect(-blurSize,-blurSize,tx+blurSize,ty+blurSize)) as TBGRABitmap;
333324 BGRAReplace(temp,temp.FilterBlurRadial(blurSize,rbFast));
334325
335326 phong := TPhongShading.Create;
336327 phong.LightSourceDistanceFactor := 0;
337328 phong.LightDestFactor := 0;
338329 phong.LightSourceIntensity := 150;
339330 phong.LightPositionZ := 80;
340331 phong.LightColor := BGRA(105,233,240);
341332 phong.NegativeDiffusionFactor := 0.3;
342333 phong.SpecularIndex := 20;
343334 phong.AmbientFactor := 0.4;
344335
345336 phong.Draw(result,temp,20,-blurSize,-blurSize,BGRA(28,139,166));
346337 phong.Free;
347338 temp.Free;
348339end;
349340```
350341
351342Der Hauptunterschied ist, dass wir einen Weichzeichner auf das Wasser anwenden und die Lichtfarbe anders setzen.
352343
353-<figure>
354-<img src="BGRATutorial9d.png" title="BGRATutorial9d.png" />
355-<figcaption>BGRATutorial9d.png</figcaption>
356-</figure>
344+![](/wiki-images/f/f1/BGRATutorial9d.png)
357345
358346### Verwendung von Schwellenwerten liefert Spuren im Schnee
359347
360348Wenn wir uns auf auf einen kleinen Bereich von Höhen beschränken, haben wir eine Textur, die Fussabdrücken im Schnee ähnelt.
361349
362350``` pascal
363351function CreateSnowPrintTexture(tx,ty: integer): TBGRABitmap;
364352var
365353 v: integer;
366354 p: PBGRAPixel;
367355 i: Integer;
368356
369357 temp: TBGRABitmap;
370358 phong: TPhongShading;
371359begin
372360 //hier wird eine Zufallskarte erzeugt
373361 result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1.2);
374362
375363 //jetzt die Schwellenwerte anwenden
376364 p := result.Data;
377365 for i := 0 to result.NbPixels-1 do
378366 begin
379367 v := p^.red;
380368 //wenn der Wert über 80 oder unter 50 ist, dividieren wir durch 10, dadurch wird es fast horizontal
381369 if v > 80 then v := (v-80) div 10+80;
382370 if v < 50 then v := 50-(50-v) div 10;
383371 p^.red := v;
384372 p^.green := v;
385373 p^.blue := v;
386374 inc(p);
387375 end;
388376
389377 //wir geben dem Phong-Shader den Zyklus bekannt
390378 temp:= result.GetPart(rect(-2,-2,tx+2,ty+2)) as TBGRABitmap;
391379 //einen radialen Weichzeichner anwenden
392380 BGRAReplace(temp,temp.FilterBlurRadial(2,rbFast));
393381 phong := TPhongShading.Create;
394382 phong.LightSourceDistanceFactor := 0;
395383 phong.LightDestFactor := 0;
396384 phong.LightSourceIntensity := 100;
397385 phong.LightPositionZ := 100;
398386 phong.NegativeDiffusionFactor := 0.3; //ergibt Schatten
399387 phong.Draw(result,temp,30,-2,-2,BGRAWhite);
400388 phong.Free;
401389 temp.Free;
402390end;
403391```
404392
405393Wir erhalten dies:
406394
407-<figure>
408-<img src="BGRATutorial9e.png" title="BGRATutorial9e.png" />
409-<figcaption>BGRATutorial9e.png</figcaption>
410-</figure>
395+![](/wiki-images/d/de/BGRATutorial9e.png)
411396
412397[[BGRABitmap tutorial 8/de|Voriges Tutorial (Texturen)]] \| [[BGRABitmap tutorial 10/de|Nächstes Tutorial (Textur-Transformationen)]]
413398
414399---
415400*From the Free Pascal wiki, page "BGRABitmap tutorial 9/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