Operáciou, ktorá je podobná operácii vrcholového prichytávania, je prichytávanie polygónu (Face). Niekde sa uvádza Face ako štvorec (obdĺžnik), ktorý súvisí s dvoma trojuholníkmi a niekde sa uvádza ako polygón. V každom prípade sa jedná o synonymum.
Vytvoriť teda Face snapping je už na základe Vertex snappingu relatívne jednoduchá záležitosť. Pri algoritme Vertex snappingu sa pri nájdení jedného vertexu, ostatné vertexy dohľadávali. V tomto prípade to bude analogické. Zistia sa súradnice (x, y, z) jednotlivých vertexov pre štvorec (Face) a nad týmito súradnicami vertexov sa postupne budú generovať úsečky, v prípade Unity to bude predstavovať trieda LineRenderer. Určite by bolo možné použiť aj objekt štvorca, ak by existovala nejaká funkcia pre tento objekt, avšak aj štvorec obsahuje 4 vrcholy, ktoré by sme museli definovať, priradiť. Takže z hľadiska výpočtového času by bolo vykreslenie za pomoci úsečiek alebo štvorca ekvivalentné.
Je zaujímavé spomenúť jednu vec. V počítačovej grafike pojem hrana ako taká prakticky neexistuje. Je len záležitosťou indexu v indices poli. Teda, nie je prakticky možné označiť hranu explicitne z nejakých súradníc tak ako je možné označiť jednotlivé vrcholy za pomoci špecifických súradníc, x, y, z. Mohla by existovať nejaká metaprezentácia, napr. grafová reprezentácia z matematiky, ale v konečnom dôsledku by musela byť táto reprezentácia pregenerovaná do indices poľa. Pretože na vykreslenie objektov v 3D súradnicovej sústave v priemyselných grafických štandardoch, DirectX/OpenGL a mnohých iných, je nutné definovať vrcholy a hrany. Aj keď definujeme hranu, nevieme ju explicitne označiť akosi jednotkovo. Že teda zavoláme nejakú funkciu, kde budú uložené hrany a po dopyte napr. s označením hrany H7, nám systém vráti hranu H7. Mohlo by to existovať, ale museli by sme si my dodatočne doimplementovať vrstvu, ktorá by toto riešila.
Takže z toho vyplýva, že na označenie hrany budeme potrebovať 2 vrcholy, pretože hrana ako taká je definovaná dvoma vrcholmi.
Moje programové kódy pre LineFace a MeshFace snapping:
(GIT, LineFace: https://github.com/indicatrix-git/tycoon-terrain-enhanced/blob/main/SnapLineFace.cs)
(GIT, MeshFace: https://github.com/indicatrix-git/tycoon-terrain-enhanced/blob/main/SnapMeshFace.cs)
Moje programové kódy pre LineFace a MeshFace snapping:
(GIT, LineFace: https://github.com/indicatrix-git/tycoon-terrain-enhanced/blob/main/SnapLineFace.cs)
(GIT, MeshFace: https://github.com/indicatrix-git/tycoon-terrain-enhanced/blob/main/SnapMeshFace.cs)
public Vector3 SnapLineFace(Vector3 hitPoint)
{
float[] Xaxis = new float[4];
float[] Yaxis = new float[4];
float[] Zaxis = new float[4];
int xx = (int)hitPoint.x; float x = hitPoint.x - xx;
int zz = (int)hitPoint.z; float z = hitPoint.z - zz;
if (x >= 0.0f && x <= 1.0f)
{
Xaxis[0] = xx;
Xaxis[1] = xx;
Xaxis[2] = xx + 1;
Xaxis[3] = xx + 1;
}
if (z >= 0.0f && z <= 1.0f)
{
Zaxis[0] = zz;
Zaxis[1] = zz + 1;
Zaxis[2] = zz + 1;
Zaxis[3] = zz;
}
Yaxis[0] = FunctionalValueY(Xaxis[0], Zaxis[0]);
Yaxis[1] = FunctionalValueY(Xaxis[1], Zaxis[1]);
Yaxis[2] = FunctionalValueY(Xaxis[2], Zaxis[2]);
Yaxis[3] = FunctionalValueY(Xaxis[3], Zaxis[3]);
lineRenderer01.SetPosition(0, new Vector3(Xaxis[0], Yaxis[0], Zaxis[0]));
lineRenderer01.SetPosition(1, new Vector3(Xaxis[1], Yaxis[1], Zaxis[1]));
lineRenderer02.SetPosition(0, new Vector3(Xaxis[1], Yaxis[1], Zaxis[1]));
lineRenderer02.SetPosition(1, new Vector3(Xaxis[2], Yaxis[2], Zaxis[2]));
lineRenderer03.SetPosition(0, new Vector3(Xaxis[2], Yaxis[2], Zaxis[2]));
lineRenderer03.SetPosition(1, new Vector3(Xaxis[3], Yaxis[3], Zaxis[3]));
lineRenderer04.SetPosition(0, new Vector3(Xaxis[0], Yaxis[0], Zaxis[0]));
lineRenderer04.SetPosition(1, new Vector3(Xaxis[3], Yaxis[3], Zaxis[3]));
return GetCenterFace(hitPoint);
}
public Vector3 SnapMeshFace(Vector3 hitPoint)
{
Vector3[] verticesFace;
Vector3[] normalsFace;
Vector2[] uvFace;
int[] trianglesFace;
float[] Xaxis = new float[4];
float[] Yaxis = new float[4];
float[] Zaxis = new float[4];
int xx = (int)hitPoint.x; float x = hitPoint.x - xx;
int zz = (int)hitPoint.z; float z = hitPoint.z - zz;
float dy = 0.01f;
if (x >= 0.0f && x <= 1.0f)
{
Xaxis[0] = xx;
Xaxis[1] = xx;
Xaxis[2] = xx + 1;
Xaxis[3] = xx + 1;
}
if (z >= 0.0f && z <= 1.0f)
{
Zaxis[0] = zz;
Zaxis[1] = zz + 1;
Zaxis[2] = zz + 1;
Zaxis[3] = zz;
}
Yaxis[0] = FunctionalValueY(Xaxis[0], Zaxis[0]);
Yaxis[1] = FunctionalValueY(Xaxis[1], Zaxis[1]);
Yaxis[2] = FunctionalValueY(Xaxis[2], Zaxis[2]);
Yaxis[3] = FunctionalValueY(Xaxis[3], Zaxis[3]);
verticesFace = new Vector3[]
{
new Vector3(Xaxis[0], Yaxis[0] + dy, Zaxis[0]),
new Vector3(Xaxis[1], Yaxis[1] + dy, Zaxis[1]),
new Vector3(Xaxis[2], Yaxis[2] + dy, Zaxis[2]),
new Vector3(Xaxis[3], Yaxis[3] + dy, Zaxis[3])
};
trianglesFace = new int[]
{
0, 1, 2,
2, 3, 0
};
normalsFace = new Vector3[]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
uvFace = new Vector2[]
{
new Vector2(Xaxis[0], Zaxis[0]),
new Vector2(Xaxis[1], Zaxis[1]),
new Vector2(Xaxis[2], Zaxis[2]),
new Vector2(Xaxis[3], Zaxis[3])
};
meshFace.Clear();
meshFace.vertices = verticesFace;
meshFace.triangles = trianglesFace;
meshFace.normals = normalsFace;
meshFace.uv = uvFace;
meshFace.RecalculateNormals();
return GetCenterFace(hitPoint);
}
Uvedený kód je platný pre tzv. LineFace a tzv. MeshFace. Je to analogické, v prvom prípade máme Face pozostávajúci z 4 úsečiek a v druhom prípade máme Face pozostávajúci z Mesh-u. Mesh je pojem z počítačovej grafiky, ktorý označuje plochu, ktorá môže mať definovanú farbu alebo aj textúru (obrázok). V prípade LineFace je to z kódu pochopiteľné v zmysle toho, že teda nájdeme 4 vertexy a tieto 4 vertexy priradíme jednotlivým úsečkám. V prípade MeshFace je to analogické, kde vytvoríme bázicky vertices a indices (triangleFace) a dodatočne aj UV mapy a normálu. Rovnako pre 4 vertexy v rámci tvorby Mesh plôšky, priradíme jednotlivé súradnice týmto vertexom. Pre indices maticu už len priradíme priradené 4 vertexy v smere hodinových ručičiek v niektorej z 3 konštelácií podľa definície tvorby Mesh plôšky.
Pri VerticesFace figuruje malý prírastok dy pre y súradnicu (y = 0.01). Je to z toho dôvodu, aby bolo vidieť samotný Face. Ak by tam tento prírastok nebol, tak úroveň plôšky, Face by bola na rovnakej úrovni ako úroveň samotných vertexov pre terén, ktorý obsahuje tiež textúru. Viditeľnosť dvoch Mesh objektov s textúrou s rovnakými súradnicami znemožňuje viditeľnosť jedného z nich, resp. v limitnom prípade by figurovala Mesh plôška pod úrovňou terénu a teda toto je najpravdepodobnejší dôvod toho, že sa samotná Face plôška nezobrazí na teréne, ale tesne pod ňou. Z toho dôvodu som zadal prírastok dy na y súradnicu.
Pridávam ešte kód pre získanie funkčnej hodnoty zo súradníc x a z:
float FunctionalValueY(float snapX, float snapZ)
{
float snapY = 0;
for (int Ci = 0, Cz = 0; Cz <= TerrainManager.instance.terrainWidth; Cz++)
{
for (int Cx = 0; Cx <= TerrainManager.instance.terrainWidth; Cx++, Ci++)
{
if (TerrainManager.instance.coords[Ci].x == snapX &&
TerrainManager.instance.coords[Ci].z == snapZ)
{
snapY = TerrainManager.instance.coords[Ci].y;
}
}
}
return snapY;
}
Napísal som to úplne intuitívne, tak jednoducho. Samozrejme, je možné to napísať sofistikovanejšie, ale minimálne v prvej verzii môjho kódu to nechávam zatiaľ v takejto základnej forme a možno to už bude aj konečná forma.
V nasledujúcom videu to popisujem podrobnejšie:





.png)
.png)
.png)
.png)

