Java a 3D grafika – graf scény
V předchozím článku jsme si ukázali, jak se s pomocí Java 3D API vytváří jednoduchá scéna. V tomto článku se podíváme podrobněji na problematiku grafu scény. Ukážeme si, jak jej zakreslovat a seznámíme se s bázovými třídami většiny objektů objevujících se ve scéně.
Jak zakreslovat graf scény
Jak známo, dokáže občas jeden obrázek osvětlit určitou problematiku daleko lépe než několik desítek řádků textu a v případě grafu scény to platí dvojnásob. Jen si zkuste představit, jak slovy popisujete následující jednoduchý graf:
A to obsahuje pouze tři barevné krychle (ColorCube), z nichž dvě jsou transformovány jedním společným objektem TransformGroup, z čehož jedna je transformována ještě dalším objektem TransformGroup, a třetí je transformována jinými dvěma objekty TransformGroup.
A teď popravdě. Čemu jste rozuměli lépe? Obrázku, přestože jste v něm neznali nejméně polovinu použitých symbolů, nebo předcházejícímu zmatenému textu? A co teprve, kdybyste v obrázku význam všech symbolů znali? Myslím si, že obrázek vyhrává.
Nyní si pojďme vysvětlit význam použitých symbolů. Následující obrázek je všechny shrnuje. (Tento způsob zápisu je převzat z oficiálního tutoriálu.)
Se třídami VirtualUniverse a Locale jsme se seznámili již minule. Teď je na čase vysvětlit si, k čemu slouží ty zbývající. Instance tříd odvozených od první z nich, třídy Group, mají v grafu, řečeno slovy klasické terminologie pro popis stromů, roli uzlů, tzn. mohou mít pouze jednoho rodiče a neomezeně potomků.
Třída Leaf je nadtřídou pro třídy, jejichž instance jsou v daném stromu listy, což znamená, že už nemají žádné další potomky. Příkladem může být třída ColorCube, se kterou jsme se seznámili v minulém článku a se kterou pracujeme i dnes.
Možná vás nyní napadá otázka, proč jsou v ukázkovém grafu objekty ColorCube zobrazeny jako obdélníky a ne jako trojúhelníky, což by podle výše uvedeného bylo jistě správnější. Inu, tady zase jednou zvítězil pragmatismus nad přesným vyjadřováním. On totiž trojúhelník není právě nejvhodnější pro zápis delšího textu. Z toho důvodu, pokud nás bude v budoucnu zajímat u nějakého objektu v grafu jeho přesný název, zobrazíme jej jako obdélník.
Předposlední ze symbolů v tabulce, ovál, označuje instance tříd, které jsou odvozeny od třídy NodeComponent. Podtřídami třídy NodeComponent jsou například třídy Appearance a Geometry, se kterými se blíže seznámíme v některém z dalších článků této série. Prozatím snad postačí, když si řekneme, že třídy odvozené od této třídy nejsou formálně přímo součástí stromu, protože na ně odkazují objekty listů (Leaf), což by jinak nebylo možné (list přece nemůže mít potomky), nejedná se tedy formálně o vztah potomek-rodič.
Žijící a zkompilované objekty
Vložíme-li objekt BranchGroup do objektu Locale, stanou se tento objekt a objekty v něm obsažené takzvaně živými. To znamená, že kvůli výkonu bude graf scény převeden do výhodnější podoby, což s sebou nevýhodu v tom, že již nebudeme moci nadále přidávat objekty do objektů Group nebo měnit transformační matici v objektech TransformGroup.
Pochopitelně jsou však situace, kdy scénu chceme měnit i nadále – ať už potřebujeme animovat existující objekty nebo přidávat nové. Pak musíme nějak označit ty části scény, které se budou měnit. K tomu slouží metody void setCapability(int bit)
, void clearCapability(int bit)
a boolean getCapability(int bit)
. Parametr bit typu int, předávaný všem těmto metodám, nese bitový příznak určující, co je s daným objektem (respektive jeho potomky), možné dělat. Metoda setCapability(int bit) „zapíná“ tento příznak, metoda clearCapability(int bit) tento příznak vypíná a konečně metoda getCapability(int bit) vrací true, pokud je daný příznak nastavený.
Například ve třídě Group jsou definovány mimo jiné následující příznaky: ALLOW_CHILDREN_EXTEND
dovolující přidávat další objekty do daného objektu Group, ALLOW_CHILDREN_READ
dovolující přistupovat k potomkům daného objektu a ALLOW_CHILDREN_WRITE
umožňující upravovat odkazy na potomky tohoto objektu. Ve třídě TransformGroup jsou pak definovány další příznaky: ALLOW_TRANSFORM_READ
dovolující přistupovat k transformační matici a potažmo i jejím jednotlivým složkám (rotace, posunutí) a ALLOW_TRANSFORM_WRITE
umožňující měnit transformaci, což je nezbytné například pro animování. Kromě již zmíněných příznaků však existují i další, s nimiž se setkáme v některém z dalších článků.
Sice je možné renderovat i scénu, která je pouze žijící, ale pokud chcete větší rychlost, je potřeba objekty BranchGroup ve scéně ještě navíc „zkompilovat“. K tomu slouží metoda compile()
, jejíž volání způsobí další změny v interní reprezentaci scény. Její používání je navýsost užitečné a neexistuje prakticky žádný důvod, proč ji ignorovat.
Malý příklad
Nyní si na krátkém příkladu ukážeme použití toho, co jsme se dnes naučili. Výsledek nebude nijak oslňující, půjde o další variaci na téma barevné krychle. Nejprve vytvoříme scénu s barevnou krychlí, jejímž rodičem bude objekt TransformGroup, pak ji zkompilujeme a teprve až potom ji budeme transformovat úpravou objektu TransformGroup, což znamená, že se nevyhneme použití metody setCapability(int bit), což je v podstatě hlavním účelem tohoto příkladu. Celou scénu si pro procvičení rovněž zakreslíme.
Zde následuje zdrojový kód příkladu:
package interval.j3d;
import java.awt.*;
import javax.swing.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import javax.media.j3d.*;
import javax.vecmath.*;
public class Capabilities extends JFrame{
TransformGroup tg;
public Capabilities() {
super(„Ukázka použití setCapability()“);
//Na následujících řádcích vytvoříme Canvas3D
Container pane = getContentPane();
pane.setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas = new Canvas3D(config, false);
pane.add(„Center“, canvas);
//vytvoříme objekt SimpleUniverse
SimpleUniverse universe = new SimpleUniverse(canvas);
//nastavíme vzdálenost pozorovatele od monitoru na 2m
universe.getViewingPlatform().setNominalViewingTransform();
//přidáme BranchGroup vytvořený v metodě vytvorBranchGroup()
//do objektu SimpleUniverse
universe.addBranchGraph(vytvorBranchGroup());
//upravíme transformaci v objektu TransformGroup tg,
//který je již součástí grafu scény, což by nebylo možné,
//kdybychom v metodě vytvorBranchGroup nevolali
//metodu setCapability s parametrem ALLOW_TRANSFORM_GROUP
tg.setTransform(vytvorTransform());
addWindowListener(new java.awt.event.WindowAdapter() {
 public void windowClosing(java.awt.event.WindowEvent evt) {
System.exit(0);
}
});
}
protected BranchGroup vytvorBranchGroup(){
//kořen této části scény
BranchGroup bg = new BranchGroup();
//tento objekt upravujeme až dále v konstruktoru
tg = new TransformGroup();
//nastavíme, že chceme nadále měnit transformační matici
//tohoto objektu
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
//přidáme objekt TransformGroup tg jako potomka
//do objektu bg
bg.addChild(tg);
//vložíme ještě barevnou krychli jako potomka zmíněného
//objektu TransformGroup tg
tg.addChild(new ColorCube(0.3));
//zkompilujeme scénu
bg.compile();
return bg;
}
protected Transform3D vytvorTransform(){
Transform3D tr1 = new Transform3D();
//nastavíme úhel otočení na 30°
tr1.rotX(Math.PI/6);
//vytvoříme druhou transformační matici
Transform3D tr2 = new Transform3D();
//nastavíme úhel otočení na 60°
tr2.rotY(-Math.PI/3);
//vynásobíme spolu matice
tr2.mul(tr1);
return tr2;
}
public static void main(String[] args){
new Capabilities().show();
 }
}
Na tomto příkladu sice není užitečnost popsaných technik příliš zřetelná, až se ale budeme zabývat animováním objektů, neobejdeme se bez nich. Následující obrázek je výsledkem použití předcházejícího kódu:
Příště se seznámíme s třídami pro tvorbu geometrických primitiv a ukážeme si, jak upravovat jejich vzhled (barvu a další vlastnosti) pomocí objektů Appearance.
Mohlo by vás také zajímat
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024