Sign in Join
Wiki copytemporary

BGRABitmap tutorial 9/de: what changed

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

Title: BGRABitmap tutorial 9/de

OldNewLine
1+Dieses Tutorial zeigt, wie Sie mit der Phong-Schattierung Texturen erzeugen können.
2+
3+### Erzeugen Sie ein neues Projekt
4+
5+Erzeugen Sie ein neues Projekt und fügen Sie eine Referenz auf [[BGRABitmap/de|BGRABitmap]] hinzu, genau so wie im [[BGRABitmap tutorial/de|ersten Tutorial]].
6+
7+### Phong-Schattierung und Beleuchtung
8+
9+Um die Phong-Schattierung zu benutzen, müssen Sie eine TPhongShading-Klasse instantiieren. Diese befindet sich in der Unit 'BGRAGradients'.
10+
11+Fügen wir eine Variable in der Formulardefinition hinzu:
12+
13+``` pascal
14+TForm1 = class(TForm)
15+ ...
16+ phong: TPhongShading;
17+```
18+
19+Wenn das Formular erzeugt wird, erzeugen wir auch die Klasse:
20+
21+``` pascal
22+procedure TForm1.FormCreate(Sender: TObject);
23+begin
24+ phong := TPhongShading.Create;
25+ phong.LightPositionZ := 150;
26+ phong.SpecularIndex := 20;
27+ phong.AmbientFactor := 0.4;
28+ phong.LightSourceIntensity := 250;
29+ phong.LightSourceDistanceTerm := 200;
30+end;
31+```
32+
33+Der Specularindex zeigt an, wie konzentriert das reflektierte Licht ist.
34+
35+Wenn das Formular zerstört wird:
36+
37+``` pascal
38+procedure TForm1.FormDestroy(Sender: TObject);
39+begin
40+ phong.Free;
41+end;
42+```
43+
44+Wenn das Formular gezeichnet wird, fügen wir ein phong-schattiertes Objekt ein:
45+
46+``` pascal
47+var
48+ image: TBGRABitmap;
49+
50+begin
51+ image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
52+
53+ phong.DrawSphere(image,rect(20,20,120,120),50,BGRA(255,0,0));
54+
55+ image.Draw(Canvas,0,0,True);
56+ image.free;
57+end;
58+```
59+
60+Die 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.
61+
62+Zuletzt wäre es nett, wenn die Lichtquelle den Mauszeigerbewegungen folgen würde:
63+
64+``` pascal
65+procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
66+ Y: Integer);
67+begin
68+ phong.LightPosition := point(X,Y);
69+ FormPaint(Sender);
70+end;
71+```
72+
73+### Starten Sie das Programm
74+
75+Sie sollten mit dem Licht auf der Kugel spielen können:
76+
77+<figure>
78+<img src="BGRATutorial9a.png" title="BGRATutorial9a.png" />
79+<figcaption>BGRATutorial9a.png</figcaption>
80+</figure>
81+
82+### Verwenden Sie die Phong-Schattierung, um Texturen zu erzeugen
83+
84+Die folgende Prozedur erzeugt ein Stück Schokolade:
85+
86+``` pascal
87+function CreateChocolateTexture(tx,ty: integer): TBGRABitmap;
88+var
89+ square,map: TBGRABitmap;
90+ phong: TPhongShading;
91+ margin: integer;
92+begin
93+ margin := tx div 20; //empty space around the square
94+ square := CreateRectangleMap(tx-2*margin,ty-2*margin,tx div 8);
95+
96+ //erzeugt eine Bitmap mit einem Quadrat in der Mitte
97+ map := TBGRABitmap.Create(tx,ty,BGRABlack);
98+ map.PutImage(margin,margin,square,dmDrawWithTransparency);
99+
100+ //durch Verwischen erscheint es weicher
101+ BGRAReplace(map,map.FilterBlurRadial(tx div 40,rbFast));
102+ square.free;
103+
104+ //erzeugt die resultierende Bitmap
105+ result := TBGRABitmap.Create(tx,ty);
106+
107+ //benutzt die Phong-Schattierung
108+ phong := TPhongShading.Create;
109+ phong.LightSourceDistanceFactor := 0;
110+ phong.LightDestFactor := 0;
111+ phong.LightSourceIntensity := 200;
112+ phong.AmbientFactor := 0.5;
113+ phong.LightPosition := Point(-50,-100);
114+ phong.LightPositionZ := 80;
115+
116+ //zeichnet ein Stück Schokolade mit maximaler Höhe 20
117+ phong.Draw(result,map,20,0,0,BGRA(86,41,38));
118+ map.Free;
119+ phong.Free;
120+end;
121+```
122+
123+Der Phong-Shader benutzt eine Höhenkarte zum Darstellen der Lichteffekte. Hier enthält die Karte ein Quadrat.
124+
125+Unter 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.
126+
127+Wenn jetzt das Formular erzeugt wird, dann erzeugen wir auch die Schokoladentextur:
128+
129+``` pascal
130+ chocolate := CreateChocolateTexture(80,80);
131+```
132+
133+Und wenn das Formular zerstört wird:
134+
135+``` pascal
136+ chocolate.Free;
137+```
138+
139+Fügen Sie im OnPaint-Ereignis vor 'phong.DrawSphere' folgende Zeile ein:
140+
141+``` pascal
142+ image.FillRect(0,0,80*7,80*4,chocolate,dmSet);
143+```
144+
145+### Resultierender Code
146+
147+``` pascal
148+unit UMain;
149+
150+{$mode objfpc}{$H+}
151+
152+interface
153+
154+uses
155+ Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
156+ ExtCtrls, Buttons, BGRABitmap, BGRABitmapTypes, BGRAGradients;
157+
158+type
159+ { TForm1 }
160+
161+ TForm1 = class(TForm)
162+ Timer1: TTimer;
163+ procedure FormCreate(Sender: TObject);
164+ procedure FormDestroy(Sender: TObject);
165+ procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
166+ procedure FormPaint(Sender: TObject);
167+ private
168+ { private declarations }
169+ public
170+ { public declarations }
171+ phong: TPhongShading;
172+ chocolate: TBGRABitmap;
173+ end;
174+
175+var
176+ Form1: TForm1;
177+
178+implementation
179+
180+function CreateChocolateTexture(tx,ty: integer): TBGRABitmap;
181+var
182+ square,map: TBGRABitmap;
183+ phong: TPhongShading;
184+ margin: integer;
185+begin
186+ margin := tx div 20;
187+ square := CreateRectangleMap(tx-2*margin,ty-2*margin,tx div 8);
188+ map := TBGRABitmap.Create(tx,ty,BGRABlack);
189+ map.PutImage(margin,margin,square,dmDrawWithTransparency);
190+ BGRAReplace(map,map.FilterBlurRadial(tx div 40,rbFast));
191+ square.free;
192+
193+ result := TBGRABitmap.Create(tx,ty);
194+ phong := TPhongShading.Create;
195+ phong.LightSourceDistanceFactor := 0;
196+ phong.LightDestFactor := 0;
197+ phong.LightSourceIntensity := 200;
198+ phong.AmbientFactor := 0.5;
199+ phong.LightPosition := Point(-50,-100);
200+ phong.LightPositionZ := 80;
201+ phong.Draw(result,map,20,0,0,BGRA(86,41,38));
202+ map.Free;
203+ phong.Free;
204+end;
205+
206+{ TForm1 }
207+
208+procedure TForm1.FormCreate(Sender: TObject);
209+begin
210+ phong := TPhongShading.Create;
211+ phong.LightPositionZ := 150;
212+ phong.SpecularIndex := 20;
213+ phong.AmbientFactor := 0.4;
214+ phong.LightSourceIntensity := 250;
215+ phong.LightSourceDistanceTerm := 200;
216+
217+ chocolate := CreateChocolateTexture(80,80);
218+end;
219+
220+procedure TForm1.FormDestroy(Sender: TObject);
221+begin
222+ phong.Free;
223+ chocolate.Free;
224+end;
225+
226+procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
227+ Y: Integer);
228+begin
229+ phong.LightPosition := point(X,Y);
230+ FormPaint(Sender);
231+end;
232+
233+procedure TForm1.FormPaint(Sender: TObject);
234+var
235+ image: TBGRABitmap;
236+begin
237+ image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
238+
239+ image.FillRect(0,0,80*7,80*4,chocolate,dmSet);
240+ phong.DrawSphere(image,rect(20,20,120,120),50,BGRA(255,0,0));
241+
242+ image.Draw(Canvas,0,0,True);
243+ image.free;
244+end;
245+
246+initialization
247+ {$I UMain.lrs}
248+
249+end.
250+```
251+
252+### Starten Sie das Programm
253+
254+Sie sehen hoffentlich eine leckere Tafel Schokolade mit einer großen Kirsche:
255+
256+<figure>
257+<img src="BGRATutorial9b.png" title="BGRATutorial9b.png" />
258+<figcaption>BGRATutorial9b.png</figcaption>
259+</figure>
260+
261+### Gemeinsame Nutzung von Perlin noise und Phong-Schattierung
262+
263+Die 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:
264+
265+``` pascal
266+ function CreateStoneTexture(tx,ty: integer): TBGRABitmap;
267+ var
268+ temp: TBGRABitmap;
269+ phong: TPhongShading;
270+ begin
271+ result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,0.6);
272+ temp:= result.GetPart(rect(-2,-2,tx+2,ty+2)) as TBGRABitmap;
273+
274+ phong := TPhongShading.Create;
275+ phong.LightSourceDistanceFactor := 0;
276+ phong.LightDestFactor := 0;
277+ phong.LightSourceIntensity := 100;
278+ phong.LightPositionZ := 100;
279+ phong.NegativeDiffusionFactor := 0.3;
280+ phong.AmbientFactor := 0.5;
281+ phong.Draw(result,temp,30,-2,-2,BGRA(170,170,170));
282+
283+ phong.Free;
284+ temp.Free;
285+ end;
286+```
287+
288+Zuerst 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.
289+
290+Der 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.
291+
292+Jetzt lautet das OnPaint-Ereignis:
293+
294+``` pascal
295+procedure TForm1.FormPaint(Sender: TObject);
296+var
297+ image: TBGRABitmap;
298+ stone: TBGRABitmap;
299+begin
300+ image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
301+
302+ stone := CreateStoneTexture(100,100);
303+ image.FillEllipseAntialias(200,100,150,50,stone);
304+ stone.free;
305+
306+ image.Draw(Canvas,0,0,True);
307+ image.free;
308+end;
309+```
310+
311+### Starten Sie das Programm
312+
313+Sie sehen ein Formular mit einem steinartigen Hintergrund.
314+
315+<figure>
316+<img src="BGRATutorial9c.png" title="BGRATutorial9c.png" />
317+<figcaption>BGRATutorial9c.png</figcaption>
318+</figure>
319+
320+### Darstellung von Wasser
321+
322+Fast die gleiche Prozedur erzeugt uns eine Wassertextur:
323+
324+``` pascal
325+function CreateWaterTexture(tx,ty: integer): TBGRABitmap;
326+const blurSize = 5;
327+var
328+ temp: TBGRABitmap;
329+ phong: TPhongShading;
330+begin
331+ result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1.2);
332+ temp:= result.GetPart(rect(-blurSize,-blurSize,tx+blurSize,ty+blurSize)) as TBGRABitmap;
333+ BGRAReplace(temp,temp.FilterBlurRadial(blurSize,rbFast));
334+
335+ phong := TPhongShading.Create;
336+ phong.LightSourceDistanceFactor := 0;
337+ phong.LightDestFactor := 0;
338+ phong.LightSourceIntensity := 150;
339+ phong.LightPositionZ := 80;
340+ phong.LightColor := BGRA(105,233,240);
341+ phong.NegativeDiffusionFactor := 0.3;
342+ phong.SpecularIndex := 20;
343+ phong.AmbientFactor := 0.4;
344+
345+ phong.Draw(result,temp,20,-blurSize,-blurSize,BGRA(28,139,166));
346+ phong.Free;
347+ temp.Free;
348+end;
349+```
350+
351+Der Hauptunterschied ist, dass wir einen Weichzeichner auf das Wasser anwenden und die Lichtfarbe anders setzen.
352+
353+<figure>
354+<img src="BGRATutorial9d.png" title="BGRATutorial9d.png" />
355+<figcaption>BGRATutorial9d.png</figcaption>
356+</figure>
357+
358+### Verwendung von Schwellenwerten liefert Spuren im Schnee
359+
360+Wenn wir uns auf auf einen kleinen Bereich von Höhen beschränken, haben wir eine Textur, die Fussabdrücken im Schnee ähnelt.
361+
362+``` pascal
363+function CreateSnowPrintTexture(tx,ty: integer): TBGRABitmap;
364+var
365+ v: integer;
366+ p: PBGRAPixel;
367+ i: Integer;
368+
369+ temp: TBGRABitmap;
370+ phong: TPhongShading;
371+begin
372+ //hier wird eine Zufallskarte erzeugt
373+ result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1.2);
374+
375+ //jetzt die Schwellenwerte anwenden
376+ p := result.Data;
377+ for i := 0 to result.NbPixels-1 do
378+ begin
379+ v := p^.red;
380+ //wenn der Wert über 80 oder unter 50 ist, dividieren wir durch 10, dadurch wird es fast horizontal
381+ if v > 80 then v := (v-80) div 10+80;
382+ if v < 50 then v := 50-(50-v) div 10;
383+ p^.red := v;
384+ p^.green := v;
385+ p^.blue := v;
386+ inc(p);
387+ end;
388+
389+ //wir geben dem Phong-Shader den Zyklus bekannt
390+ temp:= result.GetPart(rect(-2,-2,tx+2,ty+2)) as TBGRABitmap;
391+ //einen radialen Weichzeichner anwenden
392+ BGRAReplace(temp,temp.FilterBlurRadial(2,rbFast));
393+ phong := TPhongShading.Create;
394+ phong.LightSourceDistanceFactor := 0;
395+ phong.LightDestFactor := 0;
396+ phong.LightSourceIntensity := 100;
397+ phong.LightPositionZ := 100;
398+ phong.NegativeDiffusionFactor := 0.3; //ergibt Schatten
399+ phong.Draw(result,temp,30,-2,-2,BGRAWhite);
400+ phong.Free;
401+ temp.Free;
402+end;
403+```
404+
405+Wir erhalten dies:
406+
407+<figure>
408+<img src="BGRATutorial9e.png" title="BGRATutorial9e.png" />
409+<figcaption>BGRATutorial9e.png</figcaption>
410+</figure>
411+
412+[[BGRABitmap tutorial 8/de|Voriges Tutorial (Texturen)]] \| [[BGRABitmap tutorial 10/de|Nächstes Tutorial (Textur-Transformationen)]]
413+
414+---
415+*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