artykuły

Delphi - Elektroniczny kalejdoskop

5:50
Fri, 19 October 2007
Artykuł opisuje ciekawe możliwości generowania obrazów poprzez obliczanie koloru pikseli składających się na obraz według wzorów wymyślonych przez użytkownika. Naprawdę warto przeczytać.

Wstęp

Cześć Wam! Fajny tytuł? Postaram się aby artykuł też się spodobał. Rzucę więc na początek kilka fotek.

Tabela 1.1 - Przykładowe obrazy w odcieniach szarości
Obraz Opis
Kwadraty45

Kwadraty45

Obraz, powstały w wyniku równania:ABS((Power(y,2)-Power(x,2)))gdzie:
  • "y" oznacza aktualnie rysowaną współrzędną punktu w pionie.
  • "x" oznacza aktualnie rysowaną współrzędną punktu w poziomie.
Kolce

Kolce

Obraz, powstały w wyniku równania:ABS(y-Power(x,2))gdzie:
  • "y" oznacza aktualnie rysowaną współrzędną punktu w pionie.
  • "x" oznacza aktualnie rysowaną współrzędną punktu w poziomie.
Okręgi

Okręgi

Obraz, powstały w wyniku równania:ABS( (x-Power(x,2))+(y-Power(y,2)) )gdzie:
  • "y" oznacza aktualnie rysowaną współrzędną punktu w pionie.
  • "x" oznacza aktualnie rysowaną współrzędną punktu w poziomie.

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:

Tabela 1.2 - Przykładowe obrazy w kolorze
Obraz Opis
Płótno

Płótno

Obraz, powstały w wyniku równania:ABS( (x-Power(x,4))+(y-Power(y,4)) )gdzie:
  • "y" oznacza aktualnie rysowaną współrzędną punktu w pionie.
  • "x" oznacza aktualnie rysowaną współrzędną punktu w poziomie.
Kolory uzyskane dzięki modyfikacji składowych widma:R := obl; G := SQR(20*obl); B := SQR(obl);

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

  1. Uruchom Delphiego.
  2. Połóż na formie przycisk (komponent "Button" z palety "Standard")
  3. 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;
  4. 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:

  1. Błąd dzielenia przez 0 (popularny "division by (0)").
  2. 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ć.
  3. Nieprawidłowa operacja zmiennoprzecinkowa (Invaild floating point operation) również pojawiająca się w przypadku dzielenia przez 0, bądź innych niedozwolonych operacji.
  4. 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.

12345
Delphi - Elektroniczny kalejdoskop Autor opinii: Czytelnicy, data przesłania: 0

Podobne artykuly:

Skomentuj

Aby zamieścić komentarz, proszę włączyć JavaScript - niestety roboty spamujące dają mi niezmiernie popalić.






Komentarze czytelników

    Nie ma jeszcze żadnych komentarzy.
    Dexter