前言
关于3D有关的东西,我十分感兴趣,因为我想自己手搓一个MC,我可是MC资深老玩家
又在一个平常的下午,刷到了编程侯老师的视频,就跟着一起做了
结果也是非常成功,只不过使用scratch做的
所以,我在这里用C++和EasyX把代码写了出来
温馨提示:本人还只是初一,大部分理论知识都不太清楚,所以不要问我为什么,问我就是不知道
网址在此奉上
正文
因为我不清楚原理,准确来说是看不懂,所以全部我都是照着代码抄的(仅限scratch)
但C++和scratch有所不同所以有些地方在scratch里十分复杂,但在C++就十分简单了
并且我还修复了一些我觉得有问题的地方:
1.我把侯老师的 当方块的面的其中一个角超过了z轴裁剪位置,整个面就会被裁剪 的bug;
2.把z轴裁剪位置改为了极小值(不然在方块内部就会看的很别扭,会误删方块的面)
并且我发现,当两个面的 当前面到相机的距离 相同时,会先绘制先加入的面,再绘制后加入的面,就会导致当两个面的颜色不同时,可能会出现渲染排序的问题(方块的一部分会被覆盖)
不过这些都要看我们的侯老师改不改了
完整代码
要记得改成 UTF-8 with BOM 的编码格式哦(不然标题会是乱码)
#include <bits/stdc++.h>
#include <windows.h>
#include <conio.h>
#include <graphics.h>
#define get_key(key) (GetAsyncKeyState(key)&0x8000)
using namespace std;
const int N = 10000005;
bool running = true;
struct x_y_z {
double x, y, z;
};
double x1, y_1, z1;
double x2, y2, z2;
double x3, y3, z3;
double x4, y4, z4;
double camera_x, camera_y, camera_z;//相机x,y,z
double pianyi_x, pianyi_y, pianyi_z;//位置偏移x,y,z
x_y_z pianyi[N];
double suofang_x, suofang_y, suofang_z;//边长缩放x,y,z
x_y_z suofang[N];
string type;//方块类型
string type_[N];
int cnt;
double cos_x, sin_x;
double cos_y, sin_y;
double shuipin_x, chuizhi_y;
int paint_x, paint_y;//画笔位置
int jiaoju;//焦距
double weizhi_z, bili_z;//z轴裁剪位置,z轴裁剪比例
int _i, _j;
int window_h, window_w;//窗口高度,窗口宽度
string vec[10] = {
"",
"_000100110010",
"_001101111011",
"_000001011010",
"_100101111110",
"_010011111110",
"_000001101100"
};
struct color {
int r, g, b;
};
struct node {
double x1, x2, x3;
double y_1, y2, y3;
double z1, z2, z3;
color colors;
double distance;
}vecs[N];
int vecs_cnt;
void set_vec_1(double x, double y, double z) {
x1 = x;
y_1 = y;
z1 = z;
}
void set_vec_2(double x, double y, double z) {
x2 = x;
y2 = y;
z2 = z;
}
void set_vec_3(double x, double y, double z) {
x3 = x;
y3 = y;
z3 = z;
}
void set_vec_4(double x, double y, double z) {
x4 = x;
y4 = y;
z4 = z;
}
void move(double x, double y, double z) {
paint_x = jiaoju * (x / z) + window_w / 2;
paint_y = jiaoju * (y / z) + window_h / 2;
}
void deep_sort() {
for (_i = 1;_i <= 6;_i++) {
set_vec_1(pianyi_x + (vec[_i][1] – '0') * suofang_x, pianyi_y + (vec[_i][2] – '0') * suofang_y, pianyi_z + (vec[_i][3] – '0') * suofang_z);
set_vec_2(pianyi_x + (vec[_i][4] – '0') * suofang_x, pianyi_y + (vec[_i][5] – '0') * suofang_y, pianyi_z + (vec[_i][6] – '0') * suofang_z);
set_vec_3(pianyi_x + (vec[_i][7] – '0') * suofang_x, pianyi_y + (vec[_i][8] – '0') * suofang_y, pianyi_z + (vec[_i][9] – '0') * suofang_z);
set_vec_4(pianyi_x + (vec[_i][10] – '0') * suofang_x, pianyi_y + (vec[_i][11] – '0') * suofang_y, pianyi_z + (vec[_i][12] – '0') * suofang_z);
set_vec_1(x1 – camera_x, y_1 – camera_y, z1 – camera_z);
set_vec_2(x2 – camera_x, y2 – camera_y, z2 – camera_z);
set_vec_3(x3 – camera_x, y3 – camera_y, z3 – camera_z);
set_vec_4(x4 – camera_x, y4 – camera_y, z4 – camera_z);
set_vec_1(x1 * cos_x – z1 * sin_x, y_1, x1 * sin_x + z1 * cos_x);
set_vec_2(x2 * cos_x – z2 * sin_x, y2, x2 * sin_x + z2 * cos_x);
set_vec_3(x3 * cos_x – z3 * sin_x, y3, x3 * sin_x + z3 * cos_x);
set_vec_4(x4 * cos_x – z4 * sin_x, y4, x4 * sin_x + z4 * cos_x);
set_vec_1(x1, y_1 * cos_y – z1 * sin_y, y_1 * sin_y + z1 * cos_y);
set_vec_2(x2, y2 * cos_y – z2 * sin_y, y2 * sin_y + z2 * cos_y);
set_vec_3(x3, y3 * cos_y – z3 * sin_y, y3 * sin_y + z3 * cos_y);
set_vec_4(x4, y4 * cos_y – z4 * sin_y, y4 * sin_y + z4 * cos_y);
if (z1 > weizhi_z || z2 > weizhi_z || z3 > weizhi_z || z4 > weizhi_z) {//侯老师的方法会漏掉一些面……
double distance = sqrt(((x1 + x2 + x3 + x4) / 4) * ((x1 + x2 + x3 + x4) / 4) + ((y_1 + y2 + y3 + y4) / 4) * ((y_1 + y2 + y3 + y4) / 4) + ((z1 + z2 + z3 + z4) / 4) * ((z1 + z2 + z3 + z4) / 4));
vecs[++vecs_cnt] = { x1,x2,x3,y_1,y2,y3,z1,z2,z3,{0,0,191},distance };
vecs[++vecs_cnt] = { x1,x4,x3,y_1,y4,y3,z1,z4,z3,{0,0,191},distance };
}
}
}
void caijian_z() {
bili_z = 0;
if (z1 < weizhi_z) {
bili_z = (weizhi_z – z1) / (z2 – z1);
set_vec_1(x1 + (x2 – x1) * bili_z, y_1 + (y2 – y_1) * bili_z, weizhi_z);
}
if (z2 < weizhi_z) {
bili_z = (weizhi_z – z2) / (z1 – z2);
set_vec_2(x2 + (x1 – x2) * bili_z, y2 + (y_1 – y2) * bili_z, weizhi_z);
}
}
void paint_line(double X1, double Y1, double Z1, double X2, double Y2, double Z2) {
set_vec_1(X1 – camera_x, Y1 – camera_y, Z1 – camera_z);
set_vec_2(X2 – camera_x, Y2 – camera_y, Z2 – camera_z);
set_vec_1(x1 * cos_x – z1 * sin_x, y_1, x1 * sin_x + z1 * cos_x);
set_vec_2(x2 * cos_x – z2 * sin_x, y2, x2 * sin_x + z2 * cos_x);
set_vec_1(x1, y_1 * cos_y – z1 * sin_y, y_1 * sin_y + z1 * cos_y);
set_vec_2(x2, y2 * cos_y – z2 * sin_y, y2 * sin_y + z2 * cos_y);
caijian_z();
if (bili_z < 1) {
double t_x1, t_y1, t_x2, t_y2;
move(x1, y_1, z1);
t_x1 = paint_x;
t_y1 = paint_y;
move(x2, y2, z2);
t_x2 = paint_x;
t_y2 = paint_y;
line(t_x1, t_y1, t_x2, t_y2);
}
}
void paint_triangle(double X1, double Y1, double Z1, double X2, double Y2, double Z2, double X3, double Y3, double Z3) {
move(X1, Y1, Z1);
x1 = paint_x;
y_1 = paint_y;
move(X2, Y2, Z2);
x2 = paint_x;
y2 = paint_y;
move(X3, Y3, Z3);
x3 = paint_x;
y3 = paint_y;
double len_A = sqrt((x3 – x2) * (x3 – x2) + (y3 – y2) * (y3 – y2));
double len_B = sqrt((x1 – x3) * (x1 – x3) + (y_1 – y3) * (y_1 – y3));
double len_C = sqrt((x2 – x1) * (x2 – x1) + (y2 – y_1) * (y2 – y_1));
paint_x = (len_A * x1 + len_B * x2 + len_C * x3) / (len_A + len_B + len_C);
paint_y = (len_A * y_1 + len_B * y2 + len_C * y3) / (len_A + len_B + len_C);
POINT pts[3] = { {x1,y_1},{x2,y2},{x3,y3} };
setfillcolor(RGB(vecs[_i].colors.r, vecs[_i].colors.g, vecs[_i].colors.b));
solidpolygon(pts, 3);
//setlinecolor(RGB(vecs[_i].colors.r, vecs[_i].colors.g, vecs[_i].colors.b));
setlinecolor(RGB(255, 255, 255));
if ((x1 > 0 && x1 < window_w) || (x2 > 0 || x2 < window_h)) {
line(x1, y_1, x2, y2);
}
if ((x3 > 0 && x3 < window_w) || (x2 > 0 || x2 < window_h)) {
line(x2, y2, x3, y3);
}
}
void jisuan() {
sin_x = sin(shuipin_x);
sin_y = sin(chuizhi_y);
cos_x = cos(shuipin_x);
cos_y = cos(chuizhi_y);
}
void control() {
int key_w_down=0, key_s_down=0, key_a_down=0, key_d_down=0;
int key_up_down=0, key_down_down=0, key_left_down=0, key_right_down=0;
int key_space_down = 0, key_shift_down = 0;
if (get_key('w') || get_key('W')) {
key_w_down = 1;
}
if (get_key(38)) {
key_up_down = 1;
}
if (get_key('s') || get_key('S')) {
key_s_down = 1;
}
if (get_key(40)) {
key_down_down = 1;
}
if (get_key('a') || get_key('A')) {
key_a_down = 1;
}
if (get_key(37)) {
key_left_down = 1;
}
if (get_key('d') || get_key('D')) {
key_d_down = 1;
}
if(get_key(32)) {
key_space_down = 1;
}
if (get_key(16)) {
key_shift_down = 1;
}
if (get_key(39)) {
key_right_down = 1;
}
if (get_key(VK_ESCAPE))running = false;
camera_x += (key_d_down – key_a_down) * 0.02 * cos_x;
camera_z += (key_d_down – key_a_down) * 0.02 * (0 – sin_x);
camera_x += (key_w_down – key_s_down) * 0.02 * sin_x;
camera_z += (key_w_down – key_s_down) * 0.02 * cos_x;
camera_y += (key_shift_down – key_space_down) * 0.02;
shuipin_x += (key_right_down – key_left_down) * 0.01;
chuizhi_y += (key_down_down – key_up_down) * 0.01;
if (chuizhi_y > 1.57) chuizhi_y = 1.57;
if (chuizhi_y < -1.57) chuizhi_y = -1.57;
if (shuipin_x > 3.14) shuipin_x = -3.14;
if (shuipin_x < -3.14) shuipin_x = 3.14;
}
void paint_cube(double pianyi_X, double pianyi_Y, double pianyi_Z, double suofang_X, double suofang_Y, double suofang_Z, string Type) {
pianyi_x = pianyi_X;
pianyi_y = pianyi_Y;
pianyi_z = pianyi_Z;
suofang_x = suofang_X;
suofang_y = suofang_Y;
suofang_z = suofang_Z;
type = Type;
}
void init_xuanran() {
weizhi_z = 0.0000000001;
camera_x = 1;
camera_y = 1;
camera_z = -3;
shuipin_x = 0;
chuizhi_y = 0;
jiaoju = 400;
cnt = 1;
pianyi[1] = { 1,1,1 };
suofang[1] = { 1,1,1 };
}
bool cmp(node x, node y) {
return x.distance > y.distance;
}
void xuanran() {
vecs_cnt = 0;
for (_j = 1;_j <= cnt;_j++) {
paint_cube(pianyi[_j].x, pianyi[_j].y, pianyi[_j].z, suofang[_j].x, suofang[_j].y, suofang[_j].z, type_[_j]);
deep_sort();
}
sort(vecs + 1, vecs + vecs_cnt + 1, cmp);
for (_i = 1;_i <= vecs_cnt;_i++) {
paint_triangle(vecs[_i].x1, vecs[_i].y_1, vecs[_i].z1, vecs[_i].x2, vecs[_i].y2, vecs[_i].z2, vecs[_i].x3, vecs[_i].y3, vecs[_i].z3);
}
}
int main() {
window_h = 500;
window_w = 900;
initgraph(900, 500);
SetWindowText(GetHWnd(), L"3D引擎(编程侯老师版)");
init_xuanran();
BeginBatchDraw();
const double PHYSICS_STEP = 1.0 / 90.0;
double accumulator = 0.0;
LARGE_INTEGER freq, prev_time, curr_time;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&prev_time);
while (running) {
cleardevice();
QueryPerformanceCounter(&curr_time);
double delta_time = (curr_time.QuadPart – prev_time.QuadPart) / (double)freq.QuadPart;
prev_time = curr_time;
jisuan();
control();
xuanran();
FlushBatchDraw();
if (delta_time < PHYSICS_STEP) {
Sleep((PHYSICS_STEP – delta_time) * 1000);
}
}
EndBatchDraw();
closegraph();
return 0;
}
结语
明天就要考八级了,能祝我rp++么?
![[特殊字符]GPT‑6 Astra 实测一晚上|审美、Agent 智能体、3D 能力全面爆发,AI 又进化了✨-171主机测评](https://www.171host.com/wp-content/uploads/2026/09/20260911125632-6aa3fa80883e6-220x150.png)


