Rendering Text in ogre-next

Problems building or running the engine, queries about how to use features etc.
Post Reply
psysu
Halfling
Posts: 56
Joined: Tue Jun 01, 2021 7:47 am
x 2

Rendering Text in ogre-next

Post by psysu »

Hi,

I'm looking into rendering text in an ogre-next application without using overlay. the reason why I don't intend to use overlay system is because overlay objects doesn't really acknowledge RenderQueue's order.

Overlay Objects can either be rendered before v2 Objects or after v2 Objects, can't do both at the same time.

For this reason, I intend to implement a v2 Renderable to render texts. so that i can have control over in which order each object is rendered and control over its depth as well.

Now, my knowledge about text rendering is very limited, i like to know about how text overlay elements are rendered. so that I can try my hand at porting it to v2 objects.

Any resources or samples for this is highly appreciated.

Thanks.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5156
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1219
Contact:

Re: Rendering Text in ogre-next

Post by dark_sylinc »

May I suggest Colibri?

It's a 2D UI rendering library that obeys V2 rules and uses HlmsUnlit customization to render efficiently.

It also has advanced font rendering capabilities such as CJK rendering and RTL (right to left) for languages like Arabic and Hebrew.

The only thing is that Colibri normally assumes that it is rendered as its own layer in its own pass: if you want to interleave stuff (e.g. Render a cube, then text, then a sphere on top of that text, then text again) it would be possible but clunky.

However you can look at ColibriLabel.cpp, ColibriManager::render and HlmsColibri.cpp to see how it's rendered.

For further details you'll have to explain what you're trying to achieve. For example if you only have a few pieces of text that doesn't change very often then perhaps it would just be easier to use FreeType to render your text into a CPU buffer, then upload that as a GPU texture and render that as a single quad.

psysu
Halfling
Posts: 56
Joined: Tue Jun 01, 2021 7:47 am
x 2

Re: Rendering Text in ogre-next

Post by psysu »

I'm working on a labeling feature that a user can label a specific point on a mesh. Also I'm working on a measurement feature that I need to present the distance between two hit points on a mesh as text between those hit points.

I will look into the Colibri library you mentioned as well.

psysu
Halfling
Posts: 56
Joined: Tue Jun 01, 2021 7:47 am
x 2

Re: Rendering Text in ogre-next

Post by psysu »

The only thing is that Colibri normally assumes that it is rendered as its own layer in its own pass: if you want to interleave stuff (e.g. Render a cube, then text, then a sphere on top of that text, then text again) it would be possible but clunky.

Hi,

I created a sample colibri label application. I'm wondering about your answer here, how can I achieve the mixing of order between Ogre::Item and Colibri:: Label. ( Creating a custom pass for this particular case? I'm guessing)

If you can direct me towards it, it'll be really helpful.

Thanks.

psysu
Halfling
Posts: 56
Joined: Tue Jun 01, 2021 7:47 am
x 2

Re: Rendering Text in ogre-next

Post by psysu »

Alright I had Success at what I'm trying to do ( rendering objects in this particular order v2 object( background renderable ), colibri objects, v2 object, colibri object ).

my approach involves creating a separate Pass and Colibri::Manager instances for handling all the objects that is to be rendered before a v2 object rather than doing it from one Colibri::Manager instance. So there will be 2 Ogre::CompositorPassColibriGui & Colibri::Manager instances one for background and another for foreground.

For this implementation, I implemented a custom Ogre::CompositorPassProvider for creating the Colibri Pass Defs and Passes.

this is how my .compositor looks:

Code: Select all

compositor_node RenderingNode
{
    in 0 renderWindow

target renderWindow
{
    pass render_scene
    {
        load 
        {
            all clear
            colour_value 1.0 1.0 1.0 1.0
        }
        store
        {
            colour store_or_resolve
            depth dont_care
            stencil dont_care
        }

        rq_first 6
        rq_last 7

        profiling_id "Bg Pass"
    }

    pass custom dup_colibri_gui // Pass def for handling the backround colibri objects
    {
 
        skip_load_store_semantics true

        profiling_id "Back Colibri GUI"
        aspect_ratio_mode keep_width
    }

    pass render_scene
    {
        skip_load_store_semantics true

        rq_first 7
        rq_last max
        overlays	on
    }

    pass custom colibri_gui // Pass def for handling the foreground colibri objects
    {
        skip_load_store_semantics true

        profiling_id "Front Colibri GUI"
        aspect_ratio_mode keep_width
    }
}
}

