klepto2 Posted August 31, 2023 Share Posted August 31, 2023 I already posted a small screenshot in the Gallery showing an early proof of concept for integrating ImGui into UltraEngine. https://www.ultraengine.com/community/gallery/image/2676-imgui-integration-in-ultraengine/ Now I have made some progress and finished a lot of the integration stuff. Ordered Rendering (not completely working, sometimes the order seems a bit off) Keyboard and MouseInput Shader and Material stuff General-Rendering is working What is still to do: Resolve some clipping errors Make the whole integration more Ultra-like not the c approach ImGui is normally using for initialisation Add multiple texture and font support (for images or framebuffer display) This small gif shows a small sample with the provided demo window and a custom debug window showing the renderstats: Here is a small code snippet showing the debug window code: #define MAX_FRAMES 100 struct StatCounter { float data[MAX_FRAMES]; float getMax() { return *max_element(data, data + MAX_FRAMES); } float getAvarge() { float average = 0.0f; int removeCounts = 0; for (int n = 0; n < IM_ARRAYSIZE(data); n++) { auto v = data[n]; if (v < 0.0) { v = 0.0; removeCounts++; } average += v; } average /= (float)(MAX_FRAMES - removeCounts); return average; } }; class ImDebugRenderer : public Object { shared_ptr<World> _world; StatCounter _fpsCounter; StatCounter _cullCounter; StatCounter _renderCounter; int _currentFrame = 0; bool _isOpen = true; public: ImDebugRenderer(shared_ptr<World> world) : _world(world) { _world->RecordStats(true); } void CollectStatistics() { _fpsCounter.data[_currentFrame] = _world->renderstats.framerate; _cullCounter.data[_currentFrame] = _world->renderstats.cullingtime; _renderCounter.data[_currentFrame] = _world->renderstats.rendertime; } void Render() { CollectStatistics(); if (_isOpen) { ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_Appearing); ImGui::SetNextWindowBgAlpha(0.5); //ImGui::SetNextWindowSize(ImVec2(350, 420), ImGuiCond_Appearing); ImGui::Begin("Debug", &_isOpen, ImGuiWindowFlags_AlwaysAutoResize); ImGui::PlotLines(("Framerate (" + String(_world->renderstats.framerate) + " fps )").c_str(), _fpsCounter.data, IM_ARRAYSIZE(_fpsCounter.data), _currentFrame, ("average : " + String(_fpsCounter.getAvarge())).c_str(), 0.0, _fpsCounter.getMax(), ImVec2(0, 80.0f)); ImGui::PlotLines(("Culltime (" + String(_world->renderstats.cullingtime) + " ms)").c_str(), _cullCounter.data, IM_ARRAYSIZE(_cullCounter.data), _currentFrame, ("average : " + String(_cullCounter.getAvarge())).c_str(), 0.0, _cullCounter.getMax(), ImVec2(0, 80.0f)); ImGui::PlotLines(("Rendertime (" + String(_world->renderstats.rendertime) + " ms)").c_str(), _renderCounter.data, IM_ARRAYSIZE(_renderCounter.data), _currentFrame, ("average : " + String(_renderCounter.getAvarge())).c_str(), 0.0, _renderCounter.getMax(), ImVec2(0, 80.0f)); ImGui::Text("Cameras : %d", _world->renderstats.cameras); ImGui::Text("Meshbatches : %d", _world->renderstats.meshbatches); ImGui::Text("Pipelines : %d", _world->renderstats.pipelines); ImGui::Text("Polygons : %d", _world->renderstats.polygons); ImGui::Text("Vertices : %d", _world->renderstats.vertices); ImGui::Text("Instances : %d", _world->renderstats.instances); ImGui::Text("Shadows : %d", _world->renderstats.shadows); ImGui::Text("Shadowpolygons: %d", _world->renderstats.shadowpolygons); ImGui::Text("VRam : %d", _world->renderstats.vram); ImGui::End(); } _currentFrame = (_currentFrame + 1) % MAX_FRAMES; } void Show() { _isOpen = true; }; }; The setup is more or less the same as for the default GUI, you need an orthographic camera and a separate renderlayer. But then you can simply call: // This is how i imagine a more ultra-way of rendering the ImGui auto ui_manager = ImGuiUltraManager::Create(window, world, renderlayer); //Framebuffer will work as well void main() { ui_manager->BeginFrame(); // Begins the frame-recording debugWindow->Render(); // Add the commands to draw the debug window (code from above) ui_manager->Render(); // Stops the frame-recording and prepares the models for rendering world->Update(); world->Render(framebuffer,true); } 4 1 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
klepto2 Posted September 1, 2023 Author Share Posted September 1, 2023 small update: clipping errors and z-order problems are fixed. Now working on the simplyfied (ultralike) access and setting up a github repo for this to give access to this gem to everyone. 2 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
klepto2 Posted September 1, 2023 Author Share Posted September 1, 2023 Made a lot of progress today I have finished the basic ImGuiManager for UltraEngine (not yet commited) with some additional features: you can now register your own UltraEngine Textures to be used by ImGui ImGuiManager::RegisterTexture(texture) will return an ImTextureID which can be used then by eg: ImGui::Image(...) Multiple-Fonts are now supported + reload and recreation of the texture-atlas This is a small sample which i am using to test some features: #include "UltraEngine.h" #include "Components/Motion/Mover.hpp" #include "imgui-integration/ImGuiManager.h" using namespace UltraEngine; using namespace UltraEngine::ImGuiIntegration; using namespace std; #define MAX_FRAMES 100 struct StatCounter { float data[MAX_FRAMES]; float getMax() { return *max_element(data, data + MAX_FRAMES); } float getAvarge() { float average = 0.0f; int removeCounts = 0; for (int n = 0; n < IM_ARRAYSIZE(data); n++) { auto v = data[n]; if (v < 0.0) { v = 0.0; removeCounts++; } average += v; } average /= (float)(MAX_FRAMES - removeCounts); return average; } }; class ImDebugRenderer : public Object { shared_ptr<World> _world; StatCounter _fpsCounter; StatCounter _cullCounter; StatCounter _renderCounter; int _currentFrame = 0; bool _isOpen = true; public: ImDebugRenderer(shared_ptr<World> world) : _world(world) { _world->RecordStats(true); } void CollectStatistics() { _fpsCounter.data[_currentFrame] = _world->renderstats.framerate; _cullCounter.data[_currentFrame] = _world->renderstats.cullingtime; _renderCounter.data[_currentFrame] = _world->renderstats.rendertime; } void Render() { CollectStatistics(); if (_isOpen) { ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_Appearing); ImGui::SetNextWindowBgAlpha(0.5); //ImGui::SetNextWindowSize(ImVec2(350, 420), ImGuiCond_Appearing); ImGui::Begin("Debug", &_isOpen, ImGuiWindowFlags_AlwaysAutoResize); ImGui::PlotLines(("Framerate (" + String(_world->renderstats.framerate) + " fps )").c_str(), _fpsCounter.data, IM_ARRAYSIZE(_fpsCounter.data), _currentFrame, ("average : " + String(_fpsCounter.getAvarge())).c_str(), 0.0, _fpsCounter.getMax(), ImVec2(0, 80.0f)); ImGui::PlotLines(("Culltime (" + String(_world->renderstats.cullingtime) + " ms)").c_str(), _cullCounter.data, IM_ARRAYSIZE(_cullCounter.data), _currentFrame, ("average : " + String(_cullCounter.getAvarge())).c_str(), 0.0, _cullCounter.getMax(), ImVec2(0, 80.0f)); ImGui::PlotLines(("Rendertime (" + String(_world->renderstats.rendertime) + " ms)").c_str(), _renderCounter.data, IM_ARRAYSIZE(_renderCounter.data), _currentFrame, ("average : " + String(_renderCounter.getAvarge())).c_str(), 0.0, _renderCounter.getMax(), ImVec2(0, 80.0f)); ImGui::Text("Cameras : %d", _world->renderstats.cameras); ImGui::Text("Meshbatches : %d", _world->renderstats.meshbatches); ImGui::Text("Pipelines : %d", _world->renderstats.pipelines); ImGui::Text("Polygons : %d", _world->renderstats.polygons); ImGui::Text("Vertices : %d", _world->renderstats.vertices); ImGui::Text("Instances : %d", _world->renderstats.instances); ImGui::Text("Shadows : %d", _world->renderstats.shadows); ImGui::Text("Shadowpolygons: %d", _world->renderstats.shadowpolygons); ImGui::Text("VRam : %d", _world->renderstats.vram); ImGui::End(); } _currentFrame = (_currentFrame + 1) % MAX_FRAMES; } void Show() { _isOpen = true; }; void Toggle() { _isOpen = !_isOpen; }; }; int main(int argc, const char* argv[]) { auto plg = LoadPlugin("Plugins/FITextureLoader"); auto plg2 = LoadPlugin("Plugins/KTX2TextureLoader"); //Get the displays auto displays = GetDisplays(); //Create a window auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); //Create a world auto world = CreateWorld(); //Create a framebuffer auto framebuffer = CreateFramebuffer(window); //Create a camera auto camera = CreateCamera(world); camera->SetPosition(0, 0, -1); camera->SetFov(70); camera->SetClearColor(0.125); camera->SetTessellation(4); //Create a light auto light = CreateBoxLight(world); light->SetRange(-10, 10); light->SetRotation(35, 35, 0); light->SetColor(4); //Display material auto model = CreateCubeSphere(world, 0.5, 8, MESH_QUADS); auto mtl = LoadMaterial("Materials/rocks_ground_02.json"); mtl->SetTessellation(true); mtl->SetDisplacement(0.075f); model->SetMaterial(mtl); //Entity component system auto component = model->AddComponent<Mover>(); component->rotationspeed.y = 45; // Init the Manager auto imGuiManager = CreateImGuiManager(window, world); auto debugRenderer = make_shared<ImDebugRenderer>(world); // A custom class to render debug information for the world auto sampleTexture = mtl->GetTexture(0); // Get the diffuse Texture auto imGuiTexture = imGuiManager->RegisterTexture(sampleTexture); // Register the texture for usage with ImGui //Define some settings to control the camera and material settings bool camera_wireFrame = false; float tesselation_level = 4.0; Vec2 mtl_displacement = mtl->GetDisplacement(); //Main loop while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { //Begin the ui-definition imGuiManager->BeginFrame(); debugRenderer->Render(); //render the debug panel (only when open) //Start rendering of the Settings ImGui::Begin("Settings", NULL, ImGuiWindowFlags_AlwaysAutoResize); ImGui::Checkbox("Wireframe", &camera_wireFrame); ImGui::SliderFloat("Tesselation-Level", &tesselation_level,0.0,32); ImGui::SliderFloat2("Displacement", &mtl_displacement[0], -1.0, 1.0); if (ImGui::Button("Toggle Debug-Window")) { debugRenderer->Toggle(); } ImGui::End(); //Render a window containing the UltraEngine texture ImGui::Begin("Texture", NULL, ImGuiWindowFlags_AlwaysAutoResize); ImGui::Image(imGuiTexture,ImVec2(128,128)); ImGui::End(); //Stop UI-Recording and update/create the models for UltraEngine imGuiManager->Sync(); //Update the Settings modified by the UI camera->SetWireframe(camera_wireFrame); camera->SetTessellation(tesselation_level); mtl->SetDisplacement(mtl_displacement.x, mtl_displacement.y); world->Update(); world->Render(framebuffer); } return 0; } 3 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
klepto2 Posted September 7, 2023 Author Share Posted September 7, 2023 Next Step: Finished the update to the "Dear ImGui" "docking"-branch. The docking branch is a stable dev branch which contains the latest features as docking or multi-viewport systems. Docking is self explaining and I show it in the image below. Essentially multi-viewport means, that you can move windows out of your application, i haven't tested that (new windows will be generated, etc.) Other remarkable milestones: Rendering is more or less optimized. (With some dirty hacks ) I have refactored the Model/Mesh generation and updating method and the main loop still updates with 60fps even with high complex ui's Multiple Fonts rendering is also possible Texture-System is in place. What needs to be done: Replace the current Win32 driver with a native UltraEngine way Add feature to allow render to texture and proper Input handling in this case and of course optimization 3 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
klepto2 Posted September 7, 2023 Author Share Posted September 7, 2023 One small addition: While this Ui-System is mainly for prototyping or debugging/dev things. It might come in handy, that it has a lot of lowlevel drawing functions. Which means, that when i have done the Rendertarget implementation, it could be possible to draw all kinds of 2d shapes, etc into a texture, which can then be rendered into a UltraEngine::Widget. Or you can combine these things and use the Widget system and ImGui together, e.g.: for something like this: https://github.com/thedmd/imgui-node-editor 1 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
Josh Posted September 8, 2023 Share Posted September 8, 2023 Although IMgui is using immediate mode to render, you still have an advantage with the Ultra architecture because all the mesh generation code is executing in the game logic thread (I assume). That means the only rendering cost is the bandwidth of uploading the updated mesh to the GPU, and it sounds like that mesh data is not huge. Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
klepto2 Posted September 12, 2023 Author Share Posted September 12, 2023 On 9/8/2023 at 5:57 PM, Josh said: Although IMgui is using immediate mode to render, you still have an advantage with the Ultra architecture because all the mesh generation code is executing in the game logic thread (I assume). That means the only rendering cost is the bandwidth of uploading the updated mesh to the GPU, and it sounds like that mesh data is not huge. You*re completely right. And with the new updates, it is even better The only thing is that in debug mode the culling takes a lot of time (10 - 13ms at average), which leads to a lower update even only one mesh is on screen. I remember that @SpiderPig has made the suggestion, to be able to disable the culling for certain cameras. And for orthographic cameras i fully agree with him. Normally in a 2d space it could be leed to the programmer, what to render and what not. Here are some progress screens of the current Statistics panel i have done with Dear ImGui: 2 1 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
Josh Posted September 12, 2023 Share Posted September 12, 2023 Yeah, so I think we are talking about a feature for a static visibility list. 1 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
franck22000 Posted September 14, 2023 Share Posted September 14, 2023 Hello @klepto2, nice work, IMGUI is very useful for rapidly making tools / utility stuff. Are you planning to release the integration source code publicly ? Quote You guys are going to be the death of me. Josh Link to comment Share on other sites More sharing options...
klepto2 Posted September 14, 2023 Author Share Posted September 14, 2023 Yes, I plan so. The repo is already Setup and will be filled soon. ( maybe tomorrow;)) 1 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
klepto2 Posted September 15, 2023 Author Share Posted September 15, 2023 You can give it a try now: https://github.com/klepto2/ImGui-UltraEngine Everything but MultiViewport rendering should work out of the box. Look at main.cpp for a more detailed sample. 3 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
franck22000 Posted September 15, 2023 Share Posted September 15, 2023 Thank you very much ! Greatly appreciated. Now I only need to wait for the official engine release to try this out Quote You guys are going to be the death of me. Josh Link to comment Share on other sites More sharing options...
khotan Posted December 18, 2023 Share Posted December 18, 2023 So cool for integration to ImGui ! Quote Link to comment Share on other sites More sharing options...
reepblue Posted November 4 Share Posted November 4 Tried to give this a try for my project due to my simple solution relying on the OpenGL3 implementation not working. It seems some API changes with both imgui and Ultra broke this. Do you plan to fix this in the future? Quote Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon! Link to comment Share on other sites More sharing options...
klepto2 Posted November 4 Author Share Posted November 4 Hi, thanks for pointing this out. I will take a look as soon as possible, I think it will just be some small details. 2 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.