Files
UnrealEngine/Engine/Source/Editor/UnrealEd/Private/ThumbnailRendering/VolumeTextureThumbnailRenderer.cpp
2025-05-18 13:04:45 +08:00

189 lines
6.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ThumbnailRendering/VolumeTextureThumbnailRenderer.h"
#include "Misc/App.h"
#include "ShowFlags.h"
#include "Materials/Material.h"
#include "Engine/VolumeTexture.h"
#include "SceneView.h"
#include "ThumbnailHelpers.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/StaticMesh.h"
#include "Engine/StaticMeshActor.h"
#include "UnrealEdGlobals.h"
#include "ThumbnailRendering/ThumbnailManager.h"
#include "ThumbnailRendering/SceneThumbnailInfoWithPrimitive.h"
#include "Editor/UnrealEdEngine.h"
// FPreviewScene derived helpers for rendering
#include "RendererInterface.h"
#include "EngineModule.h"
/*
***************************************************************
FVolumeTextureThumbnailScene
***************************************************************
*/
class UNREALED_API FVolumeTextureThumbnailScene : public FThumbnailPreviewScene
{
public:
/** Constructor */
FVolumeTextureThumbnailScene();
/** Sets the material to use in the next CreateView() */
void SetMaterialInterface(UMaterialInstance* InMaterial);
protected:
// FThumbnailPreviewScene implementation
virtual void GetViewMatrixParameters(const float InFOVDegrees, FVector& OutOrigin, float& OutOrbitPitch, float& OutOrbitYaw, float& OutOrbitZoom) const override;
protected:
/** The static mesh actor used to display all material thumbnails */
class AStaticMeshActor* PreviewActor;
};
FVolumeTextureThumbnailScene::FVolumeTextureThumbnailScene()
: FThumbnailPreviewScene()
{
bForceAllUsedMipsResident = false;
// Create preview actor
// checked
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
SpawnInfo.bNoFail = true;
SpawnInfo.ObjectFlags = RF_Transient;
PreviewActor = GetWorld()->SpawnActor<AStaticMeshActor>( SpawnInfo );
PreviewActor->GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable);
PreviewActor->SetActorEnableCollision(false);
}
void FVolumeTextureThumbnailScene::SetMaterialInterface(UMaterialInstance* InMaterial)
{
check(PreviewActor);
check(PreviewActor->GetStaticMeshComponent());
if (InMaterial)
{
// Transform the preview mesh as necessary
FTransform Transform = FTransform::Identity;
const USceneThumbnailInfoWithPrimitive* ThumbnailInfo = Cast<USceneThumbnailInfoWithPrimitive>(InMaterial->ThumbnailInfo);
if ( !ThumbnailInfo )
{
ThumbnailInfo = USceneThumbnailInfoWithPrimitive::StaticClass()->GetDefaultObject<USceneThumbnailInfoWithPrimitive>();
}
PreviewActor->GetStaticMeshComponent()->SetStaticMesh(GUnrealEd->GetThumbnailManager()->EditorCube);
PreviewActor->GetStaticMeshComponent()->SetRelativeTransform(Transform);
PreviewActor->GetStaticMeshComponent()->UpdateBounds();
// Center the mesh at the world origin then offset to put it on top of the plane
const float BoundsZOffset = GetBoundsZOffset(PreviewActor->GetStaticMeshComponent()->Bounds);
Transform.SetLocation(-PreviewActor->GetStaticMeshComponent()->Bounds.Origin + FVector(0, 0, BoundsZOffset));
PreviewActor->GetStaticMeshComponent()->SetRelativeTransform(Transform);
}
PreviewActor->GetStaticMeshComponent()->SetMaterial(0, InMaterial);
PreviewActor->GetStaticMeshComponent()->RecreateRenderState_Concurrent();
}
void FVolumeTextureThumbnailScene::GetViewMatrixParameters(const float InFOVDegrees, FVector& OutOrigin, float& OutOrbitPitch, float& OutOrbitYaw, float& OutOrbitZoom) const
{
check(PreviewActor);
check(PreviewActor->GetStaticMeshComponent());
check(PreviewActor->GetStaticMeshComponent()->GetMaterial(0));
// Fit the mesh in the view using the following formula
// tan(HalfFOV) = Width/TargetCameraDistance
const float HalfFOVRadians = FMath::DegreesToRadians<float>(InFOVDegrees) * 0.5f;
// Add extra size to view slightly outside of the bounds to compensate for perspective
const float BoundsMultiplier = 1.15f;
const float HalfMeshSize = PreviewActor->GetStaticMeshComponent()->Bounds.SphereRadius * BoundsMultiplier;
const float BoundsZOffset = GetBoundsZOffset(PreviewActor->GetStaticMeshComponent()->Bounds);
const float TargetDistance = HalfMeshSize / FMath::Tan(HalfFOVRadians);
// Since we're using USceneThumbnailInfoWithPrimitive in SetMaterialInterface, we should use it here instead of USceneThumbnailInfoWithPrimitive for consistency.
USceneThumbnailInfoWithPrimitive* ThumbnailInfo = Cast<USceneThumbnailInfoWithPrimitive>(PreviewActor->GetStaticMeshComponent()->GetMaterial(0)->ThumbnailInfo);
if ( ThumbnailInfo )
{
if ( TargetDistance + ThumbnailInfo->OrbitZoom < 0 )
{
ThumbnailInfo->OrbitZoom = -TargetDistance;
}
}
else
{
ThumbnailInfo = USceneThumbnailInfoWithPrimitive::StaticClass()->GetDefaultObject<USceneThumbnailInfoWithPrimitive>();
}
OutOrigin = FVector(0, 0, -BoundsZOffset);
OutOrbitPitch = ThumbnailInfo->OrbitPitch;
OutOrbitYaw = ThumbnailInfo->OrbitYaw;
OutOrbitZoom = TargetDistance + ThumbnailInfo->OrbitZoom;
}
UVolumeTextureThumbnailRenderer::UVolumeTextureThumbnailRenderer(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, ThumbnailScene(nullptr)
{
}
void UVolumeTextureThumbnailRenderer::Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, FRenderTarget* RenderTarget, FCanvas* Canvas, bool bAdditionalViewFamily)
{
UVolumeTexture* VolumeTexture = Cast<UVolumeTexture>(Object);
if (VolumeTexture != nullptr)
{
if (!ThumbnailScene)
{
ThumbnailScene = new FVolumeTextureThumbnailScene();
}
if (!MaterialInstance)
{
UMaterial* BaseMaterial = LoadObject<UMaterial>(nullptr, TEXT("/Engine/EngineMaterials/VolumeTextureThumbnailMaterial.VolumeTextureThumbnailMaterial"), nullptr, LOAD_None, nullptr);
if (BaseMaterial)
{
MaterialInstance = NewObject<UMaterialInstanceConstant>(GetTransientPackage());
MaterialInstance->SetParentEditorOnly(BaseMaterial);
}
}
if (MaterialInstance)
{
MaterialInstance->SetTextureParameterValueEditorOnly(FName("PreviewVolume"), VolumeTexture);
MaterialInstance->PostEditChange();
ThumbnailScene->SetMaterialInterface(MaterialInstance);
FSceneViewFamilyContext ViewFamily( FSceneViewFamily::ConstructionValues( RenderTarget, ThumbnailScene->GetScene(), FEngineShowFlags(ESFIM_Game) )
.SetTime(UThumbnailRenderer::GetTime())
.SetAdditionalViewFamily(bAdditionalViewFamily));
ViewFamily.EngineShowFlags.DisableAdvancedFeatures();
ViewFamily.EngineShowFlags.SetSeparateTranslucency(true);
ViewFamily.EngineShowFlags.MotionBlur = 0;
ViewFamily.EngineShowFlags.AntiAliasing = 0;
RenderViewFamily(Canvas, &ViewFamily, ThumbnailScene->CreateView(&ViewFamily, X, Y, Width, Height));
}
ThumbnailScene->SetMaterialInterface(nullptr);
}
}
void UVolumeTextureThumbnailRenderer::BeginDestroy()
{
if ( ThumbnailScene != nullptr )
{
delete ThumbnailScene;
ThumbnailScene = nullptr;
}
Super::BeginDestroy();
}