}w !"#$%&'()+,-./012345
Masarykova univerzita Fakulta informatiky
Symetrické 3D modelování ovládané haptickým zařízením Bakalářská práce
Jan Šťastný
Brno, podzim 2013
Prohlášení Prohlašuji, že tato bakalářská práce je mým původním autorským dílem, které jsem vypracoval samostatně. Všechny zdroje, prameny a literaturu, které jsem při vypracování používal nebo z nich čerpal, v práci řádně cituji s uvedením úplného odkazu na příslušný zdroj.
Vedoucí práce: Mgr. Jan Byška ii
Poděkování Chtěl bych touto cestou poděkovat vedoucímu mé práce Mgr. Janu Byškovi, za cenné rady, trpělivost a ochotu v průběhu tvorby práce a také Mgr. Vilému Šustrovi za poskytnutí konzultací, týkajících se programování haptického zařízení. Dále bych rád poděkoval svým přátelům a rodině za podporu.
iii
Shrnutí Cílem práce bylo seznámení se s zařízením senseable PHANToM a vytvoření aplikace umožňující jednoduché modelování v 3D prostoru s využitím rotačních symetrií. Aplikace umožňuje export vytvořeného modelu do .obj formátu. Dále bylo nutné prozkoumat možnosti balíku JTouchToolkit, knihovny napsané v jazyce Java, která je alternativou k balíku OpenHaptics pro jazyk C++. Práci se snažím koncipovat jako návod pro nástupce, kteří by chtěli vyvíjet haptické aplikace v jazyce Java. V úvodu práce se věnuji popisu digitálního sochařství, vizuálního a hmatového vjemu ve virtuální realitě. V další kapitole je stručně popsáno stereoskopické zobrazování. Následuje část věnována datovým strukturám používaným v počítačové grafice a text popisující využití vláken v programování. Jedna kapitola je zaměřena na popis postupu vytvoření haptické aplikace a komunikace se zařízením. Závěr práce obsahuje postřehy, ke kterým jsem se dostal v průběhu vývoje aplikace a nápady na její možné rozšíření a vylepšení.
iv
Klíčová slova Senseable Phantom, PHANToM, Reachin Display, NVIDiA CrystalEyes, JTouchToolkit, JOGL, sculpting, modelování, symetrie
v
Obsah 1 Úvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1 Vizuální a hmatový vjem . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.1 Vizuální vjem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1.2 Hmatový vjem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Stereoskopické zobrazování . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Datové struktury . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1 Okřídlená hrana (WingedEdge) . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Vrchol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2 Ploška (stěna) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.3 Hrana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 KD-Strom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Formáty pro ukládání 3D dat . . . . . . . . . . . . . . . . . . . . . . . . . 4.0.1 Formát 3DS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.0.2 Formát FBX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.0.3 Formát Obj . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Použité technologie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1 Reachin Display . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 PHANToM Desktop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 CrystalEyes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 JTouchToolkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.1 HDAPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.2 HLAPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Programování haptické aplikace za pomocí knihovny JTouchToolkit . 6.1 Inicializace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Implementace zpětných volání . . . . . . . . . . . . . . . . . . . . . . . . 6.3 Renderování haptických tvarů . . . . . . . . . . . . . . . . . . . . . . . . 6.4 Synchronizace souřadných systémů . . . . . . . . . . . . . . . . . . . . . 7 Vlákna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.1 Implementace rozhraní Runnable . . . . . . . . . . . . . . . . . . . . . . 7.2 Rozšíření třídy Thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Implementace aplikace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.1 Balík sculpting.demo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.1.1 OpenGLListener . . . . . . . . . . . . . . . . . . . . . . . . . . . Metoda init(GLAutodrawable glad) . . . . . . . . . . . . . Metoda dispose(GLAutodrawable glad) . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1 1 1 1 3 5 5 5 5 6 6 8 8 8 8 10 10 10 11 12 12 12 14 14 15 16 17 18 18 19 20 20 20 21 21 vi
Metoda reshape(GLAutodrawable glad) . . . . . . . . . . . . Metoda display(GLAutodrawable glad) . . . . . . . . . . . . Metoda pullPoints(List
vertices, Point3D pivot, double weight) . . . . . . . . . . . . . . . . . . . . Metoda computeWeight(double oldWeight, double distance, double maxDistance, Functions func) . . . . . . . . . Metoda flattenPoints(List vertices, HVertex pivot) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2 Balík sculpting.structure.other . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.1 Třída Highlighter . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.2 Třída ObjFactory . . . . . . . . . . . . . . . . . . . . . . . . . . . . Metoda load() . . . . . . . . . . . . . . . . . . . . . . . . . . . . Metoda write(HMesh meshToWrite) . . . . . . . . . . . . . . 8.2.3 Třída WritingThread(HMesh meshToWrite) . . . . . . . . . . . . . 8.2.4 Třída Point3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.5 Třída Vector3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.6 Třída SymmetryMaker . . . . . . . . . . . . . . . . . . . . . . . . . 8.3 Balík sculpting.structure.haptics . . . . . . . . . . . . . . . . . . . . . . . . 8.3.1 Třída HButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Ovládání aplikace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Závěr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.1 Seznam použitých knihoven . . . . . . . . . . . . . . . . . . . . . . . . . . A Obsah přiloženého CD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21 21 23 23 24 24 24 25 25 25 25 26 26 26 27 27 28 30 31 33 34
vii
Seznam obrázků 2.1
Vyobrazení tří druhů paralaxy. 4
3.1 3.2
Schéma okřídlené hrany 6 Konstrukce KD-stromu dimenze 2. 7
5.1 5.2 5.3
Reachin Display soustava [12] 10 Senseable PHANToM [11] 11 Brýle CrystalEyes od společnosti Nvidia[13] 11
9.1
Rozvržení aplikace 28
viii
Kapitola 1
Úvod Sochařství je část výtvarného umění, kdy sochař opracovává materiál, například hlínu, a pomocí nejrůznějších nástrojů tento kus materiálu přetváří v sochu. Stejného principu je využito i v případě počítačem simulovaného sochařství. Uživatel místo fyzického zpracovávání hlíny využívá implementované nástroje a pomocí nich vytváří výsledný 3D model. Digitální modely se hojně objevují ve filmovém průmyslu, v počítačových hrách, digitálním umění a řadě dalších odvětví. S rozvojem 3D tiskáren je navíc možné tyto modely vytisknout z nejrůznějších materiálů a vytvořit tak reálný model. Modelování na počítači má oproti fyzickému řadu výhod. V programech je možné udělat několik kroků zpět v případě, že sochař udělá chybu. Jednodušší je také texturování výsledných modelů, a nebo použití jednoduchých symetrií. Nevýhodou může být, že umělec nemá kontakt s hmotou. Práce se zabývá implementací modelování se silovou zpětnou vazbou za použití haptického zařízení a reprezentací 3D modelu pro počítač. K tomu se využívají speciální datové struktury navržené pro efektivní zpracování dat.
1.1
Vizuální a hmatový vjem
1.1.1 Vizuální vjem Vizuální vjem je ve virtuální realitě klíčový. Lidé vnímají věci okolo sebe prostorově, rozeznávají vzdálenosti jednotlivých objektů a jejich rychlost díky očím, které nahlížejí na okolí pod různými úhly. Každé oko zaznamenává jiný, dvojrozměrný obraz a v mozku poté dochází k jejich spojení. Tohoto faktu se využívá při trojrozměrném zobrazování za použití speciálních brýlí. 1.1.2 Hmatový vjem Díky vizuálnímu vjemu je možné scénu pouze pozorovat. Abychom se ještě více přiblížili naší realitě, byla vytvořena zařízení simulující hmatový vjem. Pro oklamání lidského oka stačila relativně nízká obnovovací frekvence. Bohatě postačuje 24 snímků za sekundu a obraz nebo animace vypadají plynule. K navození plynulosti hmatového vjemu je však zapotřebí frekvence až 1000 snímků za sekundu. Pokud by byla frekvence nižší, mohl by se hmatový vjem zdát trhavý a tudíž nereálný. Také může nastat problém, když se zařízení 1
1. Úvod dostane pod povrch renderovaného objektu. Neví totiž, jak zareagovat na tuto situaci. Dojde k nárazu (anglicky kick) a zařízení se snaží vrátit na povrch objektu. Stejná situace může nastat při vytvoření příliš rezistentního materiálu, a nebo modelu s větším počtem nepropojených plošek.
2
Kapitola 2
Stereoskopické zobrazování Slovo stereoskopie je složeninou dvou řeckých slov stereos (pevné, trojrozměrné) a skopien (vidět). Princip prostorového vidění je znám téměř 160 let a díky technickému pokroku prochází i stereoskopické vidění neustálým vývojem [14]. Prostorové vidění vzniká až v mozku, kdy si mozek vezme dva rozdílné obrazy z pravého a levého oka a poté si je spojí. Každé oko totiž, díky svému posunutí, vnímá okolní realitu z jiné perspektivy. Obraz, který jedno oko předává, je tak posunutý oproti obrazu z druhého oka. Stereoskopie má mnoho uplatnění. Často se využívá ve výzkumných vizualizacích, zábavním a herním průmyslu, u simulátorů pro výuku (medicína, strojní průmysl), zobrazování architektonických prostorů apod. Existuje řada možností, jak lidskému oku skrze 2D promítací plochu říci, že jeden objekt je blíže a druhý je vzdálenější. Lze použít některou z následujících metod: •
Světlo a stín – světlejší předměty se zdají být blíže než tmavší.
•
Zvýraznění texturou – se vzrůstající vzdáleností je textura méně patrná a výrazná. S touto metodou souvisí i zobrazení více detailů na bližších objektech.
•
Relativní velikost objektů – objekty blíže k pozorovateli vypadají větší.
•
Atmosferické efekty – více vzdálené objekty jsou díky mlze, kouři nebo prachu méně jasné a zamlžené. S rostoucí vzdáleností se jejich zabarvení srovnává se zabarvením mlhy (atmosféry).
•
Překrytí objektů – objekty se souvislými obrysy se zdají být blíže.
•
Lineární perspektiva – soustavné zmenšování velikosti objektů s rostoucí vzdáleností od pozorovatele.
Důležitým pojmem ve vnímání vzdálenosti je paralaxa. Paralaxa je horizontální vzdálenost mezi odpovídajícími body levého a pravého obrazu[14]. Je měřena na výstupním zařízení (monitor, plátno...), nikoliv na sítnici. Existují čtyři druhy paralaxy. Abychom určili, o jaký typ se jedná, musíme porovnat dvě vzdálenosti. Vzdálenost středů čoček oka, označme l, a velikost paralaxy, označme p. •
Nulová paralaxa – souhlasné body se shodují. Body s nulovou paralaxou se zdají být v rovině promítací plochy. 3
2. Stereoskopické zobrazování •
Pozitivní paralaxa – objekt se nachází až za promítací rovinou. Může zde nastat speciální případ, kdy se l=p. Osy jsou rovnoběžné.
•
Negativní paralaxa – jev nastává, když jsou oči překříženy. Objekty se poté zdají být před osou promítání.
•
Pozitivně divergentní paralaxa – osy se rozbíhají, divergují. V realitě tento jev nenastává, a proto může způsobovat problémy. Následující obrázky ukazují jednotlivé typy. Pozice vnímaného obrazu je označena červeným křížkem.
Obrázek 2.1: Vyobrazení tří druhů paralaxy.
4
Kapitola 3
Datové struktury 3.1
Okřídlená hrana (WingedEdge)
Okřídlená hrana se používá v počítačové grafice k uložení geometrických dat. Je také známá pod názvem Doubly connected edge list (DCEL) [15], neboli dvojitě propojený seznam hran. Struktura uchovává informace o hranách, stěnách a vrcholech a je schopna reagovat na libovolnou změnu. 3D objekt je tedy reprezentován seznamy vrcholů, stěn a hran. Každý z těchto třech útvarů navíc nese podrobnější informace o vzájemném propojení. Název „okřídlená“ si struktura vysloužila kvůli své reprezentaci (viz. obrázek 2.1).
3.1.1 Vrchol Vrchol je geometrický objekt, který nese informaci o své pozici v prostoru, tedy souřadnice (x,y,z) a informaci o vycházející hraně. Z toho je patrné, že je struktura tvořena orientovanými hranami.
3.1.2 Ploška (stěna) Ploška je tvořena obrysovými hranami. Díky jejich orientaci jsme schopni určit, zda je ploška vnitřní nebo vnější. Vnitřní ploška má veškeré ohraničující hrany orientovány proti směru hodinových ručiček, tedy každá hrana ze smyčky musí mít tuto stěnu na levé straně, v levém poloprostoru. Plošky mohou v zásadě obsahovat díry. Díra je reprezentována hranami orientovanými po směru hodinových ručiček. Ve struktuře obsahuje stěna jen jedinou informaci, a to o přiléhající hraně. Díky algoritmu pro nalezení smyčky jsme poté schopni dostat se na ostatní hrany. Algoritmus začíná na hraně, která určitě patří do stěny a pokračuje přes levou vycházející hranu dále. Takto prochází následníky, dokud se nedostane zpět na počáteční hranu. Zde algoritmus končí a vrátí seznam hran tvořících smyčku. 5
3. Datové struktury 3.1.3 Hrana Hrana je nejdůležitější součástí struktury. Obsahuje informace o počátečním a koncovém vrcholu (čímž je udán směr hrany). Poté obsahuje ukazatele na levého předchůdce, levého následníka, pravého předchůdce a pravého následníka. Dále si hrana drží informaci o levé přiléhající plošce. Zde si můžeme všimnout, že ačkoliv ploška drží informace pouze o jediné hraně, tak každá hrana drží informaci o přiléhající plošce. Dále lze strukturu rozšířit a doplnit informaci o zdvojené hraně, tedy hraně, která má opačné pořadí počátečního a cílového vrcholu.
Obrázek 3.1: Schéma okřídlené hrany
3.2
KD-Strom
KD-Strom byl poprvé popsán Johnem Bentleym v roce 1977. Je to speciální případ BSP stromu 1 určený k popisu libovolného K-rozměrného prostoru. Řezné roviny jsou vždy kolmé na některou ze souřadných os a orientace řezů se pravidelně střídají. Za K v názvu se kdysi dosazoval rozměr zpracovávaného prostoru (2D, 3D apod.), dnes se užívá jen univerzální zkratka KD (KD-Strom)[4]. Každý uzel tohoto binárního vyhledávacího stromu uchovává informace o dimensionalitě, aktuální hloubku, ukazatel na pravý a levý podstrom (nebo-li na pravého a levého potomka), ukazatel na rodiče a hodnotu v podobě k-rozměrného bodu. Nejčastěji se používá v geografických informačních systémech (GIS), počítačové grafice a databázích. Konstrukce KD-Stromu dimenze 2 vypadá následovně. Z bodů v prostoru je vybrán medián a tím je vedená řezná rovina (rovnoběžná s osou X), prostor je rozdělen na 1.
BSP - binární rozdělování prostoru, z angl. binary space partitioning
6
3. Datové struktury dva poloprostory. Z každého se opět vybere medián a těmito body se vede řez kolmý na osu Y. Podobně je tomu i u vyšší dimenze. Díky tomuto dělení by měl být strom vyvážený s průměrnou hloubkou 𝑂(𝑁 ). Časová složitost při vyhledávání, vkládání a mazání uzlů je průměrně 𝑂(𝑁 𝑙𝑜𝑔𝑁 ), kde 𝑁 je počet uzlů.
Obrázek 3.2: Konstrukce KD-stromu dimenze 2.
7
Kapitola 4
Formáty pro ukládání 3D dat 4.0.1 Formát 3DS 3DS formát je použit v programu Autodesk 3ds Max1 . Tento formát je popsán binárně. Je rozdělen do bloků, které obsahují jednotlivé úseky dat. Každý blok obsahuje identifikátor a záznam o své délce. První dva bajty bloku popisují id. Díky id může analyzátor, který vyhodnoucuje soubor 3DS, rozhodnout, zda bude blok analyzovat nebo jej přeskočí. Další čtyři byty obsahují celé číslo, které udává délku bloku včetně jeho dat, délky dílčích bloků a jeho záhlaví[16]. 4.0.2 Formát FBX FBX formát vznikl pro účely software Filmbox, dnes známého pod názvem Autodesk MotionBuilder - software pro tvorbu 3D animací. Filmbox byla aplikace pro záznam dat ze zařízení pro digitalizaci filmů. Formát podporuje data zachycení pohybu, zachycení audia a videa. Je podporován řadou současných programů pro práci s 3D daty (Maxon Cinema4D, 3D Studio MAX, SoftImage 3D, aj). FBX je reprezentován pomocí binárních nebo ASCII dat[17]. 4.0.3 Formát Obj Obj formát patří do skupiny CAD (Computer-aided design) formátů. Byl vyvinut společností Wavefront Technologies2 pro jejich 3D grafický software The Advanced Visualizer. Stal se univerzálním souborem pro uložení 3D dat. Díky Obj je možné přenášet geometrická data mezi různými aplikacemi. Navíc jsou tato data reprezentována textovou, tedy pro člověka čitelnou, formou. Díky tomu je možné upravovat soubor běžným textovým editorem. Pomocí Obj formátu je možné popsat řadu objektů počítačové grafiky. Od bodů, přes křivky a povrchy, až po informace o materiálech a renderingu. Pro účely této práce si vystačíme s informacemi o pozici každého vrcholu, normálách vrcholů a o ploškách. 1. Autodesk 3ds Max je software určený k modelování, vytváření animací a renderingu 3D modelů. 2. Wavefront Technologies byla společnost zabývající se počítačovou grafikou. Převážně tvorbou a prodejem animačních aplikací.
8
4. Formáty pro ukládání 3D dat Jako každý standardizovaný formát má i Obj svoji specifikaci pro popis jednotlivých komponent [10]. –
# – za tímto znakem následuje jednořádkový komentář
–
o název – uvádí název objektu
–
g název – otevírá skupinu objektů
–
v float float float (float) – vrchol je zapsán pomocí klíčového znaku v a následují tři případně čtyři číslice, popisující pozici vrcholu v prostoru. Vrcholy uložené v souboru Obj jsou indexovány od jedničky.
–
vn float float float (float) – normála vrcholu. Podobně jako vrchol, tak i normály jsou indexovány od 1.
–
vt float float – souřadnice textury (UV). Stejně jako u normály, každému vrcholu je přiřazena jedna souřadnice textury.
Popis plošky se může lišit. Záleží na druhu informací, které soubor nese. Je možné ji zapsat třemi způsoby, všechny ale mají společnou formu, a to, že začínají znakem f, po kterém následuje mezera a poté kombinace indexů vrcholů, texturových souřadnic a normál. Každou plošku musí tvořit minimálně tři vrcholy. Vrchol/texturová souřadnice tento zápis se používá pokud nepožadujeme údaj o normálách vrcholů (nejsou povinné). Každému vrcholu v plošce odpovídá vrchol textury. Zápis vypadá následovně: f v/vt v/vt v/vt... Vrchol/texturová souřadnice/normála podobně jako předchozí zápis, jen za souřadnici textury zapíšeme index normály oddělený lomítkem. Zápis vypadá takto: f v/vt/vn v/vt/vn v/vt/vn... Vrchol//normála texturové souřadnice je možné úplně vynechat. Počet lomítek ale zůstává: f v//vn v//vn v//vn...
9
Kapitola 5
Použité technologie 5.1
Reachin Display
Reachin display vyrobila ReachinTechnologies. Jedná se o zařízení skládající se ze stojanu, CRT monitoru s vysokou obnovovací frekvencí, který zajišťuje promítání obrazu pod úhlem 60 stupňů a polopropustného zrcadla pod tímto monitorem. Od zrcadla se obraz odráží k uživateli a je zachycován speciálními brýlemi CrystalEye. Díky těmto brýlím, které zajišťují propouštění odraženého obrazu střídavě do levého a pravého oka, se uživateli promítne obraz prostorově. Pod zrcadlem se nachází zařízení PHANToM.
Obrázek 5.1: Reachin Display soustava [12]
5.2
PHANToM Desktop
PHANToM Desktop je haptické vstupně-výstupní zařízení vyrobené firmou SensAble Technologies. Název PHANToM byl vytvořen zkrácením „Personal Haptic Interface Mechanism“. Toto haptické zařízení využívá servomotorů k simulaci doteku a interakce s virtuálními (haptickými) objekty. Existují 3DOF nebo 6DOF1 modely. 1.
DOF-z anglického degree of freedom, neboli stupně volnosti
10
5. Použité technologie V laboratoři HCI se pracuje se zařízením 6DOF/3DOF. Tedy 6 stupňů volnosti na výstupu a 3 stupně volnosti silové zpětné vazby. Lze načíst 6 hodnot ze zařízení. Mezi tyto hodnoty patří aktuální pozice nástroje v prostoru a natočení ve třech osách. Souřadný systém pracovní plochy zařízení PHANToM je uveden v kartézských souřadnicích. Kladná osa X vede doprava, kladná osa Y nahoru a osa Z směřuje k uživateli sedícímu před zařízením.
Obrázek 5.2: Senseable PHANToM [11]
5.3
CrystalEyes
StereoGraphics CrystalEyes jsou speciální brýle, díky kterým je možné vidět obraz v prostoru. Fungují na principu střídavého zatmívání skel (zvlášť pro levé a pravé oko). Toto rychlé zatemňování je umožněno vrstvou tekutých krystalů ve sklech. Brýle jsou díky speciálnímu zařízení synchronizovány s obrazem. Tato synchronizace zajišťuje, aby brýle propustily obraz vysílaný pro levé oko, skutečně pouze k levému oku a obraz pro pravé pouze pravému oku. Zařízení je připojeno přes USB port ke grafické kartě a komunikuje s brýlemi přes infračervené záření.
Obrázek 5.3: Brýle CrystalEyes od společnosti Nvidia[13]
11
5. Použité technologie
5.4
JTouchToolkit
JTouchToolkit je soubor knihoven, který byl vytvořen v roce 2006 softwarovým inženýrem Ianem John Archerem z Birninghamské městské Univerzity. Roku 2007 se stal OpenSource projektem. Cílem projektu bylo vytvořit komplexní API pro haptická zařízení v jazyce Java. Ke zpřístupnění funkcí JTouchToolkitu stačí do projektu naimportovat knihovnu, přístupnou na internetu [3]. Podobně jako její předloha v jazyce C++, i JTouchToolkit zahrnuje dvě hlavní části, HDAPI (Haptic Device API) a HLAPI (Haptic Library API). Obě rozhraní jsou vystaveny na principech OpenGL a chovají se tedy jako stavový automat. 5.4.1 HDAPI Haptic Device API dovoluje programátorovi nízkoúrovňový přístup k zařízení. Umožňuje vlastní výpočet sil odesílaných zařízení, konfiguraci a řízení běhu ovladačů. Přímé renderování síly však musí probíhat rychle. Napsané algoritmy musí být efektivní, protože je nutná vysoká obnovovací frekvence servocyklu. Servocyklus je smyčka, která neustále posílá vypočtené síly do zařízení. Aby byla hmatová simulace reálná, musí smyčka běžet s frekvencí minimálně 1000 Hz. HDAPI by měla být použita při zavádění nových tříd zařízení, nebo pro komplexní správu zařízení. Je užitečné, pokud má programátor zkušenosti s používáním C++ Toolkitu OpenHaptics. HDAPI nabízí například funkce ke zjištění stavu zařízení (pozice, orientace, rychlost a stav tlačítka/tlačítek), zjištění charakteristiky zařízení (verze, typ modelu, sériové číslo, verze ovladačů, rozměry/dimenzi pracovní plochy, vstupní a výstupní DOF aj.), nastavení stavu zařízení (síla, kroutící moment na kloubech). Dále umožňuje kalibraci (automatickou nebo manuální), výpis chybových hlášení, nebo zapnutí a vypnutí silového působení zařízení. 5.4.2 HLAPI Haptics Library API je založena na haptickém renderingu a je navržena pro programátory, kteří mají zkušenost s OpenGL. Je na vyšší úrovní než HDAPI. HLAPI dovoluje vytvářet geometrická primitiva, trojúhelníky, přímky, body, stejně jako u OpenGL. Je dokonce možné volat funkce z OpenGL. HLAPI navíc dovoluje potáhnout takto vzniklá primitiva speciálními materiály a je tedy možné simulovat chování nejrůznějších reálných povrchů. Dovoluje nastavit vlastnosti, jakými jsou tření (statické nebo dynamické), tuhost nebo pružnost. Přidání haptické vlastnosti objektu je triviální proces, nejprve je nutno vygenerovat identifikátor tvaru (shape id), aby haptika poznala, kterého objektu se právě dotýká. Poté takovýto objekt stačí vykreslit hapticky (popř. i graficky). Stejně jako OpenGL pracuje HLAPI s kartézským souřadným systémem. Pro umístění objektu do scény stačí říci, kam se má 12
5. Použité technologie renderovaný objekt přemístit pomocí, z OpenGL známých, transformačních metod (posun, rotace, změna velikosti). Na programátorovi je, aby souřadné systémy OpenGL a HLAPI synchronizoval. Rozhraní nabízí také metody pro zjištění pozice zařízení (v prostoru) nebo, pokud požadujeme i orientaci, transformaci zařízení. API nabízí možnost obsluhy událostí. To je velmi užitečné pro vývoj tzv. událostmi řízených aplikací. Tedy takových aplikací, které reagují na události, jaké mohou při práci s aplikací nastat. Pomocí zpětných volání (anglicky callback) lze zachytit události jako stisknutí tlačítka, pohyb, počátek nebo konec dotyku. Pomocí zpětných volání určujeme, jak se má aplikace zachovat, když k některé události dojde. Zpětná volání se přiřadí konkrétnímu tvaru, nebo díky konstantě HL_OBJECT_ANY libovolnému objektu ve scéně.
13
Kapitola 6
Programování haptické aplikace za pomocí knihovny JTouchToolkit V této kapitole se zaměřuji na zprovoznění haptické aplikace. Aby fungovala komunikace mezi zařízením a programem, musíme nejdříve provést inicializaci. Postup s JTouchToolkitem se téměř shoduje s postupem inicializace v OpenHaptics (knihovně pro jazyk C++), pouze s drobnými změnami. Inicializace je popsána dále.
6.1
Inicializace
Nejprve je potřeba zařízení najít a inicializovat (1), poté vytvořit kontext nalezeného zařízení (2). Dále vytváříme haptické tvary a nastavujeme zpětná volání (3). Protože většina metod v toolkitu vyhazuje výjimky, budeme na ně nuceni nějak reagovat. Pozastavíme se pouze u metody hdInitDevice (kterou nalezneme ve třídě HDAPI). Oproti C++ knihovně nebere jako argument konstantu (integer), ale řetězec s názvem zařízení, které chceme inicializovat. Standardně je to řetězec „Default PHANToM“. Velikost písmen musí být zachována. V inicializační metodě také říkáme, jaká strana má reagovat na dotyk (pomocí konstant HL_FRONT, HL_BACK nebo HL_FRONT_AND_BACK). Následující metoda slouží jako ukázka inicializace. 1 2 3 4 5 6 7
8
9 10 11 12 13 14
public void initHL () { try { if ( hHD != HDAPI . hd Ge tCu rr en tD ev ic e () ) { // (1) hHD = HDAPI . hdInitDevice ( " Default PHANToM " ) ; } } catch ( HDException e ) { System . out . println ( " Selhala inicializace zarizeni Default PHANToM . " ) ; Logger . getLogger ( Main . class . getName () ) . log ( Level . SEVERE , null , e); } \ hypertarget { context }{ hHLRC } = HLAPI . hlCreateContext ( hHD ) ; HLAPI . hlMakeCurrent ( hHLRC ) ; // (2) try { HLAPI . hlEnable ( HLAPI . H L _ H A P T I C _ C A M E R A _ V I E W ) ; HLAPI . hlTouchableFace ( HLAPI . HL_FRONT ) ;
14
6. Programování haptické aplikace za pomocí knihovny JTouchToolkit 15 16 17 18 19 20 21 22
myShapeID = HLAPI . hlGenShapes (1) ; // (3) myAnotherShapeID = HLAPI . hlGenShape () ; HLAPI . h lAd dE ve nt Ca ll ba ck ( myShapeID , HLAPI . HL_COLLISION_THREAD , myCallback , null ) ; } catch ( HLException e ) { e . printStackTrace () ; }
6.2
Implementace zpětných volání
Abychom vytvořili vlastní callback, stačí implementovat rozhraní HLEventCallback. Budeme kompilátorem přinuceni implementovat veškeré metody. Mnohé z nich však ani nevyužijeme. Takto vytvořený callback můžeme přiřadit do proměnné typu HLEventCallback. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
private HLEventCallback myCallback = new HLEventCallback () { @Override public void HL_EVENT_MOTION ( int i , int i1 , HLCache hlc , Object [] os ) { // t ě lo metody bude provedeno p ř i pohybu za ř í zen í } @Override public void H L _ E V E N T _ 1 B U T T O N D O W N ( int i , int i1 , HLCache hlc , Object [] os ) { // t ě lo metody bude provedeno p ř i stisknut í tla č í tka } @Override public void HL _EV EN T_ 1B UT TO NU P ( int i , int i1 , HLCache hlc , Object [] os ) { // t ě lo metody bude provedeno p ř i uvoln ě n í tla č í tka } // ... // dal š í zp ě tn á vol á ni pro ostatn í tla č í tka // ... @Override public void HL_EVENT_TOUCH ( int i , int i1 , HLCache hlc , Object [] os ) { // t ě lo metody bude provedeno p ř i kontaktu s objektem } @Override public void HL_EVENT_UNTOUCH ( int i , int i1 , HLCache hlc , Object [] os ) { // t ě lo metody bude provedeno p ř i ukon č en í kontaktu s objektem }};
15
6. Programování haptické aplikace za pomocí knihovny JTouchToolkit
6.3
Renderování haptických tvarů
Haptické tvary máme již iniciovány, zpětná volání přiřazena, abychom se však mohli těchto objektů dotýkat, je zapotřebí tvary vykreslit. Všechny příkazy v HLAPI musí začínat a končit příkazy hlBeginFrame() a hlEndFrame(), podobně jako je tomu u OpenGL (funkce glBegin() a glEnd()). Díky rámcům je možná synchronizace mezi stavy a renderováním haptiky. Uvnitř rámce tedy pracujeme podobně jako je tomu u OpenGL, voláme příkazy na provádění transformací a vykreslování objektů. Pokud chceme vytvořit samostatný objekt musíme jej otevřít příkazem hlBeginShape(int type, int shape), parametr type udává typ tvaru, parametr shape je id vytvářeného tvaru. Blok se musí uzavřít příkazem hlEndShape(). HLAPI poté dopočítá geometrii specifikovanou OpenGL příkazy, nacházejícími se uvnitř bloku. Dále při renderingu specifikujeme materiály pro každý tvar. HLAPI nabízí funkci hlMaterialf(int face, int pname, float param) s parametry face pro stranu plošky, na kterou má být materiál aplikován, pname udává druh materiálu a param udává hodnotu materiálu. Následující metoda ukazuje možnou implementaci. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
22 23 24 25 26 27 28 29
public void renderHL () { try { HLAPI . hlMakeCurrent ( hHLRC ) ; HLAPI . hlBeginFrame () ; HLAPI . hlMaterialf ( HLAPI . HL_FRONT_AND_BACK , HLAPI . HL_STATIC_FRICTION ,0.5 f ) ; HLAPI . hlBeginShape ( HLAPI . HL_SHAPE_DEPTH_BUFFER , myShapeID ) ; gl . glRotatef (90 , 0 , 1 , 0) ; gl . glScalef (1.5 f , 1.5 f , 1.5 f ) ; gl . glBegin ( GL2 . GL_QUADS ) ; gl . glVertex3f ( -1.0 f , 1.0 f , 0.0 f ) ; gl . glVertex3f ( 1.0 f , 1.0 f , 0.0 f ) ; gl . glVertex3f ( 1.0 f , -1.0 f , 0.0 f ) ; gl . glVertex3f ( -1.0 f , -1.0 f , 0.0 f ) ; gl . glEnd () ; HLAPI . hlEndShape () ; HLAPI . hlMaterialf ( HLAPI . HL_FRONT_AND_BACK , HLAPI . HL_DAMPING , 0.5 f ) ; // pru ž nost povrchu HLAPI . hlMaterialf ( HLAPI . HL_FRONT_AND_BACK , HLAPI . HL_STIFFNESS , 0.5 f ) ; // tuhost povrchu HLAPI . hlBeginShape ( HLAPI . HL_SHAPE_FEEDBACK_BUFFER , myAnotherSmapeID ) ; gl . glCallList ( listId ) ; HLAPI . hlEndShape () ; HLAPI . hlEndFrame () ; } catch ( Exception e ) { Logger . getLogger ( Main . class . getName () ) . log ( Level . SEVERE , null , e ) ; } }
16
6. Programování haptické aplikace za pomocí knihovny JTouchToolkit Podobně jako je tomu u OpenGL a vytváření display listů, musíme po sobě také uklidit. To je dobré provádět u metody dispose (ukončení aplikace). V této části smažeme id tvarů a odstraníme zpětná volání. Metoda hlDeleteShapes vyhazuje HLException. 1 2
private void d i s p o s e H a p t i c H a n d l e r () throws HLException { HLAPI . h l R e m o v e E v e n t C a l l b a c k ( myShapeID , HLAPI . HL_COLLISION_THREAD , myCallback ) ;
3
HLAPI . hlDeleteShapes ( myShapeID , 1) ; HLAPI . hlDeleteShapes ( myAnotherShapeID , 1) ;
4 5 6
HLAPI . hlDeleteContext ( hHLRC ) ;
7 8
}
6.4
Synchronizace souřadných systémů
Další důležitou částí, kterou musíme při programování provést, je synchronizace pracovní plochy zařízení se zobrazovanou plochou (prostorovým objemem) definovanou v OpenGL. Namapování těchto dvou souřadných systémů řekne, jak se pohyb fyzického zařízení podepíše na posunu ve grafické scéně. K tomu slouží dvě funkce: hlWorkspace(double left, double bottom, double back, double right, double top, double front) a hlOrtho(double left, double right, double bottom, double top, double zNear, double zFar). Pracovní plocha (workspace) je prostor, který poskytuje fyzické zařízení. Lze jej zjistit zavoláním metody hlGetDoublev(int pname) s parametrem HL_WORKSPACE. Vrátí pole o šesti hodnotách typu double, údaje jsou v milimetrech. Metodou hlWorkspace(...) definujeme použitelnou plochu pro zařízení. Metoda hlOrtho(...) nastaví haptický pohledový objem, který určuje, jak se bude mapovat posun zařízení po pracovní ploše na grafické vykreslení. V C++ knihovně existuje funkce hluFitWorkspace(), která nám srovnání provede. Jako parametr bere matici MODEL_VIEW. V JTouchToolkitu není implementována, proto si ji musíme doplnit sami, nebo ručně určit mapovaní mezi prostory.
17
Kapitola 7
Vlákna Programovací jazyk Java umožňuje multithreading, neboli souběžný běh dvou nebo více výpočtů v programu. Vlákno je název pro každou paralelně běžící část programu a v Javě se nazývá Thread. Každé vlákno lze naprogramovat nezávisle, pouze v případě, kdy různá vlákna přistupují ke společným prostředkům, se musí provést jejich řádná synchronizace. Nejedná se fyzicky o současný běh vláken, ale o jejich rychlé střídání. Vlákna se o procesor dělí podle pravidel, která určuje plánovač. Vlákna lze vytvořit dvěma způsoby. Implementací rozhraní Runnable, nebo rozšířením třídy Thread.
7.1
Implementace rozhraní Runnable
Jeden ze způsobů implementace vlákna. Vytvoříme třídu implementující rozhraní Runnable a přetížíme metodu run(). Je to jediná metoda, která musí být implementována. Uvnitř těla metody se potom nachází logika vlákna. Proces vytvoření vlákna tímto způsobem je následující: –
Třída implementující Runnable poskytuje vláknu svou metodu run()
–
Vlákno je vytvořeno konstruktorem třídy Thread, kterému je předána instance naší třídy implementující Runnable
–
Metoda start() třídy Thread je automaticky volána při vytvoření instance
–
Život vlákna končí po dokončení metody run() nebo vyhozením nezachycené vyjímky
Tento způsob definování vlákna je užitečný v případě, že [7]: –
program bude potřebovat pouze jedno další vlákno (kromě hlavního programu). Je tedy zbytečné vytvářet kvůli jediné instanci vlákna novou třídu
–
daná třída je potomkem nějaké třídy (případ appletu) a potřebuje mít vlastnosti vlákna 18
7. Vlákna
7.2
Rozšíření třídy Thread
Každá instance rozšiřující třídy je potomkem třídy Thread. Postup vytvoření je takový, že ve třídě přetížíme metodu run(), tím vytvoříme tělo vlákna. Metoda start(), zděděná z rodičovské třídy Thread, zajišťuje spuštění vytvořeného vlákna. Nejdůležitější metody třídy thread jsou[7]: –
Veřejné konstruktory s následujícími parametry ∗ ∗ ∗
r - reference na objekt implementující metodu run() s - řetězec reprezentující jméno vlákna g - skupina, do které bude vlákno zařazeno
–
public static Thread currentThread() - vrací referenci na právě běžící vlákno
–
public String getName() - vrací jméno vlákna
–
public int getPriority() - vrací prioritu vlákna
–
public void join() - čeká na ukončení vlákna
–
public void resume() - probudí vlákno „odstavené“ metodou suspend()
–
public void run() - jádro vlákna (def. jako prázdná metoda)
–
public void start() - zahájí běh vlákna, tj. provádění metody run()
–
public static void sleep(long ms) - uspí (dočasně zastaví) vlákno na počet milisekund, poté jej probudí a vlákno může pokračovat v běhu
–
public setPriority(int priorita) - nastaví prioritu vlákna
–
public void stop() - ukončí vlákno
–
public void suspend() - odstaví vlákno. Odstavené vlákno může probudit pouze metoda resume()
–
public static void yield() - umožní běh jiného vlákna
Pokud nějaká třída rozšiřuje třídu Thread, tak nemůže rozšířit další třídu, zatímco implementováním Runnable tuto možnost neztrácíme[9].
19
Kapitola 8
Implementace aplikace Aplikace pro 3D symetrické modelování byla navržena a naprogramována v jazyce Java. Program je rozčleněn do čtyř hlavních částí. Tyto části se nacházejí v balících sculpting.demo, sculpting.resources, sculpting.struscture.haptics, sculpting.structure.other. V následujících podkapitolách stručně popíši implementace jednotlivých tříd.
8.1
Balík sculpting.demo
V tomto balíku se nachází třídy představující hlavní logiku programu. Nalezneme zde spustitelnou třídu MainFrame, ve které se vytváří OpenGL profil, GLCapabilities 1 , GLCanvas a jemu přiřazený příslušný OpenGlListener. Aby bylo možné zpřístupnit stereo zobrazení musíme při vytváření postupovat následovně. Objektu GLCapabilities nastavit vlastnost setStereo(true). Vytvořit objekt typu 1 2 3
GraphicsDevice device = Gr ap h i cs E n vi r o nm e n t . g e t L o c a l G r a p h i c s E n v i r o n m e n t () . g e t D e f a u l t S c r e e n D e v i c e () ;
a poté vytvářet glCanvas 1 2 3
glCanvas = new GLCanvas ( glCapabilities , new D e f a u l t G L C a p a b i l i t i e s C h o o s e r () , null , device ) ; add ( glCanvas ) ;
8.1.1 OpenGLListener Třída implementující rozhraní GLEventListener. V této třídě se nachází hlavní tělo programu. Najdeme zde metodu pro inicializaci OpenGL a haptického zařízení, metodu pro překreslování scény a renderování haptických objektů. Třída obsahuje čtyři hlavní metody, převzaté z implementovaného rozhraní. 1.
GLCapabilities popisuje některé speciální vlastnosti, které nabízí OpenGL rendering
20
8. Implementace aplikace Metoda init(GLAutodrawable glad) Je volána ihned po vytvoření OpenGL kontextu ve třídě MainWindow, nachází se zde základní nastavení scény a vykreslování, vytvoření tlačítek (třída HButton bude popsána v podkapitole níže), instanciování třídy ObjFactory, která slouží k načtení modelu a vytvoření pomocné třídy zvýrazňující body – Highlighter. Na konci metody init() jsou volány dvě metody genLists(gl) a initHL(). Metoda initHL() je popsána v kapitole Programování haptické aplikace za pomocí knihovny JTouchToolkit. Metoda dispose(GLAutodrawable glad) Uvnitř metody dispose(GLAutodrawable glad) se volá jediná metoda disposeHapticHandler(), která slouží pro odregistrování zpětných volání a odebrání id tvarů haptických objektů. Metoda reshape(GLAutodrawable glad) Tato je volána při změně velikosti okna programu. Nachází se zde synchronizace haptické a grafické scény voláním metod hlWorkspace() a hlOrtho(), které se nacházejí v balíku HLAPI, s příslušnými parametry. Metoda display(GLAutodrawable glad) Metoda display(GLAutodrawable glad) je v OpenGL volána pokaždé, když se má překreslit grafická scéna. Zajišťuje renderování jak grafické (volání renderGL()), tak haptické (volání renderHL()). Umožňuje také zapnout či vypnout stereoskopické zobrazení a vypadá následovně: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
if ( showStereo ) { gl . glDrawBuffer ( GL2 . GL_BACK_LEFT ) ; gl . glClear ( GL2 . G L_ C O LO R _ BU F F ER _ B IT | GL2 . G L _D E P TH _ B UF F E R_ B I T ) ; gl . glPushMatrix () ; pseudoStereo ( gl , -0.31 f ) ; renderGL ( gl ) ; gl . glFlush () ; gl . glPopMatrix () ; gl . glDrawBuffer ( GL2 . GL_BACK_RIGHT ) ; gl . glClear ( GL2 . G L_ C O LO R _ BU F F ER _ B IT | GL2 . G L _D E P TH _ B UF F E R_ B I T ) ; gl . glPushMatrix () ; pseudoStereo ( gl , 0.31 f ) ; renderGL ( gl ) ; gl . glFlush () ;
21
8. Implementace aplikace 17 18 19 20 21 22 23 24 25 26 27 28
gl . glPopMatrix () ; } else { gl . glDrawBuffer ( GL2 . GL_BACK ) ; gl . glClear ( GL2 . G L_ C O LO R _ BU F F ER _ B IT | GL2 . G L _D E P TH _ B UF F E R_ B I T ) ; gl . glPushMatrix () ; renderGL ( gl ) ; gl . glPopMatrix () ; } gl . glPopMatrix () ; renderHL ( gl ) ; glDrawable . swapBuffers () ;
Důležitý je poslední řádek. Metoda swapBuffers() zajistí přepnutí vykreslování levého, nebo pravého zadního bufferu, a tím docílíme stereoskopického efektu. U metody pro vykreslení scény renderGL() bych se zastavil pouze u výpočtu symetrických bodů a u volby funkce pro vyhlazení ovlivněných bodů meshe. K nalezení symetrických bodů slouží instance třídy SymetryMaker, která bude popsána níže. Třída vrací seznam symetrických vrcholů, které jsou poté použity jako argument metody pro hledání nejbližších sousedů v KD-Stromu. Dále se volá metoda highlightPoint(double[] position) třídy Highlighter, aby se zvýraznily vybrané body, a pro uživatele bylo jednodušší rozeznat ovlivňovanou plochu. Pokud se uživatel nachází v módu editace, zavolá se příslušná metoda odpovídající vybranému nástroji. Jedna ze dvou metod pullPoints(List vertices, HVertex pivot, double weight), nebo flattenPoints(List vertices, HVertex pivot). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
SymmetryMaker maker = new SymmetryMaker ( angleOfSymmetry , axis ) ; Point3D p = new Point3D ( proxyPosition ) ; List < Point3D > rotatedPoints = maker . g e t S y m m e t r i c a l P o i n t s ( p ) ; for ( Point3D rotPoint : rotatedPoints ) { List < HVertex > ne arestN eighb ours = tree . nearest ( rotPoint . g e t P o s i t i o n I n D o u b l e s () , ( int ) toolRadius ) ; HVertex pivotVertex = tree . nearest ( rotPoint . g e t P o s i t i o n I n D o u b l e s () ) ; Point3D pivot = new Point3D ( pivotVertex ) ; for ( HVertex v : neares tNeigh bours ) { Point3D p2 = new Point3D ( v ) ; if ( pivot . distanceTo ( p2 ) < 2.0) { highlighter . highlightPoint ( v . getPosition () ) ; } } if ( editableMode ) { switch ( activeTool ) { case PULL : pullPoints ( nearestNeighbours , pivot , 3.0) ; break ; case FLATTEN :
22
8. Implementace aplikace flattenPoints ( nearestNeighbours , pivotVertex ) ; break ;
22 23 24 25 26
} } } editableMode = false ;
Další část metody display() zajišťuje vykreslení kurzoru. Jeho pozice a rotace v prostoru je nastavena na odpovídající pozici ramene PHANToMu. Pozice je získána voláním metody hlGetDoublev(HLAPI.HL_PROXY_TRANSFORM). 1 2 3 4 5 6 7
gl . glMultMatrixd ( proxyTransform , 0) ; gl . glEnable ( GL2 . GL _COLOR _MATE RIAL ) ; gl . glColor3f (0.75 f , 0.0 f , 0.25 f ) ; glut . gl utSoli dCylin der (0.05 , 2.5 , 15 , 1) ; glut . glutSolidSphere ( toolRadius /10.0 f , 32 , 32) ; gl . glColor3f (0.99 f , 0.99 f , 0.99 f ) ; gl . glDisable ( GL2 . GL _COLOR _MATE RIAL ) ;
Metoda pullPoints(List vertices, Point3D pivot, double weight) Metoda pullPoints(List vertices, Point3D pivot, double weight) bere jako argumenty seznam vrcholů, vedoucí vrchol (pivot) a váhu účinku nástroje. Spočítá si vzdálenosti všech bodů od pivotu a určí si největší vzdálenost (pro pozdější porovnávání). Pro každý bod v seznamu se určí váha resp. vzdálenost, o kterou se má posunout po přímce, tvořící spojnici mezi středem a vyhodnocovaným bodem. Tento bod se nejdříve smaže z KD-Stromu, provede se jeho transformace v meshi, a poté je do KD-Stromu vložen nový posunutý bod, aby bylo zajištěno jeho správné nalezení v prostoru. Váha je dopočítána pomocí metody computeWeight(double oldWeight, double distance, double maxDistance, Functions func). Metoda computeWeight(double oldWeight, double distance, double maxDistance, Functions func) Argumenty metody computeWeight(double oldWeight, double distance, double maxDistance, Functions func) jsou váha, vzdálenost, maximální vzdálenost a vybraná funkce. Metoda vrací novou přepočítanou váhu. Počítá ji podle zvolené funkce. Uživatel má možnost vybrat si ze tří základních funkcí pro vyhlazování ovlivněných bodů. Maximum, lineární a Gaussovu funkci. Jejich přepočet zajišťují příslušné metody. Maximum je triviální, všechny body jsou ovlivněny stejnou vahou, bez 23
8. Implementace aplikace ohledu na jejich relativní vzdálenost od pivota. Lineární funkce je počítána podle následujícího vzorce 𝑤 − ((𝑤 * 𝑑)/𝑑𝑚 ), kde 𝑤 je váha, 𝑑 je vzdálenost od pivota a 𝑑𝑚 je maximální rozsah působení. Poslední funkce je na výpočet poněkud složitější. Je odvozena ze vzorce 2D Gaussova vyhlazení. )︃)︃ (︃ (︃ (𝑥 − 𝑥𝑜 )2 (𝑦 − 𝑦𝑜 )2 𝑓 (𝑥, 𝑦) = 𝐴 exp − + 2𝜎𝑥2 2𝜎𝑦2 Pokud položíme 𝜎𝑥2 ≡ 𝜎𝑦2 a dosadíme za (𝑥 − 𝑥𝑜 )2 + (𝑦 − 𝑦𝑜 )2 = 𝑑𝑖𝑠𝑡𝑎𝑛𝑐𝑒2 je možné vzorec zjednodušit na (︃
(︃
𝑑𝑖𝑠𝑡𝑎𝑛𝑐𝑒2 𝑓 (𝑥, 𝑦) = 𝑤𝑒𝑖𝑔ℎ𝑡 exp − 4𝑚𝑎𝑥𝐷𝑖𝑠𝑡𝑎𝑛𝑐𝑒2
)︃)︃
Metoda flattenPoints(List vertices, HVertex pivot) Podobně jako předchozí metoda si i metoda flattenPoints() bere jako vstupní argumenty seznam ovlivněných bodů a vedoucí bod pivot. Metoda zjišťuje průměrnou vzdálenost každého bodu od středu koule. Tuto vzdálenost odečte od vzdálenosti pivotu. Pivot je poté posunut po přímce, tvořící spojnici mezi středem a pivotem, na novou pozici. Pivotem je následně proložena rovina, jejíž normála je shodná s normálou pivotu. Poté, co je určena rovina, jsou ostatní body do této roviny promítnuty. Projekce bodu do roviny je definována vztahem: 𝑝′ = 𝑝 − ([𝑝 − 𝑞] · ⃗𝑛) · ⃗𝑛 Tímto docílíme zarovnání bodů podle průměrné vzdálenosti od středu koule.
8.2
Balík sculpting.structure.other
V tomto balíku se nachází veškeré pomocné třídy. Jedná se o třídy, které buď slouží jako pomocné struktury při výpočtech, a nebo plní jinou funkci v aplikaci (zobrazují body apod.) 8.2.1 Třída Highlighter Tato třída slouží pro vykreslení (zvýraznění) bodů. V jejím konstruktoru je nastaven poloměr bodu a jeho barva. Po zavolání metody highlightPoint(double[] position) je vykreslena koule s určeným poloměrem na dané pozici. 24
8. Implementace aplikace 8.2.2 Třída ObjFactory Slouží k zpracování obj formátu. ObjFactory dokáže načíst a přečíst vstupní soubor a zapsat načítaný objekt do struktury okřídlené hrany, vytvoří mesh a zároveň KDStrom s pozicemi vrcholů. Dále slouží k uložení modifikovaného modelu a jeho zápisu do souboru. Metoda load() Metoda load() čte vstupní soubor a pokaždé, když narazí na požadovaný symbol, provede parsování načtené řádky. Při přečtení znaku o vytvoří instanci třídy HMesh a přiřadí jí jméno načítaného souboru. Podobně pracuje při přečtení řetězce v, vn a f. Pokaždé vytvoří příslušné objekty a nastaví jim potřebné parsované parametry. Jediná změna je při načítání plošek, protože plošky jsou ve formátu Obj uloženy jako indexy do pole vrcholů a normál. Proto si třída při načítání udržuje seznamy vrcholů a normál. Příslušné vrcholy a normály si poté zaznamená do okřídlené hrany. Při načtení jedné plošky se zároveň vytváří tři nové hrany metodou connectEdges(int indexOfVertexInFace). Iniciální hrana je nastavena jako vycházející hrana právě vytvořené plošky. Metoda write(HMesh meshToWrite) Po zavolání metody write(HMesh meshToWrite) se vytvoří nové zapisující vlákno a jako parametr je mu předána kopie meshe, kterou má zapsat. Zároveň takto vytvořené vlákno spustí. 8.2.3 Třída WritingThread(HMesh meshToWrite) Slouží jako zapisovací vlákno. Zapisování bylo přesunuto do nového vlákna z důvodu zrychlení aplikace. WrithingThread rozšiřuje třídu Thread a kromě konstruktoru s jediným parametrem zapisované meshe, implementuje pouze metodu run(). V metodě run() je hlavní logika vlákna. Po zavolání je vytvořen nový soubor s příponou .obj a názvem předané meshe. Metoda si postupně přidává informace do proměnné typu StringBuffer (kvůli zrychlení zápisu) a poté je zapíše pomocí třídy BufferedWriter do vytvořeného souboru. Načítání probíhá postupně, první jsou načteny a zapsány vrcholy, poté metoda prochází všechny vrcholy a bere si z nich informace o normálách. Než normálu zapíše, zkontroluje, jestli již tato normála není zapsána. Pokud není, přidá normálu do řetězce a poznamená si ji do seznamu již zapsaných normál. Následuje zápis plošek. Tato část zabere, hned po samotném ukládání do souboru, nejvíce času. Iteruje se přes všechny plošky v meshi. Pro každou plošku je uchován seznam vrcholů, které obsahuje. Ploška v okřídlené hraně si 25
8. Implementace aplikace však nepamatuje své vrcholy, musí se zavolat její metoda pro nalezení smyčky hran. Tato smyčka je poté procházena a do seznamu vrcholů jsou nahrány vrcholy z hran (počáteční a cílový vrchol). Jsou však testovány, zda se již v seznamu nenachází. Důvodem, proč není použita množina místo seznamu, je samotný formát zápisu plošky, kdy se nezapisují vrcholy, ale jejich indexy. Testování by teoreticky nemuselo být prováděno, ale zmenšíme tím objem zapisovaných dat. Poté už stačí projít seznam právě nalezených bodů a otestovat, zda je normála aktuálního bodu totožná s normálou v seznamu. Pokud ano, tak je do výsledného řetězce zaznamenán index aktuálního vrcholu, řetězec //, za ním následuje index normály a mezera. Tento cyklus by měl být proveden třikrát. Poněvadž načítaný model byl již triangualizován. Metoda run() vypisuje uživateli do konzole kontrolní hlášky, aby věděl, v jakém stavu se zapisovací vlákno právě nachází. 8.2.4 Třída Point3D Struktura Point3D slouží pro početní operace prováděné s body v trojrozměrném prostoru. Nejsou implementovány všechny, ale pouze výpočty využité v programu. Z nejvíce využitých operací bych uvedl snad jen výpočet vzdálenosti dvou bodů v prostoru a určení směru z bodu A do bodu B. 8.2.5 Třída Vector3D Podobně jako Point3D i tato třída slouží jako početní třída při matematických operacích v programu. Vector3D umí vypočítat skalární a vektorový součin, normalizaci a délku vektoru. Umožňuje také násobení skalárem. Ostatní operace je, v případě potřeby, doplnit. Ve vyvíjené aplikaci však nebyly zatím zapotřebí. 8.2.6 Třída SymmetryMaker SymmetryMaker poskytuje metodu zajišťující rotaci bodu kolem vybrané osy v 3D prostoru. Konstruktorem se instanci předá úhel otočení a příslušná osa. Zároveň se automaticky volá metoda initMatrices(), která si do hashovací tabulky uloží příslušnou rotační matici.
26
8. Implementace aplikace ⎡
⎤
⎡
⎤
⎡
⎤
1 0 0 ⎢ ⎥ A𝑋 = ⎣ 0 cos 𝜑 sin 𝜑 ⎦ 0 − sin 𝜑 cos 𝜑 cos 𝜃 0 − sin 𝜃 ⎢ ⎥ 1 0 A𝑌 = ⎣ 0 ⎦ sin 𝜃 0 cos 𝜃 cos 𝜓 sin 𝜓 0 ⎥ A𝑍 = ⎢ ⎣ − sin 𝜓 cos 𝜓 0 ⎦ 0 0 1 Metoda getSymetricalPoints(Point3D point) vrací seznam rotovaných bodů. Tyto body se dostanou provedením rotace kolem příslušné osy. Rotace je provedena rekurzivně vždy s předchozím bodem.
8.3
Balík sculpting.structure.haptics
Balík sculpting.structure.other obsahuje prvky struktury okřídlená hrana. Nachází se zde třídy HVertex, HEdge, HFace a HMesh. Každá tato třída implementuje rozhraní IHapticsObject. V tomto rozdraní se nachází metody jako genDisplayList(),render() nebo setShapeId(int id). Navíc je do balíku přidána třída HButton, která popisuje haptické tlačítko. 8.3.1 Třída HButton Třída HButton poskytuje, kromě metod z rozhraní IHapticsObject, také metody pro přiřazení textury tlačítka, nastavení jeho pozice a velikosti. Navíc lze volat metodu setActive(boolean), která zajišťuje změnu textury tlačítka z normální na aktivní a naopak.
27
Kapitola 9
Ovládání aplikace Obrazovku tvoří menu s nástroji a funkcemi, model a mřížka pro lepší orientaci. Jednotlivá tlačítka jsou navržena tak, aby uživatel intuitivně poznal, co které tlačítko znamená. Pro případ raději popíši tlačítka a jejich funkce v tabulce. K editaci slouží tlačítko na rameni Phantomu. Po jeho stisknutí se uživatel dostane do módu editace a může modelovat vybrané body. K pohodlnému ovládání je možné použít i klávesnici. Klávesy šipka nahoru a šipka dolů mění průměr použitého nástroje. Šipkami doleva a doprava lze měnit sílu nástroje, tedy vzdálenost, o kterou se modifikované body posunou. Klávesou S lze vypnout stereoskopické zobrazení. Ostatní použité klávesové zkratky jsou popsány taktéž v tabulce. Následující obrázek ukazuje rozvržení aplikace.
Obrázek 9.1: Rozvržení aplikace
28
9. Ovládání aplikace tlačítko název
funkce
klávesová zkratka
výběr úhlu rotace
Otevře menu pro výběr úhlu rotace
–
rotace 45∘
Nastaví úhel na 45∘
–
rotace 60∘
Nastaví úhel na 60∘
–
rotace 90∘
Nastaví úhel na 90∘
–
rotace 180∘
Nastaví úhel na 180∘
–
osa X
Nastavuje osu X jako osu otáčení
X
osa Y
Nastavuje osu Y jako osu otáčení
Y
osa Z
Nastavuje osu Z jako osu otáčení
Z
wireframe
Přepínání zobrazení modelu
W
solid
Přepínání zobrazení modelu
W
nástroj pull
Změna nástroje na nástroj vytažení
P
nástroj flatten
Změna nástroje na nástroj zarovnání
F
výběr vyhlazovací funkce
Otevře menu pro výběr funkce
–
Funkce maximum
Nastavení použité funkce
1
Lineární funkce
Nastavení použité funkce
2
Gaussova funkce
Nastavení použité funkce
3
Export do obj
Uloží model do souboru .obj
Exit
Ukončí aplikaci
SPACE ESC 29
Kapitola 10
Závěr Byla vytvořena aplikace umožňující modelování se silovou zpětnou vazbou za pomoci jednoduchých rotačních symetrií. Aplikace dále nabízí možnost exportu vytvářeného modelu do formátu Obj. Export je oddělen od hlavního běhu programu, čímž je zaručena plynulost práce. Formát Obj byl zvolen pro jeho jednoduchost a přenositelnost. Díky rozšířenosti tohoto formátu je možné exportovaný model dále upravovat v programech, které pracují s 3D daty. Požadavkem bylo implementovat aplikaci v jazyce Java s využitím knihovny JTouchToolkit. Musím konstatovat, že zázemí pro tvorbu haptických aplikací v jazyce Java není příliš velké. Vývoj knihovny JTouchToolkit byl nejspíš pozastaven, poněvadž poslední záznam o upgradu je z roku 2010. Největší překážkou k pochopení knihovny byla absence jednoduchých příkladů a zanedbaná dokumentace. Ke knihovně jsou přiloženy pouze dva příklady, což považuji za nedostatečné. Stálo by za zvážení, zda nevytvořit jednoduché vzorové programy a nebo pomocné metody, které jsou k nalezení v knihovně haptic utility pro jazyk C++. Knihovna haptic utility navíc nabízí funkci hluFitWorkspace(), která slouží ke sjednocení souřadných systémů hatiky a OpenGL. V průběhu vývoje jsme narazili na řadu problémů, které bylo potřeba vyřešit. Mnohé z nich se podařilo odstranit, ale některé zůstaly nedořešeny. Za nejdůležitější považuji zrychlení výpočtu nové pozice bodů a jejich následný rendering a nechtěný viewport, který je možné vidět v rohu obrazovky. Narazili jsme na problém s registrací zpětných volání (dále callback). Docházelo k volání callbacků, které byly přiřazeny jiným haptickým tvarům. Problém se ale podařilo vyřešit. Aplikace nabízí také prostor pro mnohá další vylepšení a implementaci nových funkcí. Bylo by užitečné přidat možnost pohybu ve scéně, vytvořit další nástroje a nebo připojit 3D myš, případně umožnit uživateli uložit data v dalších rozšířených formátech.
30
Literatura [1] ŠUSTR,Vilém. Motivační hra se silovou zpětnou vazbou : bakalářská práce. Brno : Masarykova univerzita, Fakulta informatiky, 2007. 33 l. Vedoucí bakalářské práce doc. Ing. Jiří Sochor, CSc. [2] SENSEABLE TECHNOLOGIES,Inc.OPENHAPTICS® TOOLKIT[online]. c1999, poslední revize 08.01.2009 [cit.2013-12-16] Dostupné z: http:// geomagic.com/files/4013/4851/4367/OpenHaptics_ProgGuide.pdf. [3] ARCHER ,John.Jtouchtoolkit[online]. c2007, poslední revize 10.02.2010 [cit.2013-12-16] Dostupné z: https://java.net/projects/jtouchtoolkit/. [4] ŽÁRA,Jiří.;BENEŠ,Bedřich.;SOCHOR,Jiří.;FELKEL,Petr.; Moderní počítačová grafika : kompletní průvodce metodami 2D a 3D grafiky. 2.vyd. Brno : Computer Press, 2004. 609 s. ISBN 80-251-0454-0. [5] RIESS,Patrick.Stereo Basics [online]. c2007, poslední revize 23.10.2007[cit.201312-16] Dostupné z: http://doc.instantreality.org/tutorial/ stereo-basics/. [6] DAVISON,Dr. Andrew.JOGL Chapter 4. Stereo Viewing [online]. c2007, poslední revize 21.06.2007[cit.2013-12-16] Dostupné z: http://fivedots.coe. psu.ac.th/~ad/jg2/jogl4/jogl4.pdf. [7] TOMAN,Petr.;KATOLA,Zdeněk.;Vlákna [online]. c2001, poslední revize 04.02.2001[cit.2013-12-16] Dostupné z: http://v1.dione.zcu.cz/java/ sbornik/16.html. [8] LAUBR,Daniel . Stereoskopická projekce : diplomová práce. Praha : České vysoké učení technické v Praze, Fakulta elektrotechnická, 2001. 61 l. Vedoucí diplomové práce Ing. Roman Berka Ph.D. [9] Java Threads Tutorial [online]. c2007, poslední revize 15.05.2007[cit.201312-16] Dostupné z: http://www.javabeginner.com/learn-java/ java-threads-tutorial. [10] REDDY,Martin.Object Files [online]. [cit.2013-12-16] Dostupné z: http:// www.martinreddy.net/gfx/3d/OBJ.spec. [11] .http://cf.mp-cdn.net/[online]. [cit.2013-12-16] Dostupné z: http://cf. mp-cdn.net/08/f7/f81b0d3cdb51f4251e3d6c46e3dd.jpg. [12] 3dcgi [online]. [cit.2013-12-16] cooltech/displays/2a-med.jpg.
Dostupné
z:
http://www.3dcgi.com/
31
[13] nvidia [online]. [cit.2013-12-16] Dostupné z: http://www.nvidia.com/. [14] LAUBR,Daniel. Stereoskopická projekce: diplomová práce.Praha : České vysoké učení technické, Fakulta elektrotechnická, 2006. 61 l. Vedoucí diplomové práce Ing. Roman Berka Ph.D. [15] HOLMES,Ryan.The DCEL Data Structure for 3D Graphics [online]. [cit.201312-16] Dostupné z: http://www.holmes3d.net/graphics/dcel/. [16] VITULLI,Damiano.THE 3DS FILE STRUCTURE [online]. c2011, poslední revize 02.12.2013 [cit.2013-12-16] Dostupné z: http://www.spacesimulator. net/wiki/index.php?title=Tutorials:3ds_Loader. [17] AUTODESK,Inc.FBX [online]. [cit.2013-12-16] Dostupné z: http://www. autodesk.com/products/fbx/overview.
32
10.1 Seznam použitých knihoven JTouchToolkit Rozsáhlé API pro jazyk Java. Dostupné z https://java.net/projects/jtouchtoolkit/downloads>. Knihovna kd.jar Implementace datové struktury KD-Stromu a operací nad ní. Dostupné z http://home.wlu.edu/~levys/software/kd/>. JOGL Knihovna OpenGL pro jazyk Java. Dostupné z http://jogamp.org/wiki/index.php/Downloading_and_installing_ JOGL>.
33
Příloha A
Obsah přiloženého CD Součástí této práce je také disk CD. Obsahuje –
zdrojový kód bakalářské práce ve formátu LATEX a hotovou práci ve formátu pdf,
–
zdrojové kódy programu včetně knihovny JTouchToolkit a kd.jar,
–
sadu knihoven JOGL,
–
zkompilovanou verzi programu Modelování pro 32b systém Windows
34