Programowanie grafiki Java 3D i Python

background image

42

Programowanie

grafiki

www.sdjournal.org

Software Developer’s Journal 6/2006

Java 3D i Python

J

ava 3D powstała przy udziale konsorcjum

złożonego z firm: Intel, SGI, Apple oraz Sun

w połowie lat 90-tych. W obecnym czasie

każdy z tych producentów posiadał już własne śro-

dowisko graficzne 3D, lecz były one ograniczone

a sposób obsługi dosyć złożony. Zadaniem kon-

sorcjum było stworzenie wersji dla powszechne-

go odbiorcy takiego środowiska na platformę Java

i tym samym rozszerzenie jej możliwości. W wyni-

ku wspólnych prac konsorcjum powstała Java 3D.

Od 2004 Java 3D stała się oprogramowaniem ty-

pu open source rozwijanym w dalszym ciągu przez

Sun-a i rzesze developerów ochotników. W równym

stopniu wspierany jest zarówno OpenGL jak i Di-

rectX.

Nie należy mylić Javy 3D z mobilną platformą

Sun’a o skrótowej nazwie M3G dla J2ME do roz-

wijania trójwymiarowych aplikacji graficznych na

urządzenia w rodzaju: telefony komórkowe, PDA,

itp.

Java 3D w obecnej postaci oferuje przenośną

platformę działająca w oparciu o maszynę wirtu-

alną Java. Jak prawie każde środowisko graficz-

ne Java 3D pozwala na tworzenie grafiki trójwy-

miarowej w oparciu o hierarchiczną strukturę grafu,

w którego węzłach znajdować się będą wszystkie

elementy wirtualnego świata (tj. geometria obiek-

tów, przekształcenia, kamery, oświetlenia, anima-

tory, etc.) konieczne do należytej reprezentacji pro-

jektowanej sceny.

Celem artykułu jest prezentacja niektórych możli-

wości, jakie może dać Java 3D programistom tworzą-

cym przestrzenne aplikacje graficzne (niekoniecznie

przy użyciu tylko i wyłącznie samej Javy !). Zaczyna-

my od krótkiej charakterystyki kluczowych pakietów

biblioteki, aby następnie przejść do napisania prostej

aplikacji typu

Hello3D

. W dalszym ciągu artykułu sku-

pimy się na integracji Javy 3D ze Swing oraz gene-

rowaniu sceny przy użyciu skryptów Pythona, a ści-

ślej mówiąc, jego implementacji na maszynę wirtual-

ną Javy (Jython) i integracji Java 3D z tym środowi-

skiem.

Java 3D – opis

API Java 3D stanowi kilka pakietów, z których naj-

ważniejsze to jądro:

javax.media.j3d.org

. Klasy

związane z konstrukcją i opisem geometrii obiek-

tów, budową sceny zawarte są w kilku pakietach

użytkowych, np.

com.sun.j3d.utils

, a w

javax.vec-

math

znajdują się klasy wspomagające operacje na

współrzędnych, wektorach i macierzach. Ogólnie,

mamy do dyspozycji klasy służące tworzeniu geo-

metrii (brak krzywych i powierzchni typu NURBS),

animacji, detekcji kolizji, oświetleniu i teksturowa-

niu. Java 3D, w przeciwieństwie do innych środo-

wisk typu OpenSceneGraph czy Open Inventor,

nie posiada natywnego formatu do zapisu/odczytu

sceny, w związku z czym, chcąc nie chcąc, musimy

w sytuacji, gdy np. konieczny jest import sceny do

naszej aplikacji polegać na odpowiednich konwer-

terach dla 3ds Max, VRML, itp. Najczęściej spoty-

ka się konwertery formatów

.obj

i

.vrml

, ale wspie-

rany jest także w pewnym ograniczonym zakresie

.vtk

(Virtual Toolkit),

.lwo

(LightWave) czy też po-

pularny

.dxf

.

Interaktywność, w ogólnym tego słowa zna-

czeniu, sprowadza się do możliwości zapro-

gramowania reakcji określonego obiektu na ze-

wnętrzne bodźce. W Java 3D przyjęto zasadę, iż

reakcje te wykonywane są zawsze wtedy, gdy bo-

dziec ma miejsce w określonych granicach wokół

obiektu. Zaletą takiego rozwiązania jest to, iż apli-

