計算機圖形學作業(一):利用OpenGL繪製三角形,並利用ImGUI增加顏色編輯窗口
前言
OpenGL一般被認爲是一個API(Application Programming Interface, 應用程序編程接口),包含了一系列可以操作圖形、圖像的函數。由於OpenGL是一個圖形API,並不是一個獨立的平臺,它需要一個編程語言來工作,在這裏我們使用的是C++,而編輯器使用VS2017。關於OpenGL有個非常詳細的官方教程:https://learnopengl-cn.github.io/intro/,這裏僅僅對OpenGL的學習作總結。
繪製三角形
只要按照教程的步驟一步步進行,繪製三角形的過程並不難,代碼在下面會給出。效果圖如下所示:
顏色編輯窗口
ImGUI的配置
前往ImGUI的github倉庫https://github.com/ocornut/imgui,然後將庫文件壓縮包下載到本地,然後解壓。把下圖這些文件添加到剛纔畫三角形的VS2017的項目中。
然後進入ImGUI庫的example文件夾,因爲此次我們的項目是利用ImGUI給OpenGL所畫的圖形增加顏色編輯窗口,所以我們選擇下圖的文件,添加到項目中。
還有以下兩個文件:
最終,原來的利用OpenGL畫三角形的項目中,多個ImGUI的庫文件,文件結構如下:
修改imgui_impl_opengl3.h文件
按照前面OpenGL的官方教程,配置環境時,我們使用到了一個glad的庫,而不是gl3w的庫,所以在imgui_impl_opengl3.h文件中,把IMGUI_IMPL_OPENGL_LOADER_GL3W
替換爲IMGUI_IMPL_OPENGL_LOADER_GLAD
#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \
&& !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
#define IMGUI_IMPL_OPENGL_LOADER_GLAD //IMGUI_IMPL_OPENGL_LOADER_GL3W
#endif
編寫顏色編輯器代碼
這部分主要代碼如下:
//創建並綁定ImGui
const char* glsl_version = "#version 130";
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glsl_version);
//創建imgui
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Edit color", &show_window, ImGuiWindowFlags_MenuBar);
ImGui::ColorEdit3("top color", (float*)&topColor);
ImGui::ColorEdit3("left color", (float*)&leftColor);
ImGui::ColorEdit3("right color", (float*)&rightColor);
ImGui::End();
ImGui::Render();
int display_w, display_h;
glfwMakeContextCurrent(window);
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
效果
如下圖:
項目源代碼
main.cpp的代碼如下:
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
//頂點着色器可以向片段着色器傳數據
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.x, aPos.y, aPos.z, 1.0);\n"
"ourColor = aColor;\n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"void main()\n"
"{\n"
"FragColor = vec4(ourColor, 1.0);\n"
"}\0";
int main() {
//初始化opengl窗口和配置
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(1000, 800, "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);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
//創建並綁定ImGui
const char* glsl_version = "#version 130";
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glsl_version);
//頂點着色器
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
//片段着色器
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
//着色器程序
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
/*
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
*/
//顏色數據
ImVec4 topColor = ImVec4(0.0f, 0.0f, 1.0f, 1.0f);
ImVec4 leftColor = ImVec4(0.0f, 1.0f, 0.0f, 1.0f);
ImVec4 rightColor = ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
bool show_window = true;
unsigned int VAO;
unsigned int VBO;
unsigned int EBO;
while (!glfwWindowShouldClose(window)) {
float vertices[] = { // 注意索引從0開始!
//位置 顏色
0.5f, -0.5f, 0.0f, rightColor.x, rightColor.y, rightColor.z,
-0.5f, -0.5f, 0.0f, leftColor.x, leftColor.y, leftColor.z,
0.0f, 0.5f, 0.0f, topColor.x, topColor.y, topColor.z,
1.0f, -0.5f, 0.0f, rightColor.x, rightColor.y, rightColor.z,
0.5f, -0.5f, 0.0f, leftColor.x, leftColor.y, leftColor.z,
0.75f, 0.25f, 0.0f, topColor.x, topColor.y, topColor.z,
-0.75f, 0.5f, 0.0f, rightColor.x, rightColor.y, rightColor.z,
-0.75f, -0.5f, 0.0f, leftColor.x, leftColor.y, leftColor.z,
};
unsigned int indices[] = { // 注意索引從0開始!
0, 1, 2, // 第一個三角形
3, 4, 5,
6, 7, 8
};
//必須先綁定VA0
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
//再綁定VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//使用EBO畫多個三角形,組合成其它圖形
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//再設置屬性
//位置屬性
//屬性位置值爲0的頂點屬性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//顏色屬性
//屬性位置值爲1的頂點屬性。顏色值有3個float那麼大
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
processInput(window);
//使用着色器程序
glUseProgram(shaderProgram);
glfwPollEvents();
//清除屏幕
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//創建imgui
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Edit color", &show_window, ImGuiWindowFlags_MenuBar);
ImGui::ColorEdit3("top color", (float*)&topColor);
ImGui::ColorEdit3("left color", (float*)&leftColor);
ImGui::ColorEdit3("right color", (float*)&rightColor);
ImGui::End();
ImGui::Render();
int display_w, display_h;
glfwMakeContextCurrent(window);
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
//畫三角形
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//畫線段,偏移6個點,畫2點之間的線段
glDrawArrays(GL_LINES, 6, 2);
glfwSwapBuffers(window);
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwTerminate();
return 0;
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
}