Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/SparseVolumeTexture/SparseVolumeTextureViewerComponent.cpp
2025-05-18 13:04:45 +08:00

286 lines
9.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SparseVolumeTexture/SparseVolumeTextureViewerComponent.h"
#include "SparseVolumeTexture/SparseVolumeTextureViewerSceneProxy.h"
#include "Components/ArrowComponent.h"
#include "Components/BillboardComponent.h"
#include "Engine/MapBuildDataRegistry.h"
#include "Internationalization/Text.h"
#include "Logging/MessageLog.h"
#include "Logging/TokenizedMessage.h"
#include "Misc/MapErrors.h"
#include "Misc/UObjectToken.h"
#include "UObject/UObjectIterator.h"
#include "UObject/ConstructorHelpers.h"
#if WITH_EDITOR
#include "ObjectEditorUtils.h"
#endif
#define LOCTEXT_NAMESPACE "SparseVolumeTextureViewerComponent"
constexpr int32 SVTViewerDefaultVolumeResolution = 128;
/*=============================================================================
USparseVolumeTextureViewerComponent implementation.
=============================================================================*/
USparseVolumeTextureViewerComponent::USparseVolumeTextureViewerComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, SparseVolumeTexturePreview(nullptr)
, Frame(0.0f)
, FrameRate(24.0f)
, bPlaying(false)
, bLooping(false)
, bReversePlayback(false)
, bBlockingStreamingRequests(false)
, bApplyPerFrameTransforms(true)
, bPivotAtCentroid(false)
, VoxelSize(1.0f)
, PreviewAttribute(ESVTPA_AttributesA_R)
, MipLevel(0)
, Extinction(0.025f)
, SparseVolumeTextureViewerSceneProxy(nullptr)
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickGroup = TG_DuringPhysics;
bTickInEditor = true;
}
USparseVolumeTextureViewerComponent::~USparseVolumeTextureViewerComponent()
{
}
#if WITH_EDITOR
void USparseVolumeTextureViewerComponent::CheckForErrors()
{
}
void USparseVolumeTextureViewerComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
FName PropertyName;
if (PropertyChangedEvent.Property)
{
PropertyName = PropertyChangedEvent.Property->GetFName();
}
if (PropertyName == GET_MEMBER_NAME_CHECKED(USparseVolumeTextureViewerComponent, Frame))
{
if (SparseVolumeTexturePreview)
{
const int32 FrameCount = SparseVolumeTexturePreview->GetNumFrames();
Frame = FMath::Clamp(Frame, 0, FrameCount - 1);
}
}
MarkRenderStateDirty();
}
#endif // WITH_EDITOR
void USparseVolumeTextureViewerComponent::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
}
FBoxSphereBounds USparseVolumeTextureViewerComponent::CalcBounds(const FTransform& LocalToWorld) const
{
FVector VolumeResolution = FVector(SVTViewerDefaultVolumeResolution);
if (SparseVolumeTexturePreview)
{
VolumeResolution = FVector(SparseVolumeTexturePreview->GetVolumeResolution());
}
FBoxSphereBounds NewBounds;
FVector HalfVolumeResolution = FVector(VolumeResolution) * 0.5;
if (bPivotAtCentroid)
{
NewBounds.Origin = FVector::ZeroVector;
}
else
{
NewBounds.Origin = HalfVolumeResolution;
}
NewBounds.BoxExtent = HalfVolumeResolution;
NewBounds.SphereRadius = NewBounds.BoxExtent.Length();
if (SparseVolumeTextureFrame)
{
return NewBounds.TransformBy(SparseVolumeTextureFrame->GetFrameTransform() * LocalToWorld);
}
else
{
return NewBounds.TransformBy(LocalToWorld);
}
}
void USparseVolumeTextureViewerComponent::CreateRenderState_Concurrent(FRegisterComponentContext* Context)
{
Super::CreateRenderState_Concurrent(Context);
// If one day we need to look up lightmass built data, lookup it up here using the guid from the correct MapBuildData.
bool bHidden = false;
#if WITH_EDITORONLY_DATA
bHidden = GetOwner() ? GetOwner()->bHiddenEdLevel : false;
#endif // WITH_EDITORONLY_DATA
if (!ShouldComponentAddToScene())
{
bHidden = true;
}
if (GetVisibleFlag() && !bHidden &&
ShouldComponentAddToScene() && ShouldRender() && IsRegistered() && (GetOuter() == NULL || !GetOuter()->HasAnyFlags(RF_ClassDefaultObject)))
{
// Create the scene proxy.
SparseVolumeTextureViewerSceneProxy = new FSparseVolumeTextureViewerSceneProxy(this);
GetWorld()->Scene->AddSparseVolumeTextureViewer(SparseVolumeTextureViewerSceneProxy);
SendRenderTransformCommand();
}
}
void USparseVolumeTextureViewerComponent::DestroyRenderState_Concurrent()
{
Super::DestroyRenderState_Concurrent();
if (SparseVolumeTextureViewerSceneProxy)
{
GetWorld()->Scene->RemoveSparseVolumeTextureViewer(SparseVolumeTextureViewerSceneProxy);
FSparseVolumeTextureViewerSceneProxy* SVTViewerSceneProxy = SparseVolumeTextureViewerSceneProxy;
ENQUEUE_RENDER_COMMAND(FDestroySparseVolumeTextureViewerSceneProxyCommand)(
[SVTViewerSceneProxy](FRHICommandList& RHICmdList)
{
delete SVTViewerSceneProxy;
});
SparseVolumeTextureViewerSceneProxy = nullptr;
}
}
void USparseVolumeTextureViewerComponent::SendRenderTransform_Concurrent()
{
Super::SendRenderTransform_Concurrent();
SendRenderTransformCommand();
}
void USparseVolumeTextureViewerComponent::SendRenderTransformCommand()
{
if (SparseVolumeTextureViewerSceneProxy)
{
FVector VolumeResolution = FVector(SVTViewerDefaultVolumeResolution);
FTransform FrameTransform = FTransform::Identity;
if (SparseVolumeTextureFrame)
{
VolumeResolution = FVector(SparseVolumeTextureFrame->GetVolumeResolution());
if (bApplyPerFrameTransforms)
{
FrameTransform = SparseVolumeTextureFrame->GetFrameTransform();
}
}
const FTransform GlobalTransform = GetComponentTransform();
const FVector3f VolumeRes3f = FVector3f(VolumeResolution.X, VolumeResolution.Y, VolumeResolution.Z);
FSparseVolumeTextureViewerSceneProxy* SVTSceneProxy = SparseVolumeTextureViewerSceneProxy;
ENQUEUE_RENDER_COMMAND(FUpdateSparseVolumeTextureViewerProxyTransformCommand)(
[SVTSceneProxy, GlobalTransform, FrameTransform, VolumeRes3f, CompIdx = (uint32)PreviewAttribute, Ext = Extinction, Mip = MipLevel, VoxelSizeFactor = VoxelSize, bCentroidPivot = (bool)bPivotAtCentroid](FRHICommandList& RHICmdList)
{
SVTSceneProxy->GlobalTransform = GlobalTransform;
SVTSceneProxy->FrameTransform = FrameTransform;
SVTSceneProxy->VolumeResolution = VolumeRes3f;
SVTSceneProxy->MipLevel = Mip;
SVTSceneProxy->ComponentToVisualize = CompIdx;
SVTSceneProxy->Extinction = Ext;
SVTSceneProxy->VoxelSizeFactor = VoxelSizeFactor;
SVTSceneProxy->bPivotAtCentroid = bCentroidPivot;
});
}
}
void USparseVolumeTextureViewerComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
if (SparseVolumeTexturePreview)
{
const int32 NumFrames = SparseVolumeTexturePreview->GetNumFrames();
if (bPlaying)
{
Frame += DeltaTime * FrameRate * (bReversePlayback ? -1.0f : 1.0f);
}
if (bLooping)
{
// Simple way of dealing with looping when playing back in reverse: add NumFrames to the X input of Fmod.
Frame = FMath::Fmod(Frame + NumFrames, (float)NumFrames);
}
else
{
Frame = FMath::Clamp(Frame, 0.0f, (float)(NumFrames - 1));
}
const bool bHasValidFrameRate = bPlaying != 0;
SparseVolumeTextureFrame = USparseVolumeTextureFrame::GetFrameAndIssueStreamingRequest(SparseVolumeTexturePreview, GetTypeHash(this), FrameRate, Frame, MipLevel, bBlockingStreamingRequests, bHasValidFrameRate);
}
else
{
SparseVolumeTextureFrame = nullptr;
}
MarkRenderStateDirty();
}
/*=============================================================================
ASparseVolumeTextureViewer implementation.
=============================================================================*/
#if WITH_EDITOR
#include "ObjectEditorUtils.h"
#endif
ASparseVolumeTextureViewer::ASparseVolumeTextureViewer(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
SparseVolumeTextureViewerComponent = CreateDefaultSubobject<USparseVolumeTextureViewerComponent>(TEXT("SparseVolumeTextureViewerComponent"));
RootComponent = SparseVolumeTextureViewerComponent;
#if WITH_EDITORONLY_DATA
if (!IsRunningCommandlet())
{
// Structure to hold one-time initialization
struct FConstructorStatics
{
ConstructorHelpers::FObjectFinderOptional<UTexture2D> SparseVolumeTextureViewerTextureObject;
FName ID_SparseVolumeTextureViewer;
FText NAME_SparseVolumeTextureViewer;
FConstructorStatics()
: SparseVolumeTextureViewerTextureObject(TEXT("/Engine/EditorResources/S_VolumetricCloud")) // SVT_TODO set a specific icon
, ID_SparseVolumeTextureViewer(TEXT("Fog"))
, NAME_SparseVolumeTextureViewer(NSLOCTEXT("SpriteCategory", "Fog", "Fog"))
{
}
};
static FConstructorStatics ConstructorStatics;
if (GetSpriteComponent())
{
GetSpriteComponent()->Sprite = ConstructorStatics.SparseVolumeTextureViewerTextureObject.Get();
GetSpriteComponent()->SetRelativeScale3D(FVector(0.5f, 0.5f, 0.5f));
GetSpriteComponent()->SpriteInfo.Category = ConstructorStatics.ID_SparseVolumeTextureViewer;
GetSpriteComponent()->SpriteInfo.DisplayName = ConstructorStatics.NAME_SparseVolumeTextureViewer;
GetSpriteComponent()->SetupAttachment(SparseVolumeTextureViewerComponent);
}
}
#endif // WITH_EDITORONLY_DATA
PrimaryActorTick.bCanEverTick = true;
SetHidden(false);
}
#undef LOCTEXT_NAMESPACE