kacje jest w stanie zignorować zdarzenie mające

miejsce poza zdefiniowanym dla danego obiek-

tu zakresem. Definiowanie zakresów zdarzeń jest

konieczne do określenie przez aplikacje, na któ-

re bodźce powinna zareagować. Reakcje można

powiązać z dowolną liczbą zdarzeń, np. zbliżenie

do określonego obiektu może powodować zmianę

w kolorze, obrót, etc. Co więcej, wiele reakcji

można kontrolować przy użyciu tzw. interpola-
torów
(np. przemieszczanie się obiektu wzdłuż

określonej trajektorii).

Janusz Gołdasz

Autor jest pracownikiem Centrum Technicznego firmy
Delphi Poland w Krakowie.
Kontakt z autorem: janusz.goldasz@delphi.com

Rysunek 1.

Pierwsza aplikacja: Hello3D

background image

Java 3D i Python

43

www.sdjournal.org

Software Developer’s Journal 6/2006

Listing 1.

Pierwsze kroki – Hello3D

import

java

.

applet

.

Applet

;

import

java

.

awt

.

BorderLayout

;

import

java

.

awt

.

event

.

*;

import

java

.

awt

.

GraphicsConfiguration

;

import

com

.

sun

.

j3d

.

utils

.

applet

.

MainFrame

;

import

com

.

sun

.

j3d

.

utils

.

geometry

.

*;

import

com

.

sun

.

j3d

.

utils

.

universe

.

*;

import

javax

.

media

.

j3d

.

*;

import

javax

.

vecmath

.

*;

import

com

.

sun

.

j3d

.

utils

.

behaviors

.

mouse

.

*;

import

com

.

sun

.

j3d

.

utils

.

behaviors

.

vp

.

*;

import

com

.

sun

.

j3d

.

loaders

.

objectfile

.

ObjectFile

;

import

com

.

sun

.

j3d

.

loaders

.

ParsingErrorException

;

import

com

.

sun

.

j3d

.

loaders

.

IncorrectFormatException

;

import

com

.

sun

.

j3d

.

loaders

.

Scene

;

import

java

.

io

.

*;

public

class

Hello3D

extends

Applet

