Advertisement

MFC实现太阳系系统八大行星(附完整源码)

阅读量:

MFC实现太阳系系统八大行星

创建一个完整的太阳系模拟程序需要进行大量的数学计算和图形渲染操作,并且代码实现较为繁琐。在此示例中, 我将介绍一个基于MFC的简单程序, 并展示如何利用 OpenGL 进行基本的太阳系模拟

请确认已正确安装具有 OpenGL 支持的 GLEW 和 GLFW 库。通过 NuGet 包管理工具完成这些软件包的安装过程。

以下是基于 OpenGL 的一个标准 MFC 开发框架示例代码段落,在展示一个基本的天体运行模型时采用了 OpenGL 技术进行 3D 图形渲染:

创建一个 MFC 应用程序项目。

打开 MainDialog.h 文件,并用以下内容替换其中的内容:

复制代码
    // MainDialog.h
    #pragma once
    
    #include "afxwin.h"
    #include <gl/glew.h>
    #include <GLFW/glfw3.h>
    
    class CMainDialog : public CDialog
    {
    public:
    CMainDialog(CWnd* pParent = nullptr);
    
    #ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_MAIN_DIALOG };
    #endif
    
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);
    
    protected:
    HICON m_hIcon;
    
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnDestroy();
    DECLARE_MESSAGE_MAP()
    
    private:
    GLFWwindow* m_pGLFWWindow;
    GLuint m_shaderProgram;
    GLuint m_VAO;
    GLuint m_VBO;
    };

打开 MainDialog.cpp 文件,并用以下内容替换其中的内容:

复制代码
    // MainDialog.cpp
    #include "pch.h"
    #include "SolarSystem.h"
    #include "MainDialog.h"
    #include "afxdialogex.h"
    #include <iostream>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    CMainDialog::CMainDialog(CWnd* pParent /*=nullptr*/)
    : CDialog(IDD_MAIN_DIALOG, pParent),
    m_pGLFWWindow(nullptr),
    m_shaderProgram(0),
    m_VAO(0),
    m_VBO(0)
    {
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CMainDialog::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    }
    
    BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_DESTROY()
    END_MESSAGE_MAP()
    
    BOOL CMainDialog::OnInitDialog()
    {
    CDialog::OnInitDialog();
    
    SetIcon(m_hIcon, TRUE);
    SetIcon(m_hIcon, FALSE);
    
    // 初始化 GLFW
    if (!glfwInit())
    {
        MessageBox(_T("Failed to initialize GLFW."), _T("Error"), MB_ICONERROR);
        return FALSE;
    }
    
    // 设置 GLFW 版本
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    
    // 创建 GLFW 窗口
    m_pGLFWWindow = glfwCreateWindow(800, 600, _T("Solar System Simulation"), nullptr, nullptr);
    if (!m_pGLFWWindow)
    {
        MessageBox(_T("Failed to create GLFW window."), _T("Error"), MB_ICONERROR);
        glfwTerminate();
        return FALSE;
    }
    
    // 设置当前上下文
    glfwMakeContextCurrent(m_pGLFWWindow);
    
    // 初始化 GLEW
    if (glewInit() != GLEW_OK)
    {
        MessageBox(_T("Failed to initialize GLEW."), _T("Error"), MB_ICONERROR);
        return FALSE;
    }
    
    // 设置 OpenGL 视口大小
    glViewport(0, 0, 800, 600);
    
    // 编译和链接着色器
    const char* vertexShaderSource = R"(
        #version 330 core
        layout (location = 0) in vec3 aPos;
        uniform mat4 model;
        uniform mat4 view;
        uniform mat4 projection;
        void main()
        {
            gl_Position = projection * view * model * vec4(aPos, 1.0);
        }
    )";
    
    const char* fragmentShaderSource = R"(
        #version 330 core
        out vec4 FragColor;
        void main()
        {
            FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
        }
    )";
    
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
    glCompileShader(vertexShader);
    
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
    glCompileShader(fragmentShader);
    
    m_shaderProgram = glCreateProgram();
    glAttachShader(m_shaderProgram, vertexShader);
    glAttachShader(m_shaderProgram, fragmentShader);
    glLinkProgram(m_shaderProgram);
    
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    
    // 设置顶点数据和缓冲区
    GLfloat vertices[] = {
        // 太阳
        0.0f, 0.0f, 0.0f,
        // 水星
        1.5f, 0.0f, 0.0f,
        // 金星
        3.0f, 0.0f, 0.0f,
        // 地球
        5.0f, 0.0f, 0.0f,
        // 火星
        8.0f, 0.0f, 0.0f,
        // 木星
        12.0f, 0.0f, 0.0f,
        // 土星
        18.0f, 0.0f, 0.0f,
        // 天王星
        25.0f, 0.0f, 0.0f,
        // 海王星
        35.0f, 0.0f, 0.0f
    };
    
    glGenVertexArrays(1, &m_VAO);
    glGenBuffers(1, &m_VBO);
    
    glBindVertexArray(m_VAO);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    
    // 启用深度测试
    glEnable(GL_DEPTH_TEST);
    
    return TRUE;
    }
    
    void CMainDialog::OnPaint()
    {
    // 渲染场景
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    glUseProgram(m_shaderProgram);
    
    // 设置观察矩阵和投影矩阵
    glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 30.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view));
    
    glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
    glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
    
    // 渲染行星
    for (float i = 0.0f; i < 360.0f; i += 45.0f)
    {
        glm::mat4 model = glm::mat4(1.0f);
        model = glm::rotate(model, glm::radians(i), glm::vec3(0.0f, 1.0f, 0.0f));
        glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
    
        glBindVertexArray(m_VAO);
        glDrawArrays(GL_POINTS, 0, 9);
    }
    
    glBindVertexArray(0);
    
    SwapBuffers(GetDC()->m_hDC);
    }
    
    HCURSOR CMainDialog::OnQueryDragIcon()
    {
    return static_cast<HCURSOR>(m_hIcon);
    }
    
    void CMainDialog::OnDestroy()
    {
    // 清理资源
    glDeleteVertexArrays(1, &m_VAO);
    glDeleteBuffers(1, &m_VBO);
    glDeleteProgram(m_shaderProgram);
    
    // 清理 GLFW
    glfwDestroyWindow(m_pGLFWWindow);
    glfwTerminate();
    
    CDialog::OnDestroy();
    }

