Difference between revisions of "BGRABitmap tutorial 8/de"
m (→Verwenden des Pinsels als Textur: updated) |
m (Fixed syntax highlighting; deleted category already in page template) |
||
(4 intermediate revisions by 4 users not shown) | |||
Line 14: | Line 14: | ||
Im Objektinspektor fügen Sie einen OnPaint-Handler hinzu und schreiben Sie: | Im Objektinspektor fügen Sie einen OnPaint-Handler hinzu und schreiben Sie: | ||
− | < | + | <syntaxhighlight lang="pascal">procedure TForm1.FormPaint(Sender: TObject); |
var | var | ||
image,tex: TBGRABitmap; | image,tex: TBGRABitmap; | ||
Line 40: | Line 40: | ||
image.Draw(Canvas,0,0,True); | image.Draw(Canvas,0,0,True); | ||
image.free; | image.free; | ||
− | end;</ | + | end;</syntaxhighlight> |
Wie Sie sehen ist eine Textur einfach eine Bitmap. Um eine Ellipse mit einer Textur zu füllen, übergeben Sie die Textur einfach als Parameter anstelle der Farbe. | Wie Sie sehen ist eine Textur einfach eine Bitmap. Um eine Ellipse mit einer Textur zu füllen, übergeben Sie die Textur einfach als Parameter anstelle der Farbe. | ||
Line 49: | Line 49: | ||
Fügen Sie die folgenden Zeilen ein vor 'tex.Free' : | Fügen Sie die folgenden Zeilen ein vor 'tex.Free' : | ||
− | < | + | <syntaxhighlight lang="pascal"> image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,c,11); |
− | image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,tex,9); </ | + | image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,tex,9); </syntaxhighlight> |
Der erste Befehl zeichnet ein breites, abgerundetes Rechteck (mit Breite 11), das den Rahmen enthält. Der zweite Befehl füllt mit einer Textur und einer geringeren Breite (9). Das klappt perfekt, solange die Textur nicht transparent ist. | Der erste Befehl zeichnet ein breites, abgerundetes Rechteck (mit Breite 11), das den Rahmen enthält. Der zweite Befehl füllt mit einer Textur und einer geringeren Breite (9). Das klappt perfekt, solange die Textur nicht transparent ist. | ||
Line 64: | Line 64: | ||
==== Basic Perlin noise map ==== | ==== Basic Perlin noise map ==== | ||
− | Es ist möglich, anreihbare zufällige Texturen zu erzeugen mit der Funktion 'CreateCyclicPerlinNoiseMap', die Sie in der Unit ' | + | Es ist möglich, anreihbare zufällige Texturen zu erzeugen mit der Funktion 'CreateCyclicPerlinNoiseMap', die Sie in der Unit 'BGRAGradients' finden. |
Im Objektinspektor definieren Sie einen OnPaint-Handler mit: | Im Objektinspektor definieren Sie einen OnPaint-Handler mit: | ||
− | < | + | <syntaxhighlight lang="pascal">procedure TForm1.FormPaint(Sender: TObject); |
var | var | ||
image,tex: TBGRABitmap; | image,tex: TBGRABitmap; | ||
Line 75: | Line 75: | ||
tex := CreateCyclicPerlinNoiseMap(100,100); | tex := CreateCyclicPerlinNoiseMap(100,100); | ||
− | image.FillRect(0,0,image.Width,image.Height, tex); | + | image.FillRect(0,0,image.Width,image.Height, tex, dmset); |
tex.free; | tex.free; | ||
image.Draw(Canvas,0,0,True); | image.Draw(Canvas,0,0,True); | ||
image.free; | image.free; | ||
− | end;</ | + | end;</syntaxhighlight> |
Dies erzeugt eine 100x100 Textur und füllt damit das Formular. Sie erhalten etwas ähnliches wie: | Dies erzeugt eine 100x100 Textur und füllt damit das Formular. Sie erhalten etwas ähnliches wie: | ||
Line 89: | Line 89: | ||
Dies ist zu sehr schwarz-weiß. Geben wir etwas Farbe hinein. Dazu brauchen wir eine Funktion, die die Werte interpoliert. Hier ist sie: | Dies ist zu sehr schwarz-weiß. Geben wir etwas Farbe hinein. Dazu brauchen wir eine Funktion, die die Werte interpoliert. Hier ist sie: | ||
− | < | + | <syntaxhighlight lang="pascal"> function Interp256(value1,value2,position: integer): integer; inline; |
begin | begin | ||
result := (value1*(256-position) + value2*position) shr 8; | result := (value1*(256-position) + value2*position) shr 8; | ||
− | end;</ | + | end;</syntaxhighlight> |
Diese Funktion berechnet einen Wert, der von Wert1 bis zu Wert2 läuft. Position ist eine Zahl zwischen 0 und 256 die anzeigt, wie nahe das Ergebnis bei Wert2 liegt. Der Ausdruck "shr 8" ist das optimierte Äquivalent zu "div 256" für positive Werte. Es ist eine binäre Verschiebung um 8 Stellen. | Diese Funktion berechnet einen Wert, der von Wert1 bis zu Wert2 läuft. Position ist eine Zahl zwischen 0 und 256 die anzeigt, wie nahe das Ergebnis bei Wert2 liegt. Der Ausdruck "shr 8" ist das optimierte Äquivalent zu "div 256" für positive Werte. Es ist eine binäre Verschiebung um 8 Stellen. | ||
Wir wollen Farben interpolieren, also schreiben wir eine Funktion, die Farben interpoliert: | Wir wollen Farben interpolieren, also schreiben wir eine Funktion, die Farben interpoliert: | ||
− | < | + | <syntaxhighlight lang="pascal"> function Interp256(color1,color2: TBGRAPixel; position: integer): TBGRAPixel; inline; |
begin | begin | ||
result.red := Interp256(color1.red,color2.red, position); | result.red := Interp256(color1.red,color2.red, position); | ||
Line 102: | Line 102: | ||
result.blue := Interp256(color1.blue,color2.blue, position); | result.blue := Interp256(color1.blue,color2.blue, position); | ||
result.alpha := Interp256(color1.alpha,color2.alpha, position); | result.alpha := Interp256(color1.alpha,color2.alpha, position); | ||
− | end;</ | + | end;</syntaxhighlight> |
Das ist geradlinig: jeder Farbanteil wird zwischen color1 und color2 interpoliert. | Das ist geradlinig: jeder Farbanteil wird zwischen color1 und color2 interpoliert. | ||
Jetzt haben wir alles, um es uns etwas bunter zu machen. Nach 'CreatePerlinNoiseMap' fügen Sie folgende Zeilen ein: | Jetzt haben wir alles, um es uns etwas bunter zu machen. Nach 'CreatePerlinNoiseMap' fügen Sie folgende Zeilen ein: | ||
− | < | + | <syntaxhighlight lang="pascal"> p := tex.Data; |
for i := 0 to tex.NbPixels-1 do | for i := 0 to tex.NbPixels-1 do | ||
begin | begin | ||
p^ := Interp256( BGRA(0,128,0), BGRA(192,255,0), p^.red ); | p^ := Interp256( BGRA(0,128,0), BGRA(192,255,0), p^.red ); | ||
inc(p); | inc(p); | ||
− | end; </ | + | end; </syntaxhighlight> |
Sie brauchen die Variablen 'p' und 'i', also klicken Sie auf eine jede und drücken Sie Strg-Umsch-C. | Sie brauchen die Variablen 'p' und 'i', also klicken Sie auf eine jede und drücken Sie Strg-Umsch-C. | ||
Line 123: | Line 123: | ||
Anstatt ständig zu variieren, kann die Farbänderung einen Schwellenwert berücksichtigen. Im Beispiel ergibt das ein Meer mit Inseln: | Anstatt ständig zu variieren, kann die Farbänderung einen Schwellenwert berücksichtigen. Im Beispiel ergibt das ein Meer mit Inseln: | ||
− | < | + | <syntaxhighlight lang="pascal"> p := tex.Data; |
for i := 0 to tex.NbPixels-1 do | for i := 0 to tex.NbPixels-1 do | ||
begin | begin | ||
Line 130: | Line 130: | ||
p^ := BGRA(0,128,196); //sea | p^ := BGRA(0,128,196); //sea | ||
inc(p); | inc(p); | ||
− | end; </ | + | end; </syntaxhighlight> |
Wir nehmen mehrere Schwellenwerte. Fertig ist der Tarnanzug: | Wir nehmen mehrere Schwellenwerte. Fertig ist der Tarnanzug: | ||
− | < | + | <syntaxhighlight lang="pascal"> p := result.Data; |
for i := 0 to result.NbPixels-1 do | for i := 0 to result.NbPixels-1 do | ||
begin | begin | ||
Line 142: | Line 142: | ||
p^:= BGRA(161,157,121); | p^:= BGRA(161,157,121); | ||
inc(p); | inc(p); | ||
− | end; </ | + | end; </syntaxhighlight> |
[[Image:BGRATutorial8d.png]] | [[Image:BGRATutorial8d.png]] | ||
Line 150: | Line 150: | ||
Hier wenden wir eine Sinusfunktion für die Noise-Werte an. Erzeugen wir uns dazu eine Prozedur: | Hier wenden wir eine Sinusfunktion für die Noise-Werte an. Erzeugen wir uns dazu eine Prozedur: | ||
− | < | + | <syntaxhighlight lang="pascal"> |
function CreateCustomTexture(tx,ty: integer): TBGRABitmap; | function CreateCustomTexture(tx,ty: integer): TBGRABitmap; | ||
var | var | ||
Line 166: | Line 166: | ||
end; | end; | ||
end; | end; | ||
− | </ | + | </syntaxhighlight> |
ColorOscillation ist ein Wert zwischen 0 und 256. Er wird aus der Intensität von (p^.red) berechnet. Hier wenden wir die Sinusfunktion mit einer halben Periode von 32 an. Dies liefert uns eine Zahl zwischen -1 und 1. Um sie auf den Bereich 0..1 abzubilden, addieren wir 1 und dividieren durch 2. Zuletzt multiplizieren wir mit 256 und haben eine Ganzzahl für Interp256. | ColorOscillation ist ein Wert zwischen 0 und 256. Er wird aus der Intensität von (p^.red) berechnet. Hier wenden wir die Sinusfunktion mit einer halben Periode von 32 an. Dies liefert uns eine Zahl zwischen -1 und 1. Um sie auf den Bereich 0..1 abzubilden, addieren wir 1 und dividieren durch 2. Zuletzt multiplizieren wir mit 256 und haben eine Ganzzahl für Interp256. | ||
Die OnPaint-Prozedur wird einfacher: | Die OnPaint-Prozedur wird einfacher: | ||
− | < | + | <syntaxhighlight lang="pascal"> |
var | var | ||
image,tex: TBGRABitmap; | image,tex: TBGRABitmap; | ||
Line 185: | Line 185: | ||
image.free; | image.free; | ||
end; | end; | ||
− | </ | + | </syntaxhighlight> |
Sie erhalten etwas in der Art: | Sie erhalten etwas in der Art: | ||
Line 192: | Line 192: | ||
Jetzt wollen wir, dass es wie Marmor ausschaut, wir brauchen weniger Schwingungen. Zum Beispiel können wir eine halbe Periode von 80 nehmen. Bei Marmor sind die dunklen Stellen sehr dünn. Wir verzerren die Schwingung durch Anwendung der Potenzfunktion: ein Exponent zwischen 0 und 1 bringt die Werte näher an 1 und ein Exponent größer als 1 bringt die Werte näher an 0. So ändern wir die Schwingung in 'CreateCustomTexture': | Jetzt wollen wir, dass es wie Marmor ausschaut, wir brauchen weniger Schwingungen. Zum Beispiel können wir eine halbe Periode von 80 nehmen. Bei Marmor sind die dunklen Stellen sehr dünn. Wir verzerren die Schwingung durch Anwendung der Potenzfunktion: ein Exponent zwischen 0 und 1 bringt die Werte näher an 1 und ein Exponent größer als 1 bringt die Werte näher an 0. So ändern wir die Schwingung in 'CreateCustomTexture': | ||
− | < | + | <syntaxhighlight lang="pascal"> colorOscillation := round(power((sin(p^.red*Pi/80)+1)/2,0.2)*256); </syntaxhighlight> |
Jetzt haben wir etwas marmorartiges: | Jetzt haben wir etwas marmorartiges: | ||
Line 201: | Line 201: | ||
Auch eine Holztextur erzielen wir mit Sinusfunktionen. Holztexturen enthalten zwei Schwingungen. Eine mit hellen Farben und eine weitere mit dunklen Farben. Deshalb wenden wir eine globale Variation auf diese Schwingungen an: | Auch eine Holztextur erzielen wir mit Sinusfunktionen. Holztexturen enthalten zwei Schwingungen. Eine mit hellen Farben und eine weitere mit dunklen Farben. Deshalb wenden wir eine globale Variation auf diese Schwingungen an: | ||
− | < | + | <syntaxhighlight lang="pascal"> function CreateWoodTexture(tx,ty: integer): TBGRABitmap; |
var | var | ||
colorOscillation, globalColorVariation: integer; | colorOscillation, globalColorVariation: integer; | ||
Line 217: | Line 217: | ||
inc(p); | inc(p); | ||
end; | end; | ||
− | end;</ | + | end;</syntaxhighlight> |
Hier ist die Halbperiode 16, und die globale Variation ist einfach die Intensität. Das Ergebnis sieht etwa so aus: | Hier ist die Halbperiode 16, und die globale Variation ist einfach die Intensität. Das Ergebnis sieht etwa so aus: | ||
Line 224: | Line 224: | ||
Meistens ist eine Holztextur entlang einer Achse ausgerichtet. Dazu müssen wir, anstatt die Intensität als globale Position zu verwenden, sie mit der x-Position kombinieren: | Meistens ist eine Holztextur entlang einer Achse ausgerichtet. Dazu müssen wir, anstatt die Intensität als globale Position zu verwenden, sie mit der x-Position kombinieren: | ||
− | < | + | <syntaxhighlight lang="pascal"> function CreateVerticalWoodTexture(tx,ty: integer): TBGRABitmap; |
var | var | ||
globalPos: single; | globalPos: single; | ||
Line 246: | Line 246: | ||
if x = tx then x := 0; | if x = tx then x := 0; | ||
end; | end; | ||
− | end; </ | + | end; </syntaxhighlight> |
Wir erhalten dies: | Wir erhalten dies: | ||
Line 253: | Line 253: | ||
− | [[BGRABitmap tutorial 7/de|Voriges Tutorial (Splines)]] [[BGRABitmap tutorial 9/de|Nächstes Tutorial (Phong-Schattierung und Texturen) | + | [[BGRABitmap tutorial 7/de|Voriges Tutorial (Splines)]] | [[BGRABitmap tutorial 9/de|Nächstes Tutorial (Phong-Schattierung und Texturen)]] |
− | |||
− |
Latest revision as of 07:13, 10 February 2020
│ Deutsch (de) │ English (en) │ español (es) │ français (fr) │
Home | Tutorial 1 | Tutorial 2 | Tutorial 3 | Tutorial 4 | Tutorial 5 | Tutorial 6 | Tutorial 7 | Tutorial 8 | Tutorial 9 | Tutorial 10 | Tutorial 11 | Tutorial 12 | Tutorial 13 | Tutorial 14 | Tutorial 15 | Tutorial 16 | Edit
Dieses Tutorial zeigt, wie Sie Texturen verwenden können.
Erzeugen Sie ein neues Projekt
Erzeugen Sie ein neues Projekt und fügen Sie eine Referenz auf BGRABitmap hinzu, genau so wie im ersten Tutorial.
Verwenden des Pinsels als Textur
Die einfachste Textur ist ein schraffierter Pinsel.
Im Objektinspektor fügen Sie einen OnPaint-Handler hinzu und schreiben Sie:
procedure TForm1.FormPaint(Sender: TObject);
var
image,tex: TBGRABitmap;
c: TBGRAPixel;
x,y,rx,ry: single;
begin
image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
c := ColorToBGRA(ColorToRGB(clWindowText));
//Ellipsenkoordinaten
x := 150;
y := 100;
rx := 100;
ry := 50;
//lädt einen diagonal gekreuzten Pinsel ("diagcross") mit weißem Muster und orangem Hintergrund
tex := image.CreateBrushTexture(bsDiagCross,BGRAWhite,BGRA(255,192,0)) as TBGRABitmap;
image.FillEllipseAntialias(x,y,rx-0.5,ry-0.5,tex);
image.EllipseAntialias(x,y,rx,ry,c,1); //draw outline
tex.Free;
image.Draw(Canvas,0,0,True);
image.free;
end;
Wie Sie sehen ist eine Textur einfach eine Bitmap. Um eine Ellipse mit einer Textur zu füllen, übergeben Sie die Textur einfach als Parameter anstelle der Farbe.
Zwei Befehle bestimmen die Ellipse. Der erste ist die Füllung, der zweite die Rahmenlinie. Beachten Sie, dass der Radius für die Füllung um 0,5 Pixel kleiner ist. Genau genommen ist bei einer Stiftbreite von 1 der innere Radius um 0,5 kleiner und der äußere Radius um 0,5 größer. Aber sogar wenn Sie sorgfältig darauf achten, wird das Ergebnis nicht perfekt sein. Falls Sie eine Verbindung der Polygone mit Antialiasing wollen, sollten Sie 'TBGRAMultishapeFiller' aus der Unit 'BGRAPolygon' verwenden und alles zugleich zeichnen lassen.
Mit einem Befehl für die Rahmenlinie erzielen wir eine texturierte Ellipse mit einem Rahmen. Falls die Rahmenlinienfunktion nicht verfügbar ist, können Sie auch einen Füllbefehl benutzen, zuerst mit einem größeren Radius für die Rahmenfarbe, dann mit einem kleineren Radius für das Innere.
Fügen Sie die folgenden Zeilen ein vor 'tex.Free' :
image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,c,11);
image.RoundRectAntialias(x-rx-10,y-ry-10,x+rx+10,y+ry+10,20,20,tex,9);
Der erste Befehl zeichnet ein breites, abgerundetes Rechteck (mit Breite 11), das den Rahmen enthält. Der zweite Befehl füllt mit einer Textur und einer geringeren Breite (9). Das klappt perfekt, solange die Textur nicht transparent ist.
Starten Sie das Programm
Sie erhalten ein abgerundetes Rechteck mit einer eingeschlossenen Ellipse. Jede Figur ist mit einer orangen Textur gefüllt.
Generieren von Texturen
Basic Perlin noise map
Es ist möglich, anreihbare zufällige Texturen zu erzeugen mit der Funktion 'CreateCyclicPerlinNoiseMap', die Sie in der Unit 'BGRAGradients' finden.
Im Objektinspektor definieren Sie einen OnPaint-Handler mit:
procedure TForm1.FormPaint(Sender: TObject);
var
image,tex: TBGRABitmap;
begin
image := TBGRABitmap.Create(ClientWidth,ClientHeight);
tex := CreateCyclicPerlinNoiseMap(100,100);
image.FillRect(0,0,image.Width,image.Height, tex, dmset);
tex.free;
image.Draw(Canvas,0,0,True);
image.free;
end;
Dies erzeugt eine 100x100 Textur und füllt damit das Formular. Sie erhalten etwas ähnliches wie:
Ändern der Farben
Dies ist zu sehr schwarz-weiß. Geben wir etwas Farbe hinein. Dazu brauchen wir eine Funktion, die die Werte interpoliert. Hier ist sie:
function Interp256(value1,value2,position: integer): integer; inline;
begin
result := (value1*(256-position) + value2*position) shr 8;
end;
Diese Funktion berechnet einen Wert, der von Wert1 bis zu Wert2 läuft. Position ist eine Zahl zwischen 0 und 256 die anzeigt, wie nahe das Ergebnis bei Wert2 liegt. Der Ausdruck "shr 8" ist das optimierte Äquivalent zu "div 256" für positive Werte. Es ist eine binäre Verschiebung um 8 Stellen.
Wir wollen Farben interpolieren, also schreiben wir eine Funktion, die Farben interpoliert:
function Interp256(color1,color2: TBGRAPixel; position: integer): TBGRAPixel; inline;
begin
result.red := Interp256(color1.red,color2.red, position);
result.green := Interp256(color1.green,color2.green, position);
result.blue := Interp256(color1.blue,color2.blue, position);
result.alpha := Interp256(color1.alpha,color2.alpha, position);
end;
Das ist geradlinig: jeder Farbanteil wird zwischen color1 und color2 interpoliert.
Jetzt haben wir alles, um es uns etwas bunter zu machen. Nach 'CreatePerlinNoiseMap' fügen Sie folgende Zeilen ein:
p := tex.Data;
for i := 0 to tex.NbPixels-1 do
begin
p^ := Interp256( BGRA(0,128,0), BGRA(192,255,0), p^.red );
inc(p);
end;
Sie brauchen die Variablen 'p' und 'i', also klicken Sie auf eine jede und drücken Sie Strg-Umsch-C.
Diese Schleife nimmt jedes Pixel und erzeugt eine Farbe von Dunkelgrün bis zu hellem Gelbgrün.
Wir erhalten einen baumartigen Grünton:
Verwendung von Schwellenwerten
Anstatt ständig zu variieren, kann die Farbänderung einen Schwellenwert berücksichtigen. Im Beispiel ergibt das ein Meer mit Inseln:
p := tex.Data;
for i := 0 to tex.NbPixels-1 do
begin
if p^.red > 196 then
p^ := BGRA(192,160,96) else //island
p^ := BGRA(0,128,196); //sea
inc(p);
end;
Wir nehmen mehrere Schwellenwerte. Fertig ist der Tarnanzug:
p := result.Data;
for i := 0 to result.NbPixels-1 do
begin
v := p^.red;
if v < 64 then p^:= BGRA(31,33,46) else
if v < 128 then p^:= BGRA(89,71,57) else
if v < 192 then p^:= BGRA(80,106,67) else
p^:= BGRA(161,157,121);
inc(p);
end;
Sinusfunktion
Hier wenden wir eine Sinusfunktion für die Noise-Werte an. Erzeugen wir uns dazu eine Prozedur:
function CreateCustomTexture(tx,ty: integer): TBGRABitmap;
var
colorOscillation: integer;
p: PBGRAPixel;
i: Integer;
begin
result := CreateCyclicPerlinNoiseMap(tx,ty,1,1,1);
p := result.Data;
for i := 0 to result.NbPixels-1 do
begin
colorOscillation := round(((sin(p^.red*Pi/32)+1)/2)*256);
p^ := Interp256(BGRA(181,157,105),BGRA(228,227,180),colorOscillation);
inc(p);
end;
end;
ColorOscillation ist ein Wert zwischen 0 und 256. Er wird aus der Intensität von (p^.red) berechnet. Hier wenden wir die Sinusfunktion mit einer halben Periode von 32 an. Dies liefert uns eine Zahl zwischen -1 und 1. Um sie auf den Bereich 0..1 abzubilden, addieren wir 1 und dividieren durch 2. Zuletzt multiplizieren wir mit 256 und haben eine Ganzzahl für Interp256.
Die OnPaint-Prozedur wird einfacher:
var
image,tex: TBGRABitmap;
begin
image := TBGRABitmap.Create(ClientWidth,ClientHeight,ColorToBGRA(ColorToRGB(clBtnFace)));
tex := CreateCustomTexture(100,100);
image.FillRoundRectAntialias(20,20,300,200,20,20,tex);
image.RoundRectAntialias(20,20,300,200,20,20,BGRABlack,1);
tex.free;
image.Draw(Canvas,0,0,True);
image.free;
end;
Sie erhalten etwas in der Art:
Jetzt wollen wir, dass es wie Marmor ausschaut, wir brauchen weniger Schwingungen. Zum Beispiel können wir eine halbe Periode von 80 nehmen. Bei Marmor sind die dunklen Stellen sehr dünn. Wir verzerren die Schwingung durch Anwendung der Potenzfunktion: ein Exponent zwischen 0 und 1 bringt die Werte näher an 1 und ein Exponent größer als 1 bringt die Werte näher an 0. So ändern wir die Schwingung in 'CreateCustomTexture':
colorOscillation := round(power((sin(p^.red*Pi/80)+1)/2,0.2)*256);
Jetzt haben wir etwas marmorartiges:
Holztextur
Auch eine Holztextur erzielen wir mit Sinusfunktionen. Holztexturen enthalten zwei Schwingungen. Eine mit hellen Farben und eine weitere mit dunklen Farben. Deshalb wenden wir eine globale Variation auf diese Schwingungen an:
function CreateWoodTexture(tx,ty: integer): TBGRABitmap;
var
colorOscillation, globalColorVariation: integer;
p: PBGRAPixel;
i: Integer;
begin
result := CreateCyclicPerlinNoiseMap(tx,ty);
p := result.Data;
for i := 0 to result.NbPixels-1 do
begin
colorOscillation := round(sqrt((sin(p^.red*Pi/16)+1)/2)*256);
globalColorVariation := p^.red;
p^:= Interp256( Interp256(BGRA(247,188,120),BGRA(255,218,170),colorOscillation),
Interp256(BGRA(157,97,60),BGRA(202,145,112),colorOscillation), globalColorVariation);
inc(p);
end;
end;
Hier ist die Halbperiode 16, und die globale Variation ist einfach die Intensität. Das Ergebnis sieht etwa so aus:
Meistens ist eine Holztextur entlang einer Achse ausgerichtet. Dazu müssen wir, anstatt die Intensität als globale Position zu verwenden, sie mit der x-Position kombinieren:
function CreateVerticalWoodTexture(tx,ty: integer): TBGRABitmap;
var
globalPos: single;
colorOscillation, globalColorVariation: integer;
p: PBGRAPixel;
i: Integer;
x: integer;
begin
result := CreateCyclicPerlinNoiseMap(tx,ty);
p := result.Data;
x := 0;
for i := 0 to result.NbPixels-1 do
begin
globalPos := p^.red*Pi/32+x*2*Pi/tx*8;
colorOscillation := round(sqrt((sin(globalPos)+1)/2)*256);
globalColorVariation := round(sin(globalPos/8)*128+128);
p^:= Interp256( Interp256(BGRA(247,188,120),BGRA(255,218,170),colorOscillation),
Interp256(BGRA(157,97,60),BGRA(202,145,112),colorOscillation), globalColorVariation);
inc(p);
inc(x);
if x = tx then x := 0;
end;
end;
Wir erhalten dies:
Voriges Tutorial (Splines) | Nächstes Tutorial (Phong-Schattierung und Texturen)