{

private

SimpleUniverse

universe

=

null

;

public

BranchGroup

createSceneGraph

()

{

BranchGroup

objRoot

=

new

BranchGroup

();

BoundingSphere

bounds

=

new

BoundingSphere

(

new

Point3d

(

0

,

0

,

0

)

,

100

);

Background

background

=

new

Background

();

background

.

setColor

(

new

Color3f

(

0.0f

,

0.0f

,

1.0f

));

background

.

setApplicationBounds

(

bounds

);

objRoot

.

addChild

(

background

);

Color3f

lightColor1

=

new

Color3f

(

0.7f

,

0.7f

,

0.7f

);

Vector3f

lightDirection1

=

new

Vector3f

(

1.0f

, .

0f

, .

0f

);

Color3f

ambientLightColor

=

new

Color3f

(

0.2f

,

0.2f

,

0.2f

);

AmbientLight

ambientLight

=

new

AmbientLight

(

ambientLightColor

);

ambientLight

.

setInfluencingBounds

(

bounds

);

DirectionalLight

dirLight

=

new

DirectionalLight

(

lightColor1

,

lightDirection1

);

dirLight

.

setInfluencingBounds

(

bounds

);

objRoot

.

addChild

(

ambientLight

);

objRoot

.

addChild

(

dirLight

);

Transform3D

sphereTransform

=

new

Transform3D

();

sphereTransform

.

set

(

new

Vector3f

(

0.5f

,

0.0f

,

-

0.25f

));

sphereTransform

.

setScale

(

0.5f

);

TransformGroup

objTransform1

=

new

TransformGroup

();

objTrans1

.

setTransform

(

sphereTransform

);

Transform3D

cubeTransform

=

new

Transform3D

();

cubeTransform

.

set

(

new

Vector3f

(-

0.5f

,

0f

,

0.25f

));

cubeTransform

.

setScale

(

0.5f

);

TransformGroup

objTransform2

=

new

TransformGroup

();

objTransform2

.

setTransform

(

cubeTransform

);

objTransform2

.

setCapability

(

TransformGroup

.

ALLOW_TRANSFORM_WRITE

);

objTransform2

.

setCapability

(

TransformGroup

.

ALLOW_TRANSFORM_READ

);

objRoot

.

addChild

(

objTransform1

);

objRoot

.

addChild

(

objTransform2

);

Sphere

sphere

=

new

Sphere

(

0.5f

);

ColorCube

cube

=

new

ColorCube

(

0.5f

);

Appearance

appearance

=

new

Appearance

();

Color3f

sphereColor

=

new

Color3f

(

1.0f

,

0.2f

,

0.4f

);

app

.

setMaterial

(

new

Material

(

sphereColor

,

new

Color3f

(

0f

,

0f

,

0f

)

,

sphereColor

,

new

Color3f

(

1f

,

1f

,

1f

)

,

10

));

sphere

.

setAppearance

(

appearance

);

objTransform1

.

addChild

(

sphere

);

objTransform2

.

addChild

(

cube

);

MouseRotate

rotate

=

new

MouseRotate

(

objTransform2

);

objRoot

.

addChild

(

rotate

);

rotate

.

setSchedulingBounds

(

bounds

);

MouseZoom

zoom

=

new

MouseZoom

(

objTransform2

);

objRoot

.

addChild

(

zoom

);

zoom

.

setSchedulingBounds

(

bounds

);

int

flags

=

ObjectFile

.

RESIZE

;

ObjectFile

file

=

new

ObjectFile

(

flags

);

Scene

model

=

null

;

model

=

file

.

load

(

"model.obj"

);

Transform3D

mdlTransform

=

new

Transform3D

();

mdlTransform

.

set

(

new

Vector3f

(

0f

,

0f

,

0f

));

mdlTransform

.

setScale

(

0.5f

);

TransformGroup

objTransform3

=

new

TransformGroup

();

objTransform3

.

setTransform

(

mdlTransform

);

objTransform3

.

addChild

(

model

.

getSceneGroup

());

objRoot

.

addChild

(

objTransform3

);

objRoot

.

compile

();

return

objRoot

;

}

public

Hello3D

()

{

}

public

void

init

()

{

setLayout

(

new

BorderLayout

());

GraphicsConfiguration

config

=

SimpleUniverse

.

getPreferredConfiguration

();

Canvas3D

c

=

new

Canvas3D

(

config

);

add

(

"Center"

,

c

);

BranchGroup

scene

=

createSceneGraph

();

universe

=

new

SimpleUniverse

(

c

);

universe

.

getViewingPlatform

()

.

setNominalViewingTransform

();

universe

.

addBranchGraph

(

scene

);

}

public

void

destroy

()

{

u

.

cleanup

();

}

public

static

void

main

(

String

[]

args

)

{

new

MainFrame

(

new

Hello3D

()

,

256

,

256

);

}

}

background image

44

Programowanie

grafiki

www.sdjournal.org

Software Developer’s Journal 6/2006

Pierwsze kroki

Tworzenie aplikacji w oparciu o Java 3D pokażemy na ra-

czej typowym dla tej biblioteki przykładzie zawierającym

kilka najczęściej spotykanych elementów (prymitywy, kom-

ponowanie sceny, wczytanie modelu z zewnętrznego pli-

ku, reakcje) – na ekranie (Rysunek 1) pojawią się kula, sze-

ścian i (wczytany z pliku

.obj

) obiekt 3D. Kula i obiekt pozo-

staną nieruchome, a użytkownik może manipulować jedy-

nie sześcianem.

Na początek przyjrzyjmy się implementacji klasy

Hello-

3D

w Listingu 1. Nasza aplikacja to typowy applet, w związ-

ku z czym konieczne jest dziedziczenie po klasie

Applet

i implementacja metody

init()

. Do rysowania wykorzystuje-

my odpowiednio skonfigurowane okno klasy

Canvas3D

– kla-

sa

Canvas3D

dziedziczy po

awt.Canvas

. Kluczowa dla zawar-

tości trójwymiarowej sceny jest stworzona przez nas metoda

createScene()

, zwracająca korzeń sceny (

scene

) klasy

Branch-

Group

(

javax.media.j3d.BranchGroup

). Chcąc stworzoną scenę

wyświetlić, w dalszej części metody musimy dołączyć korzeń

do naszego wszechświata (

universe

). W metodzie

