Sign in Join
Wiki copytemporary

BGRABitmap tutorial 8/es: what changed

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

Title: BGRABitmap tutorial 8/es

OldNewLine
1+Esta tutoría muestra como usar texturas.
2+
3+### Crear un nuevo proyecto
4+
5+Crea un nuevo proyecto y añade referencia a [[BGRABitmap]], de la misma forma que en [[BGRABitmap tutorial/es|la primer tutoría]].
6+
7+### Usando pinceles de textura
8+
9+La textura mas simple es un pincel eclosionado.
10+
11+Con el inspector de objetos, añade un manejador OnPaint y escribe :
12+
13+``` pascal
14+procedure TForm1.FormPaint(Sender: TObject);
15+var
16+ image,tex: TBGRABitmap;
17+ c: TBGRAPixel;
18+ x,y,rx,ry: single;
19+
20+begin
21+ image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
22+ c := ColorToBGRA(ColorToRGB(clWindowText));
23+
24+ //ellipse coordinates
25+ x := 150;
26+ y := 100;
27+ rx := 100;
28+ ry := 50;
29+
30+ // carga un pincel "diagcross" con un patron blanco y fondo naranja
31+ tex := image.CreateBrushTexture(bsDiagCross,BGRAWhite,BGRA(255,192,0)) as TBGRABitmap;
32+
33+ image.FillEllipseAntialias(x,y,rx-0.5,ry-0.5,tex);
34+ image.EllipseAntialias(x,y,rx,ry,c,1); //draw outline
35+
36+ tex.Free;
37+
38+ image.Draw(Canvas,0,0,True);
39+ image.free;
40+end;
41+```
42+
43+Como puedes ver, una textura es un bitmap. Para rellenar un elipse con una textura, pasa la textura como parametro en vez del color.
44+
45+Dos comandos definen el elipse. El primero es el rellenado, y el segundo el contorno. Ten en cuenta que el radio es 0.5 píxeles mas pequeños que el rellenado. De todas fromas, cuando el ancho de la pluma es 1, el radio interior es 0.5 mas pequeño y el radio exterior es 0.5 mas grande. Sin embargo, incluso si se presta atención a esto, el resultado no será perfecto. Si desea una unión suavizado entre polígonos, es necesario utilizar TBGRAMultishapeFiller en la unidad de BGRAPolygon y sacar todo de una vez.
46+
47+Uso de un comando para el esquema, logramos establecer una elipse con textura con un borde. Pero si la función de esquema no está disponible, también puede utilizar otro comando se llenan de un radio mayor con el color del borde, y luego un radio más pequeño para el interior.
48+
49+Agregue las líneas siguientes antes de tex.Free:
50+
51+``` pascal
52+ image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,c,11);
53+ image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,tex,9);
54+```
55+
56+El primer comando dibuja un rectángulo alrededor de ancho (ancho de 11) que incluye la frontera. El segundo comando se llenan de la textura con un ancho menor (9). Esto funciona perfectamente, siempre y cuando la textura no es transparente.
57+
58+### Ejecuta el programa
59+
60+Deberías obtener un rectángulo redondeado con un elipse dentro. Cada capa está rellenada con una textura naranja.
61+
62+<figure>
63+<img src="BGRATutorial8.png" title="BGRATutorial8.png" />
64+<figcaption>BGRATutorial8.png</figcaption>
65+</figure>
66+
67+### Generating textures
68+
69+#### Basic Perlin noise map
70+
71+It is possible to generate tilable random textures using CreateCyclicPerlinNoiseMap that can be found in the BGRAGradient unit.
72+
73+With the object inspector, define the OnPaint handler with :
74+
75+``` pascal
76+procedure TForm1.FormPaint(Sender: TObject);
77+var
78+ image,tex: TBGRABitmap;
79+
80+begin
81+ image := TBGRABitmap.Create(ClientWidth,ClientHeight);
82+
83+ tex := CreateCyclicPerlinNoiseMap(100,100);
84+ image.FillRect(0,0,image.Width,image.Height, tex);
85+ tex.free;
86+
87+ image.Draw(Canvas,0,0,True);
88+ image.free;
89+end;
90+```
91+
92+This creates a 100x100 texture, and fills the form with it. You should obtain something like this :
93+
94+<figure>
95+<img src="BGRATutorial8b.png" title="BGRATutorial8b.png" />
96+<figcaption>BGRATutorial8b.png</figcaption>
97+</figure>
98+
99+#### Changing color
100+
101+This is very black and white. We can add some colors. For this, we will need some function to interpolate values. Here it is :
102+
103+``` pascal
104+ function Interp256(value1,value2,position: integer): integer; inline;
105+ begin
106+ result := (value1*(256-position) + value2*position) shr 8;
107+ end;
108+```
109+
110+This function computes a value going from value1 to value2. Position is a number between 0 and 256 which indicates how close the result is to the second value. The expression "shr 8" is an optimized equivalent to "div 256" for positive values. It is a binary shift of 8 digits.
111+
112+We want to interpolate colors, so let's write a function to interpolate colors :
113+
114+``` pascal
115+ function Interp256(color1,color2: TBGRAPixel; position: integer): TBGRAPixel; inline;
116+ begin
117+ result.red := Interp256(color1.red,color2.red, position);
118+ result.green := Interp256(color1.green,color2.green, position);
119+ result.blue := Interp256(color1.blue,color2.blue, position);
120+ result.alpha := Interp256(color1.alpha,color2.alpha, position);
121+ end;
122+```
123+
124+It is straightforward : each color component is interpolated between color1 and color2 values.
125+
126+Now we have everything to make some colors. After CreatePerlinNoiseMap, add the following lines :
127+
128+``` pascal
129+ p := tex.Data;
130+ for i := 0 to tex.NbPixels-1 do
131+ begin
132+ p^ := Interp256( BGRA(0,128,0), BGRA(192,255,0), p^.red );
133+ inc(p);
134+ end;
135+```
136+
137+You'll need variables 'p' and 'i', so click on each and press Ctrl-Shift-C.
138+
139+This loop takes each pixel and creates a color from dark green to light green-yellow.
140+
141+We obtain a tree-like green color :
142+
143+<figure>
144+<img src="BGRATutorial8c.png" title="BGRATutorial8c.png" />
145+<figcaption>BGRATutorial8c.png</figcaption>
146+</figure>
147+
148+#### Using thresholds
149+
150+Instead of varying continuously, the color can be changed with a threshold. For example, we can delimit sea and islands :
151+
152+``` pascal
153+ p := tex.Data;
154+ for i := 0 to tex.NbPixels-1 do
155+ begin
156+ if p^.red > 196 then
157+ p^ := BGRA(192,160,96) else //island
158+ p^ := BGRA(0,128,196); //sea
159+ inc(p);
160+ end;
161+```
162+
163+We can use more thresholds. Here is a camouflage :
164+
165+``` pascal
166+ p := result.Data;
167+ for i := 0 to result.NbPixels-1 do
168+ begin
169+ v := p^.red;
170+ if v < 64 then p^:= BGRA(31,33,46) else
171+ if v < 128 then p^:= BGRA(89,71,57) else
172+ if v < 192 then p^:= BGRA(80,106,67) else
173+ p^:= BGRA(161,157,121);
174+ inc(p);
175+ end;
176+```
177+
178+<figure>
179+<img src="BGRATutorial8d.png" title="BGRATutorial8d.png" />
180+<figcaption>BGRATutorial8d.png</figcaption>
181+</figure>
182+
183+#### Sine function
184+
185+We will apply here a sine function to noise values. Let's create a procedure for this :
186+
187+``` pascal
188+ function CreateCustomTexture(tx,ty: integer): TBGRABitmap;
189+ var
190+ colorOscillation: integer;
191+ p: PBGRAPixel;
192+ i: Integer;
193+ begin
194+ result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1);
195+ p := result.Data;
196+ for i := 0 to result.NbPixels-1 do
197+ begin
198+ colorOscillation := round(((sin(p^.red*Pi/32)+1)/2)*256);
199+ p^ := Interp256(BGRA(181,157,105),BGRA(228,227,180),colorOscillation);
200+ inc(p);
201+ end;
202+ end;
203+```
204+
205+The color oscillation is a value between 0 and 256. It is calculated out of the intensity (p^.red). Here we apply a sine function with a half-period of 32. This gives a number between -1 and 1. To put it in the range 0..1, we add 1 and divide by 2. Finally, we multiply by 256 to have an integer for Interp256.
206+
207+The OnPaint procedure becomes simpler :
208+
209+``` pascal
210+var
211+ image,tex: TBGRABitmap;
212+
213+begin
214+ image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
215+
216+ tex := CreateCustomTexture(100,100);
217+ image.FillRoundRectAntialias(20,20,300,200,20,20,tex);
218+ image.RoundRectAntialias(20,20,300,200,20,20,BGRABlack,1);
219+ tex.free;
220+
221+ image.Draw(Canvas,0,0,True);
222+ image.free;
223+end;
224+```
225+
226+You should obtain something like this :
227+
228+<figure>
229+<img src="BGRATutorial8e.png" title="BGRATutorial8e.png" />
230+<figcaption>BGRATutorial8e.png</figcaption>
231+</figure>
232+
233+Now, if we want it to look like marble, we need less oscillations. For example, we can use a half-period of 80. On marble, the black parts are very thin. We can distort the oscillation by applying the power function : an exponent between 0 and 1 will make the values closer to 1 and an exponent greater than 1 will make the values closer to 0. Let's change the oscillation like this in CreateCustomTexture :
234+
235+``` pascal
236+ colorOscillation := round(power((sin(p^.red*Pi/80)+1)/2,0.2)*256);
237+```
238+
239+Now we have something much more like marble :
240+
241+<figure>
242+<img src="BGRATutorial8f.png" title="BGRATutorial8f.png" />
243+<figcaption>BGRATutorial8f.png</figcaption>
244+</figure>
245+
246+#### Wood texture
247+
248+Wood texture can be achieved with sine functions too. Wood texture contains two oscillations, one with light colors, and another one with dark colors. So we need to apply a global variation between these oscillations :
249+
250+``` pascal
251+ function CreateWoodTexture(tx,ty: integer): TBGRABitmap;
252+ var
253+ colorOscillation, globalColorVariation: integer;
254+ p: PBGRAPixel;
255+ i: Integer;
256+ begin
257+ result := CreateCyclicPerlinNoiseMap(tx,ty);
258+ p := result.Data;
259+ for i := 0 to result.NbPixels-1 do
260+ begin
261+ colorOscillation := round(sqrt((sin(p^.red*Pi/16)+1)/2)*256);
262+ globalColorVariation := p^.red;
263+ p^:= Interp256( Interp256(BGRA(247,188,120),BGRA(255,218,170),colorOscillation),
264+ Interp256(BGRA(157,97,60),BGRA(202,145,112),colorOscillation), globalColorVariation);
265+ inc(p);
266+ end;
267+ end;
268+```
269+
270+Here the half-period is 16, and the global variation is simply the intensity. The result is something like this :
271+
272+<figure>
273+<img src="BGRATutorial8g.png" title="BGRATutorial8g.png" />
274+<figcaption>BGRATutorial8g.png</figcaption>
275+</figure>
276+
277+Most of the time, a wood texture is oriented along an axis. To do this, instead of using intensity only as a global position, we need to combine it with the x position :
278+
279+``` pascal
280+ function CreateVerticalWoodTexture(tx,ty: integer): TBGRABitmap;
281+ var
282+ globalPos: single;
283+ colorOscillation, globalColorVariation: integer;
284+ p: PBGRAPixel;
285+ i: Integer;
286+ x: integer;
287+ begin
288+ result := CreateCyclicPerlinNoiseMap(tx,ty);
289+ p := result.Data;
290+ x := 0;
291+ for i := 0 to result.NbPixels-1 do
292+ begin
293+ globalPos := p^.red*Pi/32+x*2*Pi/tx*8;
294+ colorOscillation := round(sqrt((sin(globalPos)+1)/2)*256);
295+ globalColorVariation := round(sin(globalPos/8)*128+128);
296+ p^:= Interp256( Interp256(BGRA(247,188,120),BGRA(255,218,170),colorOscillation),
297+ Interp256(BGRA(157,97,60),BGRA(202,145,112),colorOscillation), globalColorVariation);
298+ inc(p);
299+ inc(x);
300+ if x = tx then x := 0;
301+ end;
302+ end;
303+```
304+
305+We obtain this :
306+
307+<figure>
308+<img src="Tutorial8h.png" title="Tutorial8h.png" />
309+<figcaption>Tutorial8h.png</figcaption>
310+</figure>
311+
312+[[BGRABitmap tutorial 7/es|Tutoría anterior (splines)]] \| [[BGRABitmap tutorial 9/es|Siguiente tutoría (phong shading y texturas)]]
313+
314+---
315+*From the Free Pascal wiki, page "BGRABitmap tutorial 8/es", 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).*
316+Category: Castellano
317+Category: Español

Back to history