StOneDOes Posted January 31, 2023 Share Posted January 31, 2023 It seems when a widget is constantly resized, the UI does not appear to either sync or re-render correctly. Using the following sample of code, use the mouse left click to create and draw a rectangle. You can see the rectangle disappears for moments at a time. It doesn't seem to be too bad by itself, but it becomes extremely noticeable when you add the 3D camera and the terrain. This is mostly just the terrain sample and UI sample glued together. See attached video. video.zip Can anyone please confirm if this happens on your PC. ----------------------------------------------- CPU - AMD Ryzen 9 3900X 12 Core @3.8GHz GFX - AMD Radeon RX 6600 XT RAM - Corsair Vengeance RGB PRO 16GB DDR4 @3200MHz #include "UltraEngine.h" using namespace UltraEngine; #define MB_LEFT 1 int main(int argc, const char* argv[]) { //Get the displays auto displays = GetDisplays(); //Create window auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0]); //Create framebuffer auto framebuffer = CreateFramebuffer(window); //Create world auto world = CreateWorld(); //Create a 3d camera auto camera = CreateCamera(world); camera->SetFov(70); camera->SetPosition(0, 50, 0); camera->SetRotation(45, 0, 0); camera->SetClearColor(0.125); //Sunlight auto light = CreateDirectionalLight(world); light->SetRotation(45, 35, 0); light->SetColor(2); //Create terrain auto terrain = CreateTerrain(world, 512); terrain->LoadHeightmap("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Terrain/512.r16"); terrain->SetScale(1, 100, 1); //Create base material auto ground = CreateMaterial(); auto diffusemap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/river_small_rocks_diff_4k.dds"); auto normalmap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/river_small_rocks_nor_gl_4k.dds"); ground->SetTexture(diffusemap, TEXTURE_DIFFUSE); ground->SetTexture(normalmap, TEXTURE_NORMAL); terrain->SetMaterial(ground); //Create paint material auto rocks = CreateMaterial(); diffusemap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/Rocks_Dirt_Ground_2k.dds"); normalmap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/Rocks_Dirt_Ground_2k_dot3.dds"); auto dispmap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/Rocks_Dirt_Ground_2k_disp.dds"); rocks->SetTexture(diffusemap, TEXTURE_DIFFUSE); rocks->SetTexture(normalmap, TEXTURE_NORMAL); rocks->SetTexture(dispmap, TEXTURE_DISPLACEMENT); //Apply material based on terrain slope for (int x = 0; x < terrain->resolution.x; ++x) { for (int y = 0; y < terrain->resolution.y; ++y) { float slope = terrain->GetSlope(x, y); if (slope > 15.0f) { float wt = Min((slope - 15.0f) / 10.0f, 1.0f); terrain->SetMaterial(x, y, rocks, wt); } } } //Load a font auto font = LoadFont("Fonts/arial.ttf"); //Create user interface auto ui = CreateInterface(world, font, framebuffer->size); //Create camera auto uiCamera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC); uiCamera->SetPosition(float(framebuffer->size.x) * 0.5f, float(framebuffer->size.y) * 0.5f, 0); uiCamera->SetClearMode( ClearMode::CLEAR_DEPTH ); auto rect = CreatePanel( 0, 0, 0, 0, ui->root, PANEL_BORDER ); rect->SetColor( Vec4( 0, 0.f, 0.f, 0.f ), WIDGETCOLOR_BACKGROUND ); rect->SetColor( Vec4( 255, 255, 255.f, 255.f ), WIDGETCOLOR_BORDER ); auto mouseDown = false; iVec2 clickPos; while (true) { while (PeekEvent()) { const Event ev = WaitEvent(); switch (ev.id) { case EVENT_WINDOWCLOSE: { if (ev.source == window) { return 0; } break; } case EVENT_MOUSEDOWN: { const auto button = ev.data; if( !mouseDown && button == MB_LEFT ) { mouseDown = true; clickPos = { window->GetMousePosition().x, window->GetMousePosition().y }; } break; } case EVENT_MOUSEUP: { const auto button = ev.data; if( button == MB_LEFT ) { rect->SetShape( 0, 0, 0, 0 ); mouseDown = false; } break; } default: { ui->ProcessEvent(ev); break; } } } if( mouseDown ) { auto mousePosition = window->GetMousePosition(); rect->SetShape( Min( mousePosition.x, clickPos.x ), Min( mousePosition.y, clickPos.y ), Abs( clickPos.x - mousePosition.x ) + 1, Abs( clickPos.y - mousePosition.y ) + 1 ); } world->Update(); world->Render(framebuffer); } return 0; } Quote Link to comment Share on other sites More sharing options...
Josh Posted January 31, 2023 Share Posted January 31, 2023 I can tell exactly what is happening. When you change the size of the widget, the GUI system creates a new sprite and deletes the old one. But the culling thread does not create a new visibility list that contains the new sprite until it receives its existence from the main thread and returns another visibility set to the renderer. So you have this period where the old sprite disappears but the new one is not yet visible. A way to eliminate this would be to create a wireframe sprite and just rescale it when the rectangle changes size. 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...
StOneDOes Posted January 31, 2023 Author Share Posted January 31, 2023 Ok thanks for the explanation. But I can't get the sprite to show with the cameras present. Is there a trick to get this to work correctly? Quote Link to comment Share on other sites More sharing options...
Solution Josh Posted February 1, 2023 Solution Share Posted February 1, 2023 Here you go. I had problems using a wireframe rect. I suspect the scaling breaks the pixel-perfect alignment. I will look into that now, but this gives you enough to work with: #include "UltraEngine.h" using namespace UltraEngine; #define MB_LEFT 1 int main(int argc, const char* argv[]) { //Get the displays auto displays = GetDisplays(); //Create window auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0]); //Create framebuffer auto framebuffer = CreateFramebuffer(window); //Create world auto world = CreateWorld(); //Create a 3d camera auto camera = CreateCamera(world); camera->SetFov(70); camera->SetPosition(0, 50, 0); camera->SetRotation(45, 0, 0); camera->SetClearColor(0.125); //Sunlight auto light = CreateDirectionalLight(world); light->SetRotation(45, 35, 0); light->SetColor(2); //Create terrain auto terrain = CreateTerrain(world, 512); terrain->LoadHeightmap("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Terrain/512.r16"); terrain->SetScale(1, 100, 1); //Create base material auto ground = CreateMaterial(); auto diffusemap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/river_small_rocks_diff_4k.dds"); auto normalmap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/river_small_rocks_nor_gl_4k.dds"); ground->SetTexture(diffusemap, TEXTURE_DIFFUSE); ground->SetTexture(normalmap, TEXTURE_NORMAL); terrain->SetMaterial(ground); //Create paint material auto rocks = CreateMaterial(); diffusemap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/Rocks_Dirt_Ground_2k.dds"); normalmap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/Rocks_Dirt_Ground_2k_dot3.dds"); auto dispmap = LoadTexture("https://raw.githubusercontent.com/UltraEngine/Documentation/master/Assets/Materials/Ground/Rocks_Dirt_Ground_2k_disp.dds"); rocks->SetTexture(diffusemap, TEXTURE_DIFFUSE); rocks->SetTexture(normalmap, TEXTURE_NORMAL); rocks->SetTexture(dispmap, TEXTURE_DISPLACEMENT); //Apply material based on terrain slope for (int x = 0; x < terrain->resolution.x; ++x) { for (int y = 0; y < terrain->resolution.y; ++y) { float slope = terrain->GetSlope(x, y); if (slope > 15.0f) { float wt = Min((slope - 15.0f) / 10.0f, 1.0f); terrain->SetMaterial(x, y, rocks, wt); } } } //Load a font auto font = LoadFont("Fonts/arial.ttf"); //Create user interface auto ui = CreateInterface(world, font, framebuffer->size); ui->background->SetColor(0, 0, 0, 0); ui->SetRenderLayers(2); auto testpanel = CreatePanel(20, 20, 200, 200, ui->background); //Create camera auto uiCamera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC); uiCamera->SetPosition(float(framebuffer->size.x) * 0.5f, float(framebuffer->size.y) * 0.5f, 0); uiCamera->SetClearMode(ClearMode::CLEAR_DEPTH); uiCamera->SetRenderLayers(2); uiCamera->SetDepthPrepass(false); //auto rect = CreatePanel(0, 0, 0, 0, ui->root, PANEL_BORDER); //rect->SetColor(Vec4(0, 0.f, 0.f, 0.f), WIDGETCOLOR_BACKGROUND); //rect->SetColor(Vec4(255, 255, 255.f, 255.f), WIDGETCOLOR_BORDER); auto mouseDown = false; iVec2 clickPos; auto rect = CreateSprite(world, 1, 1, false); rect->SetRenderLayers(2); auto mtl = CreateMaterial(); mtl->SetColor(0, 1, 1, 0.25); mtl->SetTransparent(true); mtl->SetShaderFamily(LoadShaderFamily("Shaders/Unlit.json")); rect->SetMaterial(mtl); while (true) { while (PeekEvent()) { const Event ev = WaitEvent(); switch (ev.id) { case EVENT_WINDOWCLOSE: { if (ev.source == window) { return 0; } break; } case EVENT_MOUSEDOWN: { const auto button = ev.data; if (!mouseDown && button == MB_LEFT) { mouseDown = true; clickPos = { window->GetMousePosition().x, window->GetMousePosition().y }; } break; } case EVENT_MOUSEUP: { const auto button = ev.data; if (button == MB_LEFT) { rect->SetScale(0); //rect->SetShape(0, 0, 0, 0); mouseDown = false; } break; } default: { ui->ProcessEvent(ev); break; } } } if (mouseDown) { auto mousePosition = window->GetMousePosition(); float h = Abs(clickPos.y - mousePosition.y) + 1; rect->SetPosition(Min(mousePosition.x, clickPos.x), framebuffer->size.y - Min(mousePosition.y, clickPos.y) - h); rect->SetScale(Abs(clickPos.x - mousePosition.x) + 1, h, 1); //rect->SetShape(Min(mousePosition.x, clickPos.x), // Min(mousePosition.y, clickPos.y), // Abs(clickPos.x - mousePosition.x) + 1, // Abs(clickPos.y - mousePosition.y) + 1); } world->Update(); world->Render(framebuffer); } return 0; } 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...
Josh Posted February 1, 2023 Share Posted February 1, 2023 Yeah, the sprite creation code uses a small offset and when scaled that vertex offset will no longer be correct. I am glad I postponed the pixel alignment issues reported with the GUI system, because this all needs to be solved the same way... 2 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...
StOneDOes Posted February 1, 2023 Author Share Posted February 1, 2023 Thanks heaps for the fast response. Its looking good now. And almost chose the exactly colour that I wanted 5 Quote Link to comment Share on other sites More sharing options...
Josh Posted February 1, 2023 Share Posted February 1, 2023 That looks awesome. How are you handling the logic? Do you use the component system or are you treating the soldiers as one big crowd? 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...
StOneDOes Posted February 2, 2023 Author Share Posted February 2, 2023 I haven't really looked too much into the component system. I thought components would be more relevant if I was creating a world using an editor, such that I could change values and whatnot. But most of my things ingame are created by the user I didn't think it necessary. Correct me if I'm wrong? Each playable unit that moves on the ground has a NavAgent, and clearly they all work nicely together. I'm not sure if I like units punching straight through a stationary crowd to get to their destination but I'm sure I can fine tune that. Beyond that I have a unit manager in which every playable object needs to be checked each frame in order to update positions on the minimap and to make sure they correctly come to a halt when they are close enough to their next destination, and of course to auto attack enemy units if they come close enough. I'm open to suggestions if there are better ways. Quote Link to comment Share on other sites More sharing options...
Josh Posted February 2, 2023 Share Posted February 2, 2023 I'm just curious. Something like this would make a nice example. It is possible to make your units affect the navigation mesh when they are stopped. This would make other units navigate around them instead of pushing through the crowd. 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...
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.