主页 > 人工智能  > 

C++实现3D(EasyX)详细教程

C++实现3D(EasyX)详细教程
一、关于3D

我们看见,这两个三角形是相似的,因此计算很简单

若相对物体的方向是斜的,计算三角函数即可

不会的看代码

 二、EasyX简介

initgraph(长,宽)                                                        打开绘图 或initgraph(长,宽,窗口设置-见下文)

closegraph()                                                            关闭绘图

cleardevice()                                                           清屏

setlinestyle()                                                           设置线条样式

setfillstyle()                                                             设置填充样式

setcolor()                                                                设置前景色 包括setlinecolor()&settextcolor()

setbkcolor()                                                            设置背景色

setfillcolor()                                                            设置填充色

setbkmode()                                                           设置背景(不)透明

RGBtoGRAY() & RGBtoHSV() &RGBtoHSL()      转换 也可以将前后调换

EGERGB() & EGEGET_R() &  EGEGET_G() & EGEGET_B() 将R/G/B与color数据转换

putpixel(x坐标,y坐标,颜色)                                    画点

line(起点x,起点y,终点x,终点y)                                画线

rectangle(起点x,起点y,终点x,终点y)                      画空心矩形 包括fill前缀(实心)

roundrect(起点x,起点y,终点x,终点y)                     画空心矩形 包括fill前缀(实心)

circle(中心x,中心y,半径)                                         画圆 包括fill前缀(实心) & f后缀(快速)

ellipse(中心x,中心y,半径1,半径2)                           画椭圆 包括fill前缀(实心) & f后缀(快速)

polygon()                                                                画多边形 包括fill前缀(实心) 

outtextxy(x坐标,y坐标,文本)                                  输出文本

mousemsg()                                                           有没有鼠标信息

getmouse()                                                             返回鼠标信息(没有则等待)

keymsg()                                                                 有没有键盘信息

getkey()                                                                   返回键盘信息(没有则等待)

newimage()                                                             分配图片地址

getimage(指针,文件名)[仅EGE]、loadimage()[仅Easyx]  获取图像(从文件)

getimage(起点x,起点y,终点x,终点y)                       获取图像(从屏幕)

putimage(指针,起点x,起点y)                                   输出图像(到屏幕)

