A normávektor irányát minden csúcspontban definiálnunk kell. Ez az információ is puffer attribútum tömbként adódik át a hardvernek, mint például a szín információ is.
Hogyan állapítsuk meg a normálvektort?
Röviden: a legegyszerűbb az, ha a Three.js-re bízzuk a számítást, ami egy függvényhívással megtehető. Egyébként az alábbi dolgokat kell(ene) végiggondolnuk.
- Ha a síkidom valamelyik fősíkon (pl. XY) helyezkedik el, akkor a harmadik tengely iránya vagy annak ellentettje lesz az (figyelembe véve a síkidom előlap irányát).
- Ha általános helyzetű a síkidomunk, akkor a három csúcspont térbeli koordinátái meghatároznak egy síkot, aminek ki tudjuk számítani a normálvektorát és ezt használhatjuk.
- Amennyiben a síkidomunk egy íves felszín darabját közelíti, akkor a felszín egyenletének ismeretében az érintősík normálvektorát ki tudjuk számítani, ha az egyenlet differenciálható a kérdéses pontban.
- Ha külső modellező programmal állítottuk elő a geometriát, akkor jó eséllyel a normálvektorokat is kiszámította a csúcspontokhoz, amit közvetlenül felhasználhatunk.
Hogyan adjuk meg a programunkban a normálvektort?
Az első pontnak megfelelő triviális esetekben magunk is explicit megadhatjuk a normálvektor tömböt. A trapéz modellezési példában például a háromszögek az XY síkon helyezkednek el, előlapjukkal a kamera iránya felé, ami a Z-tengely negatív irányából néz az origó felé. A normálvektor irány ekkor [0, 0, 1] lesz. Hasonlóan triviális a normálvektor irányának megállapítása kocka modell esetén, amikor az élek a tengelyekkel párhuzamosak.
Az indexelt csúcspontos példaprogramot az alábbiakkal igészítsük ki.
// Normálvektor minden csúcsponthoz
let normals = new Float32Array(
[
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1
]
);
// Attribútumok beállítása
geometry = new THREE.BufferGeometry();
geometry.setIndex( indices );
geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
geometry.setAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
Így már megvilágítva jelennek meg a lapok. A megoldást a 04_04_c_ThreeJsTrapezium_Normals_Manual_Indexed példaprogram mutatja.
Az általános síkon elhelyezkedő háromszögek esete számítást igényel, ami a három térbeli csúcspont ismeretében egyértelműen elvégezhető. Ezzel itt nem foglalkozunk. Elegendő azt tudnunk, hogy a Three.js tartalmaz függvényt, amely képes erre, ez a BufferGeometry osztály computeVertexNormals() függvénye. Használata egyszerű: a 'position' puffer attribútum tömb beállítása után meg kell hívni a függvényt, ami a háttérben előllítja a megfelelő 'normals' puffer attribútum tömböt is be is állítja a geometriához.
geometry.computeVertexNormals();
Ez indexelt csúcspont megadású modellezés esetén is működik. Ebben az esetben egy csúcspont több, akár más síkokon elhelyezkedő háromszögeknek is része lehet. Mivel egy csúcsponthoz csak egy normálvektor irány tartozhat, ezért a Three.js minden olyan háromszögre, amiben részt vesz a csúcspont kiszámítja a befoglaló sík normálvektorát, és ezek eredőjét (átlagát) számítja ki.
A függvény hívásakor egy logikai értékkel megadható, hogy az átlagolás a síkidom területek arányában történjen-e (a kis területhez tartozó "ne húzza el"). Ha nem adunk meg logikai értéket, akkor a területi átlagolást jelentő true az alapérték.
geometry.computeVertexNormals( true ); // Területi átlagolással
geometry.computeVertexNormals( false ); // Normálvektorok egyszerű átlagolása
Területi átlagolás magyarázat (ábra forrása: Lighthouse3d.com)
A középső csúcspont térbeli pozíciójához 4 geometria csúcspontja is tartozik. A lapok befoglaló skíjaihoz tartozó normálvektor irányok a v12, v23, v34, v41 vektorok. A vektorok hossza a kapcsolódó lap területével arányos. Ezek eredője, vagyis a területi súlyozással vett átlaga a v vektor, amit normalizálás után az adott térbeli ponthoz tartozó csúcspontban normálvektorként beállítunk. Területi súlyozás nélküli számításhoz egységnyi hosszúságú vektorokat használhatunk az eredő számításkor.
A harmadik esettel (egyenlettel megadott íves felszín közelítés) nem foglalkozunk.