OpenGL使用C++ 绘制三角形

1. 基础环境

VSCode + XMake搭建OpenGL开发环境

2. 项目结构

拆分窗口创建、渲染逻辑等核心功能

增加glwindow.h与glwindow.cpp文件,xmake配置不变

bash 复制代码
opengl-xmake-demo/
├─ include/                # 头文件目录
│  ├─ ***                
│  └─ glwindow.h           # OpenGL核心功能模块
├─ src/
│  ├─ ***
│  ├─ glwindow.cpp         # OpenGL核心功能模块
│  └─ main.cpp             # 主程序代码(测试代码见下文)
└─ xmake.lua               # XMake 配置文件(核心)

3. 源代码

glwindow.h

cpp 复制代码
#ifndef GLWINDOW_H
#define GLWINDOW_H

#include <iostream>
#include <string>
#include <GLFW/glfw3.h>

class GLWindow
{
public:
    GLWindow(int w, int h, const std::string &title);
    ~GLWindow();

    void render();
    void update();

    bool shouldClose();
    void processInput();

private:
    // 窗口相关信息
    GLFWwindow *window;
    int width;
    int height;
    std::string title;

    // 渲染相关
    unsigned int shaderProgram;
    unsigned int VBO, VAO;

private:
    bool initGLFW();
    bool initGLAD();
    void initShaders();
    void initBuffers();

    // 窗口大小变化回调函数(静态成员函数)
    static void framebufferSizeCallback(GLFWwindow *window, int width, int height);

};

#endif // GLWINDOW_H

glwindow.cpp

cpp 复制代码
// glad必须在glwindow.h之前包含
#include <glad/glad.h>
#include "glwindow.h"

GLWindow::GLWindow(int w, int h, const std::string &title) : width(w), height(h), title(title)
{
    if (!initGLFW())
    {
        throw std::runtime_error("GLFW初始化失败!");
    }
    if (!initGLAD())
    {
        throw std::runtime_error("GLAD初始化失败!");
    }
    initShaders();
    initBuffers();
}

GLWindow::~GLWindow()
{
    // 释放VAO、VBO和着色器程序
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);
    // 销毁窗口并终止GLFW
    glfwDestroyWindow(window);
    glfwTerminate();
}

/* 渲染函数 */
void GLWindow::render()
{
    // 清空屏幕
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // 使用着色器程序并绘制三角形
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

/* 更新函数 */
void GLWindow::update()
{
    glfwSwapBuffers(window);
    glfwPollEvents();
}

/* 检查窗口是否应该关闭 */
bool GLWindow::shouldClose()
{
    return glfwWindowShouldClose(window);
}

/* 处理输入 */
void GLWindow::processInput()
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, true);
    }
}

/* 初始化GLFW */
bool GLWindow::initGLFW()
{
    // 初始化GLFW
    if (!glfwInit())
    {
        std::cerr << "GLFW初始化失败!" << std::endl;
        return false;
    }

    // 设置OpenGL版本和配置文件
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // 创建窗口
    window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
    if (!window)
    {
        std::cerr << "窗口创建失败!" << std::endl;
        glfwTerminate();
        return false;
    }

    // 绑定窗口上下文并设置大小回调
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
    // 将当前GLWindow对象指针存入窗口用户数据(供回调使用)
    glfwSetWindowUserPointer(window, this);

    return true;
}

/* 初始化GLAD*/
bool GLWindow::initGLAD()
{
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cerr << "Glad加载失败!" << std::endl;
        return false;
    }
    // 设置视口大小(初始窗口大小)
    glViewport(0, 0, width, height);
    return true;
}

