Skip navigation

Modellezési alapfogalmak

Csúcspont

A 3D grafikai modellezés alapfogalma a csúcspont, angol terminológiával a vertex. Egy csúcspont az attribútumainak megadásával kerül definiálásra. Az alábbi attribútumok tartozhatnak egy csúcsponthoz:

  • pozíció,
  • szín,
  • normálvektor,
  • textúra koordináta.

Ezek közül a pozíció megadása kötelező, a többi opcionális. Amennyiben nem definiáljuk őket, akkor egy alapértelmezett érték kerül alkalmazásra.

Grafikai primitívek

A csúcspontok segítségével úgynevezett grafikai primitíveket építhetünk fel. Ezek az alábbiak lehetnek:

  • pont,
  • egyenes vonalszakasz,
  • háromszög.

A pont primitívet egy csúcspont egyértelműen definiál. Egyenes vonalszakaszt két végpontjának csúcspontjaival adhatunk meg. Háromszög definiáláshoz három darab csúcspont kell.

Grafikai primitívek színezése

Mint azt az előző pontokban láttuk, szín információt a csúcspontokhoz rendelhetünk egyenként, nem pedig a belőlük képzett alakzatokhoz. Felmerül a kérdés, hogy a vonalszakasz és a háromszög esetén mi történik, ha az alkotó csúcspontokhoz más szín tartozik? Ebben az esetben valamilyen módon az eltérő színekből egy színt kell kiszámolni, ami az árnyaló algoritmus feladata. Ez többféle módon történhet. A grafikus hardver választhatja pl. a sorrendileg első ponthoz tartozó színt és minden belső pontban azt használja, vagy a színek interpoláltját, az azok közötti lineáris átmenetet számítja ki a csúcspontoktól való távolság függvényében. és alkalmazza a belső képpontokban.

Hasonlóan a normálvektorok is a csúcspontokhoz rendelődnek, és nem a háromszög síkidomhoz. (Pont és egyenes szakasz esetén nincs szerepe a normálvektornak.) Emlékeztetőül: a normálvektorok a felszínre beeső fény szögének a meghatározására használatosak, ami fontos része a megvilágítási egyenleteknek. A csúcspontonkénti (pl. Goruaud) árnyalás esetén az egyenletek a csúcspontokban számolódnak, és a belső képpont területek ezek interpoláltjait kapják. A Phong árnyalás esetén a belső pontokban is kiértékelődnek az egyenletek, ekkor a csúcspontokhoz rendelt normálvektorok interpolálására kerül sor, így akár minden belső pont eltérő irányú normálvektorral rendelkezhet.

JavaScript típusolt tömbök és Three.js puffer attribútum tömbök

A JavaScript nyelv nem a típusosságáról híres. A változókhoz nem is tudunk típust rendelni, az értékadás szerinti típust rendeli hozzá az értelmező. Számértékek esetén például csak lebegőpontos számot (más magasszintű nyelvekben ez a float típus) kezel, még akkor is, ha egész értéket adunk egy változónak. A tömbökben mindenféle típusú érték (szám, szöveg, stb.) vegyesen előfordulhat. A tömbök méretét futás közben szabadon módosíthatjuk.

Ezzel szemben a grafikus hardver erősen típusolt megközelítést használ: megkülönböztet 8, 16 és 32 bites, előjeles és előjel nélküli egészeket, valamint lebegőpontos típusokat, ezekből a típusokból keletkező 2, 3 és 4 elemű vektorokat.

Fontos, hogy a JavaScript nyelv oldaláról a grafikus hardvernek megfelelő, típusolt értékek kerüljenek át, elem darabszám információval. Ehhez a JavaScript megfelelő típusolt tömb konstrukcióit kell használnunk, majd a THREE.js megfelelő konstruktor függvényével puffer attribútum tömbbé kell alakítani, ami átadható a grafikus hardvernek.

Megjegyezzük, hogy JavaScript tömböt is átadhatunk inicializáláskor közvetlenül a típusolt tömbnek, vagy akár a puffer attribútum tömbnek is, vagyis a típusolt tömb létrehozási lépés elkerülhető. Ez a megközelítés másolatot készít az adatokról, így nagy adatmennyiség esetén nagyon pazarló a memóriával. Emiatt célszerű lehet eleve típusolt tömböt létrehoznunk, és abban beállítani a szükséges értékeket.

Az első példában JavaScript tömböt definiálunk, abból hozzuk létre a típusolt Float32 tömböt, amit puffer attribútum tömbbé alakítunk.

let vertices = [];
let vertexPositionAttributeSize = 3; // 3D: vx, vy, vz
vertices.push(

1, 0, 0, // V0
4, 6, 5, // V1
7, 3, 3, // V2
10, 7, -3 // V3
)
;

let positionFloatArray = new Float32Array( vertices );
let positionBuffer = new THREE.Float32BufferAttribute( positionFloatArray, vertexPositionAttributeSize );

