1. 題目:Implement an OpenGL-like 3D Rendering Pipeline
1.1. Goal
You are to write a program to read a set of commands from file and display result on screen.
1.2. Commands
- object: filer name, load a 3D model file, apply current modeling transform to the object.
- translate X Y: do a translation by (X, Y), multiply the current matrix by a translation matrix.
- rotate X Y: do a rotation by R degree, multiply the current matrix by a rotation matrix.
- scale X Y: do a scaling by (X, Y), multiply the current matrix by a scaling matrix.
- observer: PX PY PZ CX CY CZ Tilt zNear zFar hFOV. (PX, PY, PX): eye’s position; (CX, CY, CZ): COI(center of interest); Tilt: tilt degree of camera; zNear: distance of near clipping plane; zFar: distance of far clipping plane; hFOV: half Field of View.
1.3. Examples
# Sample1
# load a teapot
object teapot.asc
# set viewport
viewport 0 800 0 600
# Eye (0,0,10) Look at (0,0,0)
observer 0 0 10 0 0 0 0 1 100 45
display
end
# Sample2
# modeling trasnform
translate 3 0 0
# load a teapot
object teapot.asc
# set viewport
viewport 0 800 0 600
# Eye at(5,5,5) Look at (0,0,0)
observer 5 5 5 0 0 0 0 1 100 45
display
end
2. 源碼
translate,scale以及rotate矩陣寫法已經在上一次的文章中註明,這一次主要貼一些新的矩陣:
/* Calculate and get the eye tanslate matrix. */
void Eye_Translate(float a, float b, float c) {
float translation_matrix[4][4];
float Eye_Translate_Matrix_Copy[4][4];
int i, j, k;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
translation_matrix[i][j] = 0;
Eye_Translate_Matrix_Copy[i][j] = Eye_Translate_Matrix[i][j];
Eye_Translate_Matrix[i][j] = 0;
}
}
translation_matrix[0][0] = 1;
translation_matrix[1][1] = 1;
translation_matrix[2][2] = 1;
translation_matrix[3][3] = 1;
translation_matrix[0][3] = a;
translation_matrix[1][3] = b;
translation_matrix[2][3] = c;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
for (k = 0 ; k < 4 ; k++) {
Eye_Translate_Matrix[i][j] += translation_matrix[i][k] * Eye_Translate_Matrix_Copy[k][j];
}
}
}
}
/* Calculate and get the eye tilt matrix. */
void Eye_Tilt(float c) {
float rotate_matrix[4][4];
float Eye_Tilt_Matrix_Copy[4][4];
int i, j, k;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
rotate_matrix[i][j] = 0;
Eye_Tilt_Matrix_Copy[i][j] = Eye_Tilt_Matrix[i][j];
Eye_Tilt_Matrix[i][j] = 0;
}
}
rotate_matrix[0][0] = cos((c / 180.0 * 3.14159265 ));
rotate_matrix[0][1] = -sin((c / 180.0 * 3.14159265 ));
rotate_matrix[1][0] = sin((c / 180.0 * 3.14159265 ));
rotate_matrix[1][1] = cos((c / 180.0 * 3.14159265 ));
rotate_matrix[2][2] = 1;
rotate_matrix[3][3] = 1;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
for (k = 0 ; k < 4 ; k++) {
Eye_Tilt_Matrix[i][j] += rotate_matrix[i][k] * Eye_Tilt_Matrix_Copy[k][j];
}
}
}
}
/* Calculate and get GRM, Mirror Matrix. */
void Observer(float x1, float x2, float x3, float x4, float x5, float x6, float x7, float x8, float x9, float x10) {
H = x8, y = x9, theta = x10;
int i, j;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
GRM[i][j] = 0;
Mirror[i][j] = 0;
}
}
Mirror[0][0] = -1, Mirror[1][1] = 1, Mirror[2][2] = 1, Mirror[3][3] = 1;
float vt[3], vz[3], v1[3], v2[3], v3[3];
vt[0] = 0, vt[1] = 1, vt[2] = 0;
vz[0] = x4 - x1, vz[1] = x5 - x2, vz[2] = x6 - x3;
float length_of_vz = sqrt(vz[0] * vz[0] + vz[1] * vz[1] + vz[2] * vz[2]);
float length_of_vt = 1;
v3[0] = vz[0] / length_of_vz, v3[1] = vz[1] / length_of_vz, v3[2] = vz[2] / length_of_vz;
float length_of_v3 = 1;
v1[0] = vt[1] * vz[2] - vt[2] * vz[1], v1[1] = vt[2] * vz[0] - vt[0] * vz[1], v1[2] = vt[0] * vz[1] - vt[1] * vz[0];
float length_of_v1 = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]);
v1[0] = v1[0] / length_of_v1, v1[1] = v1[1] / length_of_v1, v1[2] = v1[2] / length_of_v1;
v2[0] = v3[1] * v1[2] - v3[2] * v1[1], v2[1] = v3[2] * v1[0] - v3[0] * v1[1], v2[2] = v3[0] * v1[1] - v3[1] * v1[0];
float length_of_v2 = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]);
v2[0] = v2[0] / length_of_v2, v2[1] = v2[1] / length_of_v2, v2[2] = v2[2] / length_of_v2;
GRM[0][0] = v1[0], GRM[0][1] = v1[1], GRM[0][2] = v1[2];
GRM[1][0] = v2[0], GRM[1][1] = v2[1], GRM[1][2] = v2[2];
GRM[2][0] = v3[0], GRM[2][1] = v3[1], GRM[2][2] = v3[2], GRM[3][3] = 1;
cout << "GRM Matrix:" << endl;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
printf("%.2f ", GRM[i][j]);
}
cout << endl;
}
cout << "---------------------------------------------------------" <<endl << endl;
cout << "Eye Mirror Matrix:" << endl;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
printf("%.2f ", Mirror[i][j]);
}
cout << endl;
}
cout << "---------------------------------------------------------" <<endl << endl;
Eye_Translate(-x1, -x2, -x3);
Eye_Tilt(-x7);
cout << "Eye Tilt Matrix: "<< endl;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
printf("%.2f ", Eye_Tilt_Matrix[i][j]);
}
cout << endl;
}
cout << "---------------------------------------------------------" <<endl << endl;
cout << "Eye Translate Matrix: "<< endl;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
printf("%.2f ", Eye_Translate_Matrix[i][j]);
}
cout << endl;
}
cout << "---------------------------------------------------------" <<endl << endl;
}
/* 3D rendering pipeline, multiply PM, eye tilt, mirror, GRM, eye translate, translate. Then get the final vertex.*/
void Display() {
int i, j, k;
float AR = w / h;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
PM[i][j] = 0;
}
}
PM[0][0] = 1;
PM[1][1] = AR;
PM[2][2] = y * tan((theta / 180.0 * 3.14159265 )) / (y - H);
PM[2][3] = H * y * tan((theta / 180.0 * 3.14159265 )) / (H - y);
PM[3][2] = tan((theta / 180.0 * 3.14159265 ));
cout << "Projection Matrix: " << endl;
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
printf("%.2f ", PM[i][j]);
}
cout << endl;
}
cout << "---------------------------------------------------------" <<endl << endl;
int l = 0;
for (l = 0 ; l < number_of_translate_matrix ; l++) {
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
Current_Matrix_Copy[i][j] = 0;
}
}
/* PM * Tilt */
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
for (k = 0 ; k < 4 ; k++) {
Current_Matrix_Copy[i][j] += PM[i][k] * Eye_Tilt_Matrix[k][j];
}
}
}
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
Current_Matrix[l][i][j] = Current_Matrix_Copy[i][j];
Current_Matrix_Copy[i][j] = 0;
}
}
/* Mirror*/
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
for (k = 0 ; k < 4 ; k++) {
Current_Matrix_Copy[i][j] += Current_Matrix[l][i][k] * Mirror[k][j];
}
}
}
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
Current_Matrix[l][i][j] = Current_Matrix_Copy[i][j];
Current_Matrix_Copy[i][j] = 0;
}
}
/* *GRM */
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
for (k = 0 ; k < 4 ; k++) {
Current_Matrix_Copy[i][j] += Current_Matrix[l][i][k] * GRM[k][j];
}
}
}
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
Current_Matrix[l][i][j] = Current_Matrix_Copy[i][j];
Current_Matrix_Copy[i][j] = 0;
}
}
/* *Eye_Translate*/
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
for (k = 0 ; k < 4 ; k++) {
Current_Matrix_Copy[i][j] += Current_Matrix[l][i][k] * Eye_Translate_Matrix[k][j];
}
}
}
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
Current_Matrix[l][i][j] = Current_Matrix_Copy[i][j];
Current_Matrix_Copy[i][j] = 0;
}
}
/* *Translate_Matrix */
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
for (k = 0 ; k < 4 ; k++) {
Current_Matrix_Copy[i][j] += Current_Matrix[l][i][k] * Translate_Matrix[l][k][j];
}
}
}
for (i = 0 ; i < 4 ; i++) {
for (j = 0 ; j < 4 ; j++) {
Current_Matrix[l][i][j] = Current_Matrix_Copy[i][j];
Current_Matrix_Copy[i][j] = 0;
}
}
for (i = 0 ; i < cube.num_vertex ; i++) {
for (j = 0 ; j < 4 ; j++) {
float temp = 0;
for (k = 0 ; k < 4 ; k++) {
temp += Current_Matrix[l][j][k] * vertex_point[l][i][k];
}
result_vertex_point[i][j] = temp;
}
}
for (i = 0 ; i < cube.num_vertex ; i++) {
float divide = result_vertex_point[i][3];
result_vertex_point[i][0] = result_vertex_point[i][0] / divide;
result_vertex_point[i][1] = result_vertex_point[i][1] / divide;
result_vertex_point[i][2] = result_vertex_point[i][2] / divide;
result_vertex_point[i][3] = result_vertex_point[i][3] / divide;
result_vertex_point[i][0] *= (Vr - Vl) / 2;
result_vertex_point[i][0] += (Vr - Vl) / 2;
result_vertex_point[i][1] *= (Vt - Vb) / 2;
result_vertex_point[i][1] += (Vt - Vb) / 2;
}
for (j = 0 ; j < cube.num_face ; j++) {
if (number_of_vertex_in_one_face == 3) {
drawLine(result_vertex_point[cube.face[j][0] - 1][0], result_vertex_point[cube.face[j][1] - 1][0], result_vertex_point[cube.face[j][0] - 1][1], result_vertex_point[cube.face[j][1] - 1][1], 2);
drawLine(result_vertex_point[cube.face[j][1] - 1][0], result_vertex_point[cube.face[j][2] - 1][0], result_vertex_point[cube.face[j][1] - 1][1], result_vertex_point[cube.face[j][2] - 1][1], 2);
drawLine(result_vertex_point[cube.face[j][2] - 1][0], result_vertex_point[cube.face[j][0] - 1][0], result_vertex_point[cube.face[j][2] - 1][1], result_vertex_point[cube.face[j][0] - 1][1], 2);
}
else if (number_of_vertex_in_one_face == 4) {
drawLine(result_vertex_point[cube.face[j][0] - 1][0], result_vertex_point[cube.face[j][1] - 1][0], result_vertex_point[cube.face[j][0] - 1][1], result_vertex_point[cube.face[j][1] - 1][1], 2);
drawLine(result_vertex_point[cube.face[j][1] - 1][0], result_vertex_point[cube.face[j][2] - 1][0], result_vertex_point[cube.face[j][1] - 1][1], result_vertex_point[cube.face[j][2] - 1][1], 2);
drawLine(result_vertex_point[cube.face[j][2] - 1][0], result_vertex_point[cube.face[j][3] - 1][0], result_vertex_point[cube.face[j][2] - 1][1], result_vertex_point[cube.face[j][3] - 1][1], 2);
drawLine(result_vertex_point[cube.face[j][3] - 1][0], result_vertex_point[cube.face[j][0] - 1][0], result_vertex_point[cube.face[j][3] - 1][1], result_vertex_point[cube.face[j][0] - 1][1], 2);
}
}
}
}