打开 resource.h 文件,在其中添加以下定义:

复制代码
    // resource.h
    //{{NO_DEPENDENCIES}}
    // Microsoft Visual C++ generated include file.
    // Used by SolarSystem.rc
    //
    #define IDD_MAIN_DIALOG                 102
    #define IDR_MAINFRAME                   128

在 SolarSystem.rc 文件中的 #MAIN_DIALOG 对话框下部署一个图标资源(ID: IDR_MAINFRAME)。

具体的实现细节需放置在此处

复制代码
    // SolarSystem.cpp
    #include "pch.h"
    #include "SolarSystem.h"
    #include "MainDialog.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    BEGIN_MESSAGE_MAP(CSolarSystemApp, CWinApp)
    ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
    END_MESSAGE_MAP()
    
    CSolarSystemApp::CSolarSystemApp()
    {
    }
    
    CSolarSystemApp theApp;
    
    BOOL CSolarSystemApp::InitInstance()
    {
    CWinApp::InitInstance();
    
    AfxEnableControlContainer();
    
    CMainDialog dlg;
    m_pMainWnd = &dlg;
    dlg.DoModal();
    
    return FALSE;
    }

在这个案例中, 我们构建了一个包含太阳及八大行星(简化为点)的太阳系模型. 利用旋转矩阵, 我们实现了行星绕太阳运行的公转效果.

请注意以下是一个简化的示例,在实际项目中可能需要采用更为复杂的数学模型与图形渲染技术。在实际开发中建议采用功能更为强大的图形渲染库或专业引擎以提升表现力。例如像 OpenGL 这样的专业图形渲染引擎或其他经过优化的渲染框架可能会更适合您的需求。

此博客内容均为原创,未经原作者许可转载者请自行联系授权。本文博客详细信息如下:

全部评论 (0)

还没有任何评论哟~