OpenGL 03--练习

1、创建相同的两个三角形,但对它们的数据使用不同的VAO和VBO

#include <glad/glad.h>  // 包含 GLAD 库的头文件,用于加载 OpenGL 函数指针
#include <GLFW/glfw3.h>  // 包含 GLFW 库的头文件,用于创建窗口和处理输入
#include <iostream>  // 包含标准输入输出流库

// 定义 framebuffer_size_callback 函数原型
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
// 定义 processInput 函数原型
void processInput(GLFWwindow* window);

// 设置窗口的宽度和高度
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// 定义顶点着色器的 GLSL 源码
const char* vertexShaderSource = "#version 400 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\n0";
// 定义片元着色器的 GLSL 源码
const char* fragmentShaderSource = "#version 400 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";

int main()
{
    // 初始化 GLFW
    glfwInit();
    // 设置 GLFW 创建 OpenGL 4.0 核心配置文件的提示
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);  // 苹果系统需要设置为向前兼容模式
#endif

    // 创建 GLFW 窗口
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // 加载 OpenGL 函数指针
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 创建和编译着色器程序
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    unsigned int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // 设置顶点数据和缓冲区
    float firstTriangle[] = {
        -0.9f, -0.5f, 0.0f,  // 左下
         0.0f, -0.5f, 0.0f,  // 右下
        -0.45f, 0.5f, 0.0f,  // 上
    };
    float secondTriangle[] = {
        0.0f, -0.5f, 0.0f,  // 左
        0.9f, -0.5f, 0.0f,  // 右
        0.45f, 0.5f, 0.0f   // 上
    };
    unsigned int VBOs[2], VAOs[2];
    glGenVertexArrays(2, VAOs);
    glGenBuffers(2, VBOs);

    // 配置第一个三角形的 VAO 和 VBO
    glBindVertexArray(VAOs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(firstTriangle), firstTriangle, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 配置第二个三角形的 VAO 和 VBO
    glBindVertexArray(VAOs[1]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glEnableVertexAttribArray(0);

    // 渲染循环
    while (!glfwWindowShouldClose(window))
    {
        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shaderProgram);
        // 绘制第一个三角形
        glBindVertexArray(VAOs[0]);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        // 绘制第二个三角形
        glBindVertexArray(VAOs[1]);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 清理资源
    glDeleteVertexArrays(2, VAOs);
    glDeleteBuffers(2, VBOs);
    glDeleteProgram(shaderProgram);

    // 终止 GLFW
    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

// 处理输入的函数
void processInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// 当窗口大小改变时调用的回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

   这段代码展示了如何在 OpenGL 中创建和管理多个三角形,每个三角形使用独立的 VAO 和 VBO。

代码解释:

  1. 初始化和配置GLFW:设置 OpenGL 的版本和配置文件,创建一个窗口,并注册一个视口改变的回调函数。

  2. 加载OpenGL函数指针:使用 GLAD 库加载所有 OpenGL 函数的指针。

  3. 创建和编译着色器程序:创建顶点着色器和片元着色器,编译它们,并将它们附加到着色器程序,然后链接着色器程序。

  4. 设置顶点数据和缓冲区:定义两个三角形的顶点数据,创建两个 VAO 和两个 VBO,将顶点数据复制到 VBO 中,并配置顶点属性指针。

  5. 渲染循环:在渲染循环中,处理输入,清除颜色缓冲区,使用着色器程序,绘制两个三角形,交换前后缓冲区,并处理事件。

  6. 清理资源:在程序结束时删除分配的 VAO、VBO 和着色器程序。

  7. 处理输入:定义 processInput 函数来处理用户输入,例如按下 ESC 键关闭窗口。

  8. 视口改变的回调函数:定义 framebuffer_size_callback 函数来处理窗口大小改变事件,设置视口以匹配新窗口尺寸。

输出结果: 

 

2、 创建两个着色器程序,第二个程序使用一个不同的片段着色器,输出橙色;再次绘制这两个三角形,让其中一个输出为黄色

     解读:

        创建两个三角形,每个三角形都有自己的 VAO 和 VBO,并且使用不同的片元着色器为它们着色。第一个三角形被渲染成橙色,第二个三角形被渲染成黄色。

#include <glad/glad.h>  // 包含 GLAD 库的头文件,用于加载 OpenGL 函数指针
#include <GLFW/glfw3.h>  // 包含 GLFW 库的头文件,用于创建窗口和处理输入
#include <iostream>  // 包含标准输入输出流库

// 定义 framebuffer_size_callback 函数原型
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
// 定义 processInput 函数原型
void processInput(GLFWwindow* window);

// 设置窗口的宽度和高度
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// 定义顶点着色器的 GLSL 源码
const char* vertexShaderSource = "#version 400 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\n\0";
// 定义第一个片元着色器的 GLSL 源码,输出颜色为橙色
const char* fragmentShader1Source = "#version 400 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
// 定义第二个片元着色器的 GLSL 源码,输出颜色为黄色
const char* fragmentShader2Source = "#version 400 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);\n"
"}\n\0";

int main()
{
    // 初始化 GLFW
    glfwInit();
    // 设置 GLFW 创建 OpenGL 3.3 核心配置文件的提示
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);  // 苹果系统需要设置为向前兼容模式
#endif

    // 创建 GLFW 窗口
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // 加载 OpenGL 函数指针
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 创建和编译我们的着色器程序
    // 我们跳过了编译日志检查,以提高可读性(如果遇到问题,请添加编译检查!参见以前的代码示例)
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    unsigned int fragmentShaderOrange = glCreateShader(GL_FRAGMENT_SHADER); // 第一个片元着色器输出橙色
    unsigned int fragmentShaderYellow = glCreateShader(GL_FRAGMENT_SHADER); // 第二个片元着色器输出黄色
    unsigned int shaderProgramOrange = glCreateProgram();
    unsigned int shaderProgramYellow = glCreateProgram(); // 第二个着色器程序
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    glShaderSource(fragmentShaderOrange, 1, &fragmentShader1Source, NULL);
    glCompileShader(fragmentShaderOrange);
    glShaderSource(fragmentShaderYellow, 1, &fragmentShader2Source, NULL);
    glCompileShader(fragmentShaderYellow);
    // 链接第一个程序对象
    glAttachShader(shaderProgramOrange, vertexShader);
    glAttachShader(shaderProgramOrange, fragmentShaderOrange);
    glLinkProgram(shaderProgramOrange);
    // 然后链接第二个程序对象,使用不同的片元着色器(但顶点着色器相同)
    // 这是完全允许的,因为两个顶点和片元着色器的输入和输出都匹配。
    glAttachShader(shaderProgramYellow, vertexShader);
    glAttachShader(shaderProgramYellow, fragmentShaderYellow);
    glLinkProgram(shaderProgramYellow);

    // 设置顶点数据(和缓冲区)并配置顶点属性
    // ------------------------------------------------------------------
    float firstTriangle[] = {
        -0.9f, -0.5f, 0.0f,  // 左下 
        -0.0f, -0.5f, 0.0f,  // 右下
        -0.45f, 0.5f, 0.0f,  // 上
    };
    float secondTriangle[] = {
        0.0f, -0.5f, 0.0f,  // 左
        0.9f, -0.5f, 0.0f,  // 右
        0.45f, 0.5f, 0.0f   // 上 
    };
    unsigned int VBOs[2], VAOs[2];
    glGenVertexArrays(2, VAOs); // 我们也可以同时生成多个 VAO 或缓冲区
    glGenBuffers(2, VBOs);
    // 第一个三角形设置
    // --------------------
    glBindVertexArray(VAOs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(firstTriangle), firstTriangle, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);	// 顶点属性保持不变
    glEnableVertexAttribArray(0);
    // glBindVertexArray(0); // 不需要全部解绑,因为我们直接绑定了不同的 VAO 下面几行
    // 第二个三角形设置
    // --------------------
    glBindVertexArray(VAOs[1]);	// 注意我们现在绑定到不同的 VAO
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);	// 和不同的 VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); // 因为顶点数据是紧密打包的,我们也可以指定 0 作为顶点属性的步长,让 OpenGL 计算出来
    glEnableVertexAttribArray(0);
    // glBindVertexArray(0); // 不是必要的,但要注意可能影响 VAO 的调用(如绑定元素缓冲区对象,或启用/禁用顶点属性)

    // 注释:取消注释这行代码以绘制线框多边形。
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // 渲染循环
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // 输入
        // -----
        processInput(window);

        // 渲染
        // ------
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // 现在,当我们绘制三角形时,我们首先使用第一个程序中的顶点和橙色片元着色器
        glUseProgram(shaderProgramOrange);
        // 使用第一个 VAO 的数据绘制第一个三角形
        glBindVertexArray(VAOs[0]);
        glDrawArrays(GL_TRIANGLES, 0, 3);	// 这个调用应该输出一个橙色三角形
        // 然后我们绘制第二个三角形,使用第二个 VAO 的数据
        // 当我们绘制第二个三角形时,我们想要使用一个不同的着色器程序,所以我们切换到着色器程序,它有我们的黄色片元着色器。
        glUseProgram(shaderProgramYellow);
        glBindVertexArray(VAOs[1]);
        glDrawArrays(GL_TRIANGLES, 0, 3);	// 这个调用应该输出一个黄色三角形

        // glfw:交换缓冲区并轮询 IO 事件(按键按下/释放,鼠标移动等)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 可选:一旦它们的目的已经达到,就释放所有资源:
    // --------------------------------------------------------------------
    glDeleteVertexArrays(2, VAOs);
    glDeleteBuffers(2, VBOs);
    glDeleteProgram(shaderProgramOrange);
    glDeleteProgram(shaderProgramYellow);

    // glfw:终止,清除所有先前分配的 GLFW 资源。
    // ------------------------------------------------------------------
    glfwTerminate();
    return 0;
}

// 处理所有输入:查询 GLFW 本帧是否有相关按键被按下/释放,并相应地做出反应
// ----------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// glfw:每当窗口大小改变(由操作系统或用户调整大小时)此回调函数执行
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // 确保视口与新窗口尺寸匹配;注意,在视网膜显示器上宽度和高度将明显大于指定值。
    glViewport(0, 0, width, height);
}

    在渲染循环中,首先激活橙色片元着色器程序,然后绘制第一个三角形,然后激活黄色片元着色器程序,绘制第二个三角形。这样,可以在同一个渲染循环中看到两个颜色不同的三角形。 

输出结果:

 

参考:

你好,三角形 - LearnOpenGL CN

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值