.png)
.png)
.png)
.png)

.png)
.png)
.png)
.png)
Situácia sa zmení pridaním ďalšieho rozmeru obrazu - rozmeru håbky. V tomto okamihu už dochádza k simulácii ľudského videnia, avšak stále len k simulácii, napodobovaniu, pretože zostrojiť úplne dokonalý obraz ľudského videnia reálneho sveta nie je doposiaľ možné. Z fyzikálneho hľadiska si môžme predstaviť okolitý svet ako spojitý, analógový a svet elektroniky ako nespojitý, digitálny. Najlepšie to reprezentuje videokamera alebo fotoaparát, ktorým snímame jednotlivé obrázky. Procesom snímania okolitého sveta prostredníctvom objektívu je vždy nejaký prevod obrazu z tohto objektívu (analógový signál) na obrazový formát (digitálny signál). Tento prevod je daný nejakou transformáciou. Doposiaľ žiadny objektív nedokáže zachytiť obraz bezchybne, takže okrem samotnej transformácie obrazu dochádza aj k transformačným, korekčným chybám objektívov. Tieto korekcie, transformácie sú vo všeobecnosti vzťahy, ktoré vyjadrujú spojitosť, väzbu, medzi jednotlivými prvkami. Premietanie v našom prípade je transformácia, ktorá charakterizuje prevod trojrozmerných súradníc objektu do dvojrozmerných súradníc, pričom v takejto reprezentácii, ako už bolo spomínané, dochádza vždy k strate priestorovej informácie. Deskriptívna geometria je jedna z matematických disciplín, ktorá sa zaoberá rôznymi prepismi geometrických scén.
Proces ľudského videnia je založený v konečnom dôsledku na vyhodnotení signálov v mozgu. Preto, čím vernejšie vykreslíme 3D scénu na monitore počítača, tým prirodzenejšie bude schopný mozog spracovať jednotlivé signály. Pri spracovaní videnia v určitej fáze prebieha v mozgu k tzv. stranovému kríženiu obrazu (okrem toho aj k zmenšeniu a dvojitému stranovému otočeniu obrazu) z ľavého a pravého oka. Týmto procesom vnímame okolitý svet priestorovo, vzniká dojem håbky. Takýto priestor nie je možné vytvoriť v mozgu z roviny akéhoko¾vek monitora, takže aj keï prakticky neustále dochádza k stranovému kríženiu obrazu, výsledný obraz bude priestorový len do kvality poskytnutej 3D transformácie.
Poznámka: V súvislosti s procesom videnia mozgom, pozná neurológia určitý stav, kedy vidíme obraz, nejaké predmety, ale nedokážeme ich identifikovať. Teda, na sietnici oka sa premieta obraz z okolitého prostredia, ale napriek tomu náš mozog nedokáže jednotlivé signály spracovať a v dôsledku toho, vlastne nevidíme nič, sme slepí. Takýto stav sprevádzajú pomerne ťažké neurologické ochorenia, ale aj keï nie presne v tomto význame ich občas môže zažiť aj zdravý človek, napr. nieko¾ko sekúnd po prebudení zo spánku, alebo tesne pri zaspávaní a v neposlednom rade aj pri požití omamných a psychotropných látok.
V súradnicovej sústave P, x_1, x_2 je axonometria reprezentovaná súradnicovou sústavou O_a, E_{a}^{x}, E_{a}^{y}, E_{a}^{z}, uhlami \xi, \eta a tzv. axonometrickým trojuholníkom, ktorý tvoria jednotkové vektory e^x, e^y, e^z.
Nech bod A \in E^3 má súradnice A(x^A, y^A, z^A) a jeho pôdorys A_1(x^A, y^A, 0). V axonometrii \phi: E^3 \rightarrow \varepsilon \times \varepsilon[/latex] je obrazom bodov A, A_1 usporiadaná dvojica bodov (A_a, A_{1a}) pre ktorú platí [latex]A_a A_{1a} \parallel z_a. Vzh¾adom na axonometrickú súradnicovú sústavu O_a, E_{a}^{x}, E_{a}^{y}, E_{a}^{z} majú body A_a A_{1a} súradnice A_a(x^A e^x, y^A e^y, z^A e^z), A_{1a}(x^A e^x, y^A e^y, 0).
Výpočet konkrétneho bodu A_a(x_1^A, x_2^A) vzhľadom na súradnicovú sústavu Px_1x_2 bude záležitosťou použitia goniometrických funkcií. Teda, podľa daného obrázku platí:.png)
.png)
.png)
.png)

