Java a 3D grafika – Geometry (PointArray, LineArray a TriangleArray)
V tomto článku se začneme zabývat vytvářením objektů prostřednictvím instancí třídy Shape3D. Ukážeme si, jak pomocí úseček vytvořit drátový model krychle, a pak si povíme, jak se dají pomocí trojúhelníků vytvářet tělesa se stěnami.
Než se pustíte do čtení tohoto článku, doporučuji vám oživit si povědomí o tom, jaké objekty se objevují v grafu scény, jaké podmínky musí graf scény splňovat a k čemu jsou dobré objekty Appearance, prostřednictvím článku Java a 3D grafika – graf scény.
Pro vytváření trojrozměrných objektů se používají objekty Shape3D, které mohou odkazovat na instance podtříd abstraktní třídy Geometry a na objekty Appearance. (Jeden objekt Shape3D může odkazovat i na několik objektů Geometry, ale ty musí být stejného typu.) Tyto objekty se jim přiřazují buď přímo v konstruktoru Shape3D(Geometry geometry, Appearance appearance)
, nebo pomocí metod setGeometry(Geometry geometry)
a setAppearance(Appearance appearance)
.
Objekty Geometry obsahují vlastní data objektů, tedy souřadnice vrcholů, normálové vektory, barvy vrcholů a souřadnice sloužící k otexturování. V objektech Appearance pak jsou uloženy informace o materiálu, šířce čar, tloušťce bodů, o tom, zda se má nebo nemá použít antialiasing a tak dále. Podrobněji jsme se ale třídě Appearance věnovali v článku o grafických primitivech, takže na tomto místě snad postačí jen tato krátká zmínka.
Třída GeometryArray a její potomci
Vzhledem k tomu, že tříd odvozených od třídy Geometry je poměrně dost, rozložíme si povídání o nich do několika článků. V tomto článku začneme několika potomky třídy GeometryArray, konkrétně třídami PointArray, LineArray a TriangleArray.
Jednodušší verze konstruktorů všech čtyř zmíněných tříd přebírají pouze dva parametry – počet vrcholů a jejich „formát“, tedy bitové příznaky říkající, co přesně bude v daném objektu Geometry uloženo. Příznaky definované ve třídě GeometryArray jsou COORDINATES
pro souřadnice, NORMALS
pro normálové vektory, COLOR_3
pro barvu bez alfa-transparence, COLOR_4
pro barvu s alfa-transparencí, TEXTURE_COORDINATES_2
, TEXTURE_COORDINATES_3
a TEXTURE_COORDINATES_4
pro souřadnice textur. Tak například budeme-li chtít vytvořit instanci třídy PointArray obsahující čtyři barevné body, bude volání konstruktoru vypadat takto: PointArray(4, GeometryArray.COORDINATES | GeometryArray.COLOR_3);
.
Máme-li už objekt GeometryArray vytvořený, musíme do něho vložit potřebná data. Následují metody sloužící pro nastavení souřadnic vrcholů:
- public void setCoordinates(int index, float[] coordinates)
- public void setCoordinates(int index, double[] coordinates)
- public void setCoordinates(int index, Point3f[] coordinates)
- public void setCoordinates(int index, Point3d[] coordinates)
V poli „coordinates“ jsou uloženy souřadnice vrcholů. Parametr „index“ označuje pozici v poli „coordinates“, kde se souřadnice nacházejí. Metody pro nastavení barev, normálových vektorů a souřadnic textur jsou velice podobné a postupně se k nim dostaneme alespoň v příkladech.
Třída LineArray
Nyní už toho víme dost na to, abychom mohli s využitím třídy LineArray, která je určena k vytváření těles z úseček, vytvořit jednoduchou třídu odvozenou od třídy Shape3D sloužící k vytváření drátových krychlí. Její kód následuje:
package interval.j3d;
import javax.media.j3d.*;
public class DratovaKrychle extends Shape3D {
float souradnice[] =
//souřadnice bodů, vždy dva body pro úsečku
{-1,-1,1, -1,1,1, -1,1,1, 1,1,1,
1,1,1, 1,-1,1, 1,-1,1, -1,-1,1,
-1,-1,-1, -1,1,-1, -1,1,-1, 1,1,-1,
1,1,-1, 1,-1,-1, 1,-1,-1, -1,-1,-1,
-1,-1,1, -1,-1,-1, -1,1,1, -1,1,-1,
1,1,1, 1,1,-1, 1,-1,1, 1,-1,-1};
public DratovaKrychle(float hrana) {
//nastavíme velikost hran
for (int i = 0; i < 72; i++)
souradnice[i] *= hrana/2f;
setGeometry(vytvorGeometry());
setAppearance(vytvorAppearance());
}
Geometry vytvorGeometry(){
//vytvoříme instanci třídy LineArray
LineArray lineArray = new LineArray(24, GeometryArray.COORDINATES);
//nastavíme souřadnice
lineArray.setCoordinates(0, souradnice);
return lineArray;
}
Appearance vytvorAppearance(){
Appearance app = new Appearance();
//nastavíme tloušťku čáry na 3 pixely, povolíme antialiasing
LineAttributes la = new LineAttributes(3, LineAttributes.PATTERN_SOLID, true);
app.setLineAttributes(la);
return app;
}
}
Jak můžete sami vidět, je kód této třídy velice jednoduchý. Pouze v konstruktoru vytváří objekt Geometry, do kterého vloží souřadnice zadané v poli „souradnice“, které ještě předtím vynásobí parametrem „hrana/2“, abychom mohli vytvářet krychle různých velikostí. Toto je výsledek:
Použití této třídy a také dalších tříd v tomto článku, kromě třídy PointArray, je mnohdy dost neúsporné z hlediska nároků na paměť – například souřadnice každého z vrcholů krychle v příkladu ukládáme třikrát. Řešením mohou být podtřídy, buď třídy GeometryStripArray nebo třídy IndexedGeometryArray. O tom ale až jindy.
Třída PointArray
Třída PointArray nám umožňuje zobrazovat jednotlivé vrcholy. Ve spojení s ní se hodí využít možnosti nastavení tloušťky bodů prostřednictvím třídy PointAttributes, jejíž instance se připojují k příslušným objektům Appearance. Konstruktor PointAttributes(float pointSize, boolean antialiasing)
přebírá dva parametry. Parametr „pointSize“ určuje tloušťku bodů a parametr „antialiasing“ určuje, jestli se má použít antialiasing.
Třídu PointArray využijeme k vylepšení předchozího příkladu tím, že do každého vrcholu krychle nakreslíme bod zadané tloušťky. Naše nová třída však nebude rozšiřovat třídu Shape3D, ale bude odvozena od třídy Group (kvůli nemožnosti vkládat do objektů Shape3D objekty Geometry různého typu, v tomto případě tedy instance tříd LineArray a PointArray).
package interval.j3d;
import javax.media.j3d.*;
public class DratovaKrychle2 extends Group {
float souradnice[] =
{1,1,1, -1,1,1, 1,-1,1, 1,1,-1,
-1,-1,1, -1,1,-1, 1,-1,-1, -1,-1,-1};
public DratovaKrychle2(float hrana) {
for (int i = 0; i < 24; i++)
souradnice[i] *= hrana/2f;
Shape3D shape2 = new Shape3D();
//objektu shape2 nastavíme objekt Geometry
shape2.setGeometry(vytvorGeometryBodu());
//objektu shape2 nastavíme objekt Appearance
shape2.setAppearance(vytvorAppearanceBodu());
//přidáme objekt DratovaKrychle
addChild(new DratovaKrychle(hrana));
addChild(shape2);
}
Geometry vytvorGeometryBodu(){
PointArray pointArray = new PointArray(8, GeometryArray.COORDINATES);
pointArray.setCoordinates(0, souradnice);
return pointArray;
}
Appearance vytvorAppearanceBodu(){
Appearance app = new Appearance();
PointAttributes pa = new PointAttributes(10, true);
app.setPointAttributes(pa);
return app;
}
}
A takto vypadá výsledek:
Pro lepší představu si ještě ukážeme, jak by mohla vypadat instance této třídy zakreslená v grafu scény, jak to můžete vidět na následujícím obrázku:
Třída TriangleArray
Třída TriangleArray slouží, jak už její název napovídá, k vytváření těles z trojúhelníků. Její využití si ukážeme na vytvoření čtyřstěnu. Abychom si také ukázali, jak pracovat s barvami přiřazenými jednotlivým vrcholům, oživíme stěny našeho čtyřstěnu náhodně vybranými barvami.
package interval.j3d;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.util.Random;
public class Ctyrsten extends Shape3D {
//vypočítáme si dvě odmocniny, které budeme potřebovat
final static float s6 = (float)Math.sqrt(6);
final static float s3 = (float)Math.sqrt(3);
//každá řádka odpovídá jednomu trojúhelníku
float souradnice[] = {
-0.5f,0,-s3/6f, 0.5f,0,-s3/6f, 0,0,s3/3f,
0,0,s3/3f, 0,s6/3f,0, -0.5f,0,-s3/6f,
0.5f,0,-s3/6f, 0,s6/3f,0, 0,0,s3/3f,
-0.5f,0,-s3/6f, 0,s6/3f,0, 0.5f,0,-s3/6f};
public Ctyrsten(float hrana) {
for (int i = 0; i < 36; i++)
souradnice[i] *= hrana;
setGeometry(vytvorGeometry());
}
Geometry vytvorGeometry(){
TriangleArray ta = new TriangleArray(12, GeometryArray.COORDINATES | GeometryArray.COLOR_3);
ta.setCoordinates(0,souradnice);
//obarvíme stěny náhodně vybranými barvami
Random rand = new Random();
for (int i = 0; i < 4; i++){
Color3f color = new Color3f(rand.nextFloat(), rand.nextFloat(), rand.nextFloat());
for (int j = 0; j < 3; j++)
ta.setColor(3*i+j, color);
}
return ta;
}
}
Obarvení tohoto tělesa provádíme v metodě vytvorGeometry()
, kde voláním metody setColor(int i, Color3f color)
nastavujeme každým třem bodům určujícím stěnu jednu náhodně vybranou barvu. Barvy jsme ale klidně mohli nastavit odlišné pro každý vrchol – pak by se v jednotlivých stěnách postupně měnily.
Objekty, které jsme v tomto článku vytvořili, mají jeden velký nedostatek – světla na ně nemají žádný účinek. Jak se s tímto nedostatkem vypořádat, o tom si povíme příště.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Globální výpadek IT systémů: Může za to jediná aktualizace
19. července 2024 -
Od iPhonu po Android: Ultra HDR přináší nový standard fotografií
1. listopadu 2024 -
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024
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