createSce-

ne()

, na początek musimy zainicjować korzeń drzewa (

root

),

do którego będziemy dokładać kolejne elementy sceny. Ko-

lejno ustawiamy: tło (

background

), światło otoczenia (

ambien-

tLight

) i kierunkowe (

dirLight

). Granice sceny ustalamy two-

rząc instancję klasy

BoundingSphere

(

bounds

). Chcąc manipu-

lować jedynie sześcianem, musimy stworzyć dla niego osob-

ną gałąź (grupę) i w rezultacie do korzenia dołączyć trzy od-

dzielne instancje klasy

TransformGroup

(

objTransform1

dla ku-

li,

objTransform2

dla sześcianu i

objTransform3

dla sceny, któ-

rą wczytywać będziemy z pliku) – tylko

objTransform2

w koń-

cowym efekcie będzie posiadać mechanizm obsługi zda-

rzeń myszki. Tak kulę jak i sześcian przesuwamy i skaluje-

my używając metod

set(Vector3f x)

i

setScale(float scale)

klasy

Transform3D

. W przypadku kuli i modelu działamy od-

powiednio na instancjach

sphereTransform

oraz

mdlTransform

,

dla sześcianu natomiast na instancji

cubeTransform

(w gałęzi

objTransform2

). Dodatkowo, kula jest kolorowana (

sphere.se-

tAppearance(appearance)

). Do manipulowania sześcianem

myszką potrzebne są nam jeszcze instancje klasy

MouseZoom

(zoom)

i

MouseRotate (rotate)

. Obydwie przyjmują

objTrans-

form2

. Dla wczytania zewnętrznego modelu (sceny) kluczo-

wy jest następujący fragment

ObjectFile file = new ObjectFile(flags);
Scene model = null;
model = file.load("model.obj");

Tak wczytany model wystarczy tylko umieścić w przeznaczo-

nej dla niego gałęzi i dołączeniu jej do korzenia:

objTrans3.addChild(model.getSceneGroup());
objRoot.addChild(objTrans3);

Musimy jeszcze tylko pamiętać o bieżącym modyfikowaniu

treści drugiej grupy

objTransform2.setCapability(
TransformGroup.ALLOW_TRANSFORM_WRITE)
objTransform2.setCapability(
TransformGroup.ALLOW_TRANSFORM_READ);

dołączeniu wszystkich potrzebnych elementów do korzenia

i pierwsza aplikacja jest gotowa.

Rysunek 2.

Przykład importu do Java 3D powierzchni

wygenerowanej w Blenderze

Rysunek 3.

Przykład połączenia GUI z Java 3D – symulator

cząsteczek

Listing 2.

Przykład użycia obiektu Canvas3D ze Swing

class

Panel3D

extends

JPanel

{

public

Panel3D

()

{

this

.

add

(

new

Canvas3D

(

config

));

}

}

Listing 3.

Rysunkowa para JTabbedPane – Canvas3D

class

Tabbed

extends

JTabbedPane

{

public

Tabbed

()

{

// …

// Gotowe: Java 3D wewnątrz Swing

this

.

addPage

(

new

Panel3D

());

//

}

}

background image

Java 3D i Python

45

www.sdjournal.org

Software Developer’s Journal 6/2006

Zwróćmy uwagę, że informacja o tworzywie wczyta-

nego modelu może znajdować się w zewnętrznej biblio-

tece materiałowej. W przypadku plików .obj jest to zwykle

tekstowy plik z rozszerzeniem

.mtl

generowany przy oka-

zji tworzenia samego modelu. Aby móc z niego skorzystać,

wystarczy w naszym modelu (w formacie

.obj

) umieścić

dwie instrukcje

mtllib model.mtl
usemtl 20

Pierwsza z nich określa zewnętrzną bibliotekę, z której mo-

żemy pobrać odpowiednie tworzywa, a druga indeks two-

rzywa, którym kolorujemy albo cały model albo wybra-

ną grupę. W tym wypadku spada z nas np. cała odpowie-

dzialność za kolor obiektu, przezroczystość, itp. Trzeba pa-

miętać, że większość istniejących w konwerter plików .obj,

a także .lwo zwykle nie obsługuje całości specyfikacji okre-

ślonego formatu. W ekstremalnych sytuacjach konieczna