Pri hľadaní perspektívneho zobrazenia sú určujúce jednotlivé priesečníky priemetne \varepsilon so stenou \nu = xz prakticky vytvárajúci pravouhlý trojhran, a tiež voľba stredu lineárnej perspektívy S(s, -d, v). Podľa obrázku (niektoré nasledujúce symboly nie sú na obrázku označené) reprezentuje v, výšku začiatočného bodu S, úsečky SR (teda táto výška rovnobežná s osou z=x_2) a z hľadiska manipulácie perspektívneho obrazu bude možné týmto parametrom meniť výšku celkového pohľadu výsledného obrazu, teda uhol otočenia okolo osy x. Jedná sa o vzdialenosť od tzv. základnej roviny. V prípade v=0 sa budeme nachádzať priamo v horizonte, na obrázku s označením h. Vzdialenosť s je daná začiatočným bodom S, úsečky SR a osy y, resp. pomyselnej roviny yz a bodu S. Týmto parametrom bude možné meniť šírku celkového pohľadu, teda uhol natočenia okolo osy z. A napokon parameter d je tzv. dištancia a je to veľkosť úsečky SH, teda vzdialenosť bodu S od bodu horizontu H. Týmto parametrom bude možné nastaviť celkovú håbku perspektívy.
Z uvedeného popisu perspektívnej scény potrebujeme vyjadriť parametrické rovnice priamky SR. Tie vyjadríme pre každú zložku nasledujúcim spôsobom:.png)
.png)
.png)
.png)
.png)
.png)
.png)
.png)

