Create custom UE4 editor viewport?

I want to create a custom viewport (to edit UVs). I looked at SStaticMeshEditorViewport and FStaticMeshEditorViewportClient.
I made a Viewport which inherits from SEditorViewport, and a ViewportClient which inherits from FEditorViewportClient.

When I create the viewport, I add some meshes to its PreviewScene with PreviewScene.AddComponent(Component, Transform);. The problem is that they do not appear on the viewport. Why?

Here is my code:

STextureViewport.h:

// [...] #includes

class STextureViewport : public SEditorViewport, public FGCObject, public ICommonEditorViewportToolbarInfoProvider
{
public:
    SLATE_BEGIN_ARGS(STextureViewport){}
	SLATE_END_ARGS()

	void Construct(const FArguments& InArgs);
    ~STextureViewport();

    virtual void AddReferencedObjects( FReferenceCollector& Collector ) override;
	void RefreshViewport();
    void SetPreviewMesh();

	/** @return The editor viewport client */
    class FEditorViewportClient& GetViewportClient();

	/** Set the parent tab of the viewport for determining visibility */
	void SetParentTab( TSharedRef<SDockTab> InParentTab ) { ParentTab = InParentTab; }

	// ICommonEditorViewportToolbarInfoProvider interface
	virtual TSharedRef<class SEditorViewport> GetViewportWidget() override;
	virtual TSharedPtr<FExtender> GetExtenders() const override;
	virtual void OnFloatingButtonClicked() override;
	// End of ICommonEditorViewportToolbarInfoProvider interface

protected:
	/** SEditorViewport interface */
	virtual TSharedRef<FEditorViewportClient> MakeEditorViewportClient() override;
	virtual EVisibility OnGetViewportContentVisibility() const override;
	virtual void BindCommands() override;
	virtual void OnFocusViewportToSelection() override;
	virtual TSharedPtr<SWidget> MakeViewportToolbar() override;

private:
//	/** Callback for updating preview socket meshes if the static mesh or socket has been modified. */
    void OnObjectPropertyChanged(UObject* ObjectBeingModified, FPropertyChangedEvent& PropertyChangedEvent);
private:
	
	/** The parent tab where this viewport resides */
	TWeakPtr<SDockTab> ParentTab;

	/** The scene for this viewport. */
	FPreviewScene PreviewScene;

	/** Editor viewport client */
    TSharedPtr<class FTextureViewportClient> TextureViewportClient;

	/** Pointer to the vertical box into which the overlay text items are added */
	TSharedPtr<SVerticalBox> OverlayTextVerticalBox;
};

STextureViewport.cpp:

// […] #includes

// In-viewport toolbar widget used in the static mesh editor
class STextureViewportToolbar : public SCommonEditorViewportToolbarBase
{
public:
	SLATE_BEGIN_ARGS(STextureViewportToolbar) {}
	SLATE_END_ARGS()

	void Construct(const FArguments& InArgs, TSharedPtr<class ICommonEditorViewportToolbarInfoProvider> InInfoProvider)
	{
		SCommonEditorViewportToolbarBase::Construct(SCommonEditorViewportToolbarBase::FArguments(), InInfoProvider);
	}

	// SCommonEditorViewportToolbarBase interface
	virtual TSharedRef<SWidget> GenerateShowMenu() const override
    {
        GetInfoProvider().OnFloatingButtonClicked();

        TSharedRef<SEditorViewport> ViewportRef = GetInfoProvider().GetViewportWidget();

        const bool bInShouldCloseWindowAfterMenuSelection = true;
        FMenuBuilder ShowMenuBuilder(bInShouldCloseWindowAfterMenuSelection, ViewportRef->GetCommandList());
		return ShowMenuBuilder.MakeWidget();
	}
	// End of SCommonEditorViewportToolbarBase
};

