Conventii

Posted in Codare cu premeditare, Stand-up philosophy on September 21st, 2010 by Mihnea

Uneori cind gindesti un sistem descoperi ca poti face sau reprezenta ceva in mai multe feluri echivalente, si atunci trebuie sa recurgi la o conventie. Bizonul prost ajuns intr-o fundatura d-asta va judeca situatia cu mintea lui si va alege bazindu-se pe ce i se pare lui oportun la momentul ala, ignorind preferintele altora de pina la el.

De obicei cind e nevoie de o conventie, alternativele au merite egale. Nu conteaza ce alegi. Nu e mai bine sa mergi cu masina pe dreapta drumului decit pe stinga lui. E tot aia, deci prima data alegerea se poate face arbitrar. Ceea ce conteaza e sa respecte toata lumea conventia aia si sa nu se trezeasca un bou ca a gasit el nu stiu ce avantaje daca face altfel decit restul lumii, iar alti boi sa se ia dupa el, ducind la schisme, probleme de interoperabilitate si in general haos.

Un teritoriu destul de fertil pentru boi neconventionali este programarea 3D, asa ca ma voi opri asupra a doua cazuri in care s-a gasit un mintos sa faca pe specialu’ si sa nenoroceasca o groaza de oameni care au venit dupa el. Primul e legat de reprezentarea vectorilor.

Cind trebuie sa inmultesti vectori cu matrici ai doua optiuni: ori consideri vectorul ca fiind o linie, si faci v’ = vM, ori consideri vectorul ca fiind o coloana, si faci v’ = Mv. In toate cartile de mate se foloseste a doua varianta, asa ca s-au gasit unii sa remarce ca nu e bine si sa faca invers. Rezultatul e ca DirectX si o groaza de alte chestii sint in momentul de fata in dezacord direct cu matematica, asa ca daca incerci sa treci de la una la alta, te ia rapid cu dureri de cap. Ca sa fie si mai misto, multi oameni confunda “column major” si “row major” cu “column vector” si “row vector”, ducind la un haos complet in terminologie. Cind dai prima data peste un sistem cu propria biblioteca de algebra liniara, esti intr-o mare ceata si sint sanse ca documentatia sa nu te scoata, pentru ca unii au simtit nevoia sa-si puna mintea la contributie cind nu era cazul. In unele manifestari de prostie deosebita, cum e 3D Studio Max, biblioteca de mate chiar are doi operatori de inmultit vectori cu matrici, astfel incit sa poti sa scrii si v*M, si M*v, si sa se intimple acelasi lucru.

Din punct de vedere matematic se poate argumenta ca e mai bine sa folosesti vectori coloane, pentru ca sa nu ajungi la spital cind ai nevoie sa derivezi functii. Chris Hecker da un exemplu aici. Pe rebelii carora le datoram dezastrul asta i-au preocupat insa alte lucruri. Un argument des intilnit este ca daca iti place pe invers, poti implementa mai eficient inmultirile intre vectori si matrici pe procesoare SIMD care n-au operatiuni orizontale (produs scalar, in speta). Cu vectori coloana poti inmulti vectorul cu o linie a matricei intr-o singura instructiune, dar dupa aia trebuie sa despachetezi numerele rezultate si sa le aduni intre ele pe rind. In 3D cu coordonate omogene, asta ar veni vreo 4 inmultiri, 8 adunari, 8 shuffle-uri si 4 store-uri (cel putin in SSE). Cu vectori linie, poti inmulti fiecare linie a matricei cu o componenta a vectorului in 2 instructiuni (un shuffle si un mul), dupa care acumulezi rezultatele si ajungi la vectorul transformat, deci ai 4 inmultiri, 4 shuffle-uri, 3 adunari si 1 store (plus mai putine dependinte deci pipelining mult mai bun). S-ar parea ca miracolul graficii 3D realtime a fost facut posibil prin scuiparea matematicii intre ochi, dar nu-i chiar asa.

Daca chiar ai nevoie sa optimizezi inmultirile dintre matrici si vectori, poti sa-ti tii matricile transpuse in memorie, sau “column major”, adica in a[0] – a[3] e prima coloana a matricei, nu prima linie. Layout-ul in memorie nu impune notatia. Poti scrie frumos v’ = Mv peste tot si sa ai un operator care se foloseste asa, dar sa-ti tii matricile column major si sa beneficiezi de viteza superluminica a tehnologiilor SIMD. Totusi, s-ar putea sa n-ai un bottleneck in inmultirea matricilor cu vectorii (mai ales daca traiesti in prezent), sau sa ai un procesor SIMD cu instructiuni orizontale, sau ambele. In particular, GPU-urile au o instructiune de produs scalar, deci daca folosesti vectori coloana, o transformare in GPU se face in 4 instructiuni si atit. D-aia aplicatiile care folosesc matricile din DirectX le tot transpun inainte sa le trimita la shadere. Noroc ca ar putea merge foarte repede inmultirile pe CPU, asta daca s-ar face vreo inmultire acolo.

A doua conventie despre care fiecare pionier al graficii 3D a simtit nevoia sa-si dea cu parerea este aranjarea axelor de coordonate. Daca pui un elev de clasa a 8-a sa-ti deseneze axele de coordonate in spatiu, primesti inapoi ori o privire timpa, ori asta:

Nu e greu. X la dreapta, Y in sus, Z inspre tine. Asa a invatat toata lumea la scoala, nu e nevoie de opinii suplimentare. Nu e mai bine daca il pui pe Z in sus, sau pe X la stinga. Se aude si acolo in spate la 3D Studio Max, in pula mea? Atunci cind treci din 3D in 2D – cum ar veni, atunci cind proiectezi – vrei sa ramii cu X la dreapta si Y in sus. Nu vrei ca axele cu care ramii sa se cheme X si Z. Oamenii normali stau in picioare si privesc inainte. D-aia daca nu esti pe medicamente, Z e adincimea.

La Max n-au lucrat niciodata oameni normali, ci doar labari care nu stiu nimic despre programare. In general, chiar daca un soft e foarte prost, se va gasi cineva care sa incerce sa domoleasca discutiile aprinse cu cuvintele magice “da, dar…”. La Max nu e asa. Orice programator care s-a atins vreodata de SDK-ul lui il uraste cu pasiune. Nimeni nu incearca sa-i gaseasca scuze. In Max, Z este inaltimea. Ca sa ajungi la o asemenea idee ca programator, trebuie sa fii obisnuit sa stai mult pe burta si sa privesti lumea de sus, adica fix pozitia in care-i sta cel mai bine unui muist care crede ca e cool sa descrii atributele nodurilor trimitind sute de parametri la un constructor variadic. Puletul care a facut asta a vrut si el, ca toata lumea, sa ramina cu X si Y cind trece in 2D, dar el se uita de sus, nu din fata, crezindu-se probabil arhitect (d-ala care proiecteaza cladiri, nu d-ala care crede ca design pattern-urile sint chestii interesante si utile). Si din cauza lui si a altora ca el, importatul geometriei dintr-o aplicatie in alta e putin mai greu decit ar trebui sa fie, ca de ce sa avem si noi o viata mai usoara si sa ne concentram pe lucrurile importante, cind putem sa pierdem vremea schimbind axe prin vertecsi si coloane prin matrici. Important e sa fie un jegos fericit ca si-a construit o lume dupa chipul si asemanarea lui, nu dupa cum faceau toti prostii de pina la el.

PS: A da, si e “bitangenta”, nu “binormala”, ca suprafetele n-au doua normale.

Tags: , , , , , , , ,