saveimage()                                                            输出图像(到文件 

GetImageBuffer()                                                   获取缓冲区指针(快速绘图、读图) 

......

三、C++实现 #include <graphics.h> #include <conio.h> #include <math.h> #include <time.h> #include <windows.h> const int WIDTH = 1200; const int HEIGHT = 1000; const float PI = 3.1415926535f; // 摄像机参数 struct Camera { float x = 0, y = 1, z = 0; // 初始位置 float yaw = 0, pitch = 0; // 视角角度 float speed = 0.1f; // 移动速度 float sensitivity = 0.008f; // 鼠标灵敏度 } camera; // 3D点结构体 struct Point3D { float x, y, z; }; // 立方体面结构体 struct Face { int points[4]; // 顶点索引 COLORREF color; // 颜色 float depth; // 深度用于排序 Point3D normal; // 法向量 }; // 立方体顶点 Point3D cubePoints[] = { {-1, -1, -1}, {1, -1, -1}, {1, 1, -1}, {-1, 1, -1}, {-1, -1, 1}, {1, -1, 1}, {1, 1, 1}, {-1, 1, 1} }; // 立方体面定义 Face cubeFaces[] = { {{0,1,2,3}, RED}, // 前 {{4,5,6,7}, BLUE}, // 后 {{0,3,7,4}, GREEN}, // 左 {{1,5,6,2}, YELLOW}, // 右 {{3,2,6,7}, CYAN}, // 上 {{0,4,5,1}, MAGENTA} // 下 }; // 计算面的法向量 void calculateNormals() { for (auto& face : cubeFaces) { Point3D p1 = cubePoints[face.points[0]]; Point3D p2 = cubePoints[face.points[1]]; Point3D p3 = cubePoints[face.points[2]]; // 计算两个向量 Point3D v1 = {p2.x - p1.x, p2.y - p1.y, p2.z - p1.z}; Point3D v2 = {p3.x - p1.x, p3.y - p1.y, p3.z - p1.z}; // 计算叉积(法向量) face.normal = { v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x }; // 归一化法向量 float len = sqrt(face.normal.x * face.normal.x + face.normal.y * face.normal.y + face.normal.z * face.normal.z); face.normal.x /= len; face.normal.y /= len; face.normal.z /= len; } } // 将3D坐标转换为屏幕坐标 POINT project(Point3D p) { // 相对摄像机的位置 float dx = p.x - camera.x; float dy = p.y - camera.y; float dz = p.z - camera.z; // 旋转(绕Y轴和X轴) float cosY = cos(camera.yaw), sinY = sin(camera.yaw); float cosP = cos(camera.pitch), sinP = sin(camera.pitch); // 旋转计算 float x = dx*cosY - dz*sinY; float z = dz*cosY + dx*sinY; float y = dy*cosP - z*sinP; z = z*cosP + dy*sinP; // 透视投影 if(z <= 0) z = 0.0001f; float f = 400 / z; return { (int)(x*f + WIDTH/2), (int)(-y*f + HEIGHT/2) }; } void drawScene() { POINT screenPoints[8]; // 投影所有顶点 for(int i=0; i<8; i++) screenPoints[i] = project(cubePoints[i]); // 计算每个面的深度并排序 for(auto& face : cubeFaces) { float avgZ = 0; for(int i : face.points) avgZ += cubePoints[i].z - camera.z; face.depth = avgZ/4; } // 按深度排序(远到近) qsort(cubeFaces, 6, sizeof(Face), [](const void* a, const void* b) { return (int)(((Face*)b)->depth - ((Face*)a)->depth); }); // 绘制每个面 for(auto& face : cubeFaces) { POINT poly[4]; for(int i=0; i<4; i++) poly[i] = screenPoints[face.points[i]]; // 直接使用面的颜色填充 setfillcolor(face.color); fillpoly(4, (int*)poly); } } // 绘制准星 void drawCrosshair() { setcolor(BLACK); line(WIDTH / 2 - 10, HEIGHT / 2, WIDTH / 2 + 10, HEIGHT / 2); line(WIDTH / 2, HEIGHT / 2 - 10, WIDTH / 2, HEIGHT / 2 + 10); } // 绘制建筑物 void drawBuilding(float x, float y, float z, float width, float height, float depth, COLORREF color) { Point3D buildingPoints[] = { {x - width / 2, y - height / 2, z - depth / 2}, {x + width / 2, y - height / 2, z - depth / 2}, {x + width / 2, y + height / 2, z - depth / 2}, {x - width / 2, y + height / 2, z - depth / 2}, {x - width / 2, y - height / 2, z + depth / 2}, {x + width / 2, y - height / 2, z + depth / 2}, {x + width / 2, y + height / 2, z + depth / 2}, {x - width / 2, y + height / 2, z + depth / 2} }; Face buildingFaces[] = { {{0,1,2,3}, color}, // 前 {{4,5,6,7}, color}, // 后 {{0,3,7,4}, color}, // 左 {{1,5,6,2}, color}, // 右 {{3,2,6,7}, color}, // 上 {{0,4,5,1}, color} // 下 }; POINT screenPoints[8]; for(int i=0; i<8; i++) screenPoints[i] = project(buildingPoints[i]); for(auto& face : buildingFaces) { POINT poly[4]; for(int i=0; i<4; i++) poly[i] = screenPoints[face.points[i]]; setfillcolor(face.color); fillpoly(4, (int*)poly); } } // 绘制树 void drawTree(float x, float y, float z) { // 树干 drawBuilding(x, y, z, 0.2f, 1.0f, 0.2f, RGB(139, 69, 19)); // 树冠 drawBuilding(x, y + 0.8f, z, 1.0f, 0.5f, 1.0f, RGB(34, 139, 34)); } // 处理输入 void processInput() { // 处理键盘输入 float moveX = 0, moveZ = 0; if (GetAsyncKeyState('W') & 0x8000) moveX = 1; // 前 if (GetAsyncKeyState('S') & 0x8000) moveX = -1; // 后 if (GetAsyncKeyState('A') & 0x8000) moveZ = -1; // 左 if (GetAsyncKeyState('D') & 0x8000) moveZ = 1; // 右 // 计算移动方向(基于当前视角) float speed = camera.speed; float dx = moveX * cos(camera.yaw) - moveZ * sin(camera.yaw); float dz = moveZ * cos(camera.yaw) + moveX * sin(camera.yaw); camera.z += dx * speed; camera.x += dz * speed; // 处理鼠标输入 MOUSEMSG m; while(MouseHit()) { m = GetMouseMsg(); if(m.uMsg == WM_MOUSEMOVE) { // 计算相对鼠标移动量 static int lastX = WIDTH / 2, lastY = HEIGHT / 2; int dx = m.x - lastX; int dy = m.y - lastY; lastX = m.x; lastY = m.y; // 更新视角 camera.yaw += dx * camera.sensitivity; camera.pitch -= dy * camera.sensitivity; // 限制垂直视角 if(camera.pitch > PI/2.5) camera.pitch = PI/2.5; if(camera.pitch < -PI/2.5) camera.pitch = -PI/2.5; } } } int main() { initgraph(WIDTH, HEIGHT); setbkcolor(WHITE); BeginBatchDraw(); ShowCursor(FALSE); // 隐藏鼠标 // 计算法向量 calculateNormals(); // 将鼠标初始位置设置为窗口中心 SetCursorPos(WIDTH / 2, HEIGHT / 2); while(true) { // 检测 ESC 键退出 if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) { break; } cleardevice(); // 清屏 processInput(); //drawScene(); drawBuilding(0, 0, 5, 2, 3, 2, RGB(128, 128, 128)); // 绘制建筑物 drawBuilding(0, 0, 5, 2, 3, 2, RGB(128, 128, 128)); // 绘制建筑物 drawTree(3, 0, 5); // 绘制树 drawTree(5, 0, 3); // 绘制树 drawCrosshair(); FlushBatchDraw(); // 刷新缓冲区 Sleep(10); // 控制帧率 } EndBatchDraw(); closegraph(); ShowCursor(TRUE); // 恢复鼠标显示 return 0; }

效果:

编译:

g++ -o 3d 3d.cpp -std=c++11 -leasyx

 w a s d可以行走

标签:

C++实现3D(EasyX)详细教程由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C++实现3D(EasyX)详细教程