/* 初始化着色器程序 */
void GLWindow::initShaders()
{
    // 顶点着色器源码
    const char *vertexShaderSource = "#version 330 core\n"
                                     "layout (location = 0) in vec3 aPos;\n"
                                     "layout (location = 1) in vec3 aColor;\n"
                                     "out vec3 ourColor;\n"
                                     "void main()\n"
                                     "{\n"
                                     "   gl_Position = vec4(aPos, 1.0);\n"
                                     "   ourColor = aColor;\n"
                                     "}\0";

    // 片段着色器源码
    const char *fragmentShaderSource = "#version 330 core\n"
                                       "in vec3 ourColor;\n"
                                       "out vec4 FragColor;\n"
                                       "void main()\n"
                                       "{\n"
                                       "   FragColor = vec4(ourColor, 1.0);\n"
                                       "}\0";
    // 编译顶点着色器
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
    glCompileShader(vertexShader);

    // 检查顶点着色器错误
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
        std::cerr << "顶点着色器编译失败:\n"
                  << infoLog << std::endl;
    }

    // 编译片段着色器
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
    glCompileShader(fragmentShader);

    // 检查片段着色器错误
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
        std::cerr << "片段着色器编译失败:\n"
                  << infoLog << std::endl;
    }

    // 链接着色器程序
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    // 检查链接错误
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
        std::cerr << "着色器程序链接失败:\n"
                  << infoLog << std::endl;
    }

    // 删除临时着色器对象
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

/* 初始化缓冲区对象 */
void GLWindow::initBuffers()
{
    // 顶点数据(位置+颜色)
    float vertices[] = {
        0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,  // 右下:红
        -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下:绿
        0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f    // 顶部:蓝
    };

    // 生成VAO和VBO
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    // 绑定VAO(必须先绑定VAO才能配置顶点属性)
    glBindVertexArray(VAO);

    // 绑定VBO并复制数据到GPU
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 配置位置属性(location=0)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);

    // 配置颜色属性(location=1)
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // 解绑缓冲(可选,避免误操作)
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

/* 窗口大小变化回调函数 */
void GLWindow::framebufferSizeCallback(GLFWwindow *window, int width, int height)
{
    // 从窗口用户数据中获取GLWindow对象指针
    GLWindow *glWindow = static_cast<GLWindow *>(glfwGetWindowUserPointer(window));
    if (glWindow)
    {
        // 更新窗口大小并设置视口
        glWindow->width = width;
        glWindow->height = height;
        glViewport(0, 0, width, height);
    }
}

main.cpp

cpp 复制代码
#include <iostream>
#include "glwindow.h"

int main()
{
    // 创建窗口(宽800,高600,标题"Triangle Demo")
    GLWindow window(800, 600, "Triangle Demo");

    // 渲染循环
    while (!window.shouldClose())
    {
        window.processInput(); // 处理输入
        window.render();       // 渲染一帧
        window.update();       // 交换缓冲区和事件处理
    }
    return 0;
}

4. 结果示例

相关推荐
code_ing-8 小时前
【Linux】命令行参数与环境变量
linux·c++·windows·笔记
wangjialelele8 小时前
Qt中的常用组件:QWidget篇
开发语言·前端·c++·qt
九德拉8 小时前
利用XPlaneConnect从X-Plane内读写数据
c++·飞行仿真·x-plane
_OP_CHEN9 小时前
C++进阶:(三)深度解析二叉搜索树原理及实现
开发语言·数据结构·c++·二叉树·二叉搜索树·键值对
郝学胜-神的一滴11 小时前
深入解析C++命令模式:设计原理与实际应用
开发语言·c++·程序人生·软件工程·命令模式
ShineSpark11 小时前
Crashpad介绍
c++·windows
苏纪云11 小时前
算法<C++>——双指针 | 滑动窗口
数据结构·c++·算法·双指针·滑动窗口
ouliten13 小时前
C++笔记:std::variant
开发语言·c++·笔记
Yupureki14 小时前
从零开始的C++学习生活 20:数据结构与STL复习课(4.4w字全解析)
c语言·数据结构·c++·学习·visual studio·1024程序员节