Sign in Join
Wiki copytemporary

BGRABitmap tutorial 9/fr: what changed

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

OldNewLine
11Ce tutoriel montre comment utiliser l'éclairage de Phong avec les textures.
22
33### Création d'un nouveau projet
44
55Cré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]].
66
77### Phong et lumière
88
99Pour utiliser l'éclairage Phong, vous devez initialiser une classe *TPhongShading*. Elle est située dans l'unité *BGRAGradients*.
1010
1111Ajoutez la variable dans la définition de la fenêtre :
1212
1313``` pascal
1414TForm1 = class(TForm)
1515 ...
1616 phong: TPhongShading;
1717```
1818
1919Quand la fenêtre est créée, créez la classe :
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
3333L'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.
3434
3535Quand le fenêtre est détruite :
3636
3737``` pascal
3838procedure TForm1.FormDestroy(Sender: TObject);
3939begin
4040 phong.Free;
4141end;
4242```
4343
4444Quand l'image est peinte, on ajoute un objet avec éclairage de Phong :
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
6060Les 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.
6161
6262Finalement, quand la souris est déplacée, ce serait bien que la source de lumière suive :
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### Exécution du programme
7474
7575Vous pouvez jouer avec la lumière sur la sphère :
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### Utiliser l'éclairage de Phong pour créer des textures
8380
8481La procédure suivante crée un carré de chocolat :
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; //espace vide autour du carré
9491 square := CreateRectangleMap(tx-2*margin,ty-2*margin,tx div 8);
9592
9693 //crée une carte avec le carré au milieu
9794 map := TBGRABitmap.Create(tx,ty,BGRABlack);
9895 map.PutImage(margin,margin,square,dmDrawWithTransparency);
9996
10097 //applique un flou pour le rendre plus arrondi
10198 BGRAReplace(map,map.FilterBlurRadial(tx div 40,rbFast));
10299 square.free;
103100
104101 //création de l'image résultante
105102 result := TBGRABitmap.Create(tx,ty);
106103
107104 //utilisation de l'éclairage de Phong
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 //dessine une pièce de chocolat avec une altitude max de 20
117114 phong.Draw(result,map,20,0,0,BGRA(86,41,38));
118115 map.Free;
119116 phong.Free;
120117end;
121118```
122119
123120Le module d'éclairage de Phong utilise une carte d'altitudes pour calculer les effets de lumière. Ici, la carte contient un carré.
124121
125122Parmi 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.
126123
127124Quand la fenêtre est créée, on crée le morceau de chocolat :
128125
129126``` pascal
130127 chocolate := CreateChocolateTexture(80,80);
131128```
132129
133130Et quand la fenêtre est détruite :
134131
135132``` pascal
136133 chocolate.Free;
137134```
138135
139136Avant *phong.DrawSphere* dans l'événement *OnPaint*, ajoutez cette ligne :
140137
141138``` pascal
142139 image.FillRect(0,0,80*7,80*4,chocolate,dmSet);
143140```
144141
145142### Code résultant
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### Exécution du programme
253250
254251Vous devriez voir une plaquette de chocolat appétissante avec une grosse cerise :
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### Utiliser le bruit de Perlin et l'éclairage de Phong ensemble
262256
263257L'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 :
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
288282D'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.
289283
290284L'appel à *phong.Draw* avec le décalage (-2,-2) dessine la carte à la position correcte, prenant en compte qu'on a ajouté 2 pixels.
291285
292286Maintenant dans l'événement *OnPaint* :
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### Exécution du programme
312306
313307Vous devriez voir une fenêtre avec un fond de pierre :
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### Faire de l'eau
321312
322313C'est presque la même procédure pour générer de l'eau :
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
351342La 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.
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### Utilisation de seuil pour faire des traces dans la neige
359347
360348Il est possible de ne garder qu'un sous-intervalle des altitudes, pour avoir une texture qui montre des traces de pas dans la neige.
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 //ici la carte aléatoire est créée
373361 result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1.2);
374362
375363 //à présent on applique les seuils
376364 p := result.Data;
377365 for i := 0 to result.NbPixels-1 do
378366 begin
379367 v := p^.red;
380368 //si la valeur est au-dessus de 80 ou en-dessous de 50, on la divise par 10 pour rendre la carte horizontale
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 //pour que l'éclairage de Phong prenne en compte le cycle
390378 temp:= result.GetPart(rect(-2,-2,tx+2,ty+2)) as TBGRABitmap;
391379 //on applique un flou radial
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; //pour avoir des ombres
399387 phong.Draw(result,temp,30,-2,-2,BGRAWhite);
400388 phong.Free;
401389 temp.Free;
402390end;
403391```
404392
405393On obtient cela :
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/fr|Tutoriel précédent (textures)]] \| [[BGRABitmap tutorial 10/fr|Tutoriel suivant (plaquage de textures)]]
413398
414399---
415400*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).*
416401Category: Graphics/fr

Back to history