定义变量
cube: 六个面,每个面由三个点确定,第四个是面的法向量(朝向外)
face: 六个面的图案
float cube[6][4][3] = {
{{-0.5, -0.5, 0.5}, {0.5, -0.5, 0.5}, {-0.5, 0.5, 0.5}, {0.0, 0.0, 1.0}}, // UP
{{-0.5, -0.5, 0.5}, {-0.5, -0.5, -0.5}, {-0.5, 0.5, 0.5}, {-1.0, 0.0, 0.0}}, // BEHIND->LEFT
{{-0.5, -0.5, 0.5}, {-0.5, -0.5, -0.5}, {0.5, -0.5, 0.5}, {0.0, -1.0, 0.0}}, // LEFT->FRONT
{{-0.5, 0.5, 0.5}, {0.5, 0.5, 0.5}, {-0.5, 0.5, -0.5}, {0.0, 1.0, 0.0}}, // RIGHT->BEHIND
{{0.5, -0.5, 0.5}, {0.5, -0.5, -0.5}, {0.5, 0.5, 0.5}, {1.0, 0.0, 0.0}}, // FRONT->RIGHT
{{-0.5, -0.5, -0.5}, {0.5, -0.5, -0.5}, {-0.5, 0.5, -0.5}, {0.0, 0.0, -1.0}} // DOWN
};
int face[6][3][3] = {
{{0, 0, 0}, {0, 1, 0}, {0, 0, 0}}, // UP 1
{{0, 0, 1}, {0, 0, 0}, {1, 0, 0}}, // BEHIND 2
{{0, 0, 1}, {0, 1, 0}, {1, 0, 0}}, // LEFT 3
{{1, 0, 1}, {0, 0, 0}, {1, 0, 1}}, // RIGHT 4
{{1, 0, 1}, {0, 1, 0}, {1, 0, 1}}, // FRONT 5
{{1, 0, 1}, {1, 0, 1}, {1, 0, 1}} // DOWN 6
};旋转矩阵
void rotate(float *x_, float *y_, float *z_, float ux, float uy, float uz, float angle) {
float len = hypot(ux, uy, uz);
ux /= len, uy /= len, uz /= len;
float x = *x_, y = *y_, z = *z_;
float c = cos(rad), s = sin(rad);
float m00 = c + ux * ux * (1 - c);
float m01 = ux * uy * (1 - c) - uz * s;
float m02 = ux * uz * (1 - c) + uy * s;
float m10 = uy * ux * (1 - c) + uz * s;
float m11 = c + uy * uy * (1 - c);
float m12 = uy * uz * (1 - c) - ux * s;
float m20 = uz * ux * (1 - c) - uy * s;
float m21 = uz * uy * (1 - c) + ux * s;
float m22 = c + uz * uz * (1 - c);
*x_ = m00 * x + m01 * y + m02 * z;
*y_ = m10 * x + m11 * y + m12 * z;
*z_ = m20 * x + m21 * y + m22 * z;
}
void rotateAll(float ux, float uy, float uz, float angle) {
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 4; j++) {
rotate(&cube[i][j][0], &cube[i][j][1], &cube[i][j][2], ux, uy, uz, angle);
}
}
}计算旋转矩阵
rotMatrix[x_, y_, z_, theta_] := Module[
{normalizedVector = Normalize[{x, y, z}], c = Cos[theta], s = Sin[theta],},
With[{nx = normalizedVector[[1]], ny = normalizedVector[[2]], nz = normalizedVector[[3]]},
{{c + nx^2*(1 - c), nx*ny*(1 - c) - nz*s, nx*nz*(1 - c) + ny*s},
{nx*ny*(1 - c) + nz*s, c + ny^2*(1 - c), ny*nz*(1 - c) - nx*s},
{nx*nz*(1 - c) - ny*s, ny*nz*(1 - c) + nx*s, c + nz^2*(1 - c)}}]]import math
from sympy import symbols, cos, sin, Matrix
x, y, z, theta = symbols("x y z θ")
x, y, z = (1, 1, 0)
len = math.sqrt(x**2 + y**2 + z**2)
x /= len
y /= len
z /= len
c = cos(theta)
s = sin(theta)
rotation_matrix = Matrix(
[
[c + x**2 * (1 - c), x * y * (1 - c) - z * s, x * z * (1 - c) + y * s],
[x * y * (1 - c) + z * s, c + y**2 * (1 - c), y * z * (1 - c) - x * s],
[x * z * (1 - c) - y * s, y * z * (1 - c) + x * s, c + z**2 * (1 - c)],
]
)
print(rotation_matrix)渲染函数
预处理旋转到一个角度。
float time = 0;
rotateAll(0, 1, 1, 45);
while (1) {
time = time + 0.05;
// ...
}Z_buffer 和 output
// 定义 z_buffer 深度缓冲区
float z_buffer[screen_height + 1][screen_width + 1];
for (int i = 0; i <= screen_height; i++)
for (int j = 0; j <= screen_width; j++)
z_buffer[i][j] = -100;
// 定义屏幕输出
char output[screen_height + 1][screen_width + 1];
memset(output, ' ', sizeof(output));计算投影
通过面内基向量的线性组合,面内的每个点 。每个点和面的法向量绕y轴旋转time(rad)
根据投影公式
计算出在平面 ,视点为 的投影 ,根据投影点更新z_buffer
判断面法向量的z分量,如果为正,则可以看见,根据面的法向量z分量设置不同亮度的字符,注意特殊判断点是否在空心圆内,在圆内亮度为0。
for (int i = 0; i < 6; i++) {
for (float u = 0; u < 1; u = u + 0.01)
for (float v = 0; v < 1; v = v + 0.01) {
// 基向量m
float m_x = (cube[i][1][0] - cube[i][0][0]);
float m_y = (cube[i][1][1] - cube[i][0][1]);
float m_z = (cube[i][1][2] - cube[i][0][2]);
// 基向量n
float n_x = (cube[i][2][0] - cube[i][0][0]);
float n_y = (cube[i][2][1] - cube[i][0][1]);
float n_z = (cube[i][2][2] - cube[i][0][2]);
// 面内每一个坐标(x,y,z)
float x = m_x * u + n_x * v + cube[i][0][0];
float y = m_y * u + n_y * v + cube[i][0][1];
float z = m_z * u + n_z * v + cube[i][0][2];
// 绕y轴旋转time
float rotation_x = cos(time) * x - sin(time) * z;
float rotation_y = y;
float rotation_z = sin(time) * x + cos(time) * z;
// 法向量旋转time
float normal_x = (cube[i][3][0]) * cos(time) - sin(time) * (cube[i][3][2]);
float normal_y = cube[i][3][1];
float normal_z = (cube[i][3][0]) * sin(time) + cos(time) * (cube[i][3][2]);
// 投影到屏幕
int screen_x = (rotation_x / (1 - rotation_z / cc) + 1) / 2 * screen_width;
int screen_y = (rotation_y / (1 - rotation_z / cc) + 1) / 2 * screen_height;
float screen_z = rotation_z / (1 - rotation_z / cc);
float L = normal_z;
// 更新z_buffer
if (z_buffer[screen_y][screen_x] < screen_z) {
z_buffer[screen_y][screen_x] = screen_z;
// 法向量z分量>0,可以看到
if (L > 0) {
if (judgeCircle(i, u, v))
L = 0;
else
L = (L + 0.1) * sqrt(2);
int luminance_index = L * 8;
if (luminance_index > 11)
luminance_index = 11;
output[screen_y][screen_x] = ".,-~:;=!*#$@"[luminance_index];
}
}
}
}打印字符
for (int j = screen_height; j >= 0; j--) {
putchar('|');
for (int i = 0; i <= screen_width; i++)
putchar(output[j][i]);
putchar('|');
putchar('\n');
}
usleep(15000);
printf("\x1b[%dA", screen_height + 1);