jest edycja pliku i usunięcie kłopotliwych elementów. Z ist-

niejących modelerów open source dobre wyniki dają Blen-

der oraz Wings – zob. Rysunek 2.

Okienka

Integracja Javy 3D ze Swing nie jest bezproblemowa. Po-

prawnie Java 3D pracuje jedynie ze starszymi kontenera-

Listing 4.

Java 3D w Jythonie

import

java

.

awt

.

GraphicsConfiguration

from

java

.

applet

import

Applet

from

java

.

awt

import

BorderLayout

from

java

.

awt

.

event

import

*

from

com

.

sun

.

j3d

.

utils

.

geometry

import

*

from

com

.

sun

.

j3d

.

utils

.

universe

import

*

from

javax

.

media

.

j3d

import

*

from

javax

.

vecmath

import

*

from

com

.

sun

.

j3d

.

utils

.

behaviors

.

mouse

import

*

from

com

.

sun

.

j3d

.

utils

.

behaviors

.

vp

import

*

# Tworzymy applet…

class

Hello3D

(

Applet

):

def

init

(

self

):

self

.

setLayout

(

BorderLayout

())

self

.

_bounds

=

BoundingSphere

(

Point3d

(

0.0

,

0.0

,

0.0

)

,

100.0

)

config

=

SimpleUniverse

.

getPreferredConfiguration

()

c

=

Canvas3D

(

config

)

self

.

add

(

"Center"

,

c

)

self

.

_scene

=

self

.

createScene

()

self

.

_universe

=

SimpleUniverse

(

c

)

self

.

_viewingPlatform

=

self

.

_universe

.

getViewingPlatform

();

self

.

_viewingPlatform

.

setNominalViewingTransform

();

self

.

_universe

.

addBranchGraph

(

self

.

_

scene

)

# Kolej na tworzenie sceny…

def

createScene

(

self

):

# korzeń

objRoot

=

BranchGroup

()

background

=

Background

()

background

.

setColor

(

Color3f

(

0

,

0

,

1

))

background

.

setApplicationBounds

(

self

.

_bounds

)

objRoot

.

addChild

(

background

)

lightColor1

=

Color3f

(

0.7

,

0.7

,

0.7

)

lightDirection1

=

Vector3f

(

1.0

, .

0

, .

0

)

ambientColor

=

Color3f

(

0.2

,

0.2

,

0.2

)

ambientLight

=

AmbientLight

(

alColor

)

ambientLight

.

setInfluencingBounds

(

self

.

_bounds

)

dirLight

=

DirectionalLight

(

lightColor1

,

lightDir1

)

dirLight

.

setInfluencingBounds

(

self

.

_bounds

)

objRoot

.

addChild

(

ambientLight

)

objRoot

.

addChild

(

dirLight

)

sphereTransform

=

Transform3D

()

sphereTransform

.

set

(

Vector3f

(

0

.,

0.5

,

-

0.25

))

sphereTransform

.

setScale

(

0.5

)

objTransform1

=

TransformGroup

()

objTransform1

.

setTransform

(

sphereTransform

)

cubeTransform

=

Transform3D

()

cubeTransform

.

set

(

Vector3f

(

0

.,

-

0.5

,

0.25

))

cubeTransform

.

setScale

(

0.5

)

objTransform2

=

TransformGroup

()

objTransform2

.

setCapability

(

TransformGroup

.

ALLOW_TRANSFORM_WRITE

)

objTransform2

.

setCapability

(

TransformGroup

.

ALLOW_TRANSFORM_READ

)

objTransform2

.

setTransform

(

cubeTransform

)

objRoot

.

addChild

(

objTransform1

)

objRoot

.

addChild

(

objTransform2

)

sphere

=

Sphere

(

0.5

)

cube

=

ColorCube

(

0.5

)

appearance

=

Appearance

()

objColor

=

Color3f

(

1.0

,

0.2

,

0.4

)

appearance

.

setMaterial

(

Material

(

objColor

,

Color3f

(

0

,

0

,

0

)

,

objColor

,

Color3f

(

1

,

1

,

1

)

,

10

))

sphere

.

setAppearance

(

appearance

)

objTransform1

.

addChild

(

sphere

)

objTransform2

.

addChild

(

cube

)

rotate

=

MouseRotate

(

objTransform2

)

