使用easyx.h实现3D旋转立方体效果

话不多说,先上效果
拖动下方的滚动条可以实现立方体沿XYZ轴的旋转
拖动下方的滚动条可以实现立方体沿XYZ轴的旋转

C的图形化库中,easyx.h是比较适合上手的一款。本次教程涉及的内容:

  • 简易3D对象的数据结构
  • 使用线性代数旋转3D对象
  • 3D对象的投影法(不包括近大远小的效果)
  • 控件:按钮,滚动条,提示栏的实现

(先叠一个甲)楼主只是一只菜狗大学生,在暑假闲来无事做的小项目。发到网上只是为了方便更多的初学者少走弯路。可能有更好的实现效果,希望可以指出,大家理性讨论😶‍🌫️
一些建议:

  1. 注意!请提前配置完成easyx.h的环境。
  2. 推荐使用VS环境进行编程
  3. 遇到读不懂的函数,下载easyx官网上的说明文档
  4. 不懂绕XYZ轴旋转的数学原理?推荐[这篇知乎文章,写的挺好的]
    (https://zhuanlan.zhihu.com/p/183973440)

下面是代码以及注释

#include <graphics.h>
#include <math.h>
#include <easyx.h>
#include <stdbool.h>
#include <stdio.h>
#define SIZE 100 // 立方
int SCRW = 800;
int SCRH = 600;
//操控区
struct Bar {
    //操控杆。横放
    int x;
    int y;
    int w;
    int h;
    COLORREF nowcolor;
    COLORREF outcolor;
    COLORREF incolor;
    bool keydown;
};
struct button {//最上方的还原按钮
    int x;
    int y;
    int w;
    int h;
    COLORREF nowcolor;
    COLORREF outcolor;
    COLORREF incolor;
};
struct button* createbutton(int x, int y, int w, int h,COLORREF out,COLORREF in) {
    struct button* pB = (struct button*)malloc(sizeof(struct button));
    pB->x = x;
    pB->y = y;
    pB->w = w;
    pB->h = h;
    pB->outcolor = out;
    pB->incolor = in;
    pB->nowcolor = out;
    return pB;
}
bool isInbutton(struct button* pB, ExMessage m) {
    if (m.x > pB->x && m.y > pB->y &&
        m.x < pB->x + pB->w && m.y < pB->y + pB->h) {
        pB->nowcolor = pB->incolor;
        return true;
    }
    pB->nowcolor = pB->outcolor;
    return false;
}
void drawbutton(struct button* pB) {
    int right = pB->w + pB->x;
    int buttom = pB->y + pB->h;
    setfillcolor(pB->nowcolor);
    solidrectangle(pB->x, pB->y, right, buttom);
    settextstyle(20, 0, _T("Arial"));  // 设置文本样式
    // 设置文本背景色为透明色
    setbkmode(TRANSPARENT);
    settextcolor(BLACK);
    outtextxy(15,15, "RE");
}
struct Bar* createBar(int x, int y, int w, int h, COLORREF outcolor, COLORREF incolor) {
    struct Bar* pbar = (struct Bar*)malloc(sizeof(struct Bar));
    pbar->x = x;
    pbar->y = y;
    pbar->w = w;
    pbar->h = h;
    pbar->outcolor = outcolor;
    pbar->incolor = incolor;
    pbar->nowcolor = outcolor;
    pbar->keydown = false;
    return pbar;
}
bool isInBar(struct Bar* pB, ExMessage m) {
    if (m.x > pB->x && m.y > pB->y &&
        m.x < pB->x + pB->w && m.y < pB->y + pB->h) {
        pB->nowcolor = pB->incolor;
        return true;
    }
    pB->nowcolor = pB->outcolor;
    return false;
}
void movebar(struct Bar* pB, ExMessage m) {
    static int temp = 0;
    if (m.message == WM_LBUTTONDOWN) {
        pB->keydown = true;
        temp = m.x;
    }
    if (m.message == WM_LBUTTONUP) {
        pB->keydown = false;

    }
    if (pB->keydown && m.message == WM_MOUSEMOVE) {
        int deltaX = m.x - temp;
        pB->x += deltaX;
        temp = m.x; // 更新temp
    }
    if (pB->x <= 0)
        pB->x = 0;
    if (pB->x >= 700)
        pB->x = 700;
}
void drawBar(struct Bar* pxbar) {
    setlinestyle(1, 5);
    setlinecolor(BLACK);
    line(0, pxbar->y + pxbar->h / 2, SCRW, pxbar->y + pxbar->h / 2);
    setfillcolor(pxbar->nowcolor);
    solidrectangle(pxbar->x, pxbar->y, pxbar->x + pxbar->w, pxbar->y + pxbar->h);
    
}
//底层区
double Xangle = 0;
double Yangle = 0;
double Zangle = 0;
double PI = 3.1415926;

double cube[8][3] = {
    {-1, -1, -1}, {1, -1, -1}, {1, 1, -1}, {-1, 1, -1},
    {-1, -1, 1}, {1, -1, 1}, {1, 1, 1}, {-1, 1, 1}
};
struct Link {
    int str;
    int end;//一个LINK,表示cube中下标元素的连接
};
struct Link Lincube[12]{
    {0,1},{0,3},{1,2},{2,3},
    {4,5},{5,6},{6,7},{7,4},
    {1,5},{2,6},{3,7},{0,4}
    //这里更改数据结构之后,还可以旋转不同的形状
};
void project(double x, double y, int* sx, int* sy) {
    *sx = (int)(x * SIZE + SCRW / 2-50);
    *sy = (int)(y * SIZE + SCRH / 2 -80);
}
void drawCube(double cube[8][3]) {
    int sx, sy, ex, ey;
    for (int i = 0; i < 12; i++) {
        project(cube[Lincube[i].str][0], cube[Lincube[i].str][1], &sx, &sy);
        project(cube[Lincube[i].end][0], cube[Lincube[i].end][1], &ex, &ey);
        setlinecolor(BLACK);
        line(sx, sy, ex, ey);
    }
}
//旋转
//绕X轴旋转
void XrotateCube(double Angle) {
    int angle = Angle - Xangle;//这里是变化的角度
    double sinA = sin(angle * PI / 180);
    double cosA = cos(angle * PI / 180);
    for (int i = 0; i < 8; i++) {
        double x = cube[i][0], y = cube[i][1], z = cube[i][2];
        cube[i][0] = x;
        cube[i][1] = y * cosA - z * sinA;
        cube[i][2] = sinA * y + cosA * z;
    }
}
//绕Y轴旋转
void YrotateCube(double Angle) {
    int angle = Angle - Yangle;
    double sinA = sin(angle * PI / 180);
    double cosA = cos(angle * PI / 180);
    for (int i = 0; i < 8; i++) {
        double x = cube[i][0], y = cube[i][1], z = cube[i][2];
        cube[i][0] = cosA * x - sinA * z;
        cube[i][1] = y;
        cube[i][2] = sinA * x + cosA * z;
    }
}
//绕Z轴旋转
void ZrotateCube(double Angle) {
    int angle = Angle - Zangle;
    double sinA = sin(angle * PI / 180);
    double cosA = cos(angle * PI / 180);
    for (int i = 0; i < 8; i++) {
        double x = cube[i][0], y = cube[i][1], z = cube[i][2];
        cube[i][0] = cosA * x - sinA * y;
        cube[i][1] = sinA * x + cosA * y;
        cube[i][2] = z;
    }
}

void outtextxy_int(int x, int y, double data, char name) {
    char text[64] = { 0 };
    sprintf_s(text, "Radian parameter of %c axis rotation:%.3f PI", name, data);
    outtextxy(x, y, text);
}

void drawParameterTable(struct Bar* pxbar, struct Bar* pybar, struct Bar* pzbar) {
    settextcolor(BLACK);
    setlinecolor(BLACK);
    setlinestyle(3);
    rectangle(450, 20, 790, 95);
    outtextxy_int(460, 25, (pxbar->x-350)*0.005714, 'x');
    outtextxy_int(460, 45, (pybar->x - 350) * 0.005714, 'y');
    outtextxy_int(460, 65, (pzbar->x - 350) * 0.005714, 'z');
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{   
    initgraph(SCRW, SCRH);
    setbkcolor(WHITE);
    cleardevice();
    struct Bar* pxbar = createBar(350, 500, 100, 30, RGB(204, 213, 240), RGB(236, 244, 255));
    struct Bar* pybar = createBar(350, 535, 100, 30, RGB(204, 213, 240), RGB(236, 244, 255));
    struct Bar* pzbar = createBar(350, 570, 100, 30, RGB(204, 213, 240), RGB(236, 244, 255));
    struct button* pb = createbutton(0, 0, 50, 50, RGB(204, 213, 240), RGB(236, 244, 255));
    ExMessage m;
    BeginBatchDraw();
    while (1) {
        cleardevice();
        peekmessage(&m, EM_MOUSE);
        drawBar(pxbar);
        drawBar(pybar);
        drawBar(pzbar);
        drawbutton(pb);
        drawParameterTable(pxbar, pybar, pzbar);
        if (isInBar(pxbar, m)) {
            movebar(pxbar, m);
            if (pxbar->x != Xangle) {
                XrotateCube(pxbar->x);
                Xangle = pxbar->x;
            }
        }
        if (isInBar(pybar, m)) {
            movebar(pybar, m); 
            if (pybar->x != Yangle) {
                YrotateCube(pybar->x);
                Yangle = pybar->x;
                
            }
        }
        if (isInBar(pzbar, m)) {
            movebar(pzbar, m); 
            if (pzbar->x != Zangle) {
                ZrotateCube(pzbar->x);
                Zangle = pzbar->x;
            }
        }
        if (isInbutton(pb, m)&& m.message == WM_LBUTTONDOWN) {
            pxbar->x = 350;
            pybar->x = 350;
            pzbar->x = 350;
            Xangle = 0;
            Yangle = 0;
            Zangle = 0;
            cube[0][0] = -1;cube[0][1] = -1; cube[0][2] = -1;
            cube[1][0] =  1;cube[1][1] = -1; cube[1][2] = -1;
            cube[2][0] = 1; cube[2][1] =  1; cube[2][2] = -1;
            cube[3][0] = -1; cube[3][1] = 1; cube[3][2] = -1;
            cube[4][0] = -1; cube[4][1] = -1; cube[4][2] = 1;
            cube[5][0] = 1; cube[5][1] = -1; cube[5][2] =  1;
            cube[6][0] = 1; cube[6][1] =  1; cube[6][2] =  1;
            cube[7][0] = -1; cube[7][1] = 1; cube[7][2] = 1;
            //回正 
        }

        setlinestyle(PS_SOLID,2);
        drawCube(cube);
        FlushBatchDraw();
    }
    EndBatchDraw();
    closegraph();
    return 0;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值