LoginSignup
6
6

More than 3 years have passed since last update.

imguiのwindowの中で3d cubeの描画をしてやった

Last updated at Posted at 2020-01-12

はじめに

久しぶりの投稿になります。pythonでは速度が足りなくなったのでc++に移植作業をしていたのですが、描画をどうしようかということになりまして、imguiなるものをいじっています。公式にはopenglのオブジェクトをimguiのwindowの中で描画をするようなチュートリアルが見当たらなかったのでかなり色々と遠回りしましたが、複数個のcubeをimguiのウィンドウの中に描画することができるようになったので投稿します。下にプログラムを起動したイメージを示します
Screenshot from 2020-01-12 18-52-09.png

検証した環境・必要なライブラリ

  • ubuntu18.04
  • glfw3
  • glew
  • glm
  • imgui

code

main.cpp
// dear imgui: standalone example application for GLFW + OpenGL 3, using programmable pipeline
// If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp.
// (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)

#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#include <iostream> //cerr
#include <fstream>
#include <vector>
#include <array>
#include <GL/glew.h>    // Initialize with glewInit()

// Include glfw3.h after our OpenGL definitions
#include <GLFW/glfw3.h>

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;

#include <shader.hpp>

class texture_maker{
public:
    // width,height
    GLint width,height;

    // vao/vbo
    std::vector<GLuint> vvao;
    std::vector<std::array<GLuint, 2>> vvbo;

    // shader
    GLuint program;
    GLuint mvp;

    // texture
    GLuint framebuffer;
    GLuint depthbuffer;
    GLuint texture;
    GLenum drawbuffer;

