0


一篇搞定利用开源库写一个OpenGL测试窗口小工具

由于代码不好抽离,所有的代码最终我会上传至百度网盘,附上连接,需要的可以对照的看文章,包括前面所有的学习笔记的,代码都有详细中文注释。Application为就main函数,ApplicationNew为新main函数,如有其他疑问,可以留言评论。

链接:https://pan.baidu.com/s/1gmosgzliBi4eqL22vmP1Cw?pwd=o2wg

提取码:o2wg

话不多说,我把我看的视频链接贴出来,下面的笔记是由视频学习和自己的补充而来。这次是(22-26)的笔记

跟着这个小哥的教学视频学的(YouTube原视频,科学上网AI字幕) ► http://bit.ly/2lt7ccM
这个是哔哩哔哩网站有人搬运的 ►https://www.bilibili.com/video/BV1MJ411u7Bc/?share_source=copy_web&vd_source=80ce9fa9cc5a33fdc2b9a467859dd047

一、引入imgui库

现在我们来做一个可视化的调试工具,方便我们动态的创建调试更改我们的OpenGL
https://github.com/ocornut/imgui

引入开源imgui,然后按照例子学一个demo出来,可视化的界面就显示出来了。

我下载的是1.6.0版本的imgui,然后下载源码,把需要的的头文件,源文件拷贝到项目源代码的一个文件夹下,我的是:xxxxxx项目文件夹\src\vender\imgui

然后记得把main排除在项目外

我们可以通过这个main查看imgui这个demo是怎么使用实现的,我大致抽离了一下再OpenGL中imgui 的使用流程如下:

 // Setup ImGui binding
        ImGui::CreateContext();
        ImGui_ImplGlfwGL3_Init(window, true);
        ImGui::StyleColorsDark();

            ImGui_ImplGlfwGL3_NewFrame();

            ImGui::Render();
            ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());

    // Cleanup
    ImGui_ImplGlfwGL3_Shutdown();
    ImGui::DestroyContext();

二、制作一个可操控的模型变换矩阵的demo

然后我们根据demo做一个可以操控的模型变换矩阵的视图

        // Setup ImGui binding
        ImGui::CreateContext();
        ImGui_ImplGlfwGL3_Init(window, true);
        ImGui::StyleColorsDark();
        
        glm::vec3 translationA(200, 200, 0);

        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            //glClear(GL_COLOR_BUFFER_BIT);
            renderer.Clear();

            ImGui_ImplGlfwGL3_NewFrame();

            texture.Bind(0);
            {
                glm::mat4 model = glm::translate(glm::mat4(1.0f), translationA);
                glm::mat4 mvp = proj * view * model;
                shader.Bind();
                shader.SetUniformMat4f("u_MVP", mvp);
                shader.SetUniform1i("u_Texture", 0);
                //我们可以在每次画之前从cpu更改uniform变量的值然后传入,这样就可以有变化的效果了
                //shader.SetUniform4f("u_Color", r, 0.3f, 0.8f, 1.0f);

                //当我们使用索引缓冲区之后,我们就不是DrawArrays了,而是DrawElement了
                //GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
                
                renderer.Draw(va, ib, shader);

            }

            {   
                // Edit 1 float using a slider from 0.0f to 1.0f             
                ImGui::SliderFloat3("translationB", &translationB.x, 0.0f, 960.0f);            
                ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / 
                ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
            }
            ImGui::Render();
            ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());

            /* Swap front and back buffers */
            glfwSwapBuffers(window);

            /* Poll for and process events */
            glfwPollEvents();
        }

    ImGui_ImplGlfwGL3_Shutdown();
    ImGui::DestroyContext();
    glfwTerminate();

效果如下gif


