Professional Documents
Culture Documents
Lab03 - Nguyen Đuc Hoai Vu - 102220048
Lab03 - Nguyen Đuc Hoai Vu - 102220048
Lab03 - Nguyen Đuc Hoai Vu - 102220048
1. lab03AffineMatrix.cpp..........................................................................................1
2. labmatrixCG - Thực hiện các phép biến đổi affine thông qua các hàm tự xây
dựng 7
2.1 Vectors.h.........................................................................................................................7
2.2 Matrices.h.....................................................................................................................14
2.3 main.cpp........................................................................................................................23
3. BÀI TẬP................................................................................................................40
1. lab03AffineMatrix.cpp
#include <math.h>
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
points[1][0] = 10;
points[1][1] = 2 * a + 10;
points[1][2] = 2 * a + 10;
points[2][0] = 10;
points[2][1] = 10;
points[2][2] = 2 * a + 10;
points[3][0] = 2 * a + 10;
points[3][1] = 10;
points[3][2] = 2 * a + 10;
points[4][0] = 2 * a + 10;
points[4][1] = 2 * a + 10;
points[5][0] = 10;
points[5][1] = 2 * a + 10;
points[5][2] = 10;
points[6][0] = 10;
points[6][1] = 10;
points[6][2] = 10;
points[7][0] = 2 * a + 10;
points[7][1] = 10;
points[7][2] = 10;
}
//In ma tran
void printMatrix(Matrix4x4 b){
for (int i=0;i<4;i++){
std::cout << std::endl << std::setw(5) << "|" << std::setw(10);
for (int j=0;j<4;j++){
std::cout << std::setw(10);
std::cout << b[i][j];
if(j==3) std::cout << std::setw(3)<< "|";
}
}
std::cout << std::endl << std::endl;
}
//Bien doi ty le
void Scale(float sx, float sy, float sz)
{
Matrix4x4 m;
matrixSetIdentity(m);
m[0][0] = sx;
m[1][1] = sy;
m[2][2] = sz;
matrixMul(m, Matrix);
printf("Ma tran ty le:");
printMatrix(m);
}
//Bien doi toa do cac dinh theo yeu cau (tinh tien, ty le, quay, doi xung)
void TransPoints(void)
{
int i, k;
float tmp;
for (k = 0; k < 8; k++)
for (i = 0; i < 3; i++)
pointsFin[k][i] = Matrix[i][0] * points[k][0] + Matrix[i][1] * points[k][1] +
Matrix[i][2] * points[k][2] + Matrix[i][3];
void drawCoordinateAxisX()
{
glPushMatrix();
glRotatef(90.0f, 0.0f, 2000.0f, 0.0f);
drawCoordinateAxisZ();
glPopMatrix();
}
void drawCoordinateAxisY()
{
glPushMatrix();
glRotatef(-90.0f, 2000.0f, 0.0f, 0.0f);
drawCoordinateAxisZ();
glPopMatrix();
}
void drawFrame()
{
glLineWidth(2.0f);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glColor3f(0.0f, 0.0f, 0.0f);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glLineWidth(1.0f);
}
i = 0;
glColor3f(0.8, 0.6, 0.5);
glBegin(GL_POLYGON);
glVertex3s(a[0 + i][0], a[0 + i][1], a[0 + i][2]);
glVertex3s(a[1 + i][0], a[1 + i][1], a[1 + i][2]);
glVertex3s(a[5 + i][0], a[5 + i][1], a[5 + i][2]);
glVertex3s(a[4 + i][0], a[4 + i][1], a[4 + i][2]);
glEnd();
glColor3f(0.2, 0.4, 0.7);
glBegin(GL_POLYGON);
glVertex3f(a[0][0], a[0][1], a[0][2]);
glVertex3f(a[3][0], a[3][1], a[3][2]);
glVertex3f(a[7][0], a[7][1], a[7][2]);
glVertex3f(a[4][0], a[4][1], a[4][2]);
glEnd();
i = 1;
glColor3f(0.5, 0.4, 0.3);
glBegin(GL_POLYGON);
glVertex3s(a[0 + i][0], a[0 + i][1], a[0 + i][2]);
glVertex3s(a[1 + i][0], a[1 + i][1], a[1 + i][2]);
glVertex3s(a[5 + i][0], a[5 + i][1], a[5 + i][2]);
glVertex3s(a[4 + i][0], a[4 + i][1], a[4 + i][2]);
glEnd();
i = 2;
glColor3f(0.5, 0.6, 0.2);
glBegin(GL_POLYGON);
glVertex3s(a[0 + i][0], a[0 + i][1], a[0 + i][2]);
glVertex3s(a[1 + i][0], a[1 + i][1], a[1 + i][2]);
glVertex3s(a[5 + i][0], a[5 + i][1], a[5 + i][2]);
glVertex3s(a[4 + i][0], a[4 + i][1], a[4 + i][2]);
glEnd();
i = 4;
glColor3f(0.7, 0.3, 0.4);
glBegin(GL_POLYGON);
glVertex3f(a[0 + i][0], a[0 + i][1], a[0 + i][2]);
glVertex3f(a[1 + i][0], a[1 + i][1], a[1 + i][2]);
glVertex3f(a[2 + i][0], a[2 + i][1], a[2 + i][2]);
glVertex3f(a[3 + i][0], a[3 + i][1], a[3 + i][2]);
glEnd();
}
//Hien thi
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawFrame();
gluLookAt(5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
drawCoordinateAxis();
glColor3f(1.0, 0.0, 0.0);
Draw(points);
matrixSetIdentity(Matrix);
switch (choice)
{
case 1:
Translate(TransDistX, TransDistY, TransDistZ);
break;
//Khoi tao
void init(void)
{
glOrtho(-1000.0, 1000.0, -500.0, 500.0, -500.0, 500.0);
glEnable(GL_DEPTH_TEST); //Hien thi theo chieu sau cua vat the
}
//Nhap canh
float a;
printf("Nhap do dai canh: ");
scanf("%f", &a);
inputPoint(a/2.0);
printf("\tCac dinh ban dau:\n");
printPoint(points);
Kết quả đối với phép tịnh tiến Ma trận biến đổi : Hình ảnh sau khi biến đổi tịnh tiến
theo trục X
#ifndef VECTORS_H_DEF
#define VECTORS_H_DEF
#include <cmath>
#include <iostream>
///////////////////////////////////////////////////////////////////////////////
// 2D vector
///////////////////////////////////////////////////////////////////////////////
struct Vector2
{
float x;
float y;
// ctors
Vector2() : x(0), y(0) {};
Vector2(float x, float y) : x(x), y(y) {};
// utils functions
void set(float x, float y);
float length() const; //
float distance(const Vector2& vec) const; // distance between two vectors
Vector2& normalize(); //
float dot(const Vector2& vec) const; // dot product
bool equal(const Vector2& vec, float e) const; // compare with epsilon
// operators
Vector2 operator-() const; // unary operator (negate)
Vector2 operator+(const Vector2& rhs) const; // add rhs
Vector2 operator-(const Vector2& rhs) const; // subtract rhs
Vector2& operator+=(const Vector2& rhs); // add rhs and update this object
Vector2& operator-=(const Vector2& rhs); // subtract rhs and update this object
Vector2 operator*(const float scale) const; // scale
Vector2 operator*(const Vector2& rhs) const; // multiply each element
Vector2& operator*=(const float scale); // scale and update this object
Vector2& operator*=(const Vector2& rhs); // multiply each element and update
this object
Vector2 operator/(const float scale) const; // inverse scale
Vector2& operator/=(const float scale); // scale and update this object
bool operator==(const Vector2& rhs) const; // exact compare, no epsilon
bool operator!=(const Vector2& rhs) const; // exact compare, no epsilon
bool operator<(const Vector2& rhs) const; // comparison for sort
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]
///////////////////////////////////////////////////////////////////////////////
// 3D vector
///////////////////////////////////////////////////////////////////////////////
struct Vector3
{
float x;
float y;
float z;
// ctors
Vector3() : x(0), y(0), z(0) {};
Vector3(float x, float y, float z) : x(x), y(y), z(z) {};
// operators
Vector3 operator-() const; // unary operator (negate)
Vector3 operator+(const Vector3& rhs) const; // add rhs
Vector3 operator-(const Vector3& rhs) const; // subtract rhs
Vector3& operator+=(const Vector3& rhs); // add rhs and update this object
Vector3& operator-=(const Vector3& rhs); // subtract rhs and update this object
Vector3 operator*(const float scale) const; // scale
Vector3 operator*(const Vector3& rhs) const; // multiplay each element
Vector3& operator*=(const float scale); // scale and update this object
Vector3& operator*=(const Vector3& rhs); // product each element and update
this object
Vector3 operator/(const float scale) const; // inverse scale
Vector3& operator/=(const float scale); // scale and update this object
bool operator==(const Vector3& rhs) const; // exact compare, no epsilon
bool operator!=(const Vector3& rhs) const; // exact compare, no epsilon
bool operator<(const Vector3& rhs) const; // comparison for sort
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]
///////////////////////////////////////////////////////////////////////////////
// 4D vector
///////////////////////////////////////////////////////////////////////////////
struct Vector4
{
float x;
float y;
float z;
float w;
// ctors
Vector4() : x(0), y(0), z(0), w(0) {};
Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {};
// utils functions
void set(float x, float y, float z, float w);
float length() const; //
float distance(const Vector4& vec) const; // distance between two vectors
Vector4& normalize(); //
float dot(const Vector4& vec) const; // dot product
bool equal(const Vector4& vec, float e) const; // compare with epsilon
// operators
Vector4 operator-() const; // unary operator (negate)
Vector4 operator+(const Vector4& rhs) const; // add rhs
Vector4 operator-(const Vector4& rhs) const; // subtract rhs
Vector4& operator+=(const Vector4& rhs); // add rhs and update this object
Vector4& operator-=(const Vector4& rhs); // subtract rhs and update this object
Vector4 operator*(const float scale) const; // scale
Vector4 operator*(const Vector4& rhs) const; // multiply each element
Vector4& operator*=(const float scale); // scale and update this object
Vector4& operator*=(const Vector4& rhs); // multiply each element and update
this object
Vector4 operator/(const float scale) const; // inverse scale
Vector4& operator/=(const float scale); // scale and update this object
bool operator==(const Vector4& rhs) const; // exact compare, no epsilon
bool operator!=(const Vector4& rhs) const; // exact compare, no epsilon
bool operator<(const Vector4& rhs) const; // comparison for sort
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]
///////////////////////////////////////////////////////////////////////////////
// inline functions for Vector2
///////////////////////////////////////////////////////////////////////////////
inline Vector2 Vector2::operator-() const {
return Vector2(-x, -y);
}
///////////////////////////////////////////////////////////////////////////////
// inline functions for Vector3
///////////////////////////////////////////////////////////////////////////////
inline Vector3 Vector3::operator-() const {
return Vector3(-x, -y, -z);
}
///////////////////////////////////////////////////////////////////////////////
// inline functions for Vector4
///////////////////////////////////////////////////////////////////////////////
inline Vector4 Vector4::operator-() const {
return Vector4(-x, -y, -z, -w);
}
#endif
2.2 Matrices.h
///////////////////////////////////////////////////////////////////////////////
// Matrice.h
// =========
// NxN Matrix Math classes
//
// All matrices are row major. (OpenGL uses column-major matrix)
// | 0 1 | | 0 1 2 | | 0 1 2 3 |
// | 2 3 | | 3 4 5 | | 4 5 6 7 |
// | 6 7 8 | | 8 9 10 11 |
// | 12 13 14 15 |
///////////////////////////////////////////////////////////////////////////////
#ifndef MATH_MATRICES_H
#define MATH_MATRICES_H
#include "Vectors.h"
Matrix2& identity();
Matrix2& transpose(); // transpose itself and return
reference
Matrix2& invert();
// operators
Matrix2 operator+(const Matrix2& rhs) const; // add rhs
Matrix2 operator-(const Matrix2& rhs) const; // subtract rhs
Matrix2& operator+=(const Matrix2& rhs); // add rhs and update this object
Matrix2& operator-=(const Matrix2& rhs); // subtract rhs and update this object
Vector2 operator*(const Vector2& rhs) const; // multiplication: v' = M * v
Matrix2 operator*(const Matrix2& rhs) const; // multiplication: M3 = M1 * M2
Matrix2& operator*=(const Matrix2& rhs); // multiplication: M1' = M1 * M2
bool operator==(const Matrix2& rhs) const; // exact compare, no epsilon
bool operator!=(const Matrix2& rhs) const; // exact compare, no epsilon
float operator[](int index) const; // subscript operator v[0], v[1]
float& operator[](int index); // subscript operator v[0], v[1]
protected:
private:
float m[4];
};
///////////////////////////////////////////////////////////////////////////
// 3x3 matrix
///////////////////////////////////////////////////////////////////////////
class Matrix3
{
public:
// constructors
Matrix3(); // init with identity
Matrix3(const float src[9]);
Matrix3(float xx, float xy, float xz,
float yx, float yy, float yz,
float zx, float zy, float zz);
Matrix3& identity();
Matrix3& transpose(); // transpose itself and return
reference
Matrix3& invert();
protected:
private:
float m[9];
};
///////////////////////////////////////////////////////////////////////////
// 4x4 matrix
///////////////////////////////////////////////////////////////////////////
class Matrix4
{
public:
// constructors
Matrix4(); // init with identity
Matrix4(const float src[16]);
Matrix4(float xx, float xy, float xz, float xw,
float yx, float yy, float yz, float yw,
float zx, float zy, float zz, float zw,
float wx, float wy, float wz, float ww);
Matrix4& identity();
Matrix4& transpose(); // transpose itself and return
reference
Matrix4& invert(); // check best inverse method before
inverse
Matrix4& invertEuclidean(); // inverse of Euclidean transform
matrix
Matrix4& invertAffine(); // inverse of affine transform matrix
Matrix4& invertProjective(); // inverse of projective matrix using
partitioning
Matrix4& invertGeneral(); // inverse of generic matrix
// transform matrix
Matrix4& translate(float x, float y, float z); // translation by (x,y,z)
Matrix4& translate(const Vector3& v); //
Matrix4& rotate(float angle, const Vector3& axis); // rotate angle(degree) along the
given axix
Matrix4& rotate(float angle, float x, float y, float z);
Matrix4& rotateX(float angle); // rotate on X-axis with degree
Matrix4& rotateY(float angle); // rotate on Y-axis with degree
Matrix4& rotateZ(float angle); // rotate on Z-axis with degree
Matrix4& scale(float scale); // uniform scale
Matrix4& scale(float sx, float sy, float sz); // scale by (sx, sy, sz) on each axis
protected:
private:
float getCofactor(float m0, float m1, float m2,
float m3, float m4, float m5,
float m6, float m7, float m8);
float m[16];
float tm[16]; // transpose m
};
///////////////////////////////////////////////////////////////////////////
// inline functions for Matrix2
///////////////////////////////////////////////////////////////////////////
inline Matrix2::Matrix2()
{
// initially identity matrix
identity();
}
inline void Matrix2::set(float xx, float xy, float yx, float yy)
{
m[0]= xx; m[1] = xy; m[2] = yx; m[3]= yy;
}
///////////////////////////////////////////////////////////////////////////
// inline functions for Matrix3
///////////////////////////////////////////////////////////////////////////
inline Matrix3::Matrix3()
{
// initially identity matrix
identity();
}
inline void Matrix4::set(float xx, float xy, float xz, float xw,
float yx, float yy, float yz, float yw,
float zx, float zy, float zz, float zw,
float wx, float wy, float wz, float ww)
{
m[0] = xx; m[1] = xy; m[2] = xz; m[3] = xw;
m[4] = yx; m[5] = yy; m[6] = yz; m[7] = yw;
m[8] = zx; m[9] = zy; m[10]= zz; m[11]= zw;
m[12]= wx; m[13]= wy; m[14]= wz; m[15]= ww;
}
2.3 main.cpp
///////////////////////////////////////////////////////////////////////////////
// matrix.cpp
// ==========
// Example of understanding OpenGL transform matrix(GL_MODELVIEW)
///////////////////////////////////////////////////////////////////////////////
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <iomanip>
//#include "Matrices.h"
#include "Vectors.h"
using std::stringstream;
using std::cout;
using std::endl;
using std::ends;
//==================================================
///////////////////////////////////////////////////////////////////////////////
// Matrice.cpp
// ===========
// NxN Matrix Math classes
//
// All matrices are row major. (OpenGL uses column-major matrix)
// | 0 1 | | 0 1 2 | | 0 1 2 3 |
// | 2 3 | | 3 4 5 | | 4 5 6 7 |
// | 6 7 8 | | 8 9 10 11 |
// | 12 13 14 15 |
//
///////////////////////////////////////////////////////////////////////////////
#include <cmath>
#include <algorithm>
#include "Matrices.h"
///////////////////////////////////////////////////////////////////////////////
// return the determinant of 2x2 matrix
///////////////////////////////////////////////////////////////////////////////
float Matrix2::getDeterminant()
{
return m[0] * m[3] - m[1] * m[2];
}
///////////////////////////////////////////////////////////////////////////////
// inverse of 2x2 matrix
// If cannot find inverse, set identity matrix
///////////////////////////////////////////////////////////////////////////////
Matrix2& Matrix2::invert()
{
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// return determinant of 3x3 matrix
///////////////////////////////////////////////////////////////////////////////
float Matrix3::getDeterminant()
{
return m[0] * (m[4] * m[8] - m[5] * m[7]) -
m[1] * (m[3] * m[8] - m[5] * m[6]) +
m[2] * (m[3] * m[7] - m[4] * m[6]);
}
///////////////////////////////////////////////////////////////////////////////
// inverse 3x3 matrix
// If cannot find inverse, set identity matrix
///////////////////////////////////////////////////////////////////////////////
Matrix3& Matrix3::invert()
{
float determinant, invDeterminant;
float tmp[9];
// check determinant if it is 0
determinant = m[0] * tmp[0] + m[1] * tmp[3] + m[2] * tmp[6];
if(fabs(determinant) <= 0.00001f)
{
return identity(); // cannot inverse, make it idenety matrix
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// transpose 4x4 matrix
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::transpose()
{
std::swap(m[1], m[4]);
std::swap(m[2], m[8]);
std::swap(m[3], m[12]);
std::swap(m[6], m[9]);
std::swap(m[7], m[13]);
std::swap(m[11], m[14]);
return *this;
///////////////////////////////////////////////////////////////////////////////
// inverse 4x4 matrix
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invert()
{
// If the 4th row is [0,0,0,1] then it is affine matrix and
// it has no projective transformation.
if(m[12] == 0 && m[13] == 0 && m[14] == 0 && m[15] == 1) this->invertAffine();
else this->invertGeneral();
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// compute the inverse of 4x4 Euclidean transformation matrix
//
// Euclidean transformation is translation, rotation, and reflection.
// With Euclidean transform, only the position and orientation of the object
// will be changed. Euclidean transform does not change the shape of an object
// (no scaling). Length and angle are reserved.
//
// Use inverseAffine() if the matrix has scale and shear transformation.
//
// M = [ R | T ]
// [ --+-- ] (R denotes 3x3 rotation/reflection matrix)
// [ 0 | 1 ] (T denotes 1x3 translation matrix)
//
// y = M*x -> y = R*x + T -> x = R^-1*(y - T) -> x = R^T*y - R^T*T
// (R is orthogonal, R^-1 = R^T)
//
// [ R | T ]-1 [ R^T | -R^T * T ] (R denotes 3x3 rotation matrix)
// [ --+-- ] = [ ----+--------- ] (T denotes 1x3 translation)
// [ 0 | 1 ] [ 0 | 1 ] (R^T denotes R-transpose)
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invertEuclidean()
{
// transpose 3x3 rotation matrix part
// | R^T | 0 |
// | ----+-- |
// | 0 | 1 |
float tmp;
tmp = m[1]; m[1] = m[4]; m[4] = tmp;
tmp = m[2]; m[2] = m[8]; m[8] = tmp;
tmp = m[6]; m[6] = m[9]; m[9] = tmp;
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// compute the inverse of a 4x4 affine transformation matrix
//
// Affine transformations are generalizations of Euclidean transformations.
// Affine transformation includes translation, rotation, reflection, scaling,
// and shearing. Length and angle are NOT preserved.
// M = [ R | T ]
// [ --+-- ] (R denotes 3x3 rotation/scale/shear matrix)
// [ 0 | 1 ] (T denotes 1x3 translation matrix)
//
// y = M*x -> y = R*x + T -> x = R^-1*(y - T) -> x = R^-1*y - R^-1*T
//
// [ R | T ]-1 [ R^-1 | -R^-1 * T ]
// [ --+-- ] = [ -----+---------- ]
// -R^-1 * T
float x = m[3];
float y = m[7];
float z = m[11];
m[3] = -(r[0] * x + r[1] * y + r[2] * z);
m[7] = -(r[3] * x + r[4] * y + r[5] * z);
m[11] = -(r[6] * x + r[7] * y + r[8] * z);
return * this;
}
///////////////////////////////////////////////////////////////////////////////
// inverse matrix using matrix partitioning (blockwise inverse)
// It devides a 4x4 matrix into 4 of 2x2 matrices. It works in case of where
// det(A) != 0. If not, use the generic inverse method
// inverse formula.
// M = [ A | B ] A, B, C, D are 2x2 matrix blocks
// [ --+-- ] det(M) = |A| * |D - ((C * A^-1) * B)|
// [ C | D ]
//
// M^-1 = [ A' | B' ] A' = A^-1 - (A^-1 * B) * C'
// [ ---+--- ] B' = (A^-1 * B) * -D'
// [ C' | D' ] C' = -D' * (C * A^-1)
// D' = (D - ((C * A^-1) * B))^-1
//
// NOTE: I wrap with () if it it used more than once.
// The matrix is invertable even if det(A)=0, so must check det(A) before
// calling this function, and use invertGeneric() instead.
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invertProjective()
{
// partition
Matrix2 a(m[0], m[1], m[4], m[5]);
Matrix2 b(m[2], m[3], m[6], m[7]);
Matrix2 c(m[8], m[9], m[12], m[13]);
Matrix2 d(m[10], m[11], m[14], m[15]);
// compute C'
Matrix2 c1 = d2 * ca; // -D' * (C * A^-1)
// compute B'
Matrix2 b1 = ab * d2; // (A^-1 * B) * -D'
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// compute the inverse of a general 4x4 matrix using Cramer's Rule
// If cannot find inverse, return indentity matrix
// M^-1 = adj(M) / det(M)
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::invertGeneral()
{
// get cofactors of minor matrices
float cofactor0 = getCofactor(m[5],m[6],m[7], m[9],m[10],m[11], m[13],m[14],m[15]);
float cofactor1 = getCofactor(m[4],m[6],m[7], m[8],m[10],m[11], m[12],m[14],m[15]);
float cofactor2 = getCofactor(m[4],m[5],m[7], m[8],m[9], m[11], m[12],m[13],m[15]);
float cofactor3 = getCofactor(m[4],m[5],m[6], m[8],m[9], m[10], m[12],m[13],m[14]);
// get determinant
float determinant = m[0] * cofactor0 - m[1] * cofactor1 + m[2] * cofactor2 - m[3] *
cofactor3;
if(fabs(determinant) <= 0.00001f)
{
return identity();
}
return *this;
}
///////////////////////////////////////////////////////////////////////////////
// return determinant of 4x4 matrix
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// compute cofactor of 3x3 minor matrix without sign
// input params are 9 elements of the minor matrix
// NOTE: The caller must know its sign.
///////////////////////////////////////////////////////////////////////////////
float Matrix4::getCofactor(float m0, float m1, float m2,
float m3, float m4, float m5,
float m6, float m7, float m8)
{
return m0 * (m4 * m8 - m5 * m7) -
m1 * (m3 * m8 - m5 * m6) +
m2 * (m3 * m7 - m4 * m6);
}
///////////////////////////////////////////////////////////////////////////////
// translate this matrix by (x, y, z)
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::translate(const Vector3& v)
{
return translate(v.x, v.y, v.z);
}
///////////////////////////////////////////////////////////////////////////////
// uniform scale
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::scale(float s)
{
return scale(s, s, s);
}
///////////////////////////////////////////////////////////////////////////////
// build a rotation matrix with given angle(degree) and rotation axis, then
// multiply it with this object
///////////////////////////////////////////////////////////////////////////////
Matrix4& Matrix4::rotate(float angle, const Vector3& axis)
{
return rotate(angle, axis.x, axis.y, axis.z);
}
// multiply it
*this = m * (*this);
return *this;
}
m[4] = m4 * c + m8 *-s;
m[5] = m5 * c + m9 *-s;
m[6] = m6 * c + m10*-s;
m[7] = m7 * c + m11*-s;
m[8] = m4 * s + m8 * c;
m[9] = m5 * s + m9 * c;
m[10]= m6 * s + m10* c;
m[11]= m7 * s + m11* c;
return *this;
}
m[0] = m0 * c + m8 * s;
m[1] = m1 * c + m9 * s;
m[2] = m2 * c + m10* s;
m[3] = m3 * c + m11* s;
m[8] = m0 *-s + m8 * c;
m[9] = m1 *-s + m9 * c;
m[10]= m2 *-s + m10* c;
m[11]= m3 *-s + m11* c;
return *this;
}
m[0] = m0 * c + m4 *-s;
m[1] = m1 * c + m5 *-s;
m[2] = m2 * c + m6 *-s;
m[3] = m3 * c + m7 *-s;
m[4] = m0 * s + m4 * c;
m[5] = m1 * s + m5 * c;
m[6] = m2 * s + m6 * c;
m[7] = m3 * s + m7 * c;
return *this;
}
//===================================================
void initGL();
int initGLUT(int argc, char **argv);
bool initSharedMem();
void clearSharedMem();
void initLights();
void setCamera(float posX, float posY, float posZ, float targetX, float targetY, float
targetZ);
void drawString(const char *str, int x, int y, float color[4], void *font);
void drawString3D(const char *str, float pos[3], float color[4], void *font);
void showInfo();
void toOrtho();
void toPerspective();
void drawAxis(float size=2.5f);
void drawModel();
void anglesToMatrix(const Vector3 angles, Matrix4& matrix);
Matrix4 setFrustum(float l, float r, float b, float t, float n, float f);
Matrix4 setFrustum(float fovY, float aspectRatio, float front, float back);
Matrix4 setOrthoFrustum(float l, float r, float b, float t, float n, float f);
// constants
const int SCREEN_WIDTH = 400;
const int SCREEN_HEIGHT = 300;
const float CAMERA_DISTANCE = 6.0f;
const int TEXT_WIDTH = 8;
const int TEXT_HEIGHT = 13;
//const float DEG2RAD = 3.141593f / 180;
// global variables
void *font = GLUT_BITMAP_8_BY_13;
int screenWidth;
int screenHeight;
bool mouseLeftDown;
bool mouseRightDown;
float mouseX, mouseY;
float cameraAngleX;
float cameraAngleY;
float cameraDistance;
int drawMode = 0;
Matrix4 matrixView;
Matrix4 matrixModel;
Matrix4 matrixModelView; // = matrixView * matrixModel
Matrix4 matrixProjection;
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
/*
// Matrix4 usage examples =================================================
// Note that Matrix4 is row-major order
// accessors (getter/setter)
m1.set(a); // init with array
m2.set(3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3); // init with 16 elements
m3 = m2; // init with assignemt operator
(=)
const float* a1 = m1.get(); // return pointer to matrix
elements
const float* a2 = m2.getTranspose(); // return transposed matrix
elements
// comparison (exact)
if(m1 == m2)
std::cout << "COMPARISON: EQUAL\n\n";
else
std::cout << "COMPARISON: NOT EQUAL\n\n";
// addition
m3 = m1 + m2; // M3 = M1 + M2
std::cout << "ADD:\n" << m3 << std::endl;
// subtraction
m3 = m1 - m2; // M3 = M1 - M2
std::cout << "SUBTRACT:\n" << m3 << std::endl;
// multiplication
m3 = m1 * m2; // M3 = M1 * M2
m3 *= m1; // M3 = M3 * M1 (=
glMultMatrixf(M1))
std::cout << "MULTIPLY:\n" << m3 << std::endl;
// vector multiplication
Vector3 v1 = Vector3(2,2,2);
Vector3 v2;
v2 = m1 * v1; // vector product: M * v
std::cout << "VECTOR MULTIPLY 1: " << v2 << std::endl;
v2 = v1 * m1; // pre-product: v * M
std::cout << "VECTOR MULTIPLY 2: " << v2 << "\n\n";
// transpose
m3.set(1,1,1,1, 2,2,2,2, 3,3,3,3, 4,4,4,4);
m3.transpose(); // transpose
std::cout << "TRANSPOSE:\n" << m3 << std::endl;
// inverse of non-singluar
m3.set(1,0,0,0, 0,2,0,0, 0,0,3,0, 0,0,0,4); // non-singular M
m3.invert(); // inverse
std::cout << "INVERSE:\n" << m3 << std::endl;
// translate transform
m3.identity();
m3.translate(1, 2, 3); // = glTranslatef(x, y, z)
//m3.translate(v1);
std::cout << "TRANSLATE:\n" << m3 << std::endl;
// scale
m3.identity();
m3.scale(1, 2, 3); // = glScalef(x, y, z)
std::cout << "SCALE:\n" << m3 << std::endl;
*/
//=========================================================================
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// draw the local axis of an object
///////////////////////////////////////////////////////////////////////////////
void drawAxis(float size)
{
glDepthFunc(GL_ALWAYS); // to avoid visual artifacts with grid lines
glDisable(GL_LIGHTING);
// draw axis
glLineWidth(3);
glBegin(GL_LINES);
glColor3f(1, 0, 0);
glVertex3f(0, 0, 0);
glVertex3f(size, 0, 0);
glColor3f(0, 1, 0);
glVertex3f(0, 0, 0);
glVertex3f(0, size, 0);
glColor3f(0, 0, 1);
glVertex3f(0, 0, 0);
glVertex3f(0, 0, size);
glEnd();
glLineWidth(1);
///////////////////////////////////////////////////////////////////////////////
// draw a model (tetrahedron)
///////////////////////////////////////////////////////////////////////////////
void drawModel()
{
glColor3f(1, 1, 1);
glBegin(GL_TRIANGLES);
glNormal3f(0.6667f, 0.6667f, 0.3334f);
glVertex3f(1, 0, 0);
glVertex3f(0, 1, 0);
glVertex3f(0, 0, 2);
/*
glNormal3f(-0.6667f, 0.6667f, 0.3334f);
glVertex3f(-1, 0, 0);
glVertex3f(0, 0, 2);
glVertex3f(0, 1, 0);
glNormal3f(0, 0, -1);
glVertex3f(1, 0, 0);
glVertex3f(0, 0, 2);
glVertex3f(-1, 0, 0);
///////////////////////////////////////////////////////////////////////////////
return handle;
}
///////////////////////////////////////////////////////////////////////////////
// initialize OpenGL
// disable unused features
///////////////////////////////////////////////////////////////////////////////
void initGL()
{
glShadeModel(GL_SMOOTH); // shading mathod: GL_SMOOTH or GL_FLAT
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
// track material ambient and diffuse from surface color, call it before
glEnable(GL_COLOR_MATERIAL)
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
initLights();
}
///////////////////////////////////////////////////////////////////////////////
// write 2d text using GLUT
// The projection matrix must be set to orthogonal before call this function.
///////////////////////////////////////////////////////////////////////////////
void drawString(const char *str, int x, int y, float color[4], void *font)
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glPopAttrib();
}
///////////////////////////////////////////////////////////////////////////////
// draw a string in 3D space
///////////////////////////////////////////////////////////////////////////////
void drawString3D(const char *str, float pos[3], float color[4], void *font)
{
glPushAttrib(GL_LIGHTING_BIT | GL_CURRENT_BIT); // lighting and color mask
glDisable(GL_LIGHTING); // need to disable lighting for proper text color
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glPopAttrib();
}
///////////////////////////////////////////////////////////////////////////////
// initialize global variables
///////////////////////////////////////////////////////////////////////////////
bool initSharedMem()
{
screenWidth = SCREEN_WIDTH;
screenHeight = SCREEN_HEIGHT;
cameraAngleX = cameraAngleY = 0;
cameraDistance = CAMERA_DISTANCE;
return true;
}
///////////////////////////////////////////////////////////////////////////////
// initialize lights
///////////////////////////////////////////////////////////////////////////////
void initLights()
{
// set up light colors (ambient, diffuse, specular)
GLfloat lightKa[] = {.2f, .2f, .2f, 1.0f}; // ambient light
GLfloat lightKd[] = {.7f, .7f, .7f, 1.0f}; // diffuse light
GLfloat lightKs[] = {1, 1, 1, 1}; // specular light
glLightfv(GL_LIGHT0, GL_AMBIENT, lightKa);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightKd);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightKs);
///////////////////////////////////////////////////////////////////////////////
// set camera position and lookat direction
///////////////////////////////////////////////////////////////////////////////
void setCamera(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float
centerZ)
{
Vector3 eye(eyeX, eyeY, eyeZ);
Vector3 center(centerX, centerY, centerZ);
Vector3 up(0, 1, 0); // assume the camera is always straight up (no roll)
///////////////////////////////////////////////////////////////////////////////
// display info messages
///////////////////////////////////////////////////////////////////////////////
void showInfo()
{
// backup current model-view matrix
glPushMatrix(); // save current modelview matrix
glLoadIdentity(); // reset modelview matrix
stringstream ss;
ss << std::fixed << std::setprecision(3);
///////////////////////////////////////////////////////////////////////////////
// set projection matrix as orthogonal
///////////////////////////////////////////////////////////////////////////////
void toOrtho()
{
// set viewport to be the entire window
glViewport(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight);
///////////////////////////////////////////////////////////////////////////////
// set the projection matrix as perspective
///////////////////////////////////////////////////////////////////////////////
void toPerspective()
{
// set viewport to be the entire window
glViewport(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight);
///////////////////////////////////////////////////////////////////////////////
// convert Euler angles(x,y,z) to matrix4
// Each column of the rotation matrix represents left, up and forward axis.
// The order of rotation is Roll->Yaw->Pitch (Rx*Ry*Rz)
// Rx: rotation about X-axis, pitch
// Ry: rotation about Y-axis, yaw(heading)
// Rz: rotation about Z-axis, roll
// Rx Ry Rz
// |1 0 0| | Cy 0 Sy| |Cz -Sz 0| | CyCz -CySz Sy |
// |0 Cx -Sx|*| 0 1 0|*|Sz Cz 0| = | SxSyCz+CxSz -SxSySz+CxCz -SxCy|
// |0 Sx Cx| |-Sy 0 Cy| | 0 0 1| |-CxSyCz+SxSz CxSySz+SxCz CxCy|
///////////////////////////////////////////////////////////////////////////////
void anglesToMatrix(const Vector3 angles, Matrix4& matrix)
{
const float DEG2RAD = 3.141593f / 180;
float sx, sy, sz, cx, cy, cz, theta;
Vector3 left, up, forward;
// determine up axis
up.x = -cy*sz;
up.y = -sx*sy*sz + cx*cz;
up.z = cx*sy*sz + sx*cz;
///////////////////////////////////////////////////////////////////////////////
// set a perspective frustum with 6 params similar to glFrustum()
// (left, right, bottom, top, near, far)
// Note: this is for row-major notation. OpenGL needs transpose it
///////////////////////////////////////////////////////////////////////////////
Matrix4 setFrustum(float l, float r, float b, float t, float n, float f)
{
Matrix4 mat;
mat[0] = 2 * n / (r - l);
mat[2] = (r + l) / (r - l);
mat[5] = 2 * n / (t - b);
mat[6] = (t + b) / (t - b);
mat[10] = -(f + n) / (f - n);
mat[11] = -(2 * f * n) / (f - n);
mat[14] = -1;
mat[15] = 0;
return mat;
}
///////////////////////////////////////////////////////////////////////////////
// set a symmetric perspective frustum with 4 params similar to gluPerspective
// (vertical field of view, aspect ratio, near, far)
///////////////////////////////////////////////////////////////////////////////
Matrix4 setFrustum(float fovY, float aspectRatio, float front, float back)
{
float tangent = tanf(fovY/2 * DEG2RAD); // tangent of half fovY
float height = front * tangent; // half height of near plane
float width = height * aspectRatio; // half width of near plane
///////////////////////////////////////////////////////////////////////////////
// set a orthographic frustum with 6 params similar to glOrtho()
// (left, right, bottom, top, near, far)
// Note: this is for row-major notation. OpenGL needs transpose it
///////////////////////////////////////////////////////////////////////////////
Matrix4 setOrthoFrustum(float l, float r, float b, float t, float n, float f)
{
Matrix4 mat;
mat[0] = 2 / (r - l);
mat[3] = -(r + l) / (r - l);
mat[5] = 2 / (t - b);
mat[7] = -(t + b) / (t - b);
mat[10] = -2 / (f - n);
mat[11] = -(f + n) / (f - n);
return mat;
}
//=============================================================================
// CALLBACKS
void displayCB()
{
// clear buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// tramsform camera
matrixView.identity();
matrixView.rotate(cameraAngleY, 0, 1, 0);
matrixView.rotate(cameraAngleX, 1, 0, 0);
matrixView.translate(0, 0, -cameraDistance);
// The equivalent code for using OpenGL routine is:
// glTranslatef(0, 0, -cameraDistance);
// glRotatef(cameraAngleX, 1, 0, 0); // pitch
// glRotatef(cameraAngleY, 0, 1, 0); // heading
drawAxis();
drawModel();
// DEBUG
std::cout << "===== Projection Matrix =====\n";
std::cout << matrixProjection << std::endl;
void idleCB()
{
glutPostRedisplay();
}
default:
;
}
}
if(button == GLUT_LEFT_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseLeftDown = true;
}
else if(state == GLUT_UP) mouseLeftDown = false;
}
3. BÀI TẬP
Viết chương trình thực hiện các yêu cầu sau:
1) Cho điểm Pobj(xobj, yobj, zobj, 1) trong hệ tọa độ thế giới thực (world wpace), với xobj,
yobj, zobj là các giá trị được trích từ mã sinh viên.
Xác định các ma trận biến đổi và điểm Pw(xw, yw, zw, 1) khi thực hiện các phép biến đổi
sau:
// Điểm Pobj(xobj, yobj, zobj, 1) trong hệ tọa độ thế giới thực (world wpace)
GLfloat xobj = 2.0f;
GLfloat yobj = 3.0f;
GLfloat zobj = 1.0f;
// Điểm Pw(xw, yw, zw, 1) khi thực hiện các phép biến đổi
GLfloat xw, yw, zw;
// Phép biến đổi quay quanh trục Ox, Oy, Oz một góc theta
void rotate(GLfloat angle, GLfloat axis_x, GLfloat axis_y, GLfloat axis_z) {
GLfloat rad = angle * M_PI / 180.0f;
// Phép biến đổi quay quanh trục PQ có P(xp, yp, zp), Q(xq, yq, zq)
void rotatePQ(GLfloat angle, GLfloat xp, GLfloat yp, GLfloat zp, GLfloat xq,
GLfloat yq, GLfloat zq) {
GLfloat axis_x = xq - xp;
GLfloat axis_y = yq - yp;
GLfloat axis_z = zq - zp;
GLfloat length = sqrt(axis_x * axis_x + axis_y * axis_y + axis_z * axis_z);
axis_x /= length;
axis_y /= length;
axis_z /= length;
GLfloat px = xobj - xp;
GLfloat py = yobj - yp;
GLfloat pz = zobj - zp;
GLfloat cos_theta = cos(angle * M_PI / 180.0f);
GLfloat sin_theta = sin(angle * M_PI / 180.0f);
------------------------------------------------