I’m trying to work out how I can utilize the new 4.11 SMeshWidget to draw Static Meshes as part of my User Interface. All I actually want to draw at first is a very simple plane, but I need to transform the vertices such that the plane is flat with my radar widget, which currently looks like the screenshot below. All of the blips on the radar are currently UImage widgets, which are added to the Radar Widget dynamically during play.
Now if an object is far enough away that it goes off of the radar’s grid (which is a circular radius around the player) - it get’s clamped to the edge, at which point I want the square blip to turn into an arrow, pointing to it’s location. The arrow also needs to be distorted such that it’s displayed as if on the same plane as the radar grid itself (which is around 30/40 degree incline). Since the radar also rotates with the player rotation, the widgets also need to move around the edge of the radar and keep pointing to their respective objects.
Since there could be hundreds if not thousands of these blips on the radar at once, it seems like a perfect use-case for the new SMeshWidget which appears to be able to render lots of things like this very quickly. However it seems as as powerful as this new feature is I still haven’t really figured out how to use it. For a quick test-case, I wrapped SMeshWidget in a UWidget and placed it in my HUD with UMG. I then gave it a mesh to use and a very simple UI-material, and this is the result:
If anybody is interested, this is the relatively simple code that makes this possible:
Custom Mesh UWidget
#include "BZGame_BlipWidget.generated.h"
class USlateVectorArtData;
class SMeshWidget;
UCLASS()
class BZGAME_API UBZGame_BlipWidget : public UWidget
{
GENERATED_BODY()
public:
UBZGame_BlipWidget(const FObjectInitializer& ObjectInitializer);
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mesh")
USlateVectorArtData* MeshData;
virtual void SynchronizeProperties() override;
virtual void ReleaseSlateResources(bool bReleaseChildren) override;
#if WITH_EDITOR
// Begin UWidget Interface
virtual const FSlateBrush* GetEditorIcon() override;
virtual const FText GetPaletteCategory() override;
virtual void OnCreationFromPalette() override;
// End UWidget Interface
#endif
protected:
// Native Slate Widget
TSharedPtr<SMeshWidget> MyMeshWidget;
// UWidget Interface
virtual TSharedRef<SWidget> RebuildWidget() override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "BZGame.h"
#include "Hud/Widgets/Game/BZGame_BlipWidget.h"
#include "Runtime/UMG/Public/Slate/SMeshWidget.h"
#include "Runtime/UMG/Public/UMGStyle.h"
#define LOCTEXT_NAMESPACE "UMG"
UBZGame_BlipWidget::UBZGame_BlipWidget(const FObjectInitializer& ObjectInitializer)
{
//SMeshWidget::FArguments SlateDefaults;
}
TSharedRef<SWidget> UBZGame_BlipWidget::RebuildWidget()
{
MyMeshWidget = SNew(SMeshWidget);
return MyMeshWidget.ToSharedRef();
}
void UBZGame_BlipWidget::SynchronizeProperties()
{
Super::SynchronizeProperties();
if (MyMeshWidget.IsValid() && MeshData != nullptr)
{
const uint32 NewMeshIndex = MyMeshWidget->AddMesh(*MeshData);
}
}
void UBZGame_BlipWidget::ReleaseSlateResources(bool bReleaseChildren)
{
Super::ReleaseSlateResources(bReleaseChildren);
}
#if WITH_EDITOR
const FSlateBrush* UBZGame_BlipWidget::GetEditorIcon()
{
return FUMGStyle::Get().GetBrush("Widget.ProgressBar");
}
const FText UBZGame_BlipWidget::GetPaletteCategory()
{
return LOCTEXT("Common", "Common");
}
void UBZGame_BlipWidget::OnCreationFromPalette()
{
}
#endif
#undef LOCTEXT_NAMESPACE
And here it is placed in UMG. Notice that despite the widgets position at the center of the screen, the mesh is drawing on the top-left still (you can see the edge of it poking out).
Now even though my custom mesh widget is placed directly central in my custom UMG widget, the mesh always draws at the top-left of the screen, and in fact it seems to be based not on the viewport size, but on the size of the entire monitor. According to Nick on slack, I need to pass information about the mesh position in via it’s UV’s, and I sense that this is what the new ‘Screen Position’ input on the material is for.
However, nothing I try seems to work. I’ve used a bunch of default nodes that I think might be the right ones to mirror what I’m already seeing (such as View Size, Screen Position, a vector 2D etc.) - but each one makes it disappear, so I’m obviously not doing something right. I know that these are being used in Paragon for the widgets that are above the minion heads, so I’d really like to see how that was done. I’ve been trying to figure this out for a few days but it’s going way over my head.
Additionally, if I still can’t use this to transform my widgets as if they are in 3D space - I’m open to other suggestions Eventually, I’d like to draw a static mesh ‘disc’ underneath the existing wire-frame if possible.