Jump to content

Edge outline shader example


Josh
 Share

Recommended Posts

This shows how to render specific objects to another texture and display an outline around them:

#include "UltraEngine.h"
#include "ComponentSystem.h"

using namespace UltraEngine;

int main(int argc, const char* argv[])
{
    //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->SetClearColor(0.125);
    camera->SetFov(70);
    camera->SetPosition(0, 0, -3);

    //Create a light
    auto light = CreateBoxLight(world);
    light->SetRotation(35, 45, 0);
    light->SetRange(-10, 10);

    //Create a box
    auto box = CreateBox(world);
    
    //Entity component system
    auto actor = CreateActor(box);
    auto component = actor->AddComponent<Mover>();
    component->rotation.y = 45;

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  
  
    //Render to texture
    box->SetRenderLayers(1 + 2);
    auto cam2 = CreateCamera(world);
    cam2->SetClearColor(0, 0, 0, 0);
    cam2->SetRenderLayers(2);
    cam2->SetFov(camera->GetFov());
    cam2->SetMatrix(camera->matrix);
    cam2->AddPostEffect(LoadPostEffect("Shaders/PostEffects/Outline.json"));
    auto sz = framebuffer->GetSize();
    auto texbuffer = CreateTextureBuffer(sz.x, sz.y);
    cam2->SetRenderTarget(texbuffer);

    //Display overlay
    auto sprite = CreateSprite(world, sz.x, sz.y);
    sprite->SetColor(0, 1, 1, 1);
    sprite->SetRenderLayers(4);
    auto mtl = CreateMaterial();
    sprite->SetMaterial(mtl);
    mtl->SetTransparent(true);
    mtl->SetTexture(texbuffer->GetColorAttachment());
    auto cam3 = CreateCamera(world, PROJECTION_ORTHOGRAPHIC);
    cam3->SetClearMode(CLEAR_DEPTH);
    cam3->SetRenderLayers(4);
    cam3->SetPosition(sz.x * 0.5f, sz.y * 0.5f, 0);

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Main loop
    while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
    {
        world->Update();
        world->Render(framebuffer);
    }
    return 0;
}

 

  • Like 1
  • Thanks 3

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

  • 1 month later...

I think you would want to render the outlined objects each to a separate camera using the render layers feature to control what appears where, and then have a transparent sprite for each one that gets drawn in the final 2D camera.

  • Thanks 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

Outlines drops FPS a lot, noticed only now :D Difference is crazy between 2 and 3 outlines already - from 230-240 to 120-130. RTX 2070, 2K screen res.

Can anything be done about that (in my code or in the engine later) or i should limit my self by 2 outlines?

#include "UltraEngine.h"
#include "Components/Mover.hpp"

using namespace UltraEngine;


enum OUTLINE_TYPE
{
    OUTLINE_RENDER_LAYER = 4,
    OUTLINE_MOVEMENT = 8,
    OUTLINE_TARGET_MOVEMENT = 16,
    OUTLINE_ACTION = 32,
    OUTLINE_SELECTABLE_UNIT = 64,
    OUTLINE_SELECTED_UNIT = 128,
    OUTLINE_ENEMY = 256
};