    texture_maker() {};
    void config(GLint width, GLint height, std::vector<float> box);
    void render();
private:
};
void texture_maker::config(GLint width, GLint height, std::vector<float> box){
    // set width, height
    this->width = width;
    this->height = height;
    GLfloat triangleColor[] = {
        0.583f,  0.771f,  0.014f,
        0.609f,  0.115f,  0.436f,
        0.327f,  0.483f,  0.844f,
        0.822f,  0.569f,  0.201f,
        0.435f,  0.602f,  0.223f,
        0.310f,  0.747f,  0.185f,
        0.597f,  0.770f,  0.761f,
        0.559f,  0.436f,  0.730f,
        0.359f,  0.583f,  0.152f,
        0.483f,  0.596f,  0.789f,
        0.559f,  0.861f,  0.639f,
        0.195f,  0.548f,  0.859f,
        0.014f,  0.184f,  0.576f,
        0.771f,  0.328f,  0.970f,
        0.406f,  0.615f,  0.116f,
        0.676f,  0.977f,  0.133f,
        0.971f,  0.572f,  0.833f,
        0.140f,  0.616f,  0.489f,
        0.997f,  0.513f,  0.064f,
        0.945f,  0.719f,  0.592f,
        0.543f,  0.021f,  0.978f,
        0.279f,  0.317f,  0.505f,
        0.167f,  0.620f,  0.077f,
        0.347f,  0.857f,  0.137f,
        0.055f,  0.953f,  0.042f,
        0.714f,  0.505f,  0.345f,
        0.783f,  0.290f,  0.734f,
        0.722f,  0.645f,  0.174f,
        0.302f,  0.455f,  0.848f,
        0.225f,  0.587f,  0.040f,
        0.517f,  0.713f,  0.338f,
        0.053f,  0.959f,  0.120f,
        0.393f,  0.621f,  0.362f,
        0.673f,  0.211f,  0.457f,
        0.820f,  0.883f,  0.371f,
        0.982f,  0.099f,  0.879f
    };

    // デプステストを有効にする
    glEnable(GL_DEPTH_TEST);
    // 前のものよりもカメラに近ければ、フラグメントを受け入れる
    glDepthFunc(GL_LESS);

    // vao/vbo
    int size = box.size();
    for(int i=0,j=0;i<size;i+=6,j++){
        GLfloat Vertex[] = {
            box[i]         ,box[i+1]         ,box[i+2]+box[i+5],//1
            box[i]         ,box[i+1]+box[i+4],box[i+2]+box[i+5],
            box[i]+box[i+3],box[i+1]         ,box[i+2]+box[i+5],

            box[i]         ,box[i+1]+box[i+4],box[i+2]+box[i+5],//2
            box[i]+box[i+3],box[i+1]+box[i+4],box[i+2]+box[i+5],
            box[i]+box[i+3],box[i+1]         ,box[i+2]+box[i+5],

            box[i]         ,box[i+1]         ,box[i+2]         ,//3
            box[i]         ,box[i+1]+box[i+4],box[i+2]         ,
            box[i]+box[i+3],box[i+1]         ,box[i+2]         ,

            box[i]         ,box[i+1]+box[i+4],box[i+2]         ,//4
            box[i]+box[i+3],box[i+1]+box[i+4],box[i+2]         ,
            box[i]+box[i+3],box[i+1]         ,box[i+2]         ,

            box[i]         ,box[i+1]+box[i+4],box[i+2]+box[i+5],//5
            box[i]         ,box[i+1]+box[i+4],box[i+2]         ,
            box[i]+box[i+3],box[i+1]+box[i+4],box[i+2]+box[i+5],

            box[i]+box[i+3],box[i+1]+box[i+4],box[i+2]+box[i+5],//6
            box[i]+box[i+3],box[i+1]+box[i+4],box[i+2]         ,
            box[i]         ,box[i+1]+box[i+4],box[i+2]         ,

            box[i]         ,box[i+1]         ,box[i+2]         ,//7
            box[i]+box[i+3],box[i+1]         ,box[i+2]+box[i+5],
            box[i]         ,box[i+1]         ,box[i+2]+box[i+5],

            box[i]         ,box[i+1]         ,box[i+2]         ,//8
            box[i]+box[i+3],box[i+1]         ,box[i+2]         ,
            box[i]+box[i+3],box[i+1]         ,box[i+2]+box[i+5],

            box[i]         ,box[i+1]         ,box[i+2]+box[i+5],//9
            box[i]         ,box[i+1]+box[i+4],box[i+2]+box[i+5],
            box[i]         ,box[i+1]         ,box[i+2]         ,

            box[i]         ,box[i+1]+box[i+4],box[i+2]+box[i+5],//10
            box[i]         ,box[i+1]+box[i+4],box[i+2]         ,
            box[i]         ,box[i+1]         ,box[i+2]         ,

            box[i]+box[i+3],box[i+1]         ,box[i+2]+box[i+5],//11
            box[i]+box[i+3],box[i+1]+box[i+4],box[i+2]+box[i+5],
            box[i]+box[i+3],box[i+1]         ,box[i+2]         ,

            box[i]+box[i+3],box[i+1]         ,box[i+2]         ,//12
            box[i]+box[i+3],box[i+1]+box[i+4],box[i+2]         ,
            box[i]+box[i+3],box[i+1]+box[i+4],box[i+2]+box[i+5],
        };

        this->vvao.push_back((GLuint)0);

        std::array<GLuint,2> vbo ={(GLuint)0,(GLuint)0};
        this->vvbo.push_back(vbo);

        GLuint a = this->vvao[j];

        std::array<GLuint,2> t_b = this->vvbo[j];
        GLuint b[] = {t_b[0],t_b[1]};

        glGenVertexArrays(1, &a);
        glBindVertexArray(a);

        glGenBuffers(2, b);
        glBindBuffer(GL_ARRAY_BUFFER, b[0]);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex), Vertex, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glBindBuffer(GL_ARRAY_BUFFER, b[1]);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glBufferData(GL_ARRAY_BUFFER, sizeof(triangleColor), triangleColor, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glBindVertexArray(0);
        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);

        this->vvao[j] = a;

        t_b[0] = b[0];
        t_b[1] = b[1];
        this->vvbo[j] = t_b;
    }

    // shader
    this->program = LoadShaders( "point.vert", "point.frag" );
    this->mvp = glGetUniformLocation(this->program, "MVP");

    // texture 
    glGenFramebuffers(1, &this->framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, this->framebuffer);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glGenTextures(1, &this->texture);
    glBindTexture(GL_TEXTURE_2D, this->texture);

    glTexImage2D(GL_TEXTURE_2D,    // target
                 0,                // mipmap level 
                 GL_RGB,           // internal format
                 width,            // scene width
                 height,           // scene height
                 0,                // border
                 GL_RGB,           // format
                 GL_UNSIGNED_BYTE, // type 
                 (void*)0);        // image buffer

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    // depthbuffer
    glGenRenderbuffers(1, &this->depthbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, this->depthbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->depthbuffer);

    // 出力先のバッファを GL_COLOR_ATTACHMENT0 にする
    this->drawbuffer = GL_COLOR_ATTACHMENT0;

    // 初期化終わり
    glFramebufferTexture(GL_FRAMEBUFFER, this->drawbuffer, this->texture, 0);
    glBindFramebuffer(GL_FRAMEBUFFER,0);
}

