-
Posts
929 -
Joined
-
Last visited
Content Type
Blogs
Forums
Store
Gallery
Videos
Downloads
Everything posted by klepto2
-
Indeed, a fresh install solved it. thx
-
With the latest update, the debug library is damaged.
-
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
-
yes, but that would mean, that the floor itself needs a mass otherwise the force methods will have no impact. To make it physically correct, ( i believe i read that somewhere on the Newtondynamics forums back in Blitzmax times ) Would be to turn off gravity at all and for each object apply a force pointing to the center of your "planet" or maybe in this case just downwards. Of course in the case of a plane you need to conquer the forces applied to the plane to make it stable.
-
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
-
I think the Physicsmatrix is only updated for the box itself, not taking the parent into account. You can see this in the first sample: While the box is moving you can actually move through it even though the collision shape is displayed correct. When you move to the original Position the collison will occur.
-
-
Advanced Mesh creation and modification options
klepto2 replied to klepto2's topic in Suggestion Box
This shows the current state: It is really impressive what you can do. There are tons of widgets available (the colored Texteditor is a 3rd party plugin which works nativly with the integration). Also Dear ImGui is meant to be used for tooling/prototyping and debugging, not for ingame usage. Therefore, there are other tools. -
Advanced Mesh creation and modification options
klepto2 replied to klepto2's topic in Suggestion Box
Maybe Maybe a flag to disable the Culling step for particular models/meshes might do the trick, in Orthographic projection (especially GUIs) it might be useful to always assume the mesh is visible as long as the model itself is not hidden. I was able to optimize the rendering to be flicker free and still performant. The previous flickering was due to a misconception on my side earlier. This is how Imgui provides the render data: you notify ImGui that you will render a new frame you define the GUI last you ask ImGui for the Renderdata The RenderData consists of Displaylists (for each window, foreground or background operation) The Displaylists itself contains the VertexBuffer and the indexbuffer and a commandlist the commandlists specify which texture to use and which indices (by providing an Offset and an ElementCount) The Render data is ordered front to back representing the Z-Index. In my first implementations i assumed that I need a separate Model for each command in the commandlists, and i reused these models and reordered them every frame. The Problem: if in the previous frame a big window with lots of content was rendered focused, but the next frame a small and simple window was in front. The Model of the big window was resized to the smaller window and vice versa. In the current implementation i only use one model per displaylist (which contains the _ownername) and add meshes according to the commandbuffer. So know i can identify which model belongs to a specific window (displaylist) and I only reuse this model for that particular window, when a window is closed I just hide the model and reuse it once the window is back. If a window has fewer commands than before i clear it and rebuild als meshes needed. Otherwise i use the resize approach. Surprisingly, this eliminates all the flickering but still maintains a good performance. This is what i do when the cmds are lower than the previously created meshes, but this only works by removing all meshes from the model and adding them again afterwards. There currently is no way to remove a specific mesh from a model. -
Advanced Mesh creation and modification options
klepto2 replied to klepto2's topic in Suggestion Box
I have found a very hackish workaround and this should not be used, unless you know exactly what you do: class ModifiableMesh : public Mesh { public: void ResizeVertexBuffer(shared_ptr<Mesh> base, int newSize) { static_cast<ModifiableMesh*>(base.get())->Mesh::m_vertices.resize(newSize); }; void ResizeIndexBuffer(shared_ptr<Mesh> base, int newSize) { static_cast<ModifiableMesh*>(base.get())->Mesh::m_indices.resize(newSize); }; int VertexSize(shared_ptr<Mesh> base) { return static_cast<ModifiableMesh*>(base.get())->Mesh::m_vertices.size(); }; int IndexSize(shared_ptr<Mesh> base) { return static_cast<ModifiableMesh*>(base.get())->Mesh::m_indices.size(); }; }; const shared_ptr<ModifiableMesh> ModMesh = std::make_shared<ModifiableMesh>(); with this you can now resize the Vectors even when they are protected: int v_size = ModMesh->VertexSize(mesh); int i_size = ModMesh->IndexSize(mesh); int v_diff = v_size - newVertices.size() - INDEX_FLOAT_RANGE; int i_diff = i_size - newIndices.size() - INDEX_FLOAT_RANGE; if (abs(v_diff) > INDEX_FLOAT_RANGE) { Print("Resizing (Vertex-Buffer): " + String(v_diff) + " | " + String(v_size) + "-" + String(newVertices.size())); ModMesh->ResizeVertexBuffer(mesh,newVertices.size() + INDEX_FLOAT_RANGE); } if (abs(i_diff) > INDEX_FLOAT_RANGE)//newIndices.size() > mesh->m_indices.size()) { Print("Resizing (Index-Buffer): " + String(i_diff) + " | " + String(i_size) + "-" + String(newIndices.size())); ModMesh->ResizeIndexBuffer(mesh,newIndices.size() + INDEX_FLOAT_RANGE); } mesh->Modify(newVertices); mesh->Modify(newIndices); Not really a good way, but it will do it as long as we have no ability to access the vectors directly. -
Advanced Mesh creation and modification options
klepto2 replied to klepto2's topic in Suggestion Box
Maybe I should clarify this a bit. The Architecture of 3rd party libraries (including Dear ImGui, or most nvidia libs) normalliy provide a shared VertexStructure and then just an Indexbuffer for each "surface". To replicate this behaviour in UltraEngine, you currently have to create multiple meshs and recalculate the Vertexbuffer (I have done so for ImGui) or you need to duplicate the Vertexbuffer for each mesh. The above thing is a nice to have but not essential. What is most important for me is the abillity to resize the Vertices and Indices at will. While I understand that Ultraengine is layedout for high performance I believe that some parts should also be a bit flexible. (It doesn't cost to much if you just need to resize every now and then and just upload small bits to the gpu instead of a big buffer where just a small bit is used anyway). -
While the Mesh API is very fast and also flexible, I think it could be more flexible. Background: I am working on this: and I have encountered a small issue with the mesh API. While you're able to modify vertices and indices on the fly it is not possible to change and update the size of these Vectors. I found a post where Josh describes this by design and i agree that from a performance point this is useful. On the other side it limits the usage of the class. Lets take the "Dear ImGui' as a sample: As this is an intermediate Gui system the layout is not calculated once, but instead each frame, This means that a window with small content has a small vertex and index count, but when you modify (eg: expand trees or add text) the mesh is regenerated and the vertex size and index buffer changes in size. Currently there are 2 ways to solve this: Recreate meshes on the fly (delete the old mesh, and create a new one with the new size) Surprisingly fast, but due to sync with the graphics card it leads to high flickering Create the meshes with hight vertex and inddex counts (lets say 10000 / 30000) and use the Mesh::Modify methods Works without flickering, but is extremly slow, not because of the modifcation itself, but the extreme size and unneeded uploads to the gpu. I have tested something which i assumed will not work, but surprisingly this worked flawless with nearly no impact: I modfied mesh.h and changed the protected modifier to public This gave me access to the actual Vectors for vertices and indices With access to these Vectors i can now resize them at will. I give them just a small bigger size (around 300 items) than needed to not perform resizing every frame After that i just use the Mesh::Modify methods Results: with the recreation method i get around 150 to 180 fps, but flickering with the preserved Size method i get 20 to 50 fps (depending on debug or release mode) with the resizing method i get 180 to 240 fps So maybe the resizing should be added optionaly to the Modify methods or maybe another DynamicMesh class. Another thing which might be useful for some scenarios: Shared VertexBuffers per Model or MeshGroup: Most Vulkan or modern DirectX/OpenGL use one VertexBuffer for big models, and just separate Indexbuffers per material. In Ultraengine this could be used to further increase the GPU-Bandwidth: I could Imagine that you define a Main-Mesh and this mesh can be assigned to other Meshs as parent. Then these Child meshes only need to provide indices and the vertexbuffer is the same as the the parent mesh. Use Cases: Lod, Voxel terrains etc.
-
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; }
-
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.
-
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); }
-
While the integrated GUI-System is powerful and great, I decided to give ImGui a go. ImGui is an Intermediate GUI, which means you describe the layout in every frame and get what needs to be rendered, This is useful if you want to add some simple debug values to screen. If you look onto the webpage of ImGui you can see what can be done with it. This is a screenshot showing an early stage of the prototype integration, to see if it is even possible.
-
For the reprojection i noticed, that i don't need it, but it will come in handy to render masks etc. for godrays eg. the same time you render the more complicated stuff.
-
-
I got a first version with reprojection working. it is not fine tuned, but in general the algo is very basic. This gif shows the debugging of the reprojection. Red shows the pixels which went offscreen and needs to be rerendered as well. In the non red area only every 16th pixel is rendered per frame, the others are reprojected from the previous frame.
-
I have the need to write to 2 colorattachments and i have set it up like this: "textures": [ { "size": [0.5, 0.5], "format": 97 }, { "size": [0.5, 0.5], "format": 97 } ], "subpasses": [ { "samplers": ["DEPTH", "NORMAL", "PREVPASS"], "colorAttachments": [0,1], "shader": { "float32": { "fragment": "Shaders/Environment/environment_clouds.frag.spv" } } }, in the shader file i have something like this (very simplfied): layout(location = 0) out vec4 outColor[2]; void main() { outColor[0] = vec4(1.0,0.0,0.0,1.0); outColor[1] = vec4(0.0,1.0,0.0,1.0); } only the red value is stored to the texture, the second one is still unmodified. Ate multiple attachemnts currently not supported?
-
-
-
-
Not directly, the clouds system is based on a weather texture, where red is used for the overall coverage of clouds, green is used for the cloud type and blue is used for the cloud wetness. So if you modify one of the channels it will reflect on the clud rendering. In this case i just pasted "UltraEngine" Logo directly in the red channel. Also you may notice, that currently a plain texture is used which leads to repition, i later will also support cubemaps which can then be used to create individual weather for whole planets.
-