现在我们如果要渲染另一种东西,也就是比如着色器动态化,顶点动态化,顶点索引都变化了的情况,怎么做到呢,就拿我们要在屏幕的不同位置画两个一样的图标为例,无非就是再画一个。

        // Setup ImGui binding
        ImGui::CreateContext();
        ImGui_ImplGlfwGL3_Init(window, true);
        ImGui::StyleColorsDark();
        
        glm::vec3 translationA(200, 200, 0);
        glm::vec3 translationB(400, 200, 0);

        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */
            //glClear(GL_COLOR_BUFFER_BIT);
            renderer.Clear();

            ImGui_ImplGlfwGL3_NewFrame();

            texture.Bind(0);
            {
                glm::mat4 model = glm::translate(glm::mat4(1.0f), translationA);
                glm::mat4 mvp = proj * view * model;
                shader.Bind();
                shader.SetUniformMat4f("u_MVP", mvp);
                shader.SetUniform1i("u_Texture", 0);
                //我们可以在每次画之前从cpu更改uniform变量的值然后传入,这样就可以有变化的效果了
                //shader.SetUniform4f("u_Color", r, 0.3f, 0.8f, 1.0f);

                //当我们使用索引缓冲区之后,我们就不是DrawArrays了,而是DrawElement了
                //GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
                
                renderer.Draw(va, ib, shader);

            }
            {
                glm::mat4 model = glm::translate(glm::mat4(1.0f), translationB);
                glm::mat4 mvp = proj * view * model;
                shader.Bind();
                shader.SetUniformMat4f("u_MVP", mvp);
                shader.SetUniform1i("u_Texture", 0);
                //我们可以在每次画之前从cpu更改uniform变量的值然后传入,这样就可以有变化的效果了
                //shader.SetUniform4f("u_Color", r, 0.3f, 0.8f, 1.0f);

                //当我们使用索引缓冲区之后,我们就不是DrawArrays了,而是DrawElement了
                //GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));
                
                renderer.Draw(va, ib, shader);

            }

            {
                // Edit 1 float using a slider from 0.0f to 1.0f    
                ImGui::SliderFloat3("translationA", &translationA.x , 0.0f, 960.0f);   
                // Edit 1 float using a slider from 0.0f to 1.0f             
                ImGui::SliderFloat3("translationB", &translationB.x, 0.0f, 960.0f);            
                ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / 
                ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
            }
            ImGui::Render();
            ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());

            /* Swap front and back buffers */
            glfwSwapBuffers(window);

            /* Poll for and process events */
            glfwPollEvents();
        }

    ImGui_ImplGlfwGL3_Shutdown();
    ImGui::DestroyContext();
    glfwTerminate();

效果如下:

但是这样如果要画满屏幕呢,每次画一个就要渲染一次,
想象我们现在要画一个2D的游戏地图,都是由一样的方块组成,我们如果按照模型矩阵的方式去画,那就要画一千次,那是相当慢的,
所以策略不止一次,还有种方法就是我拿到2D地图的所有顶点,然后塞到一个顶点缓冲区去,然后用顶点索引缓冲区去找位置,然后再画,这样就会快很多,所以这个例子只是展示可以这样动态改变uniform变量的方法来改变画的位置,需要举一反三,然后深入进去,灵活变通着用。

三、测试框架

活用测试框架,搭建你想搭建的所有测试。

#pragma once

#include <functional>
#include <vector>
#include <string>
#include <iostream>
//仿照着imgui这个命名空间式的方式创建一种插入式的调试类,我们先写调试类的抽象类
//可以根据这个类来做拓展,可以动态的变化出来许多实例类,然后这些类可以动态的在
//我们渲染图像的时候进行调试,比如图形的颜色啊等等,方便我们可视化我们要达到的效果
namespace test {

    class Test {
    public:
        Test(){}
        virtual  ~Test() {}

        //继承的子类都可重写
        //更新虚函数
        virtual void OnUpdate(float deltaTime) {}
        //渲染器虚函数
        virtual void OnRender() {}
        //渲染界面虚函数
        virtual void OnImGuiRender() {}

    };

    //创建一个测试菜单类,帮助我们动态创建和选择测试窗口
    class TestMenu : public Test {
    public:
        TestMenu(Test*& CurrentTestPoniter);

        void OnImGuiRender() override;

        template<typename T>
        void RegisterTest(const std::string& name)
        {
            std::cout << "RegisterTest Test :" << name << std::endl;
            m_Tests.push_back(std::make_pair(name, []() {
                    return new T();
                }));
        }
    private:
        //引用自 Test*& CurrentTestPoniter,就是Test的指针,它是抽象类,所以可以多态成为所有继承它的类
        Test*& m_CurrentTest;
        std::vector<std::pair<std::string, std::function<Test* ()>>> m_Tests;
    };
}

#include "Test.h"
#include "imgui/imgui.h"
namespace test 
{

    TestMenu::TestMenu(Test*& CurrentTestPoniter)
        : m_CurrentTest(CurrentTestPoniter)
    {

    }