int main(int argc, const char* argv[])
{
    //Get the displays
    auto displays = GetDisplays();

    //Create a window
    auto window = CreateWindow("Ultra Engine", 0, 0, displays[0]->GetSize().width, displays[0]->GetSize().height, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR | WINDOW_FULLSCREEN);

    //Create a world
    auto world = CreateWorld();

    //Create a framebuffer
    auto framebuffer = CreateFramebuffer(window);

    //Create a camera
    auto camera = CreateCamera(world);
    camera->SetClearColor(0.125);
    camera->SetFov(70);
    camera->SetPosition(3, 0, -5);

    //Create a light
    auto light = CreateBoxLight(world);
    light->SetRotation(35, 45, 0);
    light->SetRange(-10, 10);

    auto gameScene = CreateScene();

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

   
    std::vector<Vec4> outlineColors;
    outlineColors.push_back(Vec4(0.1f, 0.6f, 0.6f, 1));
    outlineColors.push_back(Vec4(0.1f, 0.3f, 1.0f, 1)); 
    outlineColors.push_back(Vec4(0.5f, 0.8f, 0.1f, 1)); 
    outlineColors.push_back(Vec4(0.1f, 0.6f, 0.1f, 1));   
    outlineColors.push_back(Vec4(0.1f, 1.0f, 0.1f, 1)); 
    outlineColors.push_back(Vec4(0.8f, 0.1f, 0.1f, 1)); 
    auto sz = framebuffer->GetSize();
    for (int i = 0; i < outlineColors.size(); i++)
    {
        auto renderToTextureCamera = CreateCamera(world);
        renderToTextureCamera->SetClearColor(0, 0, 0, 0);
        renderToTextureCamera->SetRenderLayers(OUTLINE_MOVEMENT << i);
        renderToTextureCamera->SetFov(camera->GetFov());
        renderToTextureCamera->SetMatrix(camera->matrix);
        renderToTextureCamera->AddPostEffect(LoadPostEffect("Shaders/PostEffects/Outline.json"));
        auto texbuffer = CreateTextureBuffer(sz.x, sz.y);
        renderToTextureCamera->SetRenderTarget(texbuffer);
        gameScene->AddEntity(renderToTextureCamera);
        //Display overlay
        auto displayOverlaySprite = CreateSprite(world, sz.x, sz.y);
        displayOverlaySprite->SetColor(outlineColors[i]);
        displayOverlaySprite->SetRenderLayers(OUTLINE_RENDER_LAYER);
        auto displayOverlayMaterial = CreateMaterial();
        displayOverlayMaterial->SetTransparent(true);
        displayOverlayMaterial->SetTexture(texbuffer->GetColorAttachment());
        displayOverlaySprite->SetMaterial(displayOverlayMaterial);
        gameScene->AddEntity(displayOverlaySprite);
        //Box
        auto box = CreateBox(world);
        box->SetPosition(i, 0, 0);
        box->SetRenderLayers(1 + (OUTLINE_MOVEMENT << i));
        gameScene->AddEntity(box);

    }
    auto overlayCamera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC);
    overlayCamera->SetClearMode(CLEAR_DEPTH);
    overlayCamera->SetRenderLayers(OUTLINE_RENDER_LAYER);
    overlayCamera->SetPosition(sz.x * 0.5f, sz.y * 0.5f, 0);
    gameScene->AddEntity(overlayCamera);

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Main loop
    while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
    {
        world->Update();
        world->Render(framebuffer);
    }
    return 0;
}

 

Link to comment
Share on other sites

The shader does a lot of texture lookups. If you increased the thickness, it will be even more.

The current implementation could be improved by downsampling either the depth buffer or maybe a first-pass color texture, with linear filtering. This could be used as a preliminary rough check in the final subpass, because if the value of a texture read is non-zero, it means there is some highlighted pixels in that area.

  • Thanks 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

1 hour ago, Josh said:

The current implementation could be improved by downsampling either the depth buffer or maybe a first-pass color texture, with linear filtering.

tbh i have no idea how to do this since i don't know much about graphic programing, especially in Vulkan.

Anyway it's looks shader is not what degrades perfomance. Removed AddPostEffect() - same low fps.

Just realized you probably meant Outline.json and not frag :D Anyway this did not helped.

 

        "buffers":
        [
            {
                "size": [0.5, 0.5]
            }         
        ],

 

Edited by Dreikblack
Link to comment
Share on other sites

Yeah, I think it is actually mostly the full-screen transparent blend that is being drawn seven times.

I tried combining all the passes into a single texture buffer. You would still need to change the color for each pass somehow, but currently this does not draw anything when I run it:
 

#include "UltraEngine.h"

using namespace UltraEngine;


enum OUTLINE_TYPE
{
    OUTLINE_RENDER_LAYER = 4,
    OUTLINE_MOVEMENT = 8,
    OUTLINE_TARGET_MOVEMENT = 16,
    OUTLINE_ACTION = 32,
    OUTLINE_SELECTABLE_UNIT = 64,
    OUTLINE_SELECTED_UNIT = 128,
    OUTLINE_ENEMY = 256
};

int main(int argc, const char* argv[])
{
    //Get the displays
    auto displays = GetDisplays();

    //Create a window
    auto window = CreateWindow("Ultra Engine", 0, 0, displays[0]->GetSize().width, displays[0]->GetSize().height, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR | WINDOW_FULLSCREEN);

    //Create a world
    auto world = CreateWorld();

    //Create a framebuffer
    auto framebuffer = CreateFramebuffer(window);

    //Create a camera
    auto camera = CreateCamera(world);
    camera->SetClearColor(0.125);
    camera->SetFov(70);
    camera->SetPosition(3, 0, -5);

    //Create a light
    auto light = CreateBoxLight(world);
    light->SetRotation(35, 45, 0);
    light->SetRange(-10, 10);

    auto gameScene = CreateScene();

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    std::vector<Vec4> outlineColors;
    outlineColors.push_back(Vec4(0.1f, 0.6f, 0.6f, 1));
    outlineColors.push_back(Vec4(0.1f, 0.3f, 1.0f, 1));
    outlineColors.push_back(Vec4(0.5f, 0.8f, 0.1f, 1));
    outlineColors.push_back(Vec4(0.1f, 0.6f, 0.1f, 1));
    outlineColors.push_back(Vec4(0.1f, 1.0f, 0.1f, 1));
    outlineColors.push_back(Vec4(0.8f, 0.1f, 0.1f, 1));
    auto sz = framebuffer->GetSize();

    auto texbuffer = CreateTextureBuffer(sz.x, sz.y);
    
    //Display overlay
    auto displayOverlaySprite = CreateSprite(world, sz.x, sz.y);
    displayOverlaySprite->SetRenderLayers(OUTLINE_RENDER_LAYER);
    auto displayOverlayMaterial = CreateMaterial();
    displayOverlayMaterial->SetTransparent(true);
    displayOverlayMaterial->SetTexture(texbuffer->GetColorAttachment());
    displayOverlaySprite->SetMaterial(displayOverlayMaterial);
    gameScene->AddEntity(displayOverlaySprite);

    for (int i = 0; i < outlineColors.size(); i++)
    {
        auto renderToTextureCamera = CreateCamera(world);
        renderToTextureCamera->SetClearColor(0, 0, 0, 0);
        if (i > 0) renderToTextureCamera->SetClearMode(ClearMode(0));
        renderToTextureCamera->SetRenderLayers(OUTLINE_MOVEMENT << i);
        renderToTextureCamera->SetFov(camera->GetFov());
        renderToTextureCamera->SetMatrix(camera->matrix);
        renderToTextureCamera->AddPostEffect(LoadPostEffect("Shaders/PostEffects/Outline.json"));
        renderToTextureCamera->SetRenderTarget(texbuffer);
        gameScene->AddEntity(renderToTextureCamera);

        //Box
        auto box = CreateBox(world);
        box->SetPosition(i, 0, 0);
        box->SetRenderLayers(1 + (OUTLINE_MOVEMENT << i));
        gameScene->AddEntity(box);

    }
    auto overlayCamera = CreateCamera(world, PROJECTION_ORTHOGRAPHIC);
    overlayCamera->SetClearMode(CLEAR_DEPTH);
    overlayCamera->SetRenderLayers(OUTLINE_RENDER_LAYER);
    overlayCamera->SetPosition(sz.x * 0.5f, sz.y * 0.5f, 0);
    gameScene->AddEntity(overlayCamera);

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Main loop
    while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
    {
        world->Update();
        world->Render(framebuffer, false);
    }
    return 0;
}

 

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

23 minutes ago, Josh said:

I tried combining all the passes into a single texture buffer. You would still need to change the color for each pass somehow

Not really sure how to do it and i still have 70 fps with single texture buffer. For a test i hide cameras in cycle (renderToTextureCamera->SetHidden(true)) and got 700 fps.

Link to comment
Share on other sites

It would probably be best to create another object for each outlined object, set it to use the unlit shader family, and in the post effect use the object's color as the color written into the texture buffer. Then you can have multiple colors in a single pass.

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

20 minutes ago, Josh said:

in the post effect use the object's color as the color written into the texture buffer

