x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

[Closed] Slate resource preloading

Hi,

I have a working interface with Slate. However, I notice that the first loading of some brushes can be visible. For example, a button with a brush on SetHovered() will noticeably flash the first time you hover onto it. After that, it works like a charm.

I took a look at the GetResources() method, I listed all my brushes here. Is there anything more to do ?

The code here shows the beginning of my Construct() method.

     const FSButtonStyle* Helper= &StyleRef::Get().GetWidgetStyle<FSButtonStyle>("...");
     ButtonStyle.SetDisabled(ButtonStyleHelper->WidgetBackground);
     ButtonStyle.SetNormal(Helper->WidgetBackground);
     ButtonStyle.SetHovered(Helper->ActiveWidgetBackground);
     ButtonStyle.SetPressed(Helper->ActiveWidgetBackground);

     // ... 

     SNew(SButton).ButtonStyle(&ButtonStyle)

Now the FSButtonStyle code :

 void FSButtonStyle::GetResources(TArray<const FSlateBrush*>& OutBrushes) const
 {
     OutBrushes.Add(&WidgetBackground);
     OutBrushes.Add(&ActiveWidgetBackground);
 }

 UPROPERTY(EditAnywhere, Category = Background) FSlateBrush WidgetBackground;

 UPROPERTY(EditAnywhere, Category = Background) FSlateBrush ActiveWidgetBackground;

What am I doing wrong ?

Product Version: Not Selected
Tags:
more ▼

asked Apr 13 '14 at 03:59 PM in C++ Programming

avatar image

StrangerGwenn
594 55 64 133

avatar image Jamie Dale STAFF Apr 14 '14 at 09:17 AM

What size are your textures, and are they being tiled?

The code inside FSlateD3DTextureManager::CreateTextures handles loading the textures needed by a style set, and will also create a texture atlas for any textures smaller than 256x256 that are not being tiled by a brush.

avatar image StrangerGwenn Apr 14 '14 at 05:20 PM

The texture I use to reproduce the issue is never tiled and is 150x50 in size.

avatar image Jamie Dale STAFF Apr 14 '14 at 09:11 PM

Wait, have you derived FSButtonStyle from FButtonStyle? If you have then you also need to call the parent version of GetResources:

 void FSButtonStyle::GetResources(TArray<const FSlateBrush*>& OutBrushes) const
 {
     FButtonStyle::GetResources(OutBrushes);
     OutBrushes.Add(&WidgetBackground);
     OutBrushes.Add(&ActiveWidgetBackground);
 }

Also, widget styles are really designed to work via composition rather than inheritance, in the same way that Slate widgets are.

Could you also check the texture atlas (Windows -> Development Tools -> Debug Tools -> Display Texture Atlases) and verify that the images used by your brushes exist in that texture.