Here's where the things feel really clumsy with my approach :)

Because of I'm going with 2 Colibri::Manager instances. Whatever Colibri::Shaper resources i need to register had to be done with both of them. So the resources of Colibri::ShaperManager are kind of duplicated. i want to share these resources between the managers but this is how i did it.

If anything that can be improved with this approach, feel free to share them.

Thanks.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5156
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1219
Contact:

Re: Rendering Text in ogre-next

Post by dark_sylinc »

Awesome!

As for your problem, I think you should be able to use the same ColibriManager for both passes.

Use something like this:

Code: Select all

    pass custom colibri_gui // Note it's no longer a dup
    {
         skip_load_store_semantics true

    identifier 123
    profiling_id "Back Colibri GUI"
    aspect_ratio_mode keep_width
}

pass render_scene
{
    skip_load_store_semantics true

    rq_first 7
    rq_last max
    overlays	on
}

pass custom colibri_gui // Pass def for handling the foreground colibri objects
{
    skip_load_store_semantics true

    identifier 456
    profiling_id "Front Colibri GUI"
    aspect_ratio_mode keep_width
}

Then you register a CompositorWorkspaceListener, create 2 windows and do:

Code: Select all

class MyCompoListener : public Ogre::CompositorWorkspaceListener
{
public:

void passEarlyPreExecute( CompositorPass *pass ) override
{
    const uint32_t identifier = pass->getDefinition()->mIdentifier;
    if( identifier == 123 )
    {
        backgroundWindow->setHidden( false );
        foregroundWindow->setHidden( true );
    }
    else if( identifier == 456 )
    {
        backgroundWindow->setHidden( true );
        foregroundWindow->setHidden( false );
    }
}
};

If this doesn't work perhaps you need to call colibriManager->update() after changing the visibilities.

psysu
Halfling
Posts: 56
Joined: Tue Jun 01, 2021 7:47 am
x 2

Re: Rendering Text in ogre-next

Post by psysu »

Thanks for answering

I tried this approach but i get a "Mapping the buffer twice within the same frame detected! This is not allowed." exception. I'm guessing the render command for the widgets are getting recorded regardless of hiding Colibri::Window through Colibri::Window::setHidden()

i tried updating the colibri manager if the visibilities are changed. Even tried to hide each widget populated in a Colibri::Window, but i get the same exception i mentioned above.

Code: Select all

void passEarlyPreExecute( Ogre::CompositorPass* pPass ) override
    {
        const std::uint32_t& identifier = pPass->getDefinition()->mIdentifier;
        Colibri::ColibriManager* pManager = m_pFrontWindow->getManager();
        bool bVisibilityUpdated = false;

    if( identifier == 123 )
    {
        m_pBackWindow->setVisualsEnabled(true);
        m_pBackWindow->setHidden(false);
        for (auto& widget : m_pBackWindow->getChildren())
        {
            widget->setHidden(false);
        }

        m_pFrontWindow->setVisualsEnabled(false);
        m_pFrontWindow->setHidden(true);
        for (auto& widget : m_pFrontWindow->getChildren())
        {
            widget->setHidden(true);
        }
        bVisibilityUpdated = true;
    }
    else if( identifier == 456 )
    {
        m_pBackWindow->setVisualsEnabled(false);
        m_pBackWindow->setHidden(true);
        for (auto& widget : m_pBackWindow->getChildren())
        {
            widget->setHidden(true);
        }

        m_pFrontWindow->setVisualsEnabled(true);
        m_pFrontWindow->setHidden(false);
        for (auto& widget : m_pFrontWindow->getChildren())
        {
            widget->setHidden(false);
        }

        bVisibilityUpdated = true;
    }   

    if ( bVisibilityUpdated )
    {
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - m_lastUpdateTimePoint);
        auto fDuration = static_cast<float>(duration.count());
        pManager->update(fDuration);

        m_lastUpdateTimePoint = std::chrono::system_clock::now();
    }
}
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5156
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1219
Contact:

Re: Rendering Text in ogre-next

Post by dark_sylinc »

psysu wrote: Tue May 23, 2023 9:03 am

Thanks for answering

