Jump to content

Orthogonal camera skipping frames


StOneDOes
 Share

Go to solution Solved by Josh,

Recommended Posts

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;
}

 

Link to comment
Share on other sites

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.

  • Like 1

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

  • Solution

Here you go.

image.thumb.jpeg.bec5b3dd5ed005178a137a059f2e0efd.jpeg

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;
}

 

  • Upvote 1

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

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...

  • Like 2

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

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.

Link to comment
Share on other sites

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.

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

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...