As an aside, you're also setting up your widget style in a slightly strange way. Really that should either be done via an asset in the editor (if it's for a game) or via C++ (if it's for the editor) - that said there's nothing wrong with using C++ style sets for a game, providing you're using a game specific style set.

Example C++ version.

In your style set:

 Style->Set("TestButtonStyle", FButtonStyle()
     .SetDisabled(IMAGE_BRUSH("Tex1", FVector2D(150, 50)))
     .SetNormal(IMAGE_BRUSH("Tex1", FVector2D(150, 50)))
     .SetHovered(IMAGE_BRUSH("Tex1_Hover", FVector2D(150, 50)))
     .SetPressed(IMAGE_BRUSH("Tex1", FVector2D(150, 50)))
     );

When using your button:

 SNew(SButton)
 .ButtonStyle(FMyStyle::Get(), "TestButtonStyle")

I've made a test set-up with the above code and they appear in the atlas and don't suffer from flickering.

avatar image StrangerGwenn Apr 14 '14 at 09:21 PM

Wait, have you derived FSButtonStyle from FButtonStyle?

No I don't, the class inherits from FSlateWidgetStyle. Should I call the parent too ?

Could you also check the texture atlas (Windows -> Development Tools -> Debug Tools -> Display Texture Atlases) and verify that the images used by your brushes exist in that texture.

I don't see them, but I actually don't see anything I created. I have backgrounds, borders, lots of stuff actually. None of it is showing up. I also should say that the atlas window is larger than my 1080p screen, so I don't see the menus or window title. I do see the border so I can confirm that the assets are not here.

As an aside, you're also setting up your widget style in a slightly strange way. Really that should either be done via an asset in the editor (if it's for a game) or via C++ (if it's for the editor).

Yeah, kind of wrong I know. I had just done the text thing (you know, the text style asset that can't be used...) and I didn't check, but I could actually just remove this class and use FButtonStyle directly.

avatar image Jamie Dale STAFF Apr 14 '14 at 09:24 PM

Ah, I see, I thought you were passing FSButtonStyle here:

 SNew(SButton).ButtonStyle(&ButtonStyle)

But that's actually defined elsewhere. Is it part of a style-set, and is it relevant to this example, or is it only WidgetBackground and ActiveWidgetBackground that have an issue?

avatar image StrangerGwenn Apr 14 '14 at 09:32 PM

Yeah, my example is unclear. What I am doing right now is actually copying the pointers to the slate brushes ; from the FSButtonStyle instance to a FButtonStyle.

It's kind of ugly and I guess you're going to tell me that it's also what causes the issue, but I also have the same issue on another class. In this other class, I load a custom widget style and store it's reference. Later, in a FSlateBrush* callback, I return one of the brushes to be used as a SBorder background, like you showed me in one of your posts.

avatar image StrangerGwenn Apr 14 '14 at 09:49 PM

Okay, so small update : I removed this entire class. Now I'm just passing a const FButtonStyle* to a SButton, very simple and clean. It still flickers.

avatar image Jamie Dale STAFF Apr 14 '14 at 09:56 PM

Okay, thanks.

So nothing from your style set is showing in the atlas? You've definitely called FSlateStyleRegistry::RegisterSlateStyle(*StylePtr)? (I'm sure you have since I remember helping you with an issue related to style set registration and module reloading, but I'd just like to double check).

If so, could you check FSlateRHIResourceManager::LoadStyleResources and verify that you're seeing the resources you expect when it's called for your style. From there you should be able to see it create/load/atlas the textures.

avatar image StrangerGwenn Apr 14 '14 at 10:35 PM

Yeah I called it, I just checked, along with the LoadStyleResources. So after a fresh debug build, it looks like every method that should be called is called, including the GetResources of my faulty style, one of those who flicker.

avatar image Jamie Dale STAFF Apr 14 '14 at 10:38 PM

Okay. Are you able to provide me the exact textures you're using? I'll take a look with them tomorrow to see if there's anything obvious I can see.

If you'd rather not post them publicly, I can provide my email address for you to send them to - if so I'll PM you on the forum as I'd rather not post that on here :)

avatar image StrangerGwenn Apr 14 '14 at 10:42 PM

Here they are, both the "normal" brush used on deactivated/normal states, and the "active" brush when hovering and pressing.

alt text

alt text

On a side note, I have the issue with at least another set like this one that I know of.

avatar image Jamie Dale STAFF Apr 14 '14 at 11:13 PM

I've tried those images but I still see them get loaded and atlassed correctly, and they render without any flickering from visibly being loaded.

I've attached my test case for you to take a look at. If you could give it a go and let me know if you see the same issue with it, that would be great.

It's the bare minimum to keep it small enough for AnswerHub, so:

  1. Create a new project called "MyTestFirstPerson" from the "Code First Person" template, making sure to include starter content.

  2. Place the zip file in the root of the project (where the .uproject file is) and extract it, overwriting any files that you're prompted for.

  3. Build the "MyTestFirstPerson" and run the editor. If you PIE you should see your button in the top center of the viewport. You should also see the button textures in the texture atlas.

[1]: /storage/temp/4074-mytestfirstperson.zip

avatar image Jamie Dale STAFF Apr 14 '14 at 11:14 PM

The files of interest would be MyTestFirstPersonStyle.cpp and MyTestFirstPersonHUD.cpp as these are what set-up and use the button style.

avatar image StrangerGwenn Apr 14 '14 at 11:52 PM

Thanks a lot for doing all of this !

So your test case works, of course. I took a look at what we're not doing the same way, and your style class has different initialization than ShooterGame's (FSlateStyleSet vs FSlateGameResources).

Before :

TSharedRef StyleRef = FSlateGameResources::New(FName("MyStyle"), "/Game/Slate", "/Game/Slate");

After :

TSharedRef StyleRef = MakeShareable(new FSlateStyleSet("MyStyle")); StyleRef->SetContentRoot(FPaths::GameContentDir() / "Slate");

But I can't try it because this breaks all my asset paths. I can't load a single style anymore :

Unable to find Slate Widget Style '/Styles/SS_Panel_Default'. Using FSWindowStyle defaults instead.

I don't get it. I am using a Slate folder in Content, with subfolders (Styles, Brushes, etc). Then I call GetWidgetStyle with, here, "Styles/SS_Panel_Default" as parameter, Content/Slate/Styles/SS_Panel_Default being the actual full path.

Any idea ? Is this related ? Should I try to load from PNGs instead of styles ?

avatar image Jamie Dale STAFF Apr 15 '14 at 09:46 AM

Ah, right. I just used that as an example since I spend more time in editor code than game code, so I'm more familiar with it.

I changed the FSlateStyleSet to an FSlateGameResources, and there was still no flickering.

I then added an asset for a button widget style and set it up as I had in code, updating my SButton to use this style. This flickered, and doesn't appear in the atlas. I assume this is how you're using the button style (as an asset)?

It seems only those textures loaded from disk are atlased. I'll check this with someone and get back to you.

avatar image StrangerGwenn Apr 15 '14 at 10:56 AM

Yeah, I am using assets.

Thanks !

avatar image StrangerGwenn Apr 15 '14 at 06:41 AM

Okay so it's probably not the method name since the gameresource constructor calls the gamestyle constructor.

But I have another idea. In your sample, you load the PNGs directly in the style class. I don't load anything in my class, I load the styles in the Construct() method. Here is the typical code :

  ButtonStyle = MyGameStyle::Get().GetWidgetStyle(FName(*InArgs._StyleName));
  ChildSlot     [
      SAssignNew(PhysicalButton, SButton)
      .ButtonStyle(ButtonStyle)     ];

So maybe that's the issue ? The style is not referenced until late in the gameplay, so how could the atlas be constructed ?

avatar image Jamie Dale STAFF Apr 15 '14 at 09:49 AM

As an aside, SLATE_STYLE_ARGUMENT has syntactic sugar for taking either a const ISlateStyle* or const ISlateStyle& and a FName. This is the preferred form when setting a style from a style set (for your case above).

 .ButtonStyle(MyGameStyle::Get(), InArgs._StyleName)
(comments are locked)
10|2000 characters needed characters left
Viewable by all users

The question has been closed Apr 28 '15 at 07:43 AM by StrangerGwenn for the following reason:

The question is answered, right answer was accepted


1 answer: sort voted first

MattK has taken a look at this and found a bug in the Slate resource loading that was leading to a one frame delay between requesting the texture, and the texture actually being used.

This fix will be in 4.2, however it's small, and if you're building from source you can try it out yourself before then.

Open up SlateRHIResourceManager.cpp (UE4\Engine\Source\Runtime\SlateRHIRenderer\Private).

Inside the constructor for FDynamicTextureResource, add the following line:

 Proxy->Resource = RHIRefTexture;

Inside FSlateRHIResourceManager::InitializeDynamicTextureResource, remove the following line:

 TextureResource->Proxy->Resource = TextureResource->RHIRefTexture;




more ▼

answered Apr 15 '14 at 05:14 PM

avatar image

Jamie Dale STAFF
7.5k 177 67 305

avatar image StrangerGwenn Apr 15 '14 at 05:18 PM

Hi Jamie,

I confirm that this work very well. No flickering is apparent anymore.

Thanks a lot !

avatar image Jamie Dale STAFF Apr 24 '14 at 10:26 PM

This change is now available in the git master, should you want to cherry pick it rather than apply the fix by hand. The fix itself will be in the 4.2 release.

https://github.com/EpicGames/UnrealEngine/commit/28e0d833f51958df8d8436ac240aa6633c3a8c9d

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question