Tekstury do wszystkiegoW potocznym rozumieniu tekstura to taki obrazek, który nakłada się obiekt trójwymiarowy, aby w ten sposób imitować wygląd jego powierzchni. Rzeczywiście, dawno temu była to ich jedyna funkcja. Tego rodzaju tekstury (nazywane teksturami rozproszenia) są oczywiście nadal niezbędne. Obok nich powstało jednak całe mnóstwo innych rodzajów tekstur, które są wykorzystywane podczas renderowania scen 3D.
Wśród nich są na przykład takie, które zawierają pewne niezbędne informacje na temat obiektów na scenie – nie tylko zresztą geometrii. Są to chociażby:
Mapy wysokości (height maps). To czarno-białe tekstury, używane do modelowania terenu. Jasność konkretnego piksela odpowiada wysokości terenu w danym punkcie. Taka tekstura musi być naturalnie przetworzona na odpowiednie trójkąty (co specjalnie trudne nie jest), ale jej używanie zamiast innych reprezentacji ma dwie wyraźne zalety. Po pierwsze, umożliwia regulowanie stopnia szczegółowości (Level of Detail, LoD) wyświetlanego terenu. Po drugie, mapy wysokości są bardzo łatwe do wykonania za pomocą dowolnego programu graficznego nawet przez średnio uzdolnionego w tym kierunku kodera :)
Mapy normalnych (normal maps) obrazują z kolei wektory normalne punktów powierzchni. Pomysł jest bardzo prosty: kolor każdego piksela w formacie RGB odpowiada normalnej o współrzędnych XYZ. Ponieważ współrzędne te są ograniczone (długość normalnej to zawsze 1), mogą być zapisane jako kolor. Mapa normalnych jest potem wykorzystywana przy obliczeniu oświetlenia per-pixel.
Tego rodzaju tekstury są przygotowywane wcześniej i obok modeli, tekstur rozproszenia i innych danych stanowią informacje umożliwiają renderowanie sceny. Oprócz nich w trakcie samego rysowania wykorzystywane są też inne tekstury, tworzone na bieżąco i zwykle niezachowywane na później. Wśród tych efemerycznych tekstur mamy na przykład:
Mapy odbić środowiskowych (environmental maps) służą do symulowania przedmiotów o powierzchniach lustrzanych. Podobnie jak wyżej, wymagają osobnego przebiegu renderowania, i to często nawet niejednego (jak w przypadku map sześciennych). Tak powstałe obrazy odbić są potem nakładane na przedmiot, który dzięki temu sprawia wrażenie, jakby odbijał w sobie resztę sceny.
Potencjalnych i aktualnych zastosowań tekstur jest o wiele więcej. Ale już na tych przykładach widać, że tekstury tak naprawdę nie są obrazkami, a jedynie zbiorami jakichś informacji, które tylko z konieczności są zapisywane w postaci kolorów pikseli. Być może niedługo staną się one pełnoprawną “pamięcią operacyjną” kart graficznych, którą można będzie np. alokować i zwalniać w kodzie shaderów. Jak dotąd możliwy jest ich odczyt oraz w pewnym stopniu zapis (zależnie od modelu shaderów), ale kto wie – może wkrótce doczekamy się czegoś więcej?…
Podsumowanie magicznej siódemkiPozwolę sobie poczynić zupełnie niekoderski wpis, jako że od ostatniego podobnego minęło już dobrych kilka miesięcy. Myślę, że mogę od czasu do czasu pozwolić sobie na coś takiego :) Zwłaszcza, że mam ku temu pewną dość szczególną okazję…
Dotarłem właśnie do końca niezbyt może ambitnego, za to niezwykle popularnego kawałka literatury. Mówię tu oczywiście o serii książek pod tytułem Harry Potter i jeszcze coś, której to (prawdopodobnie) ostatni tom niedawno trafił na półki polskich księgarń. Jak nietrudno się domyślić, mam nieodpartą ochotę, aby podzielić się wrażeniami z lektury ;P
I muszę przyznać, że jestem nią w pełni usatysfakcjonowany. Opowieści o przygodach Pottera już od jakiegoś czasu nie były bajkami dla dzieci, lecz chyba dopiero w tym ostatnim tomie ujawniło się, iż mamy tutaj do czynienia z całkiem dojrzałą pozycją z gatunku fantasy. Pod względem fabularnym też nie można jej wiele zarzucić, chociaż wiadomo, że dla wszystkich najważniejsze były suche fakty: jak to się skończy, kto zwycięży, kto przeżyje?… Tym niemniej cieszy to, że ostatecznie kilka spraw wyjaśnia się na sposób daleki od przewidywań: ci, którzy wydawali się być charakterami bezwarunkowo czarnymi, nie zawsze takimi się okazują, a na kryształowych obliczach postaci wyjątkowo “czystych” pojawiają się wyraźne rysy.
Koniec sagi o młodym czarodzieju to pewnie najlepsza okazja, aby zastanowić się, dlaczego historie te stały się aż tak popularne. Bo chyba stwierdzenie, że obecnie przy sprawnym marketingu można wypromować cokolwiek, nie będzie w pełni zadowalające (miejmy przynajmniej taką nadzieję). Ten produkt musi mieć po prostu takie obiektywne coś, co zadecydowało o jego sukcesie. Według mnie lista tych “cosiów” zawiera przynajmniej trzy pozycje:
Czy to prosty przepis na sukces? Bynajmniej. Połączenie tych wszystkich elementów w spójną i atrakcyjną całość to z pewnością wielka sztuka.
Najciekawsze jest jednak to, że powyższą receptę można wcale nieźle dopasować do… wytworów działalności koderskiej. W końcu tu też liczy się dobry projekt, korzystanie ze sprawdzonych rozwiązań oraz dobra treść i forma. Efekty może nie są aż tak “magiczne”, ale niekiedy udaje się nimi zachwycić nawet mało obeznanych z tematem mugoli ;-)
Przesłanianie kontra nadpisywanieJednym ze swego rodzaju kruczków programowania obiektowego jest różnica między przesłanianiem (hide) a nadpisywaniem (override) metod w klasach pochodnych. Niby nic w tym trudnego, dopóki nie uświadomimy sobie, że metody wirtualne - w przeciwieństwie do zwykłych - mogą podlegać obu tym procesom i że w ich przypadku różnią się one w dość istotny sposób.
Jeśli mianowicie mamy jakąś metodę wirtualną w klasie bazowej, to w klasie pochodnej teoretycznie możemy ją zarówno nadpisać, jak i przesłonić. Gdy zdecydujemy się na to pierwsze wyjście, wówczas nasz obiekt staje się polimorficzny. Posługując się wskaźnikiem lub referencją do obiektu klasy bazowej tak naprawdę możemy operować na obiekcie klasy pochodnej, a wywołując metodę wirtualną nie wiemy, która jej wersja będzie użyta. Wiemy jedynie, że będzie to ta "właściwa" (z klasy, do której należy nasz obiekt). No cóż, to podstawa OOP-u, jakkolwiekby na to nie patrzeć :)
// klasa pochodna
class CDerived : public CFoo
{
public:
// nadpisana metoda
void Foo() { /* ... */ }
};
Nie zawsze jednak musi tak być. Jeżeli metodę wirtualną się przesłoni, wtedy nic takiego nie zadziała i zostanie wywołana wersja z klasy bazowej. Typ obiektu nie zostanie bowiem rozpoznany w trakcie działania programu, a całe wywołanie będzie zapisane "na sztywno" w wynikowym kodzie. W gruncie rzeczy będzie tak samo, jakbyśmy przesłoni dowolną inną (niewirtualną) metodę.
O ile oczywiście możemy, bowiem w C++ metody wirtualnej przesłonić się po prostu nie da. Nadpisywanie jest po prostu wykonywane automatycznie i nie można z niego zrezygnować. W innych językach (jak w Delphi i C#) wymaga ono słowa kluczowego override. Tam też metody wirtualne można przesłaniać, stosując modyfikatory - odpowiednio reintroduce i new.
Żeby było zabawniej, przesłanianie i nadpisywanie może występować dla tej samej metody w tej samej hierarchii dziedziczenia. Metoda wirtualna zdefiniowana w klasie A może być na przykład nadpisywana w kolejnych klasach pochodnych A1, A2, A3, itd. I nagle w klasie B zostanie ona przesłonięta. Ba, ta przesłonięta wersja sama może być wirtualna i nadpisywana w dalszych klasach pochodnych: B1, B2, B3, ...
Nie spotyka się tego często, jako że podobne wielopiętrowe drzewa dziedziczenia są rzadkie (i takie być powinny). Warto jednak o tym wiedzieć, bo nigdy nie wiadomo, kiedy podobny kruczek przybierze w naszym kodzie postać wielkiego kruka i zacznie nas dziobać zagadkowymi błędami ;]
Nie całkiem brakujące ogniwo DirectXWszyscy wiedzą, że przesiadka na Vistę ma jedną niezaprzeczalną zaletę. Jeśli mianowicie dysponujemy odpowiednią kartą graficzną, to możemy cieszyć się całym bogactwem Shader Model 4 oraz dziesiątej wersji DirectX. Nadal jednak niewiele gier posiada jakieś efekty (oczywiście w(y)łączalne) uzyskiwane przy pomocy nowej wersji biblioteki. Najwyraźniej Microsoft nieumyślnie wpadł tutaj w rodzaj błędnego koła, które zapobiega powszechnemu wykorzystaniu DirectX 10.
Nie pomaga tu też za bardzo specjalna wersja "dziewiątki", czyli tak zwany Direct3D 9Ex. Cóż to za zwierz?...
Jest to mianowicie pewne rozszerzenie znanej i lubianej wersji biblioteki, które wprowadza nowe możliwości, częściowo zbieżne z tym, czego można doświadczyć w D3D10. Wśród nich mamy chociażby:
pSharedHandle. Był on opisany jako zarezerwowany i należało w jego miejsce przekazywać NULL. Rezerwacja ta jednak nie przepadła i w 9Ex jest on wykorzystywany do współdzielenia zasobów między urządzeniami - nawet takimi, które są w oddzielnych procesach. Mogę sobie wyobrazić zastosowanie tego mechanizmu chociażby do przełączania trybów graficznych bez konieczności ponownego tworzenia wszystkich tekstur, buforów, itp.IDirect3DDevice9Ex. Jest wśród nich na przykład WaitForVBlank, służąca do ręcznej synchronizacji pionowej.Wszystkie te możliwości prezentują się całkiem nieźle. Żeby jednak z nich korzystać, muszą być spełnione dwa warunki. Po pierwsze, sprzęt musi wspierać tak zwany WDDM (Windows Device Driver Model), co w przypadku popularnych kart graficznych dotyczy z grubsza tych, które udostępniają Shader Model 3.
A drugi warunek?... Niejako wynika on z pierwszego, bowiem WDDM jest częścią systemu Windows Vista. Aplikacje wykorzystujące Direct3D 9Ex będą więc działały wyłącznie na tym systemie. To pewnie trochę zniechęcające, prawda? Ale cóż, Microsoft próbuje jak może ;-)
Dziwne dokumenty RFCPod odrobinę nieadekwatną nazwą RFC (Request For Comments, czyli prośba o komentarze) kryje się zbiór standardów czy raczej zaleceń dotyczących prawie każdego aspektu funkcjonowania Internetu. Opisy większości ważnych protokołów sieciowych - takich jak HTTP, FTP, POP3, SMTP, itd. - są zawarte właśnie w dokumentach RFC. Każdy taki dokument ma swój unikalny numer, który po publikacji nie ulega zmianie - podobnie zresztą jak sam dokument.
Brzmi to całkiem poważnie, prawda? W istocie, część dokumentów RFC ma kluczowe znaczenie dla działania globalnej sieci (jak choćby RFC2616, opisujący protokół HTTP). Wśród tysięcy już opublikowanych zdarzają się jednak i takie, które ze zwyczajowym technicznym przynudzaniem nie mają zbyt wiele wspólnego. Oto kilka takich przykładów:
matter-transport/sentient-life-form. Jako że jest on przeznaczony do kodowania i przesyłania na odległości materii (nazwa wskazuje, że dotyczy to zwłaszcza organizmów żywych), będzie z pewnością bardzo użyteczny dla celów teleportacji :)Patrząc na tę listę, można stwierdzić, że wiele bardzo ciekawych pomysłów z niewiadomych przyczyn nie doczekało się realizacji. Nie wiem na przykład, dlaczego porzucono wykorzystywanie sprawdzonego sposobu komunikacji z wykorzystaniem ptaków na rzecz jakichś wydumanych i zupełnie nieprzemawiających do wyobraźni światłowodów ;-D
Pętla ‘for each’W bardzo wielu językach dostępna jest dodatkowa postać pętli for, znana powszechnie jako foreach. Jak jej nazwa wskazuje, służy ona do przeglądania elementów jakiejś kolekcji. Różnica pomiędzy tą konstrukcją a dowolną inną pętlą jest taka, iż przeglądanie to jest zrealizowane w sposób najprostszy z możliwych:
W szczególności nie potrzeba się posługiwać żadnymi indeksami ani też jawnie stosowanymi iteratorami. Dostęp do poszczególnych elementów zbioru odbywa się za pośrednictwem symbolicznej zmiennej, która przyjmuje wartości równe tymże elementom. Proste i skuteczne.
Zresztą, niektórym twórcom języków tak się ta koncepcja spodobała, że... całkowicie zrezygnowali z tradycyjnej postaci pętli for (w wersji od-do, jak w Pascalu, lub start-warunek-inkrement, jak w językach C-podobnych).Tak jest chociażby w Pythonie; można tam jednak uzyskać identyczny efekt pętli "liczbowej" w taki oto zabawny sposób:
Ogółem jednak pętla foreach wydaje się bardzo zgrabnym wynalazkiem. Świadczy o tym chociażby istnienie takich makr jak BOOST_FOREACH, które to ładnie adaptuje cały pomysł do kontenerów STL w C++, tablic i nie tylko.
Jest jednak pewne 'ale'. foreach sprawdza się świetnie, jeśli tylko kolekcję przeglądamy, bez dokonywania w niej zmian. Jeśli musimy przy okazji coś do niej dodać lub usunąć, lub nawet tylko zmienić wartość jakiegoś elementu, to nagle pętla taka przestaje nam wystarczać. Z doświadczenia wiem, że po tym, jak radośnie i bez wysiłku wpisuję pętlę foreach, w 80% muszę w którymś momencie i tak zmienić ją na zwykły for :-)
Sąd nad sondamiParę tygodni temu na Warsztat powróciły sondy, dzięki czemu dołączył do zdecydowanej większości dużych (a także nieco mniejszych) serwisów, których takie ankiety są integralną częścią. A skoro to taki powszechny obrazek w Internecie, to pewnie ma on swoje uzasadnienie i sondy generalnie być powinny... No właśnie, czy aby na pewno?