objRoot

.

addChild

(

rotate

)

rotate

.

setSchedulingBounds

(

self

.

_bounds

)

zoom

=

MouseZoom

(

objTransform2

)

objRoot

.

addChild

(

zoom

)

zoom

.

setSchedulingBounds

(

self

.

_bounds

)

objRoot

.

compile

()

return

objRoot

# koniec metody createScene

# Testujemy applet…

if

__name__

==

'

__main__

'

:

import

pawt

pawt

.

test

(

Hello3D

())

# Koniec

background image

46

Programowanie

grafiki

www.sdjournal.org

Software Developer’s Journal 6/2006

mi AWT. Powszechnym problem jest przerysowywanie i za-

krywanie kontrolek Swingowych przez Javę 3D (

Canvas3D

),

co powoduje, że użycie większości kontrolek Swingowych

jest praktycznie niemożliwe. Najlepsze wyniki, jak pokaże-

my na przykładzie, daje para

JTabbedPane

Canvas3D

i dzie-

dziczenie po klasie

JPanel

, np. w sposób pokazany w Listin-

gu 2 i 3.

Teraz wystarczy już tylko Rysunkowa para

JTabbedPane

Canvas3D

, przedstawiona na Listigu 3.

Dzięki takiemu rozwiązaniu można w łatwy sposób two-

rzyć rozbudowane aplikacje z typowym dla Swingowych

aplikacji interfejsem użytkownika, jak np. ta zilustrowana na

Rysunku 3 przedstawiając symulator cząsteczek.

Java 3D a Jython

Ciekawą alternatywą dla programistów używających obiek-

towe języki skryptowe wysokiego poziomu (np. Python) jest

możliwość integracji Javy 3D z Pythonem, a konkretnie z im-

plementacją Pythona o nazwie Jython na maszynę wirtual-

ną Javy. Zalet tworzenia aplikacji przy użyciu języków skryp-

towych w rodzaju Pythona jest wiele – np. obecność typów

danych wysokiego poziomu (listy, słowniki) przyspiesza-

jąca tworzenie aplikacji, dynamiczne typowanie, oszczęd-

ność kodu, interpretowanie zamiast kompilacji. Jython

w wersji 2.1 jest zgodny z J2SE, dzięki czemu korzystanie

w nim ze środowiska Java 3D w obecnej wersji (1.3.1) jest

bezproblemowe – Jython jest w 100% napisany w Javie, co

daje możliwość importowania klas Javy do tworzonych przez

nas skryptów. Dla porównania z poprzednim kodem, poni-

żej przykład skryptu/appletu stworzonego w Pythonie. Apli-

kacja jest identyczna z opisaną na wstępie aplikacją

Hello-

3D

poza fragmentem dotyczącym wczytania elementu sceny

z zewnątrz. Odpowiednie moduły Javy i Javy 3D importuje-

my, używając typowej konstrukcji Pythona

from com.sun.j3d.utils.behaviors.mouse import *

Listing 5.

Wykorzystanie klasy PythonInterpreter

// Import klas Java 3D…

import

org

.

python

.

core

.

PyObject

;

// Jython

import

org

.

python

.

util

.

PythonInterpreter

;

// interpreter

// Klasa dziedziczy po JFrame - Swing

public

class

embDemo

extends

JFrame

