Canvas drawing material disrupts User Widget

Hey there!

I’m displaying a User Widget in my HUD class (using AddToViewPort()).
Problem is that one of the widgets disappears when drawing in some ways to the canvas. This only happens in the standalone game. In the editor PIE it all works.

Here’s my DrawHUD function:

void AMyHUD::DrawHUD()
{
    Super::DrawHUD();
    this->Canvas->SetDrawColor(255, 255, 255, 255);

    if (this->UserWidget1)
        DrawUserWidget1(); // simply updates elements in the user widget

    // Drawing a line always works and doesn't interrupt User Widgets
    FCanvasLineItem Line(
                         FVector2D(0.0f, 0.f), FVector2D(Canvas->SizeX, Canvas->SizeY)
                         );
    Line.BlendMode = ESimpleElementBlendMode::SE_BLEND_Translucent;
    Canvas->DrawItem(Line);

    // This seems to interrupt UserWidget2. It’s not displayed any more when this line runs.
    // NOTE: If DrawMaterialTriangle (the one below) is run after DrawMaterialSimple(…) (this line) BOTH user widgets show!!!
    DrawMaterialSimple(this->MyMaterialInstanceDynamic, 0,0,300,300);

    // Though this doesn't seem to be an option for this project, I tested this and it doesn't interrupt user widgets. They both show fine.
    DrawMaterialTriangle(this->MyMaterialInstanceDynamic,
                         FVector2D(0.0f,0.0f),
                         FVector2D(100.0f, 0.0f),
                         FVector2D(100.0f,100.0f),
                         FVector2D(0.0f,0.0f),
                         FVector2D(100.0f, 0.0f),
                         FVector2D(100.0f,100.0f)
                         );

    // With this one, only UserWidget1 displays. UserWidget2 doesn’t display. Even when putting UserWidget2 drawing before UserWidget1 drawing, it won’t display. Putting UserWidget1 at the end of the function results in the same: UW1 is drawn, UW2 is not drawn. Obviously, this then has something to do with the setups of the user widgets (see below).
    // I also tried to move the tile to other positions since UserWidget2 is situated in the center. But moving still has the same results.
    // This seems to be the same as DrawMaterialSimple(…)
    FCanvasTileItem Tile(
                         FVector2D(Canvas->SizeX/2, Canvas->SizeY/2),
                         this->Chargebar->Chargebar->GetRenderProxy(false),
                         FVector2D(Canvas->SizeX*0.2, Canvas->SizeY*0.2)
                         );
    Canvas->DrawItem(Tile);

    // Drawing a simple tile without a material does NOT interrupt the user widgets.
    FCanvasTileItem Tile2(FVector2D(Canvas->SizeX/2, Canvas->SizeY/2), FVector2D(Canvas->SizeX*0.2, Canvas->SizeY*0.2), FLinearColor(1.f, 0,0));
    Canvas->DrawItem(Tile);

    if (this->UserWidget2)
        DrawUserWidget2(); // also just updates widget elements
}

Here is an excerpt of my User Widget hierarchy:

MyHUDUserWidget
    [Canvas Panel]
        [Scale Box]
            UserWidget1 (Overlay) // uses Images with materials
        [Scale Box]
            BackWidget (Overlay) // this is used to just set a UImage with a material as a background. This is also affected by the bug equally as UserWidget2
                UserWidget2 (Overlay) // uses Images with materials

I just found another “fix”. Adding a simple Border widget to BackWidget (see above) “fixes” it.
Where as:

MyHUDUserWidget
    [Canvas Panel]
        [Scale Box]
            UserWidget1 (Overlay)
        [Scale Box]
            BackWidget (Overlay)
                UserWidget2 (Overlay)
                [Border]

results in only the BackWidget showing.
And

MyHUDUserWidget
    [Canvas Panel]
        [Scale Box]
            UserWidget1 (Overlay)
        [Scale Box]
            BackWidget (Overlay)
                [Border]
                UserWidget2 (Overlay)

results in both BackWidget and UserWidget2 showing. So it seems to matter if Border is first or second child of BackWidget.

The core message is probably then:
Why does drawing a tile to canvas with a dynamic material instance interrupt UserWidget2?
Why does DrawMaterialTriangle(…) “fix” this?
Why does adding a Border to UserWidget2 “fix” this?

Hey -

Could you elaborate on what exactly is happening for you? From my understanding you are trying to draw two separate widgets inside your hud class? If you can reproduce this in a new project please include the steps that you used in your setup or send a sample project with this issue occurring.

Cheers

Hey !
Thank you for the answer : ).

Where would I be able to send the such a project to? And eventually the materials that I am using?
Trying to set up a new project just now.

Uff, I can’t set my custom blueprint hud class in the project settings of the blank c++ project which I would need to set the userWidget class to my blueprint userwidget.
Neither am I succeeding in loading the needed widgetClass from the hud’s constructer (in c++).

this->HUDWidgetClass = LoadClass<UUserWidget>(NULL, TEXT("MyWidget"), TEXT("/Game/HUDWidget_C"), LOAD_PackageForPIE, NULL);

this->HUDWidgetClass = StaticLoadClass(UUserWidget::StaticClass(), NULL, TEXT("/Game/HUDWidget_C"));

Both of these fail at loading my UserWidget class that’s in the root of the content folder and return NULL.

Hey -

If you can upload the project to dropbox you can then send me a private message on the forums with a link to download it. What are the errors reported when you try to setup the blank project? Is there any difference in the setup than how you have it set up in your personal project?

I set my custom hud class in the gamemode constructor:

AHUDBUGGameMode::AHUDBUGGameMode(const class FObjectInitializer& OI)
: Super(OI)
{
    this->HUDClass = AMyHUD::StaticClass();
}

My Hud class has a member:

UPROPERTY(EditDefaultsOnly)
TSubclassOf<UUserWidget> HUDWidgetClass;

That I need to set either per blueprint or per its class constructor.
I can’t set the project settings to use my custom blueprint instead of the MyHUD class though because it is greyed out:

Thus I’m trying to set my widget class per c++ constructor like so:

this->HUDWidgetClass = LoadClass<UUserWidget>(NULL, TEXT("MyWidget"), TEXT("/Game/HUDWidget_C"), LOAD_PackageForPIE, NULL);

this->HUDWidgetClass = StaticLoadClass(UUserWidget::StaticClass(), NULL, TEXT("/Game/HUDWidget_C"));

But both are returning a nullptr. So I have no idea how to load my custom HUDWidget class into my HUD.

I have no idea what the reason for this is. Unfortunately, I can’t create the sample project without being able to set the HUDWidget class reference.

Any suggestions on that end?

Hey -

The HUD Class field is grayed out because it is hard set inside the code. If you remove the this->HUDClass = AMyHUD::StaticClass();line from the GameMode constructor then you should be able to create a blueprint based on your custom HUD class and set that as your HUD Class instead.

Cheers

Nope, setting the HUDClass is simply telling the editor what class to use. Deriving blueprints and setting those are usually possible whether or not you customize the standard class to use.

I commented it out, but still I can’t edit any of the standard classes, i.e. still grayed out:

Have no clue why I can’t set my blueprint class…

Hey -

After further testing I found that the HUD Class (and other drop downs in the “Selected GameMode” section) are grayed out when the GameMode that is set is a code class. If you create a blueprint of your game mode these sections become editable and you can set the blueprint of your HUD class.

Thank you, I’ve set up a project and sent you the link to it on the forums. Please let me know if it works to reproduce the bug.

Hey -

I saw the behavior your were talking about when I opened the project and have entered a bug (UE-20516) for investigation.

Cheers