    void TestMenu::OnImGuiRender()
    {
        for (auto& test : m_Tests)
        {
            if (ImGui::Button(test.first.c_str()))
                m_CurrentTest = test.second();
        }
    }

}

接下来我们利用调试框架写一个颜色调试和纹理调试类

四、利用测试框架写一个颜色调试界面

类如下:

#include "Test.h"

namespace test {
    class TestClearColor : public Test 
    {
    public:
        TestClearColor() ;
        ~TestClearColor() ;

        void OnUpdate(float deltaTime) override;
        void OnRender()  override;
        void OnImGuiRender() override;
    private:
        float m_ClearColor[4];
    };

#include "TestClearColor.h"

#include "GL/glew.h"
#include "Renderer.h"
#include "imgui/imgui.h"

namespace test {

    TestClearColor::TestClearColor()
        :m_ClearColor{ 0.2f, 0.3f, 0.8f, 1.0f }
    {

    }

    TestClearColor::~TestClearColor()
    {

    }

    void TestClearColor::OnUpdate(float deltaTime)
    {

    }

    void TestClearColor::OnRender()
    {
        GLCall(glClearColor(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]))
        GLCall(glClear(GL_COLOR_BUFFER_BIT));
    }

    void TestClearColor::OnImGuiRender()
    {
        ImGui::ColorEdit4("Clear_Color", m_ClearColor);
    }

}

如何调用:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <sstream>

#include "Renderer.h"
#include "VertexBuffer.h"
#include "VertexBufferLayout.h"
#include "IndexBuffer.h"
#include "VertexArray.h"
#include "Shader.h"
#include "Texture.h"

#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "imgui/imgui.h"
#include "imgui/imgui_impl_glfw_gl3.h"

#include "tests/TestClearColor.h"

int main()
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    //if (glewInit() != GLEW_OK)
    //    std::cout << "GLEWInit ERROR!" << std::endl;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    //设置一些框架因素
    glfwSwapInterval(2);

    if (glewInit() != GLEW_OK)
        std::cout << "GLEWInit ERROR!" << std::endl;
        std::cout << "OpenGL的版本是:" << glGetString(GL_VERSION) << std::endl;
    {

        //启用混合和透明功能
        GLCall(glEnable(GL_BLEND));
        //设置混合和透明功能。。。暂不清楚详细情况
        GLCall(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));

        //创建一个渲染器实例
        Renderer renderer;

        // Setup ImGui binding
        ImGui::CreateContext();
        ImGui_ImplGlfwGL3_Init(window, true);
        ImGui::StyleColorsDark();

        test::TestClearColor testClearColor;

        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */

            GLCall(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
            //glClear(GL_COLOR_BUFFER_BIT);
            renderer.Clear();

            testClearColor.OnUpdate(0.0f);
            testClearColor.OnRender();

            ImGui_ImplGlfwGL3_NewFrame();
            
            testClearColor.OnImGuiRender();

            ImGui::Render();
            ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());

            /* Swap front and back buffers */
            glfwSwapBuffers(window);

            /* Poll for and process events */
            glfwPollEvents();
        }

        delete currenttest;
        if (currenttest != testMenu)
            delete testMenu;
        //glDeleteProgram(shaderID);
    }
    // Cleanup
    ImGui_ImplGlfwGL3_Shutdown();
    ImGui::DestroyContext();
    glfwTerminate();
    return 0;
}

五、利用测试框架写一个纹理调试界面

#pragma once

#include "Test.h"

#include "VertexBuffer.h"
#include "VertexBufferLayout.h"
#include "Texture.h"

#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include <memory>

namespace test {
    class TestTexture2D : public Test
    {
    public:
        TestTexture2D() ;
        ~TestTexture2D() ;

        void OnUpdate(float deltaTime) override;
        void OnRender()  override;
        void OnImGuiRender() override;
    private:
        //这里使用智能指针的原因,就是自动管理生命周期,防止在调用中的内存泄漏问题
        std::unique_ptr<VertexArray> m_VAO;
        std::unique_ptr <IndexBuffer> m_IndexBuffer;
        std::unique_ptr <VertexBuffer> m_VertexBuffer;
        std::unique_ptr <VertexBufferLayout> m_VertexBufferLayout;
        std::unique_ptr <Shader> m_Shader;
        std::unique_ptr <Texture> m_Texture;
        