{

// pola prywatne, etc.

public

embDemo

(

String

source

)

{

// …

// Dodajemy do ramki nasz panel 3D

this

.

getContentPane

()

.

add

(

new

Tabbed

(

source

));

// …

}

// Panel dziedziczy po klasie JPanel

class

Panel3D

extends

JPanel

{

public

Panel3D

(

String

source

)

{

// …

// Scena i wirtualny wszechświat

BranchGroup

scene

;

SimpleUniverse

sUniverse

=

new

SimpleUniverse

(

can

vas3D

);

scene

=

createSceneGraph

(

source

);

sUniverse

.

addBranchGraph

(

scene

);

//…

this

.

setLayout

(

new

BorderLayout

());

this

.

setOpaque

(

false

);

this

.

add

(

"Center"

,

canvas3D

);

}

// Metoda createSceneGraph() jest inna niż zwykle..

private

BranchGroup

createSceneGraph

(

String

source

)

{

BranchGroup

objRoot

=

new

BranchGroup

();

TransformGroup

mainGroup

=

new

TransformGroup

();

// …

// Python: uruchamiamy interpreter

// Tutaj embeddedWorld zwraca wczytaną

// z zewnątrz scenę

BranchGroup

embedded

=

embeddedWorld

(

source

);

mainGroup

.

addChild

(

embedded

);

// Python: KONIEC

objRoot

.

addChild

(

mainGroup

);

return

objRoot

;

}

private

BranchGroup

embeddedWorld

(

String

source

)

{

Object

input

=

null

;

BranchGroup

root

=

new

BranchGroup

();

// Inicjujemy interpreter…

PythonInterpreter

interp

=

new

PythonInterpreter

();

// ...i wczytujemy do niego treść skryptu

try

{

DataInputStream

in

=

new

DataInputStream

(

new

FileInputStream

(

source

));

interp

.

execfile

(

in

);

// Pobieramy określony obiekt - scene

input

=

interp

.

get

(

"scene"

,

BranchGroup

.

class

);

}

catch

(

FileNotFoundException

E

)

{

E

.

printStackTrace

(

System

.

err

);

}

// Rzutujemy - input jest instancją klasy Object

return

(

BranchGroup

)

input

;

}

}

// Dziedziczymy po klasie JTabbedPane

class

Tabbed

extends

JTabbedPane

{

// source to nazwa skryptu Pythona

public

Tabbed

(

String

source

)

{

// Zakładka z panelem 3D

this

.

addTab

(

"View"

,

new

Panel3D

(

source

));

}

}

public

static

void

main

(

String

[]

args

)

{

new

embDemo

(

args

[

0

]);

}

}

background image

47

Java 3D i Python

www.sdjournal.org

Software Developer’s Journal 6/2006

Struktura appletu (w Pythonie !) jest w zasadzie identycz-

na z pierwszym przykładem (Java). Do naszego przykła-

du stosują się, oczywiście wszystkie charakterystycz-

ne cechy Pythona, a więc oszczędność kodu, typowanie,

etc.

Wskazówka dla osób nie mających styczności z Pytho-

nem: słowo

self

jest odpowiednikiem

this

Javy, ale w Pytho-

nie

self

musi być użyte jawnie w treści klasy.

W aspekcie korzystania z Pythona, pojawia się też moż-

liwość rozszerzania funkcjonalności naszej aplikacji skryp-

tami Pythona (Jythona), co w wielu przypadkach jest rze-

czą nie do pogardzenia. Ogólnie rzecz ujmując, para Ja-

va-Jython daje dwie możliwości: kompilacja kodu Pythona

do postaci klasy Javy i wywołanie go w tworzonej aplikacji

w postaci klasy lub wykorzystanie interpretera poleceń Py-

thona (klasa

PythonInterpreter

) do wywołania zewnętrzne-

go skryptu generującego np. geometrię. Jak sprawdziliśmy

w praktyce, pierwsze rozwiązanie nie zawsze działa, nato-

miast korzystanie z interpretera jest o wiele bardziej nieza-

wodne i czytelne.

Integrację Java (i Java 3D) z Python’em (Jython’em) po-

każemy na przykładzie nieskomplikowanej aplikacji okien-

kowej (zob. Rysunek 4), skonstruowanej w opisany w Li-

stingach 2 i 3 sposób. Tym razem jednak zamiast skazywać

się tylko i wyłącznie na towarzystwo Javy w treści meto-

dy

createSceneGraph()

pojawi się wywołanie skryptu Jytho-

na o określonej zawartości (Listingi 5 i 6). W Listingu 5 brak

części powtarzających się fragmentów kodu. Najważniej-

sza zmiana w treści klasy to nowa metoda o nazwie

eme-

beddedWorld(String source)

, której parametrem jest nazwa

zewnętrznego skryptu Jythona

source

– aplikację wywołu-

jemy z parametrem w postaci nazwy skryptu. Do zinterpre-

towania treści skryptu w sposób zrozumiały dla naszej apli-

kacji konieczne jest utworzenie obiektu klasy

PythonInter-

preter

(Klasa ta posiada metodę

execfile()

, przyjmującą in-

stancję klasy

FileInputStream

(skrypt), której wykonanie po-

woduje przetworzenie treści skryptu oraz metodę

get()

, któ-

rej pierwszym parametrem jest nazwa pobieranego obiek-

tu Pythona (

scene

), a drugim odpowiednia klasa Java 3D.

W naszym przypadku jest to klasa

BranchGroup

– konieczne

jest rzutowanie do klasy

BranchGroup

.

Oprogramowanie

Wszystkie omówione w niniejszym artykule przykłady po-

wstały przy użyciu Java 3D w wersji 1.3.1, Java 2 SE, Jy-

thon 2.1 oraz środowiska Eclipse w wersji 3.1 z wtyczką Py-

Dev (Python/Jython). Wykorzystany w pierwszym przykła-

dzie model jest częścią dystrybucji Java 3D. Minimalne za-

soby potrzebne do utworzenia opisanych aplikacji są jed-

nak znacznie mniejsze i mogą ograniczać się do koniecz-

ności zainstalowania Javy (J2SE) wraz z Java 3D oraz Jy-

thona i tworzeniu opisanych aplikacji przy pomocy dowol-

nego edytora tekstowego.

Podsumowanie

Java 3D jest, pomimo pewnych swoich niedociągnięć (kiepska

współpraca ze Swing, brak bezpośredniego dostępu do funk-

cji OpenGL, prosty model oświetlenia) i wieku, stosunkowo

atrakcyjnym rozwiązaniem dla programistów WWW i gier Ja-

va. W dalszym ciągu posiada duży potencjał i możliwości po-

zwalające programistom na umieszczanie niewielkim nakła-

dem pracy elementów grafiki 3D w appletach i aplikacjach Ja-

va, choć obecnie popularniejszym rozwiązaniem, np. w sferze

gier Java, wydają się być dedykowane rozwiązania, np. oparta

na JOGL biblioteka Xijth3D. Java 3D chyba jednak najbardziej

wpasowuje się w model przeznaczony dla średnio-wymagają-

cego użytkownika. n

W Sieci

• niezależne forum developerów Java 3D, JOGL

http://www.j3d.org

• strona domowa Javy

http://www.javasoft.com

• strona domowa Eclipse IDE

http://www.eclipse.org

• strona domowa programu Blender

http://www.blender.org

Rysunek 4.

Jython zanurzony

Listing 6.

Fragment importowanego skryptu Jython’a

(brak listy modułów Java 3D)

# Lista modułów Java 3D…
# funkcja createScene()

def

createScene

():

# Tradycyjnie, korzen

objRoot

=

BranchGroup

()

bounds

=

BoundingSphere

(

Point3d

(

0.0

,

0.0

,

0.0

)

,

100.0

)

background

=

Background

()

background

.

setColor

(

Color3f

(

0

,

0

,

1

))

background

.

setApplicationBounds

(

bounds

)

objRoot

.

addChild

(

background

)

objTransform

=

TransformGroup

()

objTransform

.

setCapability

(

TransformGroup

.

ALLOW_

TRANSFORM_READ

)

objRoot

.

addChild

(

objTransform

)

objTransform

.

addChild

(

ColorCube

(

0.4

))

return

objRoot

# koniec funkcji
# Wywołujemy createScene() i wynik przypisujemy
# do zwracanej zmiennej scene

scene

=

createScene

()

# Koniec


Wyszukiwarka

Podobne podstrony:
tutorial JAVA 3D, Programowanie
OpenGL Podstawy programowania grafiki 3D opglwp
OpenGL Podstawy programowania grafiki 3D
OpenGL Podstawy programowania grafiki 3D
Grafika 2d i 3D TUTORIAL Java
OpenGL Podstawy programowania grafiki 3D 2
developerWorks Tutorial XML programming in Java (1999)
Efektywne Programowanie W Języku Java
Java - Podstawy, Programowanie, Zastosowania, Java - Podstawy, Programowanie, Zastosowania, JAVA
Java, Programowanie W Jezyku Java
Practical Artificial Intelligence Programming in Java
Instrukcja programu aldl java
Lab Java2 13, Politechnika Opolska, Programowanie II java
Modelowanie brylowe zespolow i elementow maszyn w programach grafiki inzynierskiej cz 1
Jezyk Cg Programowanie grafiki w czasie rzeczywistym cgpgrt
Program główny RM 3D
zaawansowane systemy programowania grafiki

więcej podobnych podstron