Do you mean Outline.frag by post effect in this context? Sorry, I'm not quite follow you :lol:Is whole set from signle outline (cameras, buffer. sprite etc.) still needed for this? 

Link to comment
Share on other sites

Right now the color is controlled by setting the color of the overlay sprite. I am saying that instead it could be controlled in the outline shader, by getting the color that was rendered and using that instead of just writing vec4(1,1,1,1) like it currently does.

  • Thanks 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

On 5/24/2023 at 4:28 PM, Josh said:

getting the color that was rendered and using that instead

I just don't know how to get this color in .frag. Trying this but nothing happens:

#version 450
#extension GL_GOOGLE_include_directive : enable
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_multiview : enable

#include "../Base/PushConstants.glsl"
#include "../Base/CameraInfo.glsl"
#include "../Base/TextureArrays.glsl"
#include "../Utilities/Dither.glsl"

layout(location = 0) in vec2 texCoords;
layout(location = 0) out vec4 outColor;

const vec4 SelectionColor = vec4(1,1,1,1);

void main()
{
    outColor = SelectionColor;
    outColor.a = 0.0f;
    
    float depth = texture(texture2DSampler[PostEffectTexture0], texCoords.xy).r;

    vec4 c;
    bool sel;

    //Handle selected objects
    if (depth < 1.0f)
    {
        const int m = 3;
        vec2 pixelsize = 1.0f / BufferSize;
        for (int x = -m; x <= m; ++x)
        {
            for (int y = -m; y <= m; ++y)
            {
                if (x == 0 && y == 0) continue;
                float neighbor = texture(texture2DSampler[PostEffectTexture0], texCoords.xy + pixelsize * vec2(x, y)).r;
                if (neighbor == 1.0f)
                {
                    outColor = texture(texture2DSampler[PostEffectTexture0], texCoords.xy);
                    return;
                }
            }
        }
    }
}
#include "UltraEngine.h"
#include "Components/Mover.hpp"

using namespace UltraEngine;

int main(int argc, const char* argv[])
{
    //Get the displays
    auto displays = GetDisplays();

    //Create a window
    auto window = CreateWindow("Ultra Engine", 0, 0, displays[0]->GetSize().width, displays[0]->GetSize().height, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR | WINDOW_FULLSCREEN);

    //Create a world
    auto world = CreateWorld();

    //Create a framebuffer
    auto framebuffer = CreateFramebuffer(window);

    //Create a camera
    auto camera = CreateCamera(world);
    camera->SetClearColor(0.125);
    camera->SetFov(70);
    camera->SetPosition(0, 0, -3);

    //Create a light
    auto light = CreateBoxLight(world);
    light->SetRotation(35, 45, 0);
    light->SetRange(-10, 10);

    //Create a box
    auto box = CreateBox(world);
    box->SetColor(0.5f, 0.5f, 0);
    auto outlineBox = CreateBox(world);
    outlineBox->SetColor(0, 0, 1);

    auto material = CreateMaterial();
    auto unlitShader = LoadShaderFamily("Shaders/Unlit.json");
    material->SetShaderFamily(unlitShader);
    outlineBox->SetMaterial(material);

    //Entity component system
    auto component = box->AddComponent<Mover>();
    component->rotationspeed.y = 45;
    auto component2 = outlineBox->AddComponent<Mover>();
    component2->rotationspeed.y = 45;

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Render to texture
    outlineBox->SetRenderLayers(1 + 2);
    auto cam2 = CreateCamera(world);
    cam2->SetClearColor(0, 0, 0, 0);
    cam2->SetRenderLayers(2);
    cam2->SetFov(camera->GetFov());
    cam2->SetMatrix(camera->matrix);
    cam2->AddPostEffect(LoadPostEffect("Shaders/PostEffects/Outline.json"));
    auto sz = framebuffer->GetSize();
    auto texbuffer = CreateTextureBuffer(sz.x, sz.y);
    cam2->SetRenderTarget(texbuffer);

    ////Display overlay
    auto sprite = CreateSprite(world, sz.x, sz.y);
   // sprite->SetColor(0, 1, 1, 1);
    sprite->SetRenderLayers(4);
    auto mtl = CreateMaterial();
    sprite->SetMaterial(mtl);
    mtl->SetTransparent(true);
    mtl->SetTexture(texbuffer->GetColorAttachment());
    auto cam3 = CreateCamera(world, PROJECTION_ORTHOGRAPHIC);
    cam3->SetClearMode(CLEAR_DEPTH);
    cam3->SetRenderLayers(4);
    cam3->SetPosition(sz.x * 0.5f, sz.y * 0.5f, 0);

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Main loop
    while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
    {
        world->Update();
        world->Render(framebuffer, false);
    }
    return 0;
}

 

