OpenGL–使用ImGui渲染三角形
首先看一下作业要求:
下面是我实现的代码:
#include "imgui/imgui.h"
#include "imgui_impl_glfw_gl3.h"
#include <stdio.h>
#include <GL/gl3w.h> // 使用gl3w,glad也行,注意要在项目工程中添加gl3w.c(或者glad.c/使用glad)
#include <GLFW/glfw3.h>
#include <iostream>
//当用户改变窗口的大小的时候,视口也应该被调整。我们可以对窗口注册一个回调函数,它会在每次窗口大小被调整的时候被调用。
//其实我把教程的这个函数删掉对结果也没有影响,不过教程说对于Retina屏幕输入的width和height都会比原值大,所以保留这个函数
void window_size_callback(GLFWwindow* window, int width, int height);
// 设置窗口大小
const unsigned int Window_width = 1600;
const unsigned int Window_height = 1200;
//使用GLSL编写出来的顶点着色器和片段着色器的代码
//顶点着色器主要是把输入的数据转化为标准化设备坐标,把它们转换至OpenGL的可视区域内
//片段着色器所做的是计算像素最后的颜色输出,可以理解为我们所画的图元“上色”
//这两个着色器程序都是最简单的程序,没有对输入的数据做任何处理就输出了
const char *VertexShaderCode = "#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, 1.0);\n"
" ourColor = aColor;\n"
"}\0";
const char *FragmentShaderCode = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(ourColor, 1.0f);\n"
"}\n\0";
int main()
{
// 实例化GLFW窗口
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//下面这条语句是为了适应苹果系统
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// 创建一个窗口对象,这个窗口对象存放了所有和窗口相关的数据,而且会被GLFW的其他函数频繁地用到。
// 此外增加 if (window == NULL) 判断窗口是否创建成功
GLFWwindow* window = glfwCreateWindow(Window_width, Window_height, "ImGui Triangle", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, window_size_callback);
glfwSwapInterval(1);
//初始化gl3w
gl3wInit();
//创建并绑定ImGui
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui_ImplGlfwGL3_Init(window, true);
ImGui::StyleColorsClassic();
// 建立 shader program
// 顶点着色器
int VShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(VShader, 1, &VertexShaderCode, NULL);
glCompileShader(VShader);
// 检查顶点着色器是否编译成功
int success_compiler;
char wrong_information[512];
glGetShaderiv(VShader, GL_COMPILE_STATUS, &success_compiler);
if (!success_compiler)
{
glGetShaderInfoLog(VShader, 512, NULL, wrong_information);
std::cout << "顶点着色器编译失败:\n" << wrong_information << std::endl;
}
// 片段着色器
int FShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(FShader, 1, &FragmentShaderCode, NULL);
glCompileShader(FShader);
// 检查片段着色器是否编译成功
glGetShaderiv(FShader, GL_COMPILE_STATUS, &success_compiler);
if (!success_compiler)
{
glGetShaderInfoLog(FShader, 512, NULL, wrong_information);
std::cout << "片段着色器编译失败:\n" << wrong_information << std::endl;
}
// 链接着色器
int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, VShader);
glAttachShader(shaderProgram, FShader);
glLinkProgram(shaderProgram);
// 检查链接着色器是否成功
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success_compiler);
if (!success_compiler) {
glGetProgramInfoLog(shaderProgram, 512, NULL, wrong_information);
std::cout << "着色器程序链接失败:\n" << wrong_information << std::endl;
}
//在把着色器对象链接到程序对象以后,删除不再需要的着色器对象
glDeleteShader(VShader);
glDeleteShader(FShader);
//初始化各种数据
ImVec4 top_color = ImVec4(0.0f, 1.0f, 0.0f, 1.00f);
ImVec4 left_color = ImVec4(1.0f, 0.0f, 0.0f, 1.00f);
ImVec4 right_color = ImVec4(0.0f, 0.0f, 1.0f, 1.00f);
ImVec4 bottom_color = ImVec4(0.0f, 1.0f, 1.0f, 1.00f);
ImVec4 same_color = ImVec4(0.0f, 1.0f, 0.0f, 1.00f);
bool ImGui = true;
bool the_same_color = false;
bool draw_trangle_without_render = false;
bool draw_trangle = false;
bool bonus_draw_line = false;
bool bonus_draw_another_trangle = false;
unsigned int VBO, VAO, EBO;
// 渲染循环
while (!glfwWindowShouldClose(window))
{
if (the_same_color) {
top_color = same_color;
left_color = same_color;
right_color = same_color;
bottom_color = same_color;
}
float vertices[] = {
// 坐标 // 颜色
0.2f, -0.2f, 0.0f, right_color.x, right_color.y, right_color.z, // bottom right
-0.2f, -0.2f, 0.0f, left_color.x, left_color.y, left_color.z, // bottom left
0.0f, 0.2f, 0.0f, top_color.x, top_color.y, top_color.z, // top
0.0f, -0.8f, 0.0f, bottom_color.x, bottom_color.y, bottom_color.z // bottom
};
unsigned int indices[] = { // 注意索引从0开始
0, 1, 2, // 第一个三角形
0, 1, 3 // 第二个三角形
};
//生成VAO、VBO、EBO对象
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// 1. 绑定顶点数组对象
glBindVertexArray(VAO);
// 2. 把我们的顶点数组复制到一个顶点缓冲中,供OpenGL使用
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. 复制我们的索引数组到一个索引缓冲中,供OpenGL使用
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 4. 设定顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 5. 设定顶点颜色属性指针
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
//glEnableVertexAttribArray(1);
// 6.创建一个程序对象
glUseProgram(shaderProgram);
// 创建ImGui
glfwPollEvents();
ImGui_ImplGlfwGL3_NewFrame();
ImGui::Begin("Edit color", &ImGui, ImGuiWindowFlags_MenuBar);
ImGui::ColorEdit3("Basic triangle -- top color", (float*)&top_color);
ImGui::ColorEdit3("Basic triangle -- left color", (float*)&left_color);
ImGui::ColorEdit3("Basic triangle -- right color", (float*)&right_color);
ImGui::ColorEdit3("Bonus triangle -- bottom color", (float*)&bottom_color);
ImGui::ColorEdit3("Optional -- the same color", (float*)&same_color);
ImGui::Checkbox("the same color", &the_same_color);
ImGui::Checkbox("Draw triangle without rendering", &draw_trangle_without_render);
ImGui::Checkbox("Basic draw triangle", &draw_trangle);
ImGui::Checkbox("Bonus draw line", &bonus_draw_line);
ImGui::Checkbox("Bonus draw another triangle", &bonus_draw_another_trangle);
ImGui::End();
// 渲染窗口颜色
int view_width, view_height;
glfwGetFramebufferSize(window, &view_width, &view_height);
glViewport(0, 0, view_width, view_height);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui::Render();
ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
//画Basic 三角形,没有加入渲染
if (draw_trangle_without_render) {
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
// 渲染Basic 三角形
if (draw_trangle) {
glEnableVertexAttribArray(1);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
// 渲染Bonus 线段
if (bonus_draw_line) {
glEnableVertexAttribArray(1);
glBindVertexArray(VAO);
glDrawArrays(GL_LINE_STRIP, 0, 2);
}
// 渲染Bonus 三角形
if (bonus_draw_another_trangle) {
glEnableVertexAttribArray(1);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
// 双缓冲。前缓冲保存着最终输出的图像,它会在屏幕上显示;而所有的的渲染指令都会在后缓冲上绘制。
glfwSwapBuffers(window);
}
// 释放VAO、VBO、EBO资源
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
// 释放ImGui资源
ImGui_ImplGlfwGL3_Shutdown();
ImGui::DestroyContext();
// 清除所有申请的glfw资源
glfwTerminate();
return 0;
}
void window_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}