3D立方体
2025-12-21 12:14:08
发布于:江苏
控制方法:
WASD控制方向,上下左右控制视角
空格上升,shift下降
注:运行时可适当缩小字体(按住ctrl键滚动鼠标滚轮)
#include <cmath>
#include <vector>
#include <stdio.h>
#include <windows.h>
typedef char Color;
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
const Color BLUE = '$', GREEN = 'W', YELLOW = 'q', WHITE = 'Q', ORANGE = 'f', RED = '{', PURPLE = '_', PINK = ';';
const int W = 118, H = 60;
int dx = W / 2, dy = H / 2;
double zBuffer[H][W];
Color screen[H][W];
Color str[H * (2 * W + 1) + 5];
struct Pos {
double x, y, z;
Pos(): x(0), y(0), z(0) {}
Pos(double x, double y): x(x), y(y), z(0) {}
Pos(double x, double y, double z): x(x), y(y), z(z) {}
};
struct Triangle {
Pos A, B, C;
Color color;
Triangle(Pos A, Pos B, Pos C, Color color): A(A), B(B), C(C), color(color) {}
};
struct Cam {
Pos pos;
double rotY, rotX;
Cam(): pos(), rotX(0), rotY(0) {}
Cam(double x, double y, double z, double rotX, double rotY): pos(x, y, z), rotX(rotX), rotY(rotY) {}
void move() {
double dx = sin(rotY) / 2, dy = cos(rotY) / 2;
if (KEY_DOWN('W')) pos.x += dx, pos.z += dy;
if (KEY_DOWN('S')) pos.x -= dx, pos.z -= dy;
if (KEY_DOWN('A')) pos.x -= dy, pos.z += dx;
if (KEY_DOWN('D')) pos.x += dy, pos.z -= dx;
if (KEY_DOWN(VK_LEFT)) rotY -= M_PI / 90;
if (KEY_DOWN(VK_RIGHT)) rotY += M_PI / 90;
if (KEY_DOWN(VK_UP)) rotX += M_PI / 90;
if (KEY_DOWN(VK_DOWN)) rotX -= M_PI / 90;
if (KEY_DOWN(VK_SPACE)) pos.y += 0.5;
if (KEY_DOWN(VK_SHIFT)) pos.y -= 0.5;
}
};
void gotoxy(int x, int y) {
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
Pos toWindowCoordinateSystem(Pos pos) {
return Pos(pos.x + dx, dy - pos.y);
}
int min(int a, int b, int c) {
return ((a < b ? a : b) < c ? (a < b ? a : b) : c);
}
int max(int a, int b, int c) {
return ((a > b ? a : b) > c ? (a > b ? a : b) : c);
}
int min(int a, int b) {
return (a < b ? a : b);
}
int max(int a, int b) {
return (a > b ? a : b);
}
double distance(Pos A, Pos B) {
return std::sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) + (A.z - B.z) * (A.z - B.z));
}
double triangleArea(Pos A, Pos B, Pos C) {
return std::abs((B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x));
}
double interpolateDepth(Pos A, Pos B, Pos C, Pos P) {
double D = triangleArea(A, B, C);
double A1 = triangleArea(P, B, C);
double A2 = triangleArea(P, C, A);
double A3 = triangleArea(P, A, B);
double lambda1 = A1 / D;
double lambda2 = A2 / D;
double lambda3 = A3 / D;
if (lambda1 + lambda2 + lambda3 - 1 > 1e-6) {
return -1.0;
}
return lambda1 * A.z + lambda2 * B.z + lambda3 * C.z;
}
void drawTriangle(Pos A, Pos B, Pos C, Color color) {
int minX = min(A.x, B.x, C.x);
int maxX = max(A.x, B.x, C.x);
int minY = min(A.y, B.y, C.y);
int maxY = max(A.y, B.y, C.y);
minX = max(minX, 0);
maxX = min(maxX, W - 1);
minY = max(minY, 0);
maxY = min(maxY, H - 1);
for (int i = minY; i <= maxY; i++) {
for (int j = minX; j <= maxX; j++) {
double depth = interpolateDepth(A, B, C, Pos(j, i));
if (depth >= 0) {
if (zBuffer[i][j] > depth) {
zBuffer[i][j] = depth;
screen[i][j] = color;
}
}
}
}
}
Pos rotate(Pos pos, double rot) {
double x = pos.x, y = pos.y;
double s = sin(rot), c = cos(rot);
return Pos(x * c - y * s, x * s + y * c);
}
Pos convert(Cam cam, Pos pos) {
double x = pos.x, y = pos.y, z = pos.z;
x -= cam.pos.x;
y -= cam.pos.y;
z -= cam.pos.z;
Pos rotatedPos;
rotatedPos = rotate(Pos(x, z), cam.rotY);
x = rotatedPos.x, z = rotatedPos.y;
rotatedPos = rotate(Pos(y, z), cam.rotX);
y = rotatedPos.x, z = rotatedPos.y;
return Pos(x, y, z);
}
Pos _3dTo2d(Cam cam, Pos pos) {
pos = convert(cam, pos);
double x = pos.x, y = pos.y, z = pos.z;
double f = dx / z;
x *= f, y *= f;
return Pos(x, y);
}
std::vector <Triangle> triangles;
void draw(Cam cam) {
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
screen[i][j] = ' ';
zBuffer[i][j] = 2000000000;
}
}
for (int i = 0; i < triangles.size(); i++) {
Triangle t = triangles[i];
Pos convertA = convert(cam, t.A), convertB = convert(cam, t.B), convertC = convert(cam, t.C);
double distA = distance(Pos(0, 0, 0), convertA), distB = distance(Pos(0, 0, 0), convertB), distC = distance(Pos(0, 0, 0), convertC);
if (convertA.z <= 0 || convertB.z <= 0 || convertC.z <= 0) {
continue;
}
Pos A = _3dTo2d(cam, t.A), B = _3dTo2d(cam, t.B), C = _3dTo2d(cam, t.C);
A = toWindowCoordinateSystem(A);
B = toWindowCoordinateSystem(B);
C = toWindowCoordinateSystem(C);
drawTriangle(Pos(A.x, A.y, distA), Pos(B.x, B.y, distB), Pos(C.x, C.y, distC), t.color);
}
int idx = 0;
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
str[idx++] = screen[i][j];
str[idx++] = ' ';
}
str[idx++] = '\n';
}
str[idx++] = '\0';
gotoxy(0, 0);
puts(str);
}
void cube(double x, double y, double z, double size) {
size /= 2;
Pos A, B, C, D, E, F, G, H;
A = Pos(x + size, y + size, z + size);
B = Pos(x - size, y + size, z + size);
C = Pos(x + size, y - size, z + size);
D = Pos(x - size, y - size, z + size);
E = Pos(x + size, y + size, z - size);
F = Pos(x - size, y + size, z - size);
G = Pos(x + size, y - size, z - size);
H = Pos(x - size, y - size, z - size);
triangles.push_back(Triangle(A, D, B, BLUE));
triangles.push_back(Triangle(A, D, C, BLUE));
triangles.push_back(Triangle(E, H, F, GREEN));
triangles.push_back(Triangle(E, H, G, GREEN));
triangles.push_back(Triangle(A, F, B, YELLOW));
triangles.push_back(Triangle(A, F, E, YELLOW));
triangles.push_back(Triangle(C, H, D, WHITE));
triangles.push_back(Triangle(C, H, G, WHITE));
triangles.push_back(Triangle(A, G, C, ORANGE));
triangles.push_back(Triangle(A, G, E, ORANGE));
triangles.push_back(Triangle(B, H, D, RED));
triangles.push_back(Triangle(B, H, F, RED));
}
void circle(double x, double y, double z, double r) {
double angle = 0, precision = 24;
Color color[5] = {RED, PURPLE, PINK};
for (int i = 0; i < precision; i++) {
triangles.push_back(Triangle(Pos(x, y, z), Pos(cos(angle) * r, y, sin(angle) * r), Pos(cos(angle + M_PI / 180 * (360 / precision)) * r, y, sin(angle + M_PI / 180 * (360 / precision)) * r), color[i % 3]));
angle += M_PI / 180 * (360 / precision);
}
}
void perlin() {
cube(0, 0, 0, 1);
cube(1, -1, 0, 1);
cube(2, -1, 0, 1);
cube(3, -1, 0, 1);
cube(4, -1, 0, 1);
cube(5, -1, 0, 1);
cube(6, -1, 0, 1);
cube(7, -1, 0, 1);
cube(8, -1, 0, 1);
cube(9, -1, 0, 1);
cube(10, -1, 0, 1);
cube(11, -1, 0, 1);
cube(12, -1, 0, 1);
cube(13, -1, 0, 1);
cube(14, -1, 0, 1);
cube(15, -1, 0, 1);
cube(0, -1, 1, 1);
cube(1, -1, 1, 1);
cube(2, -1, 1, 1);
cube(3, -1, 1, 1);
cube(4, -1, 1, 1);
cube(5, -1, 1, 1);
cube(6, -1, 1, 1);
cube(7, -1, 1, 1);
cube(8, -1, 1, 1);
cube(9, -1, 1, 1);
cube(10, -1, 1, 1);
cube(11, -1, 1, 1);
cube(12, -1, 1, 1);
cube(13, -1, 1, 1);
cube(14, -1, 1, 1);
cube(15, 0, 1, 1);
cube(0, -1, 2, 1);
cube(1, -1, 2, 1);
cube(2, -1, 2, 1);
cube(3, -1, 2, 1);
cube(4, -1, 2, 1);
cube(5, -1, 2, 1);
cube(6, -1, 2, 1);
cube(7, -1, 2, 1);
cube(8, -1, 2, 1);
cube(9, -1, 2, 1);
cube(10, -1, 2, 1);
cube(11, -1, 2, 1);
cube(12, -1, 2, 1);
cube(13, 0, 2, 1);
cube(14, 0, 2, 1);
cube(15, 0, 2, 1);
cube(0, -2, 3, 1);
cube(1, -2, 3, 1);
cube(2, -2, 3, 1);
cube(3, -2, 3, 1);
cube(4, -2, 3, 1);
cube(5, -2, 3, 1);
cube(6, -2, 3, 1);
cube(7, -2, 3, 1);
cube(8, -1, 3, 1);
cube(9, -1, 3, 1);
cube(10, -1, 3, 1);
cube(11, -1, 3, 1);
cube(12, -1, 3, 1);
cube(13, 0, 3, 1);
cube(14, 0, 3, 1);
cube(15, 0, 3, 1);
cube(0, -2, 4, 1);
cube(1, -2, 4, 1);
cube(2, -2, 4, 1);
cube(3, -2, 4, 1);
cube(4, -2, 4, 1);
cube(5, -2, 4, 1);
cube(6, -2, 4, 1);
cube(7, -2, 4, 1);
cube(8, -1, 4, 1);
cube(9, -1, 4, 1);
cube(10, -1, 4, 1);
cube(11, -1, 4, 1);
cube(12, -1, 4, 1);
cube(13, -1, 4, 1);
cube(14, 0, 4, 1);
cube(15, 0, 4, 1);
cube(0, -3, 5, 1);
cube(1, -3, 5, 1);
cube(2, -3, 5, 1);
cube(3, -3, 5, 1);
cube(4, -2, 5, 1);
cube(5, -2, 5, 1);
cube(6, -2, 5, 1);
cube(7, -2, 5, 1);
cube(8, -2, 5, 1);
cube(9, -1, 5, 1);
cube(10, -1, 5, 1);
cube(11, -1, 5, 1);
cube(12, -1, 5, 1);
cube(13, -1, 5, 1);
cube(14, -1, 5, 1);
cube(15, -1, 5, 1);
cube(0, -3, 6, 1);
cube(1, -3, 6, 1);
cube(2, -3, 6, 1);
cube(3, -3, 6, 1);
cube(4, -3, 6, 1);
cube(5, -2, 6, 1);
cube(6, -2, 6, 1);
cube(7, -2, 6, 1);
cube(8, -2, 6, 1);
cube(9, -1, 6, 1);
cube(10, -1, 6, 1);
cube(11, -1, 6, 1);
cube(12, -1, 6, 1);
cube(13, -1, 6, 1);
cube(14, -1, 6, 1);
cube(15, -1, 6, 1);
cube(0, -4, 7, 1);
cube(1, -4, 7, 1);
cube(2, -3, 7, 1);
cube(3, -3, 7, 1);
cube(4, -3, 7, 1);
cube(5, -2, 7, 1);
cube(6, -2, 7, 1);
cube(7, -2, 7, 1);
cube(8, -1, 7, 1);
cube(9, -1, 7, 1);
cube(10, -1, 7, 1);
cube(11, -1, 7, 1);
cube(12, -1, 7, 1);
cube(13, -1, 7, 1);
cube(14, -1, 7, 1);
cube(15, -1, 7, 1);
cube(0, -4, 8, 1);
cube(1, -4, 8, 1);
cube(2, -4, 8, 1);
cube(3, -3, 8, 1);
cube(4, -3, 8, 1);
cube(5, -2, 8, 1);
cube(6, -2, 8, 1);
cube(7, -2, 8, 1);
cube(8, -1, 8, 1);
cube(9, -1, 8, 1);
cube(10, -1, 8, 1);
cube(11, -1, 8, 1);
cube(12, -1, 8, 1);
cube(13, -1, 8, 1);
cube(14, -1, 8, 1);
cube(15, -2, 8, 1);
cube(0, -4, 9, 1);
cube(1, -4, 9, 1);
cube(2, -3, 9, 1);
cube(3, -3, 9, 1);
cube(4, -3, 9, 1);
cube(5, -2, 9, 1);
cube(6, -2, 9, 1);
cube(7, -1, 9, 1);
cube(8, -1, 9, 1);
cube(9, -1, 9, 1);
cube(10, -1, 9, 1);
cube(11, -1, 9, 1);
cube(12, -1, 9, 1);
cube(13, -1, 9, 1);
cube(14, -2, 9, 1);
cube(15, -2, 9, 1);
cube(0, -4, 10, 1);
cube(1, -4, 10, 1);
cube(2, -3, 10, 1);
cube(3, -3, 10, 1);
cube(4, -2, 10, 1);
cube(5, -2, 10, 1);
cube(6, -1, 10, 1);
cube(7, -1, 10, 1);
cube(8, 0, 10, 1);
cube(9, 0, 10, 1);
cube(10, 0, 10, 1);
cube(11, -1, 10, 1);
cube(12, -1, 10, 1);
cube(13, -1, 10, 1);
cube(14, -2, 10, 1);
cube(15, -2, 10, 1);
cube(0, -4, 11, 1);
cube(1, -3, 11, 1);
cube(2, -3, 11, 1);
cube(3, -2, 11, 1);
cube(4, -2, 11, 1);
cube(5, -1, 11, 1);
cube(6, 0, 11, 1);
cube(7, 0, 11, 1);
cube(8, 0, 11, 1);
cube(9, 0, 11, 1);
cube(10, 0, 11, 1);
cube(11, 0, 11, 1);
cube(12, -1, 11, 1);
cube(13, -1, 11, 1);
cube(14, -2, 11, 1);
cube(15, -2, 11, 1);
cube(0, -3, 12, 1);
cube(1, -3, 12, 1);
cube(2, -2, 12, 1);
cube(3, -1, 12, 1);
cube(4, -1, 12, 1);
cube(5, 0, 12, 1);
cube(6, 0, 12, 1);
cube(7, 1, 12, 1);
cube(8, 1, 12, 1);
cube(9, 1, 12, 1);
cube(10, 1, 12, 1);
cube(11, 0, 12, 1);
cube(12, 0, 12, 1);
cube(13, -1, 12, 1);
cube(14, -1, 12, 1);
cube(15, -2, 12, 1);
cube(0, -2, 13, 1);
cube(1, -2, 13, 1);
cube(2, -1, 13, 1);
cube(3, -1, 13, 1);
cube(4, 0, 13, 1);
cube(5, 1, 13, 1);
cube(6, 1, 13, 1);
cube(7, 1, 13, 1);
cube(8, 2, 13, 1);
cube(9, 2, 13, 1);
cube(10, 1, 13, 1);
cube(11, 1, 13, 1);
cube(12, 0, 13, 1);
cube(13, 0, 13, 1);
cube(14, -1, 13, 1);
cube(15, -2, 13, 1);
cube(0, -2, 14, 1);
cube(1, -1, 14, 1);
cube(2, -1, 14, 1);
cube(3, 0, 14, 1);
cube(4, 1, 14, 1);
cube(5, 1, 14, 1);
cube(6, 2, 14, 1);
cube(7, 2, 14, 1);
cube(8, 2, 14, 1);
cube(9, 2, 14, 1);
cube(10, 2, 14, 1);
cube(11, 1, 14, 1);
cube(12, 1, 14, 1);
cube(13, 0, 14, 1);
cube(14, -1, 14, 1);
cube(15, -1, 14, 1);
cube(0, -1, 15, 1);
cube(1, -1, 15, 1);
cube(2, 0, 15, 1);
cube(3, 1, 15, 1);
cube(4, 1, 15, 1);
cube(5, 2, 15, 1);
cube(6, 2, 15, 1);
cube(7, 3, 15, 1);
cube(8, 3, 15, 1);
cube(9, 3, 15, 1);
cube(10, 3, 15, 1);
cube(11, 2, 15, 1);
cube(12, 1, 15, 1);
cube(13, 1, 15, 1);
cube(14, 0, 15, 1);
cube(15, -1, 15, 1);
}
int main() {
Cam cam;
perlin();
circle(0, 1, 0, 2);
while (true) {
draw(cam);
cam.move();
Sleep(20);
}
return 0;
}
这里空空如也






有帮助,赞一个