How to Display Custom Images Using ImTextureID in ImGui
ImTextureID is an opaque, backend-specific handle (such as an OpenGL GLuint, DirectX ID3D11ShaderResourceView*, or Vulkan VkDescriptorSet) that you cast from your native GPU texture and pass to ImGui::Image() to render custom images uploaded with your own graphics code.
In the ocornut/imgui immediate-mode GUI library, displaying custom images requires bridging your renderer's native texture objects with ImGui's drawing API. Since ImGui is graphics-API agnostic, it relies on ImTextureID to store references to GPU textures without knowing the underlying implementation details. This article explains how to obtain, cast, and use these identifiers across major rendering backends.
What is ImTextureID?
In imgui.h, the default type definition is typedef ImU64 ImTextureID;, creating a 64-bit value capable of storing either an integer or a pointer depending on the backend's requirements. Each official backend in the backends/ directory reinterprets this value according to its native resource type:
- OpenGL 3: Uses a
GLuinttexture name - DirectX 11: Expects an
ID3D11ShaderResourceView*pointer - Vulkan: Stores a
VkDescriptorSethandle - SDL Renderer: Uses
SDL_Texture*
The newer ImTextureRef type provides additional safety wrappers, but the underlying principle remains identical: ImGui treats the value as an opaque token and passes it directly to the backend's rendering implementation.
The Three-Step Workflow
To display a custom image, you must handle GPU resource management yourself before involving ImGui:
- Upload: Load your image data and create a GPU texture using your renderer's API (OpenGL, DirectX, Vulkan, etc.)
- Cast: Convert the native texture handle to
ImTextureIDusing a simple cast - Draw: Pass the ID to
ImGui::Image()orImGui::ImageButton()
During the render loop, ImGui stores this ID in an ImDrawCmd structure. The backend's RenderDrawData() function retrieves it via ImDrawCmd::GetTexID() and binds the corresponding GPU resource before issuing the draw call.
Backend-Specific Implementation Examples
The exact casting depends on your graphics API. Here are minimal implementations for three major backends.
OpenGL 3
After uploading your image with glTexImage2D or similar, you receive a GLuint texture ID. Cast this directly to ImTextureID:
// Your OpenGL upload code produces: GLuint myTexture;
ImTextureID tex_id = (ImTextureID)myTexture;
ImGui::Begin("Custom Image");
ImGui::Image(tex_id,
ImVec2(256, 256), // display size
ImVec2(0, 0), ImVec2(1, 1), // UV coordinates (full texture)
ImVec4(1,1,1,1), // tint color (white = no tint)
ImVec4(0,0,0,0)); // border color (transparent)
ImGui::End();
As documented in backends/imgui_impl_opengl3.h, the backend expects ImTextureID to contain a valid OpenGL texture name.
DirectX 11
For DirectX 11, you create an ID3D11ShaderResourceView from your texture and cast the pointer:
// Your D3D11 code produces: ID3D11ShaderResourceView* srv;
ImTextureID tex_id = (ImTextureID)srv;
ImGui::Begin("DX11 Image");
ImGui::Image(tex_id, ImVec2(128, 128));
ImGui::End();
The DirectX 11 backend implementation in backends/imgui_impl_dx11.h dereferences this pointer to set the shader resource view before drawing.
Vulkan
Vulkan requires descriptor sets for binding textures. Use the descriptor set returned by ImGui_ImplVulkan_AddTexture() or your own allocation:
// VkDescriptorSet ds = ... (created via ImGui_ImplVulkan_AddTexture or manual)
ImTextureID tex_id = (ImTextureID)ds;
ImGui::Begin("Vulkan Image");
ImGui::Image(tex_id, ImVec2(200, 200));
ImGui::End();
According to backends/imgui_impl_vulkan.h, the backend binds this descriptor set during command buffer recording.
General Pattern
Regardless of backend, the ImGui API remains consistent:
ImTextureID myTexID = /* your native handle */;
ImGui::Begin("Image Window");
ImGui::Image(myTexID, ImVec2(width, height));
ImGui::End();
Only the method of obtaining and casting the native handle changes between renderers.
Rendering Pipeline Details
Internally, ImGui stores texture references in ImDrawCmd structures defined in imgui_internal.h. When you call ImGui::Image(), the library creates a draw command containing the ImTextureID you provided.
During the backend's RenderDrawData() implementation (found in files like imgui_impl_opengl3.cpp or imgui_impl_dx11.cpp), the code iterates through draw commands and retrieves the texture ID:
// Conceptual backend code
ImTextureID tex_id = draw_cmd->GetTexID();
// Backend binds the appropriate GPU resource using tex_id
This abstraction allows ImGui to remain graphics-API neutral while supporting hardware-accelerated texture rendering.
Safety Conventions and Invalid Textures
By default, ImGui considers zero (0 or nullptr) as an invalid texture ID. If you store texture indices, offsets, or custom handles in ImTextureID, define ImTextureID_Invalid in your imconfig.h file to avoid collisions with this convention:
// In imconfig.h
#define ImTextureID_Invalid ((ImTextureID)-1)
This prevents ImGui from interpreting your valid texture index 0 as "no texture."
Summary
ImTextureIDis a 64-bit opaque value defined inimgui.hthat stores backend-specific texture handles- Cast your native GPU handle (OpenGL
GLuint, DirectXID3D11ShaderResourceView*, VulkanVkDescriptorSet, etc.) toImTextureIDbefore passing it toImGui::Image() - ImGui does not load images; you must upload image data to the GPU using your own renderer code
- Backends consume the ID during
RenderDrawData()by callingImDrawCmd::GetTexID()and binding the corresponding resource - Define
ImTextureID_Invalidinimconfig.hif you use non-pointer values to avoid the zero-is-invalid convention
Frequently Asked Questions
What type should I cast my texture handle to?
Cast your native texture handle directly to ImTextureID (which is ImU64 by default). For OpenGL, cast your GLuint to ImTextureID; for DirectX 11, cast your ID3D11ShaderResourceView* pointer; for Vulkan, cast the VkDescriptorSet. The backend reinterprets the 64-bit value appropriately.
Does ImGui load images from disk for me?
No. ImGui is a GUI library only and does not handle image loading, decoding, or GPU upload. You must load image files (PNG, JPG, etc.) using a library like stb_image, upload the data to your GPU with OpenGL, DirectX, Vulkan, or other APIs, then pass the resulting native handle to ImGui as an ImTextureID.
Why is my texture showing as black or white in ImGui?
If your texture appears solid black or white, ensure your image data uploaded successfully to the GPU and that you are passing the correct native handle. Also verify that your UV coordinates (the third and fourth parameters to ImGui::Image()) map to valid regions of your texture—using (0,0) to (1,1) displays the full texture.
Can I use multiple different textures in one ImGui window?
Yes. You can call ImGui::Image() with different ImTextureID values as many times as needed within a single window. ImGui automatically generates separate draw commands with the appropriate texture IDs, and the backend handles binding the correct texture for each draw call during rendering.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →