Delphi - Elektroniczny kalejdoskop
Fri, 19 October 2007
Wstęp
Cześć Wam! Fajny tytuł? Postaram się aby artykuł też się spodobał. Rzucę więc na początek kilka fotek.
Co wy na to? Nie ciekawi Was jak powstają takie matematyczne struktury?
Najlepsze jest to, że praktycznie nie trzeba być geniuszem matematycznym by
tworzyć własne dzieła. Możliwości jest w zasadzie nieskończenie wiele.
Powyżej możecie oglądać obrazy z mojej kolekcji ;) Niestety, tylko w
odcieniach szarości. Abyście jednak nie myśleli, że tworzenie kolorowych
wzorków jest niemożliwe, pokaże Wam przykład:
I spokojnie można powiedzieć, że jest to kolejny gatunek sztuki
nowoczesnej ;)
Kolną rzeczą wartą naszej uwagi jest fakt, jak niewiele potrzeba, aby
"wyprodukować" coś zupełnie nowego. Porównajcie sobie wzory
obrazka "Płótno" i "Okręgi". Różnią się jedynie wykładnikiem
potęgi, a efekt końcowy jest zupełnie różny. Niesamowite, prawda?
Spróbujemy zatem napisać program, który rysuje nam takie cudo.
Piszemy program
- Uruchom Delphiego.
- Połóż na formie przycisk (komponent "Button" z palety "Standard")
- Kliknij nań dwukrotnie. Zostanie wygenerowana nowa procedura obsługująca
zdarzenie naciśnięcia przycisku. Wypełnij ją następująco:
Przed słówkiem begin napisz:
var bmp : TBitmap; x,y : integer; obl : integer;
Po słówku begin napisz:
bmp := TBitmap.Create; bmp.Width := 640; bmp.Height := 480; for y:=0 To bmp.Height-1 Do for x:=0 To bmp.Width-1 Do begin obl := Round(ABS( (x-Power(x,2))+(y-Power(y,2)) )); bmp.Canvas.Pixels[x,y] := RGB(obl, obl, obl); end; canvas.Draw(0,0,bmp); bmp.Free;
- Uruchom program!
No właśnie. Pewnie wielu z Was zauważyło, że i kod programu nie jest długi.
Wystarczyło zaledwie kilka linijek aby narysować coś interesującego.
Pierwsza linijka: Utworzenie zmiennej bmp.
Druga linijka: Przypisanie szerokości bitmapie (w
pikselach).
Trzecia linijka: Przypisanie wysokości bitmapie (również
w pikselach ;).
Czwarta linijka: ....jest pusta....
Piąta linijka: nagłówek pętli, która "jeździ"
nam po współrzędnych Y (pionowo, od 0 do wysokości bitmapy).
Szósta linijka: nagłówek pętli, która "jeździ"
nam po współrzędnych X (poziomo, od 0 do szerokości bitmapy).
Siódma linijka: ....begin....
Ósma linijka: obliczenie wartości ze wzoru i
przypisanie do zmiennej "obl".
Dziewiąta linijka: narysowanie punktu w aktualnej
pozycji (X,Y), o kolorze złożonym z trzech składowych (r,g,b) o wartości
obliczonej linijkę wyżej. Zauważcie, że gdy wszystkie składowe mają taką
samą wartość, wówczas otrzymujemy kolor w odcieniach szarości. Cały obraz
będzie więc szaro-bury ;P Logiczne jest więc, że chcąc otrzymać obraz
kolorowy, składowe muszą być od siebie różne (przynajmniej jedna składowa
musi być różna od pozostałych).
Dziesiąta linia: ...jest pusta....
Jedenasta linia: narysowanie obrazu na formularzu
(dokładniej: na płótnie formularza).
Dwunasta linia: zwolnienie pamięci używanej przez
bitmapę.
Co zrobić aby obraz był kolorowy?
Przed chwilą była taka mowa: jeśli chcemy mieć obraz
kolorowy, wystarczy sprawić aby przynajmniej jedna składowa była różna od
pozostałych. Można więc do jednej składowej dodać jakąś wartość, np.
100, do drugiej dodać 300, a trzecią zostawić.
Nie przejmujcie się, że składowe są typu byte i mogą przyjmować jedynie
wartości od 0 do 255. Mają one bowiem pewną własność o której wspominałem
w artykule "Delphi - Tranformacje grafiki - Przyjaśnianie i przyciemnianie".
Dla niewtajemniczonych, wyjaśnię: po przekroczeniu przez nie maksymalnie
dozwolonej bariery 255 zaczynają liczyć od początku nie powodując błędu.
Czyli, jeśli wartość takiej zmiennej ustalimy na 255, zmienna przybierze nam
wartość 255, ale jeśli wartość ustalimy na 256 (poza zakresem) wówczas
zacznie liczyć od początku i przybierze wartość 0, analogicznie dla 257 będzie
to 1, dla 258 - 2 itd...
Dlatego, aby obraz był kolorowy, musimy zmodyfikować instrukcję:
RGB(obl, obl, obl)
przykładowo na:
RGB(obl, obl+100, obl+300)
lub ciekawiej:
RGB(obl, SQR(20*obl), SQR(obl))
Jak tworzyć nowe obrazy?
To jest właśnie fajne. Chcąc stworzyć nowy obraz wystarczy zmodyfikować
wzór (w jakikolwiek sposób). Zwykle regułą jest, że im więcej zmiennych będzie
zawierał tym będzie ciekawszy. My użyliśmy dwóch zmiennych X i Y. Do wzorów
możemy dodawać np. funkcję sinus, tangens, pierwiastki ze zmiennych itp.
Należy jednak uważać by nie pojawiły się typowe błędy:
- Błąd dzielenia przez 0 (popularny "division by (0)").
- Błąd przekroczenia zakresu (przepełnienia bufora), który pojawia się, kiedy używamy np. dużych potęg generujących bardzo duże liczby, z którymi komputer często nie może sobie poradzić.
- Nieprawidłowa operacja zmiennoprzecinkowa (Invaild floating point operation) również pojawiająca się w przypadku dzielenia przez 0, bądź innych niedozwolonych operacji.
- Niezgodność typów, kiedy próbujemy przypisać wartość zmiennoprzecinkową do zmiennej typu całkowitego (to jednak wykrywa jeszcze kompilator przed uruchomieniem). W takich przypadkach należy zmienną zmiennoprzecinkową zaokrąglić (poleceniem Round()).
Nawet jeśli nie wiesz czym jest sinus, możesz go użyć we wzorze i zobaczyć jaki da fajny efekt ;)
Trochę o animacji...
Wbrew pozorom, tak powstałe obrazy możemy animować. Wystarczy wprowadzić do
wzoru jakąś zmienną i zwiększać ją np. co sekundę. Czasami udaje się
uzyskać efekt animacji, kiedy to struktura oddala się od nas, tworząc z
biegiem czasu nowe wzory, itp.
Trzeba jednak uważać, gdyż zwiększająca się czasowo zmienna po pewnym
czasie i tak doprowadzi do błędu przepełnienia bufora (wyjścia poza zakres).
Przykład takiej animacji (razem z błędem przepełnienia bufora ;) możecie zobaczyć
tutaj.
Zakończenie
No. I takie to fajne obrazki wychodzą. Tu bije źródełko.
Podobne artykuly:
- Delphi - Transformacje grafiki - Przyjaśnianie i przyciemnianie
- Delphi - Transformacje grafiki - Odbicia lustrzane
- Delphi - Transformacje grafiki - Przezroczystość
- Delphi - Transformacje grafiki - Odcienie szarości