Sign in Join
Wiki copytemporary

BGRABitmap tutorial 8/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 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### Utilisation des textures de pinceau
88
99La texture la plus simple est hachurée.
1010
1111Avec l'inspecteur d'objet, ajoutez un gestionnaire *OnPaint* et écrivez :
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 //coordonnées de l'ellipse
2525 x := 150;
2626 y := 100;
2727 rx := 100;
2828 ry := 50;
2929
3030 //charge un pinceau "diagcross" avec un motif blanc sur fond orange
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
4343Comme vous pouvez le voir, une texture est juste une image. Pour remplir une ellipse avec une texture, passez simplement la texture en paramètre à la place de la couleur.
4444
4545Deux commandes définissent l'ellipse. La première est le remplissage, la seconde le contour. Notez que le rayon est 0,5 pixel plus petit pour le remplissage. En effet, quand la taille du pinceau est 1, le rayon intérieur est 0,5 plus petit et le rayon extérieur 0,5 pixel plus grand.
4646
4747En utilisant la commande pour le contour, vous dessinez une ellipse avec texture et un bord. Mais si la fonction de contour n'est pas disponible, vous pouvez aussi utiliser une autre commande de remplissage avec un plus grand rayon et la couleur du bord, puis un rayon plus petit pour l'intérieur.
4848
4949Ajoutez les lignes suivantes avant *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
5656La première commande dessine un rectangle arrondi large (un pinceau de largeur 11) qui inclut le bord. La seconde commande remplit la texture avec une largeur plus petite (9). Cela fonctionne parfaitement tant que la texture n'est pas transparente.
5757
5858### Exécution du programme
5959
6060Vous devriez obtenir un rectangle arrondi avec une ellipse à l'intérieur. Chaque forme est remplie avec une texture orange.
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### Génération de textures
6865
6966#### Bruit de Perlin simple
7067
7168Il est possible de générer des textures aléatoires reproductibles en utilisant *CreateCyclicPerlinNoiseMap*, qui peut être trouvé dans l'unité *BGRAGradient*.
7269
7370Avec l'inspecteur d'objet, définissez un gestionnaire *OnPaint* avec :
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);
8582 tex.free;
8683
8784 image.Draw(Canvas,0,0,True);
8885 image.free;
8986end;
9087```
9188
9289Ce code crée une texture de 100x100 et remplit la fenêtre avec elle. Vous devriez obtenir quelque chose comme cela :
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#### Changer la couleur
10094
10195Le résultat est très noir et blanc. Vous pouvez ajouter quelques couleurs. Pour cela, vous disposez d'une fonction pour interpoler les valeurs. En voici une :
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
110104Cette fonction calcule une valeur allant de *value1* à *value2*. *Position* est un nombre entre 0 et 256 indiquant si on se rapproche de la deuxième valeur. L'expression *shr 8* est un équivalent optimisé de *div 256* pour des valeurs positives. C'est un décalage binaire de 8 chiffres.
111105
112106Comme vous voulez interpoler des couleurs, écrivez une fonction pour cela :
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
124118C'est assez évident : chaque composante est interpolée entre la valeur pour *color1* et pour *color2*.
125119
126120Maintenant, vous avez tout le nécessaire pour faire de la couleur. Après *CreatePerlinNoiseMap*, ajoutez les lignes suivantes :
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
137131Vous aurez besoin des variables 'p' et 'i', alors cliquez sur chacune et pressez *Ctrl-Shift-C*.
138132
139133Cette boucle prend chaque pixel et crée une couleur de vert foncé jusqu'à jaune-vert.
140134
141135Vous obtenez une couleur vert-arbre :
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#### Utilisation de seuils
149140
150141Au lieu de varier continuellement, la couleur peut être changée avec un seuil. Par exemple, vous pouvez délimiter la mer et des îles :
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 //mer
158149 p^ := BGRA(0,128,196); //île
159150 inc(p);
160151 end;
161152```
162153
163154Vous pouvez utiliser davantage de seuils. Voilà par exemple un camouflage militaire :
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#### Fonction sinus
184172
185173Vous pouvez appliquer la fonction sinus aux valeurs du bruit. Créez pour cela une procédure :
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
205193L'oscillation de couleur est une valeur entre 0 et 256. Elle est calculée à partir de l'intensité (*p^.red*). On y applique la fonction sinus avec une demi-période de 32. Cela donne un nombre entre -1 et 1. Pour le ramener dans l'intervalle 0..1, vous ajoutez 1 et divisez par 2. Enfin, vous multipliez par 256 pour avoir un entier pour *Interp256*.
206194
207195La procédure *OnPaint* devient plus simple :
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
226214Vous devriez obtenir une image ressemblant à cela :
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
233218À présent, si vous voulez que votre texture ressemble à du marbre, vous avez besoin de moins d'oscillation. Par exemple, vous pouvez utiliser une demi-période de 80. Sur le marbre, les parties sombres sont très fines. Vous pouvez déformer les oscillations en appliquant une fonction 'puissance' : un exposant entre 0 et 1 rendra la valeur plus proche de 1 et un exposant plus grand que 1 rendra la valeur plus proche de 0. Changez donc l'oscillation dans *CreateCustomTexture* :
234219
235220``` pascal
236221 colorOscillation := round(power((sin(p^.red*Pi/80)+1)/2,0.2)*256);
237222```
238223
239224Vous avez alors quelque chose qui ressemble beaucoup plus à du marbre :
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#### Texture de bois
247229
248230Une texture de bois peut être réalisée avec des fonctions sinus également. La texture de bois contient deux oscillations : une avec des couleurs claires et une autre avec des couleurs foncées. Alors, vous devons appliquer une variation globale entre ces oscillations :
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
270252Ici, la demi-période est 16 et la variation globale est simplement l'intensité. Le résultat ressemble à cela :
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
277256La plupart du temps, une texture de bois est orientée selon un axe. Pour faire cela, à la place d'utiliser l'intensité seulement comme position globale, vous avez besoin de la combiner avec la position x :
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
305284Vous obtenez cela :
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/fr|Tutoriel précédent (splines)]] [[BGRABitmap tutorial 9/fr|Tutoriel suivant (éclairage phong et textures)]]
313289
314290---
315291*From the Free Pascal wiki, page "BGRABitmap tutorial 8/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).*

Back to history