        glm::mat4 m_proj;
        glm::mat4 m_model;
        glm::mat4 m_view;
        glm::vec3 m_TranslationA;
        glm::vec3 m_TranslationB;
    };
}

#include "TestTexture2D.h"

#include "GL/glew.h"
#include "Renderer.h"
#include "imgui/imgui.h"

namespace test {

    TestTexture2D::TestTexture2D()
        :m_proj(glm::ortho(0.0f, 960.0f, 0.0f, 540.0f, -1.0f, 1.0f)),
        m_view(glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 0))),
        m_TranslationA(200, 200, 0), m_TranslationB(400, 200, 0)
    {
        float positions[] = {
            /*顶点坐标*/-50.0f,  -50.0f,
            /*这个纹理坐标就是告诉着色器,
            我们的图像需要的纹理应该对应关系,
            比如我一个矩形的左下角-0.5f, -0.5f,
            对应纹理的左下角, 0.0f, -0.0f,
            因为纹理是0,0坐标原点*/ 0.0f, -0.0f,//0
             50.0f,  -50.0f, 1.0f, -0.0f,//1
             50.0f,   50.0f, 1.0f,  1.0f,//2
            -50.0f,   50.0f, 0.0f,  1.0f//3
        };
        unsigned int indices[]{
            0,1,2,
            2,3,0
        };

        //启用混合和透明功能
        GLCall(glEnable(GL_BLEND));
        //设置混合和透明功能。。。暂不清楚详细情况
        GLCall(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));

        //通过封装的顶点阵列类来完成绑定缓冲区以及设置顶点布局
        m_VAO = std::make_unique<VertexArray>();

        //通过封装好的VertexBuffer类进行上述操作
        m_VertexBuffer = std::make_unique<VertexBuffer>(positions, 4 * 4 * sizeof(float));

        //声明一个布局对象,然后写入布局的参数,操作顶点阵列类中的AddBuffer,完成自动绑定操作
        m_VertexBufferLayout = std::make_unique<VertexBufferLayout>();
        m_VertexBufferLayout->Push<float>(2);
        //再加入的两组数是用来传纹理坐标的
        m_VertexBufferLayout->Push<float>(2);
        m_VAO->AddBuffer(*m_VertexBuffer, *m_VertexBufferLayout);

        //通过封装好的IndexBuffer类进行上述操作
        m_IndexBuffer = std::make_unique<IndexBuffer>(indices, 6);

        //通过封装好的着色器类来创建着色器
        m_Shader = std::make_unique<Shader>("res/shaders/Basic.shader");

        //通过封装好的纹理类创建纹理对象
        m_Texture = std::make_unique<Texture>("res/textures/OpenGL-removebg-preview.png");

        m_Shader->SetUniform1i("u_Texture", 0);
    }

    TestTexture2D::~TestTexture2D()
    {

    }

    void TestTexture2D::OnUpdate(float deltaTime)
    {

    }

    void TestTexture2D::OnRender()
    {
        GLCall(glClearColor(0.0f, 0.0f, 0.0f, 0.0f))
        GLCall(glClear(GL_COLOR_BUFFER_BIT));

        Renderer renderer;
        //绑定纹理槽(物理意义的槽)
        m_Texture->Bind(0);

        {
            m_model = glm::translate(glm::mat4(1.0f), m_TranslationA);
            glm::mat4 mvp = m_proj * m_view * m_model;
            m_Shader->Bind();
            m_Shader->SetUniformMat4f("u_MVP", mvp);
            //我们可以在每次画之前从cpu更改uniform变量的值然后传入,这样就可以有变化的效果了
            //shader.SetUniform4f("u_Color", r, 0.3f, 0.8f, 1.0f);

            //当我们使用索引缓冲区之后,我们就不是DrawArrays了,而是DrawElement了
            //GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));

            renderer.Draw(*m_VAO, *m_IndexBuffer, *m_Shader);

        }

        {
            m_model = glm::translate(glm::mat4(1.0f), m_TranslationB);
            glm::mat4 mvp = m_proj * m_view * m_model;
            m_Shader->Bind();
            m_Shader->SetUniformMat4f("u_MVP", mvp);
            //我们可以在每次画之前从cpu更改uniform变量的值然后传入,这样就可以有变化的效果了
            //shader.SetUniform4f("u_Color", r, 0.3f, 0.8f, 1.0f);

            //当我们使用索引缓冲区之后,我们就不是DrawArrays了,而是DrawElement了
            //GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr));

            renderer.Draw(*m_VAO, *m_IndexBuffer, *m_Shader);

        }
    }

    void TestTexture2D::OnImGuiRender()
    {
            ImGui::SliderFloat3("translationA", &m_TranslationA.x, 0.0f, 960.0f);            // Edit 1 float using a slider from 0.0f to 1.0f    
            ImGui::SliderFloat3("translationB", &m_TranslationB.x, 0.0f, 960.0f);            // Edit 1 float using a slider from 0.0f to 1.0f    
            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
    }

}

