Code
A downloadable game
void ARealtimeCaptureActor::ReadRenderTargetWithStagingBuffer()
{
if (!RenderTarget)
{
UE_LOG(LogTemp, Warning, TEXT("RenderTarget is NULL!"));
return;
}
FTextureRenderTargetResource* RTResource = RenderTarget->GameThread_GetRenderTargetResource();
if (!RTResource)
{
UE_LOG(LogTemp, Warning, TEXT("RenderTargetResource is NULL!"));
return;
}
ENQUEUE_RENDER_COMMAND(CaptureFrame)(
[RTResource, this](FRHICommandListImmediate& RHICmdList)
{
// Create a Staging Texture (CPU Readback)
FRHIResourceCreateInfo ci = FRHIResourceCreateInfo(TEXT("CreateInfo"));
FTexture2DRHIRef StagingTexture = RHICreateTexture2D(
512, 512, PF_B8G8R8A8, 1, 1, TexCreate_CPUReadback, ci);
if (!StagingTexture)
{
UE_LOG(LogTemp, Error, TEXT("Failed to create Staging Texture!"));
return;
}
// Copy RenderTarget → Staging Texture (GPU-GPU, fast)
FRHICopyTextureInfo CopyInfo;
RHICmdList.CopyTexture(RTResource->GetRenderTargetTexture(), StagingTexture, CopyInfo);
// Map and Read Data from Staging Buffer (GPU-CPU, optimized)
uint32 Stride = 0; // Let LockTexture2D set the correct stride
void* Data = RHICmdList.LockTexture2D(StagingTexture, 0, EResourceLockMode::RLM_ReadOnly, Stride, false);
if (!Data)
{
UE_LOG(LogTemp, Error, TEXT("LockTexture2D FAILED! Stride = %u"), Stride);
return;
}
// Debugging stride value
//UE_LOG(LogTemp, Log, TEXT("Stride Value: %u (Expected: %d)"), Stride, 512 * sizeof(FColor));
// Ensure stride is valid
if (Stride < 512 * sizeof(FColor))
{
UE_LOG(LogTemp, Error, TEXT("Invalid Stride! Got: %u, Expected: >= %d"), Stride, 512 * sizeof(FColor));
RHICmdList.UnlockTexture2D(StagingTexture, 0, false);
return;
}
// Read pixel data
TArray<FColor> LocalBMP;
LocalBMP.SetNum(512 * 512);
uint8* SrcPtr = static_cast<uint8*>(Data);
for (int32 Row = 0; Row < 512; ++Row)
{
FMemory::Memcpy(&LocalBMP[Row * 512], SrcPtr + (Row * Stride), 512 * sizeof(FColor));
}
RHICmdList.UnlockTexture2D(StagingTexture, 0, false);
AsyncTask(ENamedThreads::GameThread, [this, LocalBMP]()
{
UpdateDynamicTexture(LocalBMP, 512, 512);
});
});
FlushRenderingCommands(); // Ensure execution
}
//////////////
Model Loader
////////////
.cpp
////
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLModelLoader.h"
#include "CoreMinimal.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
#include "XmlParser.h"
#include "Engine/StaticMeshActor.h"
#include "Engine/StaticMesh.h"
#include "UObject/ConstructorHelpers.h"
// Sets default values
AXMLModelLoader::AXMLModelLoader()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AXMLModelLoader::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AXMLModelLoader::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AXMLModelLoader::SwapStaticMeshFromXML(FString XMLFilePath)
{
// Load XML File
FXmlFile XMLFile(XMLFilePath);
if (!XMLFile.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("Failed to read XML file: %s"), *XMLFilePath);
return;
}
// Get the Root Node
FXmlNode* RootNode = XMLFile.GetRootNode();
if (!RootNode)
{
UE_LOG(LogTemp, Error, TEXT("Invalid XML structure"));
return;
}
// Find <MeshPath> Node
FXmlNode* MeshNode = RootNode->FindChildNode("MeshPath");
if (!MeshNode)
{
UE_LOG(LogTemp, Error, TEXT("MeshPath node not found in XML"));
return;
}
FString MeshPath = MeshNode->GetContent(); // Read Mesh Path
UE_LOG(LogTemp, Log, TEXT("Found MeshPath: %s"), *MeshPath);
// Load Mesh
UStaticMesh* NewMesh = LoadObject<UStaticMesh>(nullptr, *MeshPath);
if (!NewMesh)
{
UE_LOG(LogTemp, Error, TEXT("Failed to load mesh: %s"), *MeshPath);
return;
}
// Swap Mesh on Actor's StaticMeshComponent
if (UStaticMeshComponent* MeshComp = FindComponentByClass<UStaticMeshComponent>())
{
MeshComp->SetStaticMesh(NewMesh);
UE_LOG(LogTemp, Log, TEXT("Successfully swapped mesh!"));
}
else
{
UE_LOG(LogTemp, Error, TEXT("No StaticMeshComponent found on actor!"));
}
}
////////////////
.h
///////////////
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "XMLModelLoader.generated.h"
UCLASS()
class AIRSIM_API AXMLModelLoader : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AXMLModelLoader();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
void AXMLModelLoader::SwapStaticMeshFromXML(FString XMLFilePath);
};
/////////
Dont forget to add XMLParser to build.cs, and perhaps uproject, check other projects source that use XMLReader...........
//////////
Published | 10 days ago |
Status | Released |
Author | the_gamearchitect |
Leave a comment
Log in with itch.io to leave a comment.