Link to comment
Share on other sites

In outline.json, I think if you add the previous pass into the samplers it will be available in slot 1 (PostEffectTexture1):

                "samplers": ["DEPTH", "PREVPASS"],

Have not actually tried it.

  • Thanks 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

Still no outline with main.cpp above:

{
  "postEffect": {
    "subpasses": [
      {
        "samplers": [ "DEPTH", "PREVPASS"],
        "shader": {
          "float32": {
            "fragment": "Shaders/Outline.frag.spv"
          }
        }
      }
    ]
  }
}
#version 450
#extension GL_GOOGLE_include_directive : enable
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_multiview : enable

#include "../Base/PushConstants.glsl"
#include "../Base/CameraInfo.glsl"
#include "../Base/TextureArrays.glsl"
#include "../Utilities/Dither.glsl"

layout(location = 0) in vec2 texCoords;
layout(location = 0) out vec4 outColor;

void main()
{
    outColor = texture(texture2DSampler[PostEffectTexture1], texCoords.xy);
    outColor.a = 0.0f;
    
    float depth = texture(texture2DSampler[PostEffectTexture0], texCoords.xy).r;

    vec4 c;
    bool sel;

    //Handle selected objects
    if (depth < 1.0f)
    {
        const int m = 3;
        vec2 pixelsize = 1.0f / BufferSize;
        for (int x = -m; x <= m; ++x)
        {
            for (int y = -m; y <= m; ++y)
            {
                if (x == 0 && y == 0) continue;
                float neighbor = texture(texture2DSampler[PostEffectTexture0], texCoords.xy + pixelsize * vec2(x, y)).r;
                if (neighbor == 1.0f)
                {
                    outColor = texture(texture2DSampler[PostEffectTexture1], texCoords.xy);
                    return;
                }
            }
        }
    }
}

 

Link to comment
Share on other sites

Damn, it was correct .frag this time - i just had few mistakes in a code.

image.thumb.png.546dff52d152b1a3f635e0eb1ef59142.png

#include "UltraEngine.h"
#include "Components/Mover.hpp"

using namespace UltraEngine;

