artykul_java_3d.pdf

(851 KB) Pobierz
275121816 UNPDF
Warsztaty
Świat 3D w Javie
Podstawy programowania z wykorzystaniem API Java 3D
Java jest jednym z najczęściej wykorzystywanych języków programowania,
który w połączeniu z wirtualną maszyną Javy daje aplikacjom w niej napisanym
dużą przenośność. Java 3D, darmowe API do Javy, pozwala wykorzystać
podstawowe zalety języka i platformy do renderowania obiektów 3D w bardzo
elastyczny i logiczny sposób.
Dowiesz się:
• jak wyświetlać obiekty 3D przy pomocy Javy 3D,
• jak wykorzystywać podstawowe obiekty 3D do-
stępne w Javie 3D,
• jak tworzyć własne obiekty 3D,
• jak przypisywać obiektom kolory, tekstury, wła-
ściwości oświetlenia, etc.
Powinieneś wiedzieć:
• podstawy języka Java,
• podstawy geometrii analitycznej,
• wiedzieć czym cechuje się struktura drzewa.
• Tworzymy główną gałąź (BranchGro-
up) naszego świata 3D, po czym ją kom-
pilujemy. Kompilacja sceny to swego ro-
dzaju optymalizacja struktury obiek-
tów przez nas dodanych. Czynność ta
powinna być wykonana przed wyświe-
tleniem danej grupy, gdyż może ona
zwiększyć wydajność. Szczegóły doty-
czące kompilacji można znaleźć pod
adresem http://java3d.j3d.org/tutorials/
quick_fix/compile.html oraz w dokumen-
tacji API.
• Tworzymy nowy świat 3D przypisany do
utworzonego wcześniej obiektu canvas3d.
• Dodajemy do świata utworzoną wcześniej
gałąź z obiektami 3D.
Poziom trudności
tlony z trzech stron – od przodu punktowym
światłem zielonym, z lewej kierunkowym nie-
bieskim, a z prawej kierunkowym żółtym. Za-
nim przejdziemy do samego obiektu 3D, jakim
jest ten tekst, musimy przyjrzeć się klasom nie-
zbędnym do stworzenia świata 3D, z którego
będziemy korzystać. Fragment kodu za to od-
powiedzialny widoczny jest na Listingu 1.
Kluczową rolę w tym kodzie pełni klasa Sim-
pleUniverse. Jest ona swego rodzaju kontene-
rem, który po utworzeniu zawiera wszystkie
niezbędne do renderowania świata 3D obiek-
ty z przypisanymi podstawowymi ustawienia-
mi. Nie będę szczegółowo opisywał każdego z
nich, gdyż z punktu widzenia przedstawianych
programów nie jest to konieczne. Warto jednak
zauważyć, że każdy z obiektów składowych jest
dostępny poprzez odpowiednie metody w Sim-
pleUniverse, dzięki czemu możemy zmieniać
tylko te jego elementy, które nas interesują.
Oto opis wykonywanych czynności przygo-
towawczych:
J ava 3D to darmowe, wszechstronne i potęż-
ne API pozwalające na wyświetlanie obiek-
tów 3D w czasie rzeczywistym oraz inte-
rakcję z nimi. Wykorzystuje ona w pełni moc kar-
ty graficznej poprzez DirectX lub OpenGL, przez
co renderowane sceny są naprawdę wysokiej jako-
ści. Obsługiwane są funkcje takie jak antyaliasing,
filtrowanie anizotropowe, cieniowanie, dynamicz-
ne oświetlanie, słowem, Java 3D daje programi-
ście naprawdę szerokie możliwości – począwszy
od tworzenia prostych aplikacji, poprzez wizuali-
zacje różnego rodzaju symulacji, aż po gry 3D. Co
ważniejsze, Java 3D jest naprawdę dobrze przemy-
ślanym API, choć może nie jest to widoczne przy
pierwszym zetknięciu z nim, a programowanie z
jego wykorzystaniem jest bardzo intuicyjne.
Po wykonaniu tych czynności mamy w peł-
ni funkcjonujący świat 3D, którego zawartość
wyświetlana jest poprzez obiekt canvas3d. Na-
leży jeszcze dodać go do naszego GUI: frag-
ment zaprezentowany w Listingu 2.
Dodawanie
obiektów do świata 3D
Najwyższa pora, by po stworzeniu obiektów
pozwalających na renderowanie świata 3D,
zająć się zawartością tego świata. W tym pro-
gramie cała zawartość głównej gałęzi genero-
wana jest w jednej metodzie – linijka po li-
nijce. W przypadku bardziej skomplikowa-
nych światów sugeruję, by stworzyć własne
klasy reprezentujące obiekty 3D, dzięki cze-
mu aplikacja stanie się dużo bardziej przej-
rzysta, a operowanie na nich dużo prostsze.
Przykład takiej klasy znaleźć można w pro-
gramie 3.
Świat 3D w Javie 3D tworzony jest w for-
mie drzewa. Każdy obiekt 3D musi mieć
przypisanego dokładnie jednego rodzica,
przy czym korzeniem jest w naszym przy-
padku obiekt SimpleUniverse. Ilość potom-
ków nie jest ograniczona. Strukturę tę w Ja-
vie 3D reprezentują klasy abstrakcyjne Node
Instalacja
Należy ściągnąć odpowiedni instalator (lub
ewentualnie zestaw binarek) ze strony https://
java3d.dev.java.net/binary-builds.html , po czym
go uruchomić. Java 3D zostanie zainstalowana
i zintegruje się z JRE/SDK automatycznie.
• Tworzymy obiekt GraphicsConiguration
– metodą statyczną klasy SimpleUniverse
pobieramy konfigurację grafiki, która po-
winna być optymalna dla naszej konfigu-
racji sprzętowej.
• Tworzymy obiekt Canvas3D . Jest to kom-
ponent, który służy do renderowania świa-
ta 3D. Dodajemy go później do GUI w do-
wolnym, odpowiadającym nam miejscu.
Dodatkowo ustawiamy preferowany roz-
miar tego płótna.
Pierwszy program
– J3DTextDemo – Hello 3D World!
Program ten, jak widać na obrazku, wyświetla
trójwymiarowy napis Hello 3D World oświe-
62
01/2009
275121816.049.png 275121816.060.png 275121816.063.png 275121816.064.png 275121816.001.png 275121816.002.png 275121816.003.png 275121816.004.png 275121816.005.png 275121816.006.png
Świat 3D w Javie
– węzeł oraz dziedziczące po nim Leaf – liść
(węzeł bez potomków, właściwy obiekt 3D)
oraz Group – grupa (węzeł do którego można
przypinać inne węzły, w tym liście).
Dwie najważniejsze i najczęściej stosowane
klasy potomne klasy Group to BranchGroup
oraz TransformGroup . Opiszę je teraz dokład-
niej.
BranchGroup jest takim węzłem, o które-
go poddrzewie powinno się myśleć jak o sa-
modzielnej miniscenie. Obiektu tego używa-
my do oznaczenia konkretnego obiektu lub
grupy obiektów, które tworzą pewną całość,
np. jeśli mamy w świecie 3D lampę składają-
cą się z abażuru, żarówki, stojaka oraz źródła
światła, obiekty te powinny zostać zamknię-
te w oddzielnej BranchGroupie , która będzie
reprezentować lampę jako całość. Oprócz
wprowadzania logiki i ładu, takie konstru-
owanie sceny ma zalety praktyczne – dzięki
temu możemy jedną operacją np. odłączyć od
sceny całą grupę.
TransformGroup jest węzłem, który ma przy-
pisaną transformację. Oznacza to, że wszyscy
potomkowie tego węzła mogą zostać przesu-
nięci i obróceni w dowolny (ale wszyscy w ta-
ki sam) sposób.
Oprócz węzłów-rodziców scena składa się
także z liści. W przypadku J3DTextDemo wy-
korzystywane są następujące klasy dziedziczą-
ce po Leaf:
nie było niezmienne. Gdybyśmy dodali utwo-
rzony tekst do głównej gałęzi bezpośrednio,
okazałoby się, że jest zbyt duży, by zmieścić się
na ekranie. Ponadto, tekst ten byłby ułożony
dokładnie frontem do nas, w związku z czym
w ogóle nie widzielibyśmy, że jest on obiek-
tem 3D! Dlatego właśnie shDispText dołączo-
ny jest do textScalingGroup , która zmniejsza
jego rozmiar, ta grupa zaś dołączona jest do
textRotatingGroup , która go obraca.
Mam nadzieję, że struktura J3DTextDemo
jest już dla Was zrozumiała. Program ten miał
na celu zademonstrowanie jak proste i szyb-
kie jest tworzenie scen 3D. Teraz skupimy się
na tym, co dzieje się za kulisami, czyli jak to
wszystko tak naprawdę działa.
Jest to układ współrzędnych nieco inny, niż
ten, do którego jesteśmy przyzwyczajeni ze
szkoły czy uczelni. By się z nim zaznajomić,
proponuję modyfikować wierzchołki sześcia-
nu w programie 2 i obserwować jak wpłynie to
na kształt bryły.
Każdy obiekt 3D składa się z pewnej ilo-
ści polygonów – trójkątów umieszczonych w
przestrzeni. Każdy taki trójkąt definiowany
jest przez trzy punkty o współrzędnych kar-
tezjańskich (x, y, z). By stworzyć kształt inny
niż trójkąt, musimy stworzyć pewną ilość po-
lygonów – np. na ścianę sześcianu (kwadrat)
wystarczą dwa trójkąty, zaś na cały sześcian
– 2*6 = 12 polygonów. Grupę polygonów
składających się na obiekt będę nazywał jego
geometrią - przykład jej definiowania znajdu-
je się w programie 2.
Zakładając, że mamy gotowy zestaw poly-
gonów, który chcemy umieścić w określonym
miejscu w przestrzeni, mamy dwie możliwo-
ści: albo zmodyfikujemy geometrię obiektu i
przesuniemy wszystkie jego wierzchołki ręcz-
nie , tzn. zmodyfikujemy ich współrzędne, al-
Świat Javy 3D
Pierwszą rzeczą, którą trzeba zapamiętać, jest
układ współrzędnych obowiązujący w Javie
3D, widoczny obok ilustracji 3. Patrząc na sce-
nę z domyślnego punktu, widzimy osie x i y jak
w 2D, zaś nasze oczy skierowane są w stronę
mniejszych wartości osi z.
���������������
������������������������������������
������
Shape3D , który jest dość ogólną klasą re-
prezentującą dowolny kształt w świecie
3D. W naszym przypadku zawiera ona
napis przygotowany przy pomocy klas
Text3D i Font3D .
DirectionalLight , który definiuje źró-
dło światła padające w konkretnym kie-
runku z nieskończenie dalekiego źródła,
w związku z czym promienie światła są do
siebie równoległe.
PointLight , który definiuje źródło światła
w konkretnym miejscu w przestrzeni. Pro-
mienie światła rozchodzą się koncentrycz-
nie we wszystkich kierunkach.
• Obie powyższe klasy rozszerzają klasę
Light , która definiuje także kolor emito-
wanego światła.
�����������
����������
���������������
�����������������
����������
����������
����������������
�������������
Wiedząc to wszystko, przyjrzyjmy się struktu-
rze sceny w J3DTextDemo (Rysunek 2)
Korzeniem jest obiekt klasy Locale (któ-
ry jest częścią SimpleUniverse ) i do nie-
go przypinamy stworzoną przez nas grupę
wholeScene . Bezpośrednio do niej przypina-
my źródła światła, gdyż chcemy, by ich położe-
��������������
����������������
����������������
������������
�������
����������
Rysunek 1. Hello 3D World – napis
wyrenderowany przez Javę 3D
Rysunek 2. Drzewo sceny programu J3DTextDemo
www.sdjournal.org
63
275121816.007.png 275121816.008.png 275121816.009.png 275121816.010.png 275121816.011.png 275121816.012.png 275121816.013.png 275121816.014.png 275121816.015.png 275121816.016.png 275121816.017.png 275121816.018.png 275121816.019.png 275121816.020.png 275121816.021.png 275121816.022.png 275121816.023.png 275121816.024.png 275121816.025.png 275121816.026.png 275121816.027.png 275121816.028.png 275121816.029.png 275121816.030.png
 
