#はじめに
久しぶりの投稿になります。pythonでは速度が足りなくなったのでc++に移植作業をしていたのですが、描画をどうしようかということになりまして、imguiなるものをいじっています。公式にはopenglのオブジェクトをimguiのwindowの中で描画をするようなチュートリアルが見当たらなかったのでかなり色々と遠回りしましたが、複数個のcubeをimguiのウィンドウの中に描画することができるようになったので投稿します。下にプログラムを起動したイメージを示します
#検証した環境・必要なライブラリ
- 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さんのコードを拝借しました。
#参考にしたサイト