Uvedené spôsoby poukázali na niektoré najčastejšie typy premietaní. Vykresľovanie doposiaľ prebiehalo spôsobom známym z OpenGL/DirectX, kedy len pomocou bodu a úsečky vykresľujeme komplexné objekty. Grafické priemyselné štandardy pracujú v režime vykresľovania scény v reálnom čase, to znamená, že akékoľvek grafické objekty sú na priemetni prekresľované v pravidelných časových intervaloch a navyše takýto spôsob vykresľovania úzko súvisí s hardwarovými vymoženosťami grafickej karty. V celom seriály ako aj u uvedenom prípade bol použitý spôsob vykresľovania objektov z grafických priemyselných štandardov, avšak vykresľovanie scény bolo realizované jednorazovym prepisom prostredníctvom zaznamenanych bodov z platna do obrazového suboru typu PPM. Prakticky to znamenalo to, že sme pouzili vektorovy sposob zapisu objektov, a tento zapis sme priamo aplikovali na priemetnu v povodnom stave, ktory sme uz len jednoducho ulozili do uz spominaneho obrazového suboru. Každe vykreslovanie grafických objektov urcitym systemom sa nazyva renderovanie, avšak v povodnom vyzname tohto oznacenia sa jedna o proces, ktory vedie k fotorealistickému zobrazovaniu geometrických objektov.
V nasledujucich castiach serialu pojde o tzv. renderovanie v klasickom vyzname, to znamena, proces tvorby obrazu z 2D/3D modelov pouzitim textur, osvetlovacich modelov a algoritmami tienovania. Jedna sa o systém znamy z integrovanych renderovacich nastrojov od spolocnosti Autodesk, ktora vydava svoje jednotlive produkty ako napr. 3D Studio MAX, Maya, alebo niektore verzie AutoCADu.
V zásade je jedno, či sa bude jednať o reprezentáciu 2D alebo 3D objektov. Odlišnost v zápise je len v počte súradníc, aj keï reprezentácia v 3D je z hľadiska ïalšieho spracovania zložitejšia. Samotná reprezentácia v podstate vychádza z možností zobrazovania grafickej karty počítača. Pomocou grafickej karty sme schopný vykresľovať len body a úsečky, pričom grafickým procesorom je podporované vykresľovanie trojuholníkov. Práve tento trojuholník sa javí z hľadiska reprezentácie ako efektívny, pretože existujú algoritmy, ktoré popisujú jeho vyplňovanie, je možné tiež veľmi efektívne optimalizovať výpočty priesečníkov lúčov s trojuholníkmi. Túto skutočnosť používajú rôzne vykresľovacie (renderovacie) techniky.
Takúto sieť trojuholníkov je možné vidieť napr. na jednoduchom teréne. Intuitívne by nás napadlo vyskladať takúto sieť tak, že zadáme súradnice každého bodu a nejakým spôsobom pospájame jednotlivé body hranami. Ako bolo spomenuté, ideálne je pospájať tieto body ako vrcholy trojuholníka, kde každý trojuholník bude obsahovať teda tri vrcholy (vertexy) a tri hrany (edges).

.png)

.png)
.png)
.png)



Niekedy nie je potrebné zaznamenávať informácie o všetkých hranách objektu, ale len o tých, ktoré sú z hľadiska viditeľnosti prístupné nášmu pohľadu. Ostatné hrany sa ignorujú. To je prípad hraničnej reprezentácie (boundary representation, B-rep). Mohlo by sa zdať, že tento typ rieši určitú problematiku viditeľnosti hrán, avšak je to len zdanie, pretože zadávame len tie hrany, ktoré z hľadiska pohľadu majú byť viditeľné. Teda, popisujeme len plášť objektu (aj keď samotný plášť netvorí plocha, ktorá je nejakým spôsobom definovaná), jeho obrysy. Pri jednoduchých objektoch je táto metóda ešte zvládnuteľná z hľadiska manuálnej selekcie hrán, ale pri zložitejších objektoch to býva časovo náročné.