Sign in Join
Wiki copytemporary

BGRABitmap tutorial 9/fr: what changed

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

Title: BGRABitmap tutorial 9/fr

OldNewLine
1+Ce tutoriel montre comment utiliser l'éclairage de Phong avec les textures.
2+
3+### Création d'un nouveau projet
4+
5+Créez un nouveau projet et ajoutez la référence à [[BGRABitmap]], de la même façon que dans [[BGRABitmap tutorial/fr|le premier tutoriel]].
6+
7+### Phong et lumière
8+
9+Pour utiliser l'éclairage Phong, vous devez initialiser une classe *TPhongShading*. Elle est située dans l'unité *BGRAGradients*.
10+
11+Ajoutez la variable dans la définition de la fenêtre :
12+
13+``` pascal
14+TForm1 = class(TForm)
15+ ...
16+ phong: TPhongShading;
17+```
18+
19+Quand la fenêtre est créée, créez la classe :
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+L'indice spéculaire indique la concentration de la lumière réfléchie. Le facteur ambiant indique l'éclairage de base. La variable *LightSourceDistanceTerm* indique la distance supplémentaire entre la lumière et l'objet.
34+
35+Quand le fenêtre est détruite :
36+
37+``` pascal
38+procedure TForm1.FormDestroy(Sender: TObject);
39+begin
40+ phong.Free;
41+end;
42+```
43+
44+Quand l'image est peinte, on ajoute un objet avec éclairage de Phong :
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+Les paramètres de *DrawSphere* sont l'image de destination, les bornes de l'objet, l'altitude maximum et la couleur. Le diamètre de la sphère est 100 alors l'altitude maximum est un hémisphère de 50.
61+
62+Finalement, quand la souris est déplacée, ce serait bien que la source de lumière suive :
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+### Exécution du programme
74+
75+Vous pouvez jouer avec la lumière sur la sphère :
76+
77+<figure>
78+<img src="BGRATutorial9a.png" title="BGRATutorial9a.png" />
79+<figcaption>BGRATutorial9a.png</figcaption>
80+</figure>
81+
82+### Utiliser l'éclairage de Phong pour créer des textures
83+
84+La procédure suivante crée un carré de chocolat :
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; //espace vide autour du carré
94+ square := CreateRectangleMap(tx-2*margin,ty-2*margin,tx div 8);
95+
96+ //crée une carte avec le carré au milieu
97+ map := TBGRABitmap.Create(tx,ty,BGRABlack);
98+ map.PutImage(margin,margin,square,dmDrawWithTransparency);
99+
100+ //applique un flou pour le rendre plus arrondi
101+ BGRAReplace(map,map.FilterBlurRadial(tx div 40,rbFast));
102+ square.free;
103+
104+ //création de l'image résultante
105+ result := TBGRABitmap.Create(tx,ty);
106+
107+ //utilisation de l'éclairage de Phong
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+ //dessine une pièce de chocolat avec une altitude max de 20
117+ phong.Draw(result,map,20,0,0,BGRA(86,41,38));
118+ map.Free;
119+ phong.Free;
120+end;
121+```
122+
123+Le module d'éclairage de Phong utilise une carte d'altitudes pour calculer les effets de lumière. Ici, la carte contient un carré.
124+
125+Parmi les propriétés de l'éclairage figurent *LightSourceDistanceFactor* et *LightDestFactor*. En mettant ces valeurs à zéro, on permet que la texture soit répétable. En effet, quand le facteur de distance est à zéro, la distance entre la lumière et l'objet n'est pas prise en compte, et quand le facteur de destination de la lumière est à zéro, la position de l'objet n'est pas prise en compte pour le calcul de l'angle de la lumière.
126+
127+Quand la fenêtre est créée, on crée le morceau de chocolat :
128+
129+``` pascal
130+ chocolate := CreateChocolateTexture(80,80);
131+```
132+
133+Et quand la fenêtre est détruite :
134+
135+``` pascal
136+ chocolate.Free;
137+```
138+
139+Avant *phong.DrawSphere* dans l'événement *OnPaint*, ajoutez cette ligne :
140+
141+``` pascal
142+ image.FillRect(0,0,80*7,80*4,chocolate,dmSet);
143+```
144+
145+### Code résultant
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+### Exécution du programme
253+
254+Vous devriez voir une plaquette de chocolat appétissante avec une grosse cerise :
255+
256+<figure>
257+<img src="BGRATutorial9b.png" title="BGRATutorial9b.png" />
258+<figcaption>BGRATutorial9b.png</figcaption>
259+</figure>
260+
261+### Utiliser le bruit de Perlin et l'éclairage de Phong ensemble
262+
263+L'idée est de créer une carte avec un bruit de Perlin, et ensuite d'utiliser l'éclairage de Phong pour le rendu. Voici comme créer une texture de pierre :
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+D'abord, on crée une carte cyclique. C'est important pour que la texture soit répétable. Mais ensuite, quand on appliquera l'effet Phong, on aura besoin de préciser que l'effet de lumière est lui aussi cyclique. Alors, avec *GetPart*, on extrait la carte générée avec 2 pixels en plus sur chaque bord, ainsi le calcul de lumière sera-t-il appliqué convenablement.
289+
290+L'appel à *phong.Draw* avec le décalage (-2,-2) dessine la carte à la position correcte, prenant en compte qu'on a ajouté 2 pixels.
291+
292+Maintenant dans l'événement *OnPaint* :
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+### Exécution du programme
312+
313+Vous devriez voir une fenêtre avec un fond de pierre :
314+
315+<figure>
316+<img src="BGRATutorial9c.png" title="BGRATutorial9c.png" />
317+<figcaption>BGRATutorial9c.png</figcaption>
318+</figure>
319+
320+### Faire de l'eau
321+
322+C'est presque la même procédure pour générer de l'eau :
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+La principale différence est qu'on applique un flou pour rendre l'eau ronde et qu'on définit une couleur pour la lumière.
352+
353+<figure>
354+<img src="BGRATutorial9d.png" title="BGRATutorial9d.png" />
355+<figcaption>BGRATutorial9d.png</figcaption>
356+</figure>
357+
358+### Utilisation de seuil pour faire des traces dans la neige
359+
360+Il est possible de ne garder qu'un sous-intervalle des altitudes, pour avoir une texture qui montre des traces de pas dans la neige.
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+ //ici la carte aléatoire est créée
373+ result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1.2);
374+
375+ //à présent on applique les seuils
376+ p := result.Data;
377+ for i := 0 to result.NbPixels-1 do
378+ begin
379+ v := p^.red;
380+ //si la valeur est au-dessus de 80 ou en-dessous de 50, on la divise par 10 pour rendre la carte horizontale
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+ //pour que l'éclairage de Phong prenne en compte le cycle
390+ temp:= result.GetPart(rect(-2,-2,tx+2,ty+2)) as TBGRABitmap;
391+ //on applique un flou radial
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; //pour avoir des ombres
399+ phong.Draw(result,temp,30,-2,-2,BGRAWhite);
400+ phong.Free;
401+ temp.Free;
402+end;
403+```
404+
405+On obtient cela :
406+
407+<figure>
408+<img src="BGRATutorial9e.png" title="BGRATutorial9e.png" />
409+<figcaption>BGRATutorial9e.png</figcaption>
410+</figure>
411+
412+[[BGRABitmap tutorial 8/fr|Tutoriel précédent (textures)]] \| [[BGRABitmap tutorial 10/fr|Tutoriel suivant (plaquage de textures)]]
413+
414+---
415+*From the Free Pascal wiki, page "BGRABitmap tutorial 9/fr", 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).*
416+Category: Graphics/fr

Back to history