void texture_maker::render(){
    glBindFramebuffer(GL_FRAMEBUFFER, this->framebuffer);
    glDrawBuffers(1, &this->drawbuffer);

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glViewport(0,0, this->width, this->height);

    // Projection matrix : 45� Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
    glm::mat4 Projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.0f);
    // Or, for an ortho camera :
    //glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); // In world coordinates

    // Camera matrix
    glm::mat4 View       = glm::lookAt(
                                glm::vec3(4,3,3), // Camera is at (4,3,3), in World Space
                                glm::vec3(0,0,0), // and looks at the origin
                                glm::vec3(0,1,0)  // Head is up (set to 0,-1,0 to look upside-down)
                           );
    // Model matrix : an identity matrix (model will be at the origin)
    glm::mat4 Model      = glm::mat4(1.0f);
    // Our ModelViewProjection : multiplication of our 3 matrices
    glm::mat4 MVP        = Projection * View * Model; // Remember, matrix multiplication is the other way around

    glUseProgram(this->program);
    glUniformMatrix4fv(this->mvp, 1, GL_FALSE, &MVP[0][0]);

    for(int i=0;i < this->vvao.size();i++){
        GLuint a = this->vvao[i];

        std::array<GLuint,2> t_b = this->vvbo[i];
        GLuint b[] = {t_b[0],t_b[1]};

        glBindVertexArray(a);

        glBindBuffer(GL_ARRAY_BUFFER, b[0]);
        glBindBuffer(GL_ARRAY_BUFFER, b[1]);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glDrawArrays(GL_TRIANGLES, 0, 3*12);

        glBindVertexArray(0);
    }

    glUseProgram(0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

static void glfw_error_callback(int error, const char* description)
{
    fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}

int main(int, char**)
{
    // Setup window
    glfwSetErrorCallback(glfw_error_callback);
    if (!glfwInit())
        return 1;//glfwの初期化に失敗

    // GL 3.0 + GLSL 130
    const char* glsl_version = "#version 330 core";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//opengl3.#を使用する
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);//opengl #.0
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 3.0+ only


    // Create window with graphics context
    GLFWwindow* window = glfwCreateWindow(1280, 720, "hello", NULL, NULL);
    if (window == NULL)
        return 1;
    glfwMakeContextCurrent(window);//作成したウィンドウをopenglの処理対象にする
    glfwSwapInterval(1); // Enable vsync 垂直同期のタイミングを待つ

    // Initialize OpenGL loader glewの初期化
    bool err = glewInit() != GLEW_OK;
    if (err)
    {
        fprintf(stderr, "Failed to initialize OpenGL loader!\n");
        return 1;
    }

    // Enable depth test
    glEnable(GL_DEPTH_TEST);
    // Accept fragment if it closer to the camera than the former one
    glDepthFunc(GL_LESS); 

    // Cull triangles which normal is not towards the camera
    //glEnable(GL_CULL_FACE);

    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;

    // Setup Dear ImGui style
    ImGui::StyleColorsDark();
    //ImGui::StyleColorsClassic();

    // Setup Platform/Renderer bindings
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init(glsl_version);

    // Our state
    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

    // Dark blue background
    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

    std::vector<float> _box1 = {
        -1.0,-1.0,-1.0 ,1.0,1.0,1.0,
        -2.0,-2.0,-1.0 ,1.0,1.0,1.0,
         1.0,-1.0,-1.0 ,1.0,1.0,1.0
    };//最小の座標 xyzの幅
    texture_maker tex;
    tex.config((GLint)300,(GLint)300,_box1);

    // Main loop
    while (!glfwWindowShouldClose(window))//windowが閉じられるまで繰り返す
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        //glewWaitEvents();//イベントが発生するまで待つ
        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();

        //create the imgui window
        ImGui::Begin("FBO");
        {
            //the position of the window when it gets created is going to be the mouse position
            ImVec2 pos = ImGui::GetCursorScreenPos();
            tex.render();
            ImGui::Image((void *)tex.framebuffer, ImVec2(tex.width,tex.height));
        }
        //end the imgui window
        ImGui::End();

        // Rendering
        ImGui::Render();
        int display_w, display_h;
        glfwGetFramebufferSize(window, &display_w, &display_h);
        glViewport(0, 0, display_w, display_h);
        glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
        glfwPollEvents();//イベントが発生していれば取り出す。イベントの有無にかかわらず次に進む
        glfwSwapBuffers(window);//カラーバッファーを入れ替える
    }

    // Cleanup
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();

    glfwDestroyWindow(window);
    glfwTerminate();//終了前に必ず呼ぶ必要のある関数

    return 0;
}

注意事項

shedarのプログラムはopengl tutorialさんのコードを拝借しました。

参考にしたサイト

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6