3D transformace

3D transformace

student.cpp
///////////////////////////////////////////////////////////////////////////////
// Soubor studentskych funkci
///////////////////////////////////////////////////////////////////////////////
 
#include "main.h"
 
#include <cmath>
#include <cstdio>
#include <iostream>
 
 
///////////////////////////////////////////////////////////////////////////////
// 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);
}