Ebben a példában a positionFloatArray közvetlen létrehozása tulajdonképpen felesleges, mert egyrészt a változót másra nem használjuk, csak átadjuk a puffer konstruktornak, másrészt a vertices tömb közvetlenül is átadható lenne a puffer attribútum tömb konstruktorának, ami ekkor létrehozza a lebegőpontos tömböt, de így jobban látható lezajló folyamat. Egy gyakoribb hívási szintaktika:

let positionBuffer = new THREE.Float32BufferAttribute( vertices, vertexPositionAttributeSize );

A puffer attribútum tömb létrehozásakor azt is meg kell adnunk, hogy a tömbben hány darab elem tartozik egy csúcsponthoz. Jelen esetben ez 3, mert 3 dimenziós koordinátákat adunk át, amit a vertexPositionAttributeSize változónk tartalmaz.

A memóriával jobban bánó megközelítés, ha a csúcspont koordinátákat eleve típusolt tömbként hozzuk létre, a JavaScript tömb kihagyásával. Itt nincs push() függvény, előre meg kell mondanunk a tömb méretét és tömb indexeléssel tudjuk az értékeket beállítani, illetve lehetőség van a definíciókor a teljes tömb tartalmát megadni. Jó megközelítés, ha a tömbben tárolt csúcspont információ számát, valamint az egy csúcsponthoz tartozó elemek számát külön változókban feljegyezzük, és a kódban azt használjuk. Amennyiben változatunk a méreten, elegendő a változó értékeket egy helyen módosítani, nem kell a kódba égetett konstans értékeket keresgetnünk, ami sok hibaforrást jelenthet.

let vertexCount = 5;
let vertexPositionAttributeSize = 3;

let vertices = new Float32Array(
[
-5.0, 5.0, 0.0, // V0
-2.5, 0.0, 0.0, // V1
0.0, 5.0, 0.0, // V2
2.5, 0.0, 0.0, // V3
5.0, 5.0, 0.0 // V4
]

);
positionBuffer = new THREE.BufferAttribute( vertices, vertexPositionAttributeSize );

A fenti kódrészletben a típusolt tömböt helyben inicializáljuk is. További példaprogramokban látunk majd arra példát, amikor darabszám információt adunk csak át, és később, for ciklusban adjuk meg az értékeket.

A kódból az is látható, hogy amennyiben típusolt tömbből hozzuk létre a puffert, akkor nincs szükség típus információra, mert a típusolt tömb azt tartalmazza. Elegendő a THREE.BufferAttribute() hívása.

A típusolt tömbök használati lehetőségei ennél jóval bővebbek. Részletesebben például az alábbi oldalon olvashatunk erről (angol nyelven):

BufferGeometry

A Three.js-ben a BufferGeometry osztály alkalmas geometria adatok reprezentálására. Létre kell hoznunk egy ilyen objektumpéldányt, majd be kell állítani a csúcspont attribútumokat a korábban létrehozott puffer attribútum tömböket használva. Ez a geometria objektum setAttribute() függvényével tehető meg.

Első paramétere egy sztring, ami az átadásra kerülő puffer típusát adja meg. Az alábbi értékei lehetnek:

  • 'position': 2D vagy 3D koordináták
  • 'color': szín a csúcsponthoz
  • 'normal': normálvektor a csúcsponthoz
  • 'uv': textúra koordináta a csúcsponthoz

Második paraméterként a megfelelő puffer attribútum tömböt kell átadnunk.

A gyakorlatban a programjainkban sokszor az attribútum beállításakor végezzük el a puffer attribútum tömb létrehozását, így tömörebb kódot kapunk. Például:

geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
geometry.setAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) )
;

A BufferGeometry-nek egy index tömböt is átadhatunk, ezzel a háromszög geometria létrehozáskor fogunk foglalkozni.

Anyagjellemzők

A BufferGeometry által reprezentált alakzat megjelenítéséhez szükséges az anyagjellemzők megadása is. Ez az alkalmazandó megvilágítási egyenletet, a kitöltés típusát, az alakzat globális színét, és egyéb további tulajdonságok megadását teszi lehetővé. Háromszög alakzat esetén ugyanazokat az anyag osztályokat használhatjuk, amiket a beépített geometriák esetén előzőleg megismertünk. A pont és vonalszakasz alakzatokhoz egyedi anyagosztályok állnak rendelkezésre.

Geometriából megjelenő alakzat

Fontos megérteni, hogy a BufferGeometry csak a csúcspont definíciókat foglalja magában, azt nem, hogy milyen alakzat jelenjen meg belőle a képernyőn! Ugyanabból a BufferGeometry objektumból készíthető ponthalmaz, vonalszakasz és háromszög megjelenítés is! Three.js-ben a megfelelő alakzat objektumnak a konstruktor hívásakor át kell adni a geometria és az anyagjellemző objektumokat. Az alábbi alakzatokat hozhatjuk létre.

  • THREE.Points
  • THREE.Line
  • THREE.LineSegments
  • THREE.Mesh

Alakzat összefoglaló osztály ábrák