void STextureViewport::Construct(const FArguments& InArgs)
{

	SEditorViewport::Construct( SEditorViewport::FArguments() );

	SetPreviewMesh();

	ViewportOverlay->AddSlot()
		.VAlign(VAlign_Top)
		.HAlign(HAlign_Left)
		.Padding(FMargin(10.0f, 40.0f, 10.0f, 10.0f))
		[
			SAssignNew(OverlayTextVerticalBox, SVerticalBox)
		];
}

STextureViewport::~STextureViewport()
{
	FCoreUObjectDelegates::OnObjectPropertyChanged.RemoveAll(this);
    if (TextureViewportClient.IsValid())
	{
        TextureViewportClient->Viewport = NULL;
	}
}

TSharedRef<class SEditorViewport> STextureViewport::GetViewportWidget()
{
	return SharedThis(this);
}

TSharedPtr<FExtender> STextureViewport::GetExtenders() const
{
	TSharedPtr<FExtender> Result(MakeShareable(new FExtender));
	return Result;
}

void STextureViewport::OnFloatingButtonClicked()
{
}

void STextureViewport::AddReferencedObjects( FReferenceCollector& Collector )
{
}

void STextureViewport::RefreshViewport()
{
	// Invalidate the viewport's display.
	SceneViewport->Invalidate();
}

void STextureViewport::SetPreviewMesh(/*UStaticMesh* InStaticMesh*/)
{
    FTransform Transform = FTransform::Identity;
    for(TActorIterator<AActor> ActorItr(ProBuilder::World.Get()); ActorItr; ++ActorItr)
    {
        for(UActorComponent* Component:ActorItr->GetComponents())
        {
            FComponentReregisterContext ReregisterContext( Component);
            PreviewScene.AddComponent(Component, Transform);
        }
    }
}

FEditorViewportClient& STextureViewport::GetViewportClient()
{
    return *TextureViewportClient;
}


TSharedRef<FEditorViewportClient> STextureViewport::MakeEditorViewportClient()
{
    TextureViewportClient = MakeShareable(new FTextureViewportClient(SharedThis(this), PreviewScene));

    TextureViewportClient->bSetListenerPosition = false;

    TextureViewportClient->SetRealtime( false );
    TextureViewportClient->VisibilityDelegate.BindSP( this, &STextureViewport::IsVisible );

    return TextureViewportClient.ToSharedRef();
}

TSharedPtr<SWidget> STextureViewport::MakeViewportToolbar()
{
    return SNew(STextureViewportToolbar, SharedThis(this));
}

EVisibility STextureViewport::OnGetViewportContentVisibility() const
{
	return IsVisible() ? EVisibility::Visible : EVisibility::Collapsed;
}

void STextureViewport::BindCommands()
{
    SEditorViewport::BindCommands();
}

void STextureViewport::OnFocusViewportToSelection()
{
}

TextureViewportClient.h:

class STextureViewport;

/** Viewport Client for the preview viewport */
class FTextureViewportClient : public FEditorViewportClient, public TSharedFromThis<FTextureViewportClient>
{
public:
        FTextureViewportClient(const TSharedRef<STextureViewport>& InTextureViewport, FPreviewScene& InPreviewScene);

	virtual void Tick(float DeltaSeconds) override;
	virtual void Draw(const FSceneView* View,FPrimitiveDrawInterface* PDI) override;
    virtual void DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas ) override;
    virtual FSceneView* CalcSceneView(FSceneViewFamily* ViewFamily) override;
    TWeakPtr<STextureViewport> TextureViewportPtr;
};

TextureViewportClient.cpp:

namespace {
	static const float AutoViewportOrbitCameraTranslate = 256.0f;
	static float AmbientCubemapIntensity = 0.4f;
}

FTextureViewportClient::FTextureViewportClient(const TSharedRef<STextureViewport>& InTextureViewport, FPreviewScene& InPreviewScene)
	: FEditorViewportClient(nullptr, &InPreviewScene, StaticCastSharedRef<SEditorViewport>(InTextureViewport))

{
	SetViewMode(VMI_Lit);

	EngineShowFlags.DisableAdvancedFeatures();
	EngineShowFlags.SetSnap(0);
	EngineShowFlags.CompositeEditorPrimitives = true;
	OverrideNearClipPlane(1.0f);
    bUsingOrbitCamera = true;
}

