在 Arch Linux 上使用 OpenGL 4.6 和 OpenGL ES 3.2(根据 glxinfo -B)。
在使用 official wiki snippet code 在 imgui 中将图像渲染为纹理时,我遇到了图像被渲染为全黑纹理的问题。这是我从 wiki 中(稍微)修改的辅助函数,它使用 STB 加载图像并将其放入纹理中。
// Simple helper function to load an image into a OpenGL texture with common settings
bool load_texture_from_file(const char* filename, GLuint* out_texture, unsigned char **out_raw_image,
int* out_width, int* out_height, int* out_channels) {
unsigned char* image_data = stbi_load(filename, out_width, out_height, out_channels, 4);
if (image_data == NULL) {
printf("Failed to load image: %s\n", stbi_failure_reason());
return false;
}
// Create a OpenGL texture identifier
GLuint image_texture;
glGenTextures(1, &image_texture);
glBindTexture(GL_TEXTURE_2D, image_texture);
// Setup filtering parameters for display
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // This is required on WebGL for non power-of-two textures
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Same
GLenum format;
if (*out_channels == 3)
format = GL_RGB;
else if (*out_channels == 4)
format = GL_RGBA;
else {
// Handle unsupported channel count
printf("Unsupported number of channels: %d\n", *out_channels);
stbi_image_free(image_data);
return false;
}
// Upload pixels into texture
#if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, format, *out_width, *out_height, 0, format, GL_UNSIGNED_BYTE, image_data);
GLenum error = glGetError();
if (error != GL_NO_ERROR)
{
printf("OpenGL error after glTexImage2D: %x\n", error);
stbi_image_free(image_data);
return false;
}
*out_raw_image = image_data;
*out_texture = image_texture;
assert(image_texture != 0 && *out_texture != 0);
return true;
}
我有点确信我的问题在于我如何处理将图像转换为纹理以便 imgui 可以渲染它,因为我没有收到任何使用 stb_image 加载图像的错误。令人惊讶的是,我的
load_texture_from_file
函数也没有收到任何 OpenGL 错误。在我的代码中,在 load_texture_from_file
中调用 display_ui
,它执行以下操作:
void display_ui(const GLFWvidmode *mode) {
static int width, height, channels;
static char input[256] = "";
static bool show_original = false;
static bool show_preview = false;
static unsigned char *image_data = NULL;
static GLuint texture = 0;
ImGui::Begin("Workshop", nullptr, ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
ImVec2 main_panel_size = ImVec2(2 * ImGui::GetContentRegionAvail().x / 3,
ImGui::GetContentRegionAvail().y - 75);
ImVec2 side_panel_size = ImVec2(ImGui::GetContentRegionAvail().x / 3,
(ImGui::GetContentRegionAvail().y - 80) / 2);
ImGui::SetWindowSize(main_panel_size);
ImVec2 parent_cursor_start = ImGui::GetCursorPos();
ImGui::BeginChild("Main panel", main_panel_size, true);
ImGui::SetNextItemWidth(200.0f);
if (ImGui::BeginTabBar("tab_bar", ImGuiTabBarFlags_none))
{
if (ImGui::BeginTabItem("Original image"))
{
if(show_original) {
ImGui::Text("pointer = %p", texture);
ImGui::Text("size = %d x %d", width, height);
ImGui::Image((void*)(intptr_t)&texture, ImVec2(width, height));
}
ImGui::EndTabItem();
}
}
// ... irrelevant code is omitted for brevity
// mostly just unrelated gui stuff
if (ImGuiFileDialog::Instance()->Display("ChooseFileDlgKey")) {
if (ImGuiFileDialog::Instance()->IsOk()) {
std::string file_path_name = ImGuiFileDialog::Instance()->GetFilePathName();
std::string file_path = ImGuiFileDialog::Instance()->GetCurrentPath();
sprintf(input, "%s", file_path_name.c_str());
}
ImGuiFileDialog::Instance()->Close();
}
// process file path image if user clicks button
if(ImGui::Button("Open input file")) {
if(!load_texture_from_file(input, &texture, &image_data, &width, &height, &channels)) {
ImGui::OpenPopup("Error loading image");
show_original = false;
} else {
show_original = true;
}
}
if(ImGui::BeginPopup("Error loading image")) {
ImGui::Text("Error loading image, select a valid path");
if(ImGui::Button("OK")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::End();
}
如果这可能与 OpenGL 的某些不正确设置或类似的情况有关,请注意,我在主 imgui 渲染 while 循环中调用
display_ui()
,如下所示:
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void render_gui() {
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
return;
// Decide GL+GLSL versions
#if defined(IMGUI_IMPL_OPENGL_ES2)
// GL ES 2.0 + GLSL 100
const char* glsl_version = "#version 100";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(__APPLE__)
// GL 3.2 + GLSL 150
const char* glsl_version = "#version 150";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
#else
// GL 3.0 + GLSL 130
const char* glsl_version = "#version 130";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
#endif
// Create window with graphics context
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
GLFWwindow* window = glfwCreateWindow(mode->width, mode->height, "Pixelify", nullptr, nullptr);
if (window == nullptr)
return;
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSwapInterval(1); // Enable vsync
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init(glsl_version);
// Main loop
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(mode->width, mode->height));
display_ui(mode);
// Rendering
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context);
}
glfwSwapBuffers(window);
}
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
return;
}
对于上下文,这是我使用此示例图像作为将其渲染为纹理的测试用例时得到的结果:
您不应该将
&texture
传递给 ImGui::Image
但 texture
:
ImGui::Image((void*)(intptr_t)texture, ImVec2(width, height));
后端代码撤消此转换,而不尝试将其作为指针取消引用:
GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));