Warsztaty
bo umieścimy ten obiekt wewnątrz obiektu
TransformGroup i przypiszemy mu określo-
ną transformację dokonującą tego samego. Z
punktu widzenia wydajności obie metody są
podobne, zaś z punktu widzenia prostoty roz-
wiązania, dużo lepiej umieścić dany kształt w
TransformGroupie .
Do każdego obiektu TransformGroup przy-
pisana jest pewna transformacja – obiekt
Transform3D. Z matematycznego punktu wi-
dzenia jest macierzą 4 x 4, zaś współrzędne
punktu lub wektora objętego daną transfor-
macją to iloczyn macierzy z tym wektorem.
Rozumienie mechanizmów matematycznych
jest przydatne, ale nie jest konieczne, gdyż
Java 3D daje nam możliwość tworzenia zło-
żonych transformacji poprzez składanie tych
podstawowych.
Gdy tworzymy nowy obiekt Transform3D ,
reprezentuje on przekształcenie identyczno-
ściowe, czyli niezmieniające w żaden sposób
obiektów 3D. By zmienić działanie transfor-
macji można ręcznie przypisać mu pewną ma-
cierz lub skorzystać z metod zaimplemento-
wanych w Javie 3D. Są to między innymi:
rotX ( double angle ) – przypisuje danej trans-
formacji obrót w osi x o dany kąt,
Listing 1. Inicjalizacja świata 3D
rotY ( double angle ), rotZ ( double angle )
– analogicznie do powyższego, dla róż-
nych osi,
// pobieramy podstawową konigurację graiczną z SimpleUniverse
GraphicsConiguration conig =
SimpleUniverse . getPreferredConiguration () ;
setTranslation ( Vector3f translation ) –
ustawia przesunięcie w przestrzeni o dany
wektor,
// tworzymy nowy Canvas3D z podaną koniguracją
Canvas3D canvas3d = new Canvas3D ( conig ) ;
mul ( Transform3D transform ) – łączy da-
ną transformację z podaną w argumencie,
dzięki czemu możemy otrzymać zarówno
obrót, jak i przesunięcie,
// ustawiamy preferowany rozmiar canvasa
canvas3d . setPreferredSize ( new Dimension ( 800 , 200 )) ;
mul ( Transform3D transform1 , Transform3D
transform2 ) – ustawia wartość transforma-
cji na złączenie transformacji podanych jako
parametry.
// tworzymy główną gałąź świata 3D
BranchGroup scene = createSceneGraph () ;
// po zakończeniu jej tworzenia dokonujemy kompilacji
scene . compile () ;
Przykład wykorzystania tych metod demon-
struje fragment kodu z programu 2. –Listing 3.
Zmienna newTransform , po wykonaniu po-
wyższych operacji, staje się złączeniem po-
przedniej transformacji oraz obrotów wokół
trzech osi o różne kąty. Zachęcam do poekspe-
rymentowania z tym fragmentem kodu, np. po-
przez dodanie przesunięcia.
Łącząc transformacje zawierające przesunię-
cie oraz obrót należy pamiętać, że wektor prze-
sunięcia będzie dotyczył nowej bazy, tzn. jeśli
ustawimy w transformacji przesunięcie o wek-
tor (1, 0, 0) a następnie (lub wcześniej, kolejność
nie ma znaczenia) dodamy (metodą mul) obrót
o kąt 90 stopni wokół osi y, to obiekt znajdzie się
w przestrzeni w miejscu (0, 0, 1). By zrozumieć
ten problem, sugeruję szczegółowo zapoznać się
z hierarchią transformacji w programie 3.
// tworzymy nowy świat 3D
SimpleUniverse universe = new SimpleUniverse ( canvas3d ) ;
// dodajemy do świata stworzoną wcześniej gałąź
universe . addBranchGraph ( scene ) ;
Listing 2. Wyświetlanie stworzonego świata 3D na ekranie
JFrame dialog = new JFrame () ;
dialog . setDefaultCloseOperation ( JFrame . EXIT_ON_CLOSE ) ;
dialog . setTitle ( "Hello 3D World!" ) ;
JPanel panel = new JPanel () ;
dialog . getContentPane () . add ( panel ) ;
// dodajemy Canvas3D jak zwykły komponent
panel . add ( new J3DTextDemo () . getCanvas ()) ;
dialog . pack () ;
dialog . setVisible ( true ) ;
Program 2 – J3DRotatingCube
– Wirujący sześcian
W tej części artykułu zapoznamy się m.in. z
metodami tworzenia i dodawania własnych
kształtów do świata 3D, poznamy szczegóły do-
tyczące działania oświetlenia oraz mechanizm
nakładania tekstur na obiekty 3D.
Listing 3. Złożenie transformacji
// ustalamy obrót w rotTransform - w osi x;
// zmienna curTransform zawiera transformację,
// którą mieliśmy wcześniej, chcemy do niej dodać nowe obroty
rotTransform . rotX ( Math . PI / 100 * Math . sin ( x )) ;
// ustawiamy newTransform na złożenie transformacji aktualnej i obrotu
newTransform . mul ( curTransform , rotTransform ) ;
// ustalamy obrót w rotTransform - w osi y
rotTransform . rotY ( Math . PI / 100 * Math . cos ( x )) ;
// ustawiamy new transform na złożenie siebie samego z rotTransform
newTransform . mul ( rotTransform ) ;
// ustalamy obrót w rotTransform - w osi z
rotTransform . rotZ ( - Math . PI / 100 * Math . sin ( x )) ;
// ustawiamy new transform na złożenie siebie samego z rotTransform
newTransform . mul ( rotTransform ) ;
Rysunek 3. Układ współrzędnych w Javie 3D
64
01/2009
275121816.031.png 275121816.032.png 275121816.033.png 275121816.034.png 275121816.035.png 275121816.036.png 275121816.037.png 275121816.038.png 275121816.039.png 275121816.040.png 275121816.041.png
 
