====== 3D transformace ====== [[http://www.flickr.com/photos/pitel/2426848399|{{ http://farm4.static.flickr.com/3207/2426848399_c2e6c0f45a_o.png |3D transformace}}]] /////////////////////////////////////////////////////////////////////////////// // Soubor studentskych funkci /////////////////////////////////////////////////////////////////////////////// #include "main.h" #include #include #include /////////////////////////////////////////////////////////////////////////////// // name spaces using namespace std; /////////////////////////////////////////////////////////////////////////////// // prace s transformacni matici /////////////////////////////////////////////////////////////////////////////// class Matrix { double data[16]; public: // inicializuje matici na jednotkovou Matrix() { LoadIdentity(); } // pristup k "radku" matice double *operator [] (int row) { return (data + row*4); } // nastavi matici na jednotkovou void LoadIdentity() { for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) data[i*4 + j] = (i == j) ? 1.0 : 0.0; } // kdyby si to nekdo chtel vypsat, aby zkontroloval, co tam ma... void Print() { cout << "===========================" << endl; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { cout << ios_base::fixed << data[i*4 + j]; } cout << endl; } } }; /////////////////////////////////////////////////////////////////////////////// // aktivni matice Matrix transf; /////////////////////////////////////////////////////////////////////////////// // operace nad aktivni matici // nastavi transformaci na zadanou matici void trSetMatrix(const Matrix &m) { transf = m; } // vraci aktualni transformaci const Matrix &trGetMatrix() { return transf; } // resetuje transformacni matici na jednotkovou void trLoadIdentity() { transf.LoadIdentity(); } // skladani transformaci (aktualni transformaci vynasobi zadanou matice) void trMultMatrix(Matrix &m) { Matrix newtransf; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { newtransf[i][j] = 0; for (int x = 0; x < 4; x++) { newtransf[i][j] += m[i][x] * transf[x][j]; } } } trSetMatrix(newtransf); } /////////////////////////////////////////////////////////////////////////////// // funkce, ktere provadeji ruzne druhy transformace // vynasobi hlavni matici translacni matici (ktera objekt posouva o zadane vzdalenosti) void trTranslate(double dx, double dy, double dz) { Matrix m; m[3][0] = dx; m[3][1] = dy; m[3][2] = dz; trMultMatrix(m); } // vynasobi hlavni matici rotacni matici kolem osy Y void trRotateY(double angle) { Matrix m; // aby se goniometricke funkce nepocitaly dvakrat, kdyz to staci jednou... double sina = sin(angle); double cosa = cos(angle); m[0][0] = cosa; m[0][2] = sina; m[2][0] = -sina; m[2][2] = cosa; trMultMatrix(m); } // vynasobi hlavni matici rotacni matici kolem osy X void trRotateX(double angle) { Matrix m; // aby se goniometricke funkce nepocitaly dvakrat, kdyz to staci jednou... double sina = sin(angle); double cosa = cos(angle); m[1][1] = cosa; m[1][2] = sina; m[2][1] = -sina; m[2][2] = cosa; trMultMatrix(m); } // vynasobi hlavni matici projekcni matici, ktera zaridi PERSPEKTIVNI promitani void trProjectionPerspective(double d) { Matrix m; m[2][2] = 0.0; m[2][3] = 1.0 / d; trMultMatrix(m); } /////////////////////////////////////////////////////////////////////////////// // funkce k vykresleni promitnute usecky, apod. /////////////////////////////////////////////////////////////////////////////// // promitne bod ve 3D // x,y,z souradnice ve 3D // u,v souradnice na obrazovce promitnute matici transf void ProjectVertex(int &u, int &v, double x, double y, double z) { // vynasobeni vektoru (x,y,z,1) transformacni matici - vyjde vektor (xx,yy,zz,ww) double xx = x*transf[0][0] + y*transf[1][0] + z*transf[2][0] + 1*transf[3][0]; double yy = x*transf[0][1] + y*transf[1][1] + z*transf[2][1] + 1*transf[3][1]; double ww = x*transf[0][3] + y*transf[1][3] + z*transf[2][3] + 1*transf[3][3]; // homogenni souradnice xx /= ww; yy /= ww; // vypocteni promitnutych souradnic - meritko odvozeno od frame_h v obou osach... u = int(xx + frame_w/2); v = int(yy + frame_h/2); } // vykresli usecku zadanou ve 3D po promitnuti transformaci // x1,y1,z1 jeden vrchol ve 3D // x2,y2,z2 druhy vrchol void ProjectLine(double x1, double y1, double z1, double x2, double y2, double z2, const S_RGBA &color) { // cara se promitne tak, ze se promitnou jeji krajni body int u1,v1,u2,v2; ProjectVertex(u1, v1, x1, y1, z1); ProjectVertex(u2, v2, x2, y2, z2); DrawLine(u1, v1, u2, v2, color); } // vykresli trojuhelnik zadany ve 3D po promitnuti transformaci // x1,y1,z1 jeden vrchol ve 3D // x2,y2,z2 druhy vrchol // x3,y3,z3 treti vrchol void ProjectTriangle(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3, const S_RGBA &color) { // promitnou vrcholy trojuhelniku int u1, v1, u2, v2, u3, v3; ProjectVertex(u1, v1, x1, y1, z1); ProjectVertex(u2, v2, x2, y2, z2); ProjectVertex(u3, v3, x3, y3, z3); // testujeme odvracene/privracene trojuhelniky? if (back_face_culling) { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // MISTO PRO STUDENTSKOU PRACI // - zjistete zda je trojuhelnik odvraceny nebo privraceny // - pokud neni viditelny (= odvraceny), tak nic nekreslete // - test je nutne prevratit pokud promenna invert_culling = -1 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! int vect11 = u2 - u1; int vect12 = v2 - v1; int vect21 = u3 - u1; int vect22 = v3 - v1; int normal = (vect11 * vect22 - vect12 * vect21) * invert_culling; if (normal > 0) { return; } } // vykresleni (pouze viditelne viditelne trojuhelniky) DrawLine(u1, v1, u2, v2, color); DrawLine(u2, v2, u3, v3, color); DrawLine(u3, v3, u1, v1, color); } /////////////////////////////////////////////////////////////////////////////// // funkce DrawObject // - vykresli objekt transformovany aktivni transformacni matici void DrawObject(const S_RGBA &color) { // postupne vykresleni vsech trojuhelniku T_Triangles::iterator end = triangles.end(); for( T_Triangles::iterator it = triangles.begin(); it != end; ++it ) { int v0 = it->v[0], v1 = it->v[1], v2 = it->v[2]; ProjectTriangle(vertices[v0].x, vertices[v0].y, vertices[v0].z, vertices[v1].x, vertices[v1].y, vertices[v1].z, vertices[v2].x, vertices[v2].y, vertices[v2].z, color); } } /////////////////////////////////////////////////////////////////////////////// // funkce DrawScene() volana z main.cpp // - vykresli celou scenu vcetne dvou vlozenych objektu void DrawScene() { // vymazani frame bufferu ClearBuffer(); // vycistit hlavni matici - do definovaneho stavu trLoadIdentity(); // nastavit projekcni matici trProjectionPerspective(CAMERA_DIST); // posuv cele sceny trTranslate(0.0, 0.0, scene_move_z); // natoceni cele sceny - jen ve dvou smerech - mys je jen 2D... :( trRotateX(scene_rot_x * 0.01); trRotateY(scene_rot_y * 0.01); Matrix backuptransf = transf; // vykresleni "zrcadla" modrou barvou ProjectLine(0, -2, -2, 0, 2, -2, COLOR_BLUE); ProjectLine(0, 2, -2, 0, 2, 2, COLOR_BLUE); ProjectLine(0, 2, 2, 0, -2, 2, COLOR_BLUE); ProjectLine(0, -2, 2, 0, -2, -2, COLOR_BLUE); // vykresli objekt cervene // pridame k nastaveni sceny umisteni a natoceni objektu trTranslate(obj_move_x * 0.015, obj_move_y * 0.015, 0.0); trRotateX(obj_rot_x * 0.01); trRotateY(obj_rot_y * 0.01); // a s tim co vznikne promitneme nas objekt invert_culling = 1; DrawObject(COLOR_RED); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // MISTO PRO STUDENTSKOU PRACI // - vykresleni objektu soumerneho podle modre roviny // - volejte DrawObject() // - pouzijte barvu COLOR_RED2 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Matrix mirror; invert_culling = -1; transf = backuptransf; mirror[0][0] = -1; trMultMatrix(mirror); trTranslate(obj_move_x * 0.015, obj_move_y * 0.015, 0.0); trRotateX(obj_rot_x * 0.01); trRotateY(obj_rot_y * 0.01); DrawObject(COLOR_RED2); }