void FTextureViewportClient::Tick(float DeltaSeconds)
{
	FEditorViewportClient::Tick(DeltaSeconds);

	// Tick the preview scene world.
	if (!GIntraFrameDebuggingGameThread)
	{
		PreviewScene->GetWorld()->Tick(LEVELTICK_All, DeltaSeconds);
	}
}

void FTextureViewportClient::Draw(const FSceneView* View,FPrimitiveDrawInterface* PDI)
{
	FEditorViewportClient::Draw(View, PDI);
}

void FTextureViewportClient::DrawCanvas( FViewport& InViewport, FSceneView& View, FCanvas& Canvas )
{

    auto TextureViewport = TextureViewportPtr.Pin();
    if (!TextureViewport.IsValid())
	{
		return;
	}
}

FSceneView* FTextureViewportClient::CalcSceneView(FSceneViewFamily* ViewFamily)
{
	FSceneView* SceneView = FEditorViewportClient::CalcSceneView(ViewFamily);
	FFinalPostProcessSettings::FCubemapEntry& CubemapEntry = *new(SceneView->FinalPostProcessSettings.ContributingCubemaps) FFinalPostProcessSettings::FCubemapEntry;
	CubemapEntry.AmbientCubemap = GUnrealEd->GetThumbnailManager()->AmbientCubemap;
	CubemapEntry.AmbientCubemapTintMulScaleValue = FLinearColor::White * AmbientCubemapIntensity;
	return SceneView;
}

Sorry for a comment kind of unrelated to your question, just wondering if you ever got issues with the identifier ‘ECoordSystem’ coming from SEditorViewport. I’m trying to get a simpler viewport up and running, after looking through your source and looking through all the source in SStaticMeshEditorViewport and StaticMeshEditorViewportClient, I had what I thought were the proper #include files on all the files (to get your code working), no errors come from the files themselves, but always from engine files and always related to not recognizing the ECoordSystem specifier.

No I didn’t solve this issue, sorry : /

Here are the includes of STextureViewport.h:

#include "UnrealEd.h"
#include "PreviewScene.h"
#include "SEditorViewport.h"
#include "PBEdModeToolkit.h"
#include "TextureActions.h"
#include "TextureViewportClient.h"
#include "Editor/UnrealEd/Public/SCommonEditorViewportToolbarBase.h"

Sometimes, including files in the PCH helps, because the order of the includes seem to matter…

Ah got it working, yeah the order of includes definitely matters I guess. Thanks for the help!

Athrur Masson, You solve this problem? “The problem is that they do not appear on the viewport. Why?”

No I still didn’t solve the problem, but now I use Unreal.js, it has a nice JavascriptEditorViewport implementation

Okey, thank you very much.

Arthur Masson,
I solved this problem, that code is working:

	USkeletalMesh* SkeletalMesh = bAssetData->GetSkeleton()->GetPreviewMesh();

	FTransform Transform = FTransform::Identity;

	MeshComponent = NewObject<USkeletalMeshComponent>(GetTransientPackage());
	MeshComponent->SetSkeletalMesh(SkeletalMesh);
	MeshComponent->RegisterComponentWithWorld(PreviewScene.GetWorld());

	FComponentReregisterContext ContextMeshComponent(MeshComponent);

	FRotator NewRotation = FRotator(0.0f, 180.0f, 0.0f);

	FVector NewPosition = FVector(SkeletalMesh->GetImportedBounds().SphereRadius * 1.5f);

	ViewportClient->SetViewLocation(NewPosition); // Set up new position of camera
	ViewportClient->SetViewRotation(NewRotation);

	PreviewScene.AddComponent(MeshComponent, Transform);

All that is needed is to register a component used world scene preview:

      	MeshComponent->RegisterComponentWithWorld(PreviewScene.GetWorld());

I hope, this helps somebody, Thank you for code-viewport!