Świat 3D w Javie
Najważniejsze klasy
Podstawowe obiekty, które wykorzystywać bę-
dziemy w tym programie, to:
By zrozumieć działanie poszczególnych ko-
lorów (oraz wykorzystać dotychczas zdoby-
tą wiedzę w praktyce) sugeruję stworzyć sce-
nę 3D, w której znalazłaby się kula (Sphere-
3D) oraz umiejscowione nad nią źródło świa-
tła, po czym poeksperymentować z różnymi
materiałami.
Na początek rozważmy ścianę dolną , czy-
li czerwoną. Po uruchomieniu programu
można zauważyć, że widoczna jest ona tyl-
ko wtedy, kiedy patrzy się od środka sze-
ścianu. Nie jest to przypadkowe zachowa-
nie. Każdy polygon posiada nie tylko zdefi-
niowane położenie, ale ma także swoją stro-
nę, czyli kierunek, z którego jest widocz-
ny. Po szczegóły definiowania kierunków
odsyłam do dokumentacji, dodam jednak,
że są dwie metody na sprawienie, by poly-
gon był widoczny z obu stron. Po pierw-
sze, można utworzyć drugi trójkąt, który bę-
dzie skierowany w przeciwnym kierunku.
Po drugie, do wyglądu (klasa Appearance )
obiektu 3D można przypisać obiekt
Appearance – obiekt-kontener, zawiera-
jący wszystkie ustawienia związane z wy-
glądem danego obiektu, począwszy od ko-
loru, przez sposób renderowania, aż po
przezroczystość.
Shape3D – podstawowa klasa opisują-
ca obiekt 3D. By pojawić się na ekranie,
musi posiadać swoją geometrię (Geome-
try), zaś jeśli chcemy, by pojawiała się
w formie innej niż czarne plamy, musi
także posiadać swój wygląd (Appearan-
ce).
Geometry - klasa definiująca wierzchołki
w przestrzeni 3D, a co za nimi idzie, poly-
gony, a także ich normalne (wektory defi-
niujące zorientowanie polygonu, potrzeb-
ne do obliczania wpływu oświetlenia), ko-
lory dla wierzchołków oraz współrzędne
dla tekstur.
Istnieje wiele klas rozszerzających Geo-
metry, zaś każda z nich ma właściwy dla
siebie sposób zastosowania. W J3DRo-
tatingCube wykorzystywana jest kla-
sa QuadArray. W jej konstruktorze spe-
cyfikujemy, jakie informacje będzie za-
wierać – jest to ważne, gdyż brak odpo-
wiedniej flagi będzie powodował rzuce-
nie wyjątku przy próbie zapisu związa-
nej z nią informacji.
Material – opisuje właściwości świetlne
powierzchni, musi być przypisana do kla-
sy Appearance. Materiał opisywany jest
przez:
EmmisiveColor - kolor, który jest emi-
towany przez obiekt,
AmbientColor – kolor, który jest emi-
towany przy oświetleniu światłem ty-
pu Ambient,
DiffuseColor – kolor kierunkowo
oświetlonej części obiektu,
SpecularColor – kolor efektu odbi-
cia światła od kierunkowo oświetlone-
go obiektu,
Shininess – liczba określająca roz-
miar odbłysku SpecularColor,
Sześcian
Każda ze ścian sześcianu z programu J3DRo-
tatingCube demonstruje oddzielne zagad-
nienie. Każda z nich tworzona jest jednak w
ten sam sposób – poprzez ustalenie w obiek-
cie QuadArray wierzchołków opisujących po-
wierzchnię. Wykorzystuje się do tego metodę
setCoordinate(int index, Point3f) .
Rysunek 4. Sześcian 3D – widok okna programu J3DRotatingCube
Listing 4. Deiniowanie świateł
// tworzymy światło - kierunkowe, świecące od góry
DirectionalLight sunlikeLight = new DirectionalLight ( new Color3f ( Color . RED ) , new Vector3f ( 0 , - 1 , 0 )) ;
sunlikeLight . setInluencingBounds ( new BoundingSphere ()) ;
// tworzymy światło - kierunkowe, świecące z lewej
DirectionalLight blueSideLight = new DirectionalLight ( new Color3f ( Color . BLUE ) , new Vector3f ( 1 , 0 , 0 )) ;
blueSideLight . setInluencingBounds ( new BoundingSphere ()) ;
// tworzymy światło - kierunkowe, świecące z tyłu
DirectionalLight greenBackLight = new DirectionalLight ( new Color3f ( Color . GREEN ) , new Vector3f ( 0 , 0 , 1 )) ;
greenBackLight . setInluencingBounds ( new BoundingSphere ()) ;
www.sdjournal.org
65
275121816.042.png 275121816.043.png 275121816.044.png 275121816.045.png 275121816.046.png 275121816.047.png 275121816.048.png 275121816.050.png 275121816.051.png 275121816.052.png
Warsztaty
PolygonAttributes z ustawionym CullFace
na PolygonAttributes.CULL_NONE . Warto
jednak zauważyć, że większość obiektów 3D
to obiekty zamknięte, wobec czego brak wi-
doczności od środka wcale nie jest proble-
mem, wręcz przeciwnie! Wyobraźmy sobie
kamerę umiejscowioną w głowie renderowa-
nej postaci 3D – widzielibyśmy wówczas,
zamiast świata, wnętrze głowy. Widok nie-
zbyt przydatny w grze.
Kolorowanie polygonów także może od-
bywać się na kilka sposobów. Istnieje obiekt
ColoringAttributes , w którym można usta-
wić kolor, a następnie przypisać go do obiek-
tu Appearance związanego z danym kształ-
tem ( Shape3D ). Można także przydzielić ko-
lor do konkretnego wierzchołka, co zrobio-
ne jest na ścianie górnej . Trzeba pamiętać,
że funkcja wyznaczania koloru dla dane-
go miejsca w polygonie jest w pełni mody-
fikowalna, może zależeć od światła, tekstu-
ry, koloru wierzchołka i koloru ustawionego
w ColoringAttributes . Słowem, może być
dość skomplikowana.
Wróćmy jednak do ściany górnej. Jej wy-
gląd został zdefiniowany poprzez przypisa-
nie kolorów do wierzchołków, a by to zrobić,
do konstruktora QuadArray dodaliśmy flagę
GeometryArray.COLOR_3 , po czym przypisali-
śmy kolory za pomocą metody setColor(int
index, Color3f color) . Sposób oblicza-
nia koloru dla konkretnego miejsca na po-
lygonie definiuje shadeModel w obiekcie
ColoringAttributes , w naszym przypad-
ku ma wartość SHADE_GOURAUD . Ściana górna
jest widoczna z obu stron dzięki ustawieniu
PolygonAttributes.CULL_NONE .
Ściana lewa zaś jest... po prostu biała. Tyle że
ma zdefiniowane normalne – są to, w teorii,
wektory prostopadłe do powierzchni. Cóż one
zmieniają? Otóż kolor ściany lewej będzie zale-
żeć od światła na nią padającego! Przyjrzyjmy
się definicji świateł w naszej scenie (Listing 4)
Widzimy trzy światła kierunkowe: padające
z góry czerwone, z lewej niebieskie, oraz z ty-
łu zielone. Kierunek propagacji określony jest
przez wektor podany w konstruktorze świa-
tła. Przykładowy kierunek normalnej i pada-
nia światła pokazuje ilustracja 5. Kąt φ określa
wpływ światła na kolor, dla φ =0 jest on mak-
symalny, dla φ >PI/2 (90O) jest zerowy (po-
wierzchnia nie jest oświetlona wcale). W na-
szym przykładzie mamy ścianę widoczną z
obu stron, ale z uwagi na jedną normalną, bę-
dzie oświetla tylko wtedy, gdy będzie skiero-
wana jedną stroną do światła. By uniknąć te-
go problemu, należy w PolygonAttributes
przypisanych do danego Apparance i Shape-
3D ustawić setBackFaceNormalFlip(true)
. Wówczas powierzchnia będzie oświetlana z
obu stron.
Przyjrzyjmy się teraz ścianie tylnej . Widzimy,
że jej powierzchnia jest nieregularna – jest tak,
ponieważ ściana ta pokryta jest teksturą. By na-
łożyć mapę bitową na powierzchnię, należy wy-
konać kilka kroków.
Po pierwsze, trzeba wczytać obrazek (do
BufferedImage ), po czym przypisać go do
obiektu Texture2D . Po szczegóły dotyczące tej
klasy odsyłam do dokumentacji J3D. Utwo-
rzoną w ten sposób teksturę poprzez obiekt
Appearance dodajemy do Shape3D . Trzeba pa-
miętać o tym, że nie wszystkie systemy obsłu-
gują tekstury o dowolnych wymiarach – war-
to więc, dla bezpieczeństwa, upewniać się, by
tworzone tekstury miały wymiary boków będą-
ce dowolną potęgą 2 (64, 128, 512, etc.). Wy-
miary boków nie muszą być równe (np. 128 x
512 także jest dozwolonym rozmiarem).
Po drugie, należy przypisać każdemu wierz-
chołkowi w geometrii, która ma być teksturo-
wana, współrzędne tekstury. Pokazuje to Rysu-
nek 6. Dla każdego punktu w świecie 3D przy-
porządkowujemy punkt 2D z zakresu 0 - 1. W
naszym przypadku rozwiązanie jest dość oczy-
wiste, po prostu lewy górny róg ściany to punkt
(0, 1) na teksturze. Problem pojawia się dopie-
ro w przypadku niepłaskich obiektów 3D, jak
np. kula – tym jednak na razie przejmować się
nie będziemy.
Dodatkowo, dla ściany tylnej ustawiliśmy
normalne, dzięki czemu będzie ona mogła być
oświetlana przez światła dodane do sceny. Nie
jest to jednak jedyne, co trzeba zrobić. Niezbęd-
ny jest także wybór metody obliczania wartości
koloru dla oświetlanej tekstury. Robi się to po-
przez obiekt TextureAttributes przypisany
do Appearance . Wywołujemy na nim meto-
setTextureMode(int mode) . Po listę i opi-
sy metod teksturowania odsyłam do dokumen-
tacji J3D, gdyż jest ich naprawdę wiele; można
nawet zdefiniować swoją własną.
����
Rysunek 5. Wektory: normalna powierzchni i
padające światło
�����
��������
�����
������
Rysunek 6. Współrzędne tekstur w Javie 3D
Rysunek 7. Wirujący układ słoneczny – widok okna J3DSolarSystem
66
01/2009
275121816.053.png 275121816.054.png 275121816.055.png 275121816.056.png 275121816.057.png 275121816.058.png 275121816.059.png 275121816.061.png 275121816.062.png
 
Zgłoś jeśli naruszono regulamin