int main(int argc, const char* argv[])
{
    //Get the displays
    auto displays = GetDisplays();

    //Create a window
    auto window = CreateWindow("Ultra Engine", 0, 0, displays[0]->GetSize().width, displays[0]->GetSize().height, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR | WINDOW_FULLSCREEN);

    //Create a world
    auto world = CreateWorld();

    //Create a framebuffer
    auto framebuffer = CreateFramebuffer(window);

    //Create a camera
    auto camera = CreateCamera(world);
    camera->SetClearColor(0.125);
    camera->SetFov(70);
    camera->SetPosition(0, 0, -3);

    //Create a light
    auto light = CreateBoxLight(world);
    light->SetRotation(35, 45, 0);
    light->SetRange(-10, 10);

    //Create a box
    auto box = CreateBox(world);
    box->SetColor(1, 0, 0);
    auto outlineBox = CreateBox(world);
    outlineBox->SetColor(0, 1, 0);

    auto material = CreateMaterial();
    auto unlitShader = LoadShaderFamily("Shaders/Unlit.json");
    material->SetShaderFamily(unlitShader);
    outlineBox->SetMaterial(material);

    //Create a box2 
    auto box2 = CreateBox(world);
    box2->SetColor(1, 0, 0);
    auto outlineBox2 = CreateBox(world);
    outlineBox2->SetColor(0, 0, 1);

    auto material2 = CreateMaterial();
    auto unlitShader2 = LoadShaderFamily("Shaders/Unlit.json");
    material2->SetShaderFamily(unlitShader);
    outlineBox2->SetMaterial(material);

    outlineBox2->SetPosition(2, 0, 0);
    box2->SetPosition(2, 0, 0);

    //Entity component system
    auto component = box->AddComponent<Mover>();
    component->rotationspeed.y = 45;

    auto outlineComponent = outlineBox->AddComponent<Mover>();
    outlineComponent->rotationspeed.y = 45;

    auto component2 = box2->AddComponent<Mover>();
    component2->rotationspeed.y = 45;

    auto outlineComponent2 = outlineBox2->AddComponent<Mover>();
    outlineComponent2->rotationspeed.y = 45;

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Render to texture
    outlineBox->SetRenderLayers(2);
    outlineBox2->SetRenderLayers(2);
    auto cam2 = CreateCamera(world);
    cam2->SetClearColor(0, 0, 0, 0);
    cam2->SetRenderLayers(2);
    cam2->SetFov(camera->GetFov());
    cam2->SetMatrix(camera->matrix);
    cam2->AddPostEffect(LoadPostEffect("Shaders/PostEffects/Outline.json"));
    auto sz = framebuffer->GetSize();
    auto texbuffer = CreateTextureBuffer(sz.x, sz.y);
    cam2->SetRenderTarget(texbuffer);

    ////Display overlay
    auto sprite = CreateSprite(world, sz.x, sz.y);
    sprite->SetRenderLayers(4);
    auto mtl = CreateMaterial();
    sprite->SetMaterial(mtl);
    mtl->SetTransparent(true);
    mtl->SetTexture(texbuffer->GetColorAttachment());
    auto cam3 = CreateCamera(world, PROJECTION_ORTHOGRAPHIC);
    cam3->SetClearMode(CLEAR_DEPTH);
    cam3->SetRenderLayers(4);
    cam3->SetPosition(sz.x * 0.5f, sz.y * 0.5f, 0);


    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Main loop
    while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
    {
        world->Update();
        world->Render(framebuffer, false);
    }
    return 0;
}

 

  • Like 1
Link to comment
Share on other sites

I have a new problem with this implementation- can't see outline of first object if it's above another one. It's crucial for cases when selected (and outlined) unit stays on outlined tiles (which shows where can unit go to) :( (also i used to outline avaiable tile under cursor with another color ad can't see it now as well)

    outlineBox2->SetPosition(0.5f, 0.5f, 0);
    box2->SetPosition(0.5f, 0.5f, 0);

image.thumb.png.f06eb39c448563aabce68d1962b2ccee.png

Link to comment
Share on other sites

That makes sense, because the drawing is being combined into one depth buffer. So I guess you have to choose. Maybe this isn't the best effect to use in your game.

  • Sad 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

Replaced tile outlines with brushed. Better perfomance and i think it's looks better.

image.png.fa468612d5610ccfaeae79283bda507e.png

But even one camera outline still degrade perfomance significantly and i wonder how to do proper downsampling for outline. I don't know what am i doing wrong in Outline.json for that:

{
  "postEffect": {
    "buffers": [
      {
        "size": [ 0.25, 0.25 ]
      }
    ],
    "subpasses": [
      {
        "samplers": [ "DEPTH", "PREVPASS" ],
        "shader": {
          "float32": {
            "fragment": "Shaders/Outline.frag.spv"
          }
        }
      }
    ]
  }
}

 

  • Like 1
Link to comment
Share on other sites

  • 6 months later...

Does not work anymore in latest dev beta branch:

#include "UltraEngine.h"
#include "ComponentSystem.h"

using namespace UltraEngine;

int main(int argc, const char* argv[])
{
    //Get the displays
    auto displays = GetDisplays();

    //Create a window
    auto window = CreateWindow("Ultra Engine", 0, 0, 1200, 800, 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->SetClearColor(0.125);
    camera->SetFov(70);
    camera->SetPosition(0, 0, -3);

    //Create a light
    auto light = CreateBoxLight(world);
    light->SetRotation(35, 45, 0);
    light->SetRange(-10, 10);

    //Create a box
    auto box = CreateBox(world);
    box->SetColor(1, 0, 0);
    auto outlineBox = CreateBox(world);
    outlineBox->SetColor(0, 1, 0);

    auto material = CreateMaterial();
    auto unlitShader = LoadShaderFamily("Shaders/Unlit.fam");
    material->SetShaderFamily(unlitShader);
    outlineBox->SetMaterial(material);

    //Create a box2 
    auto box2 = CreateBox(world);
    box2->SetColor(1, 0, 0);
    auto outlineBox2 = CreateBox(world);
    outlineBox2->SetColor(0, 0, 1);

    auto material2 = CreateMaterial();
    auto unlitShader2 = LoadShaderFamily("Shaders/Unlit.fam");
    material2->SetShaderFamily(unlitShader);
    outlineBox2->SetMaterial(material);

    outlineBox2->SetPosition(2, 0, 0);
    box2->SetPosition(2, 0, 0);

    //Entity component system
    auto component = box->AddComponent<Mover>();
    component->rotationspeed.y = 45;

    auto outlineComponent = outlineBox->AddComponent<Mover>();
    outlineComponent->rotationspeed.y = 45;

    auto component2 = box2->AddComponent<Mover>();
    component2->rotationspeed.y = 45;

    auto outlineComponent2 = outlineBox2->AddComponent<Mover>();
    outlineComponent2->rotationspeed.y = 45;

    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Render to texture
    outlineBox->SetRenderLayers(2);
    outlineBox2->SetRenderLayers(2);

    auto cam2 = CreateCamera(world);
    cam2->SetClearColor(0, 0, 0, 0);
    cam2->SetRenderLayers(2);
    cam2->SetFov(camera->GetFov());
    cam2->SetMatrix(camera->matrix);
    cam2->AddPostEffect(LoadPostEffect("Shaders/Outline.fx"));

    auto sz = framebuffer->GetSize();
    auto texbuffer = CreateTextureBuffer(sz.x, sz.y);
    cam2->SetRenderTarget(texbuffer);

    ////Display overlay
    auto sprite = CreateSprite(world, sz.x, sz.y);
    sprite->SetRenderLayers(4);
    auto mtl = CreateMaterial();
    sprite->SetMaterial(mtl);
    mtl->SetTransparent(true);
    mtl->SetTexture(texbuffer->GetColorAttachment());
    auto cam3 = CreateCamera(world, PROJECTION_ORTHOGRAPHIC);
    cam3->SetClearMode(CLEAR_DEPTH);
    cam3->SetRenderLayers(4);
    cam3->SetPosition(sz.x * 0.5f, sz.y * 0.5f, 0);


    //------------------------------------------------------------------------------------  
    //------------------------------------------------------------------------------------  

    //Main loop
    while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false)
    {
        world->Update();
        world->Render(framebuffer, false);
    }
    return 0;
}
#version 450
#extension GL_GOOGLE_include_directive : enable
#extension GL_ARB_separate_shader_objects : enable
#extension GL_EXT_multiview : enable

#include "../Base/PushConstants.glsl"
#include "../Base/CameraInfo.glsl"
#include "../Base/TextureArrays.glsl"
#include "../Utilities/Dither.glsl"

layout(location = 0) in vec2 texCoords;
layout(location = 0) out vec4 outColor;

void main()
{
    outColor = texture(texture2DSampler[PostEffectTextureID1], texCoords.xy);
    outColor.a = 0.0f;
    
    float depth = texture(texture2DSampler[PostEffectTextureID0], texCoords.xy).r;

    //Handle selected objects
    if (depth < 1.0f)
    {
        const int m = 4;
        vec2 pixelsize = 1.0f / BufferSize;
        for (int x = -m; x <= m; ++x)
        {
            for (int y = -m; y <= m; ++y)
            {
                if (x == 0 && y == 0) continue;
                float neighbor = texture(texture2DSampler[PostEffectTextureID0], texCoords.xy + pixelsize * vec2(x, y)).r;
                if (neighbor == 1.0f)
                {
                    outColor = texture(texture2DSampler[PostEffectTextureID1], texCoords.xy);
                    return;
                }
            }
        }
    }
}

image.thumb.png.85d3a1ecd4fbe54de65c4af786667e5b.png

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