Bardzo dawno temu (czyli mniej więcej na przełomie stuleci) sondy były - obok np. księgi gości - jednym ze standardowych "aktywnych" elementów stron. W czasach, gdy przeglądający sieć mogli właściwie tylko czytać i oglądać strony WWW, należały one do jednych z niewielu przejawów interaktywności innej niż same tylko linki. Wówczas pytanie o ich sens byłoby zupełnie nie na miejscu: w końcu liczy się tu fajność, a fajne jest to, w co można kliknąć ;)
Ale teraz, jak wiemy, serwisy internetowe wyglądają zupełnie inaczej i nikogo raczej nie ekscytuje kilka okrągłych przycisków i odpowiedzi, z których można wybrać jedną. Mimo tego sondy wcale nie umarły śmiercią naturalną i nadal trzymają się mocno. Dlaczego?
To chyba dosyć proste. Wystarczy sobie uświadomić, że takie ankiety mają pewne istotne cechy:
Mamy zatem bezmyślność, interaktywność, współtworzenie i nieistotność. Toż to niemal słowa-klucze całej filozofii stojącej za Web 2.0 :) Nic dziwnego, że sondy, jako elementy w gruncie rzeczy wyprzedzające swoją epokę, dotrwały do dziś i nadal trzymają się świetnie.
A czy to dobrze, czy źle? Na takie pytanie odpowiedzieć może chyba tylko... odpowiednia sonda ;-)