I tried this approach but i get a "Mapping the buffer twice within the same frame detected! This is not allowed." exception.

Heh, when I went to sleep I started wondering if this error would happen. This is a Colibri bug as it is expecting to only render once.

If I get some free time I'll see if this can be fixed easily (it's just a matter of cycling more buffers)

psysu
Halfling
Posts: 56
Joined: Tue Jun 01, 2021 7:47 am
x 2

Re: Rendering Text in ogre-next

Post by psysu »

Hi, can you put this as an issue in the repo so that I can track it and integrate it with my application after you fixed it.

Thanks

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5156
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1219
Contact:

Re: Rendering Text in ogre-next

Post by dark_sylinc »

I just added multi_pass branch to test a fix for this.

You must uncomment // #define COLIBRI_MULTIPASS_SUPPORT in ColibriGuiPrerequisites.h

Make sure skip_load_store_semantics is false (it should throw if you don't do this, indicating the bug), because that's a restriction of the fix.

Could you test if this fixes your problem?

psysu
Halfling
Posts: 56
Joined: Tue Jun 01, 2021 7:47 am
x 2

Re: Rendering Text in ogre-next

Post by psysu »

Followed these steps.

Getting a "StagingBuffer cannot map 0 bytes" error causing by line number 1597 on ColibriManager::prepareRenderCommands because "elementsWritten" variable is 0

this is how i setup my scene

Code: Select all

	 m_pFrontFullWindow = m_pColibriManager->createWindow(0);
        m_pBackFullWindow = m_pColibriManager->createWindow(0);
        
m_pFrontFullWindow->setTransform( Ogre::Vector2{ 0, 0 }, Ogre::Vector2{ 450, 0 } ); m_pBackFullWindow->setTransform( Ogre::Vector2{ 0, 0 }, Ogre::Vector2{ 450, 0 } ); { m_pFrontFullWindow->setSize( m_pColibriManager->getCanvasSize() ); m_pFrontFullWindow->setSkin( "EmptyBg" ); m_pFrontFullWindow->setVisualsEnabled( false ); Colibri::Label* pText = m_pColibriManager->createWidget<Colibri::Label>( m_pFrontFullWindow ); pText->setText( "Sample Text That Renders on Front" ); pText->setTextColour(Ogre::ColourValue::Red); pText->sizeToFit(); pText->setTopLeft( Ogre::Vector2{ 700, 700 } ); } { m_pBackFullWindow->setSize( m_pColibriManager->getCanvasSize() ); m_pBackFullWindow->setSkin( "EmptyBg" ); m_pBackFullWindow->setVisualsEnabled( false ); Colibri::Label* pText = m_pColibriManager->createWidget<Colibri::Label>( m_pBackFullWindow ); pText->setText( "Sample Text That Renders on the Back" ); pText->setTextColour(Ogre::ColourValue::Green); pText->sizeToFit(); pText->setTopLeft( Ogre::Vector2{ 350, 700 } ); }

This is how im handling visibilities for the two windows

Code: Select all

void passEarlyPreExecute( Ogre::CompositorPass* pPass ) override
    {
        const std::uint32_t& identifier = pPass->getDefinition()->mIdentifier;
        Colibri::ColibriManager* pManager = m_pFrontWindow->getManager();

    if( identifier == 123 )
    {
        m_pBackWindow->setHidden(false);
        m_pFrontWindow->setHidden(true);
    }
    else if( identifier == 456 )
    {
        m_pBackWindow->setHidden(true);
        m_pFrontWindow->setHidden(false);
    }   

    if( identifier == 123 || identifier == 456 )
    {
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - m_lastUpdateTimePoint);
        auto fDuration = static_cast<float>(duration.count());
        pManager->update(fDuration);

        m_lastUpdateTimePoint = std::chrono::system_clock::now();
    }
}
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5156
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1219
Contact:

Re: Rendering Text in ogre-next

Post by dark_sylinc »

Uploaded a fix for your crash. Please try again.

psysu
Halfling
Posts: 56
Joined: Tue Jun 01, 2021 7:47 am
x 2

Re: Rendering Text in ogre-next

Post by psysu »

Works only on DirectX11 rendering system but on OpenGL3Plus and Vulkan i get a "Mapping the buffer twice within the same frame detected! This is not allowed." exception raised by line 1638 in ColibriManager::render()

Post Reply