如何调用:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <sstream>

#include "Renderer.h"
#include "VertexBuffer.h"
#include "VertexBufferLayout.h"
#include "IndexBuffer.h"
#include "VertexArray.h"
#include "Shader.h"
#include "Texture.h"

#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "imgui/imgui.h"
#include "imgui/imgui_impl_glfw_gl3.h"

#include "tests/TestClearColor.h"
#include "tests/TestTexture2D.h"

int main()
{
    //std::cout << "Hello OpenGL" << std::endl;
    //std::cin.get();

    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    //if (glewInit() != GLEW_OK)
    //    std::cout << "GLEWInit ERROR!" << std::endl;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    //设置一些框架因素
    glfwSwapInterval(2);

    if (glewInit() != GLEW_OK)
        std::cout << "GLEWInit ERROR!" << std::endl;
        std::cout << "OpenGL的版本是:" << glGetString(GL_VERSION) << std::endl;
    {

        //启用混合和透明功能
        GLCall(glEnable(GL_BLEND));
        //设置混合和透明功能。。。暂不清楚详细情况
        GLCall(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));

        //创建一个渲染器实例
        Renderer renderer;

        // Setup ImGui binding
        ImGui::CreateContext();
        ImGui_ImplGlfwGL3_Init(window, true);
        ImGui::StyleColorsDark();

        //作为抽象类的指针,可以接收所有的子类的对象指针
        test::Test* currenttest = nullptr;
        test::TestMenu* testMenu = new test::TestMenu(currenttest);
        currenttest = testMenu;

        testMenu->RegisterTest<test::TestClearColor>("Clear Color");
        testMenu->RegisterTest<test::TestTexture2D>("TestTexture2D");

        生成一个testClearColor类
        //test::TestClearColor testClearColor;

        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            /* Render here */

            GLCall(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
            //glClear(GL_COLOR_BUFFER_BIT);
            renderer.Clear();

            //testClearColor.OnUpdate(0.0f);
            //testClearColor.OnRender();

            ImGui_ImplGlfwGL3_NewFrame();
            if (currenttest)
            {
                currenttest->OnUpdate(0.0f);
                currenttest->OnRender();
                ImGui::Begin("Test");
                //因为一直循环,所以当执行下面if的时候,如果currenttest != testMenu
                //则会继续执行ImGui::Button("<-"),就相当于把按钮变为返回按键了。
                //这个时候如果你在按下Button("<-"),那么这个if才是成立的,才会把菜单testMenu赋值回来
                if (currenttest != testMenu && ImGui::Button("<-"))
                {
                    delete currenttest;
                    currenttest = testMenu;
                }
                //当这里渲染测试界面的时候,作为菜单类先进入TestMenu::OnImGuiRender()
                //找到对应的注册好的按钮对应的类,然后把类赋值给m_CurrentTest
                //这个时候currenttest就是指向m_CurrentTest实例类的指针了。
                currenttest->OnImGuiRender();
                ImGui::End();
            }
            //testClearColor.OnImGuiRender();

            ImGui::Render();
            ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());

            /* Swap front and back buffers */
            glfwSwapBuffers(window);

            /* Poll for and process events */
            glfwPollEvents();
        }

        delete currenttest;
        if (currenttest != testMenu)
            delete testMenu;
        //glDeleteProgram(shaderID);
    }
    // Cleanup
    ImGui_ImplGlfwGL3_Shutdown();
    ImGui::DestroyContext();
    glfwTerminate();
    return 0;
}

之后我们就要接触批量渲染,材质,3D等等由浅入深的内容了

标签: 开源 c++ 图形渲染

本文转载自: https://blog.csdn.net/CodeWorld1999/article/details/135278215
版权归原作者 $老无所依¥ 所有, 如有侵权,请联系我们删除。

“一篇搞定利用开源库写一个OpenGL测试窗口小工具”的评论:

还没有评论