Does anyone know a way to programmatically access the images rendered by a camera ?
I do not want to change the player’s viewport or influence the environment in any kind.
The only thing I need is an object (camera) to place somewhere in the game which continously produces images from it’s point of view, that I can get access to in c++
If I understand the question you would like to spawn a camera at a specific location to capture an image?
If this is so, you could try spawning an actor of class _camera in the desired location and reference the camera you spawned to get the image you want.
Another way is to use a SceneCapture2D, the actor class which is surprisingly different from common Camera actor class (they does not inherit from each other). Here is some code from my project, hope it’ll help.
A little explanation. Here is created a USceneCaptureComponent2D, the camera attached to the portal, which gets us the view. View is send to copied Texture object, and, after start of the game, is attached to copy of material with input for texture. From the level of editor you need to create SceneCapture2D camera, create the Render Target object, set output of SceneCapture to this RenderTarget, and use this specific RenderTarget as a feed for Material. Because I spend some time trying to connect these things in script, I attach it, hoping that it can help
Second attempt - I wrote this code especially for you, so don’t tell me I’m lazy pasting all code here
Header file:
#pragma once
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMyActor();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
USceneCaptureComponent2D *Camera;
UTextureRenderTarget2D *RenderTarget;
UTexture2D *Texture2D;
};
.cpp file:
#include "MyProject.h"
#include "Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h"
#include "MyActor.h"
// Sets default values
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = true;
RootComponent = CreateDefaultSubobject<USphereComponent>(TEXT("Root"));
Camera = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("Camera"));
ConstructorHelpers::FObjectFinder<UTextureRenderTarget2D> RenderTargetAsset(TEXT("/Game/MyLittleRenderTarget"));
//here you need to have prepared MyLittleRenderTarget asset, type RenderTarget2D. You can have one for many actors, it is duplicated. What is not resolved by me: i don't know if it is stable solution or it will make crash after many calls
RenderTarget = DuplicateObject(RenderTargetAsset.Object, NULL);
RenderTarget->InitAutoFormat(1024, 1024);
Camera->TextureTarget = RenderTarget;
}
void AMyActor::BeginPlay()
{
Super::BeginPlay();
Camera->TextureTarget = RenderTarget;
int X = RenderTarget->GetSurfaceHeight();
int Y = RenderTarget->GetSurfaceWidth();
GLog->Logf(TEXT("Size: %d %d"), X, Y);
Texture2D = RenderTarget->ConstructTexture2D(this, FString("Tex2D"), EObjectFlags::RF_NoFlags);
//FTextureRenderTargetResource *Resource = RenderTarget->GetRenderTargetResource();
int xx = Texture2D->GetSizeX();
int yy = Texture2D->GetSizeY();
GLog->Logf(TEXT("Texture size: %d %d"), xx, yy);
FTexturePlatformData *Data = Texture2D->PlatformData;
EPixelFormat Format = Data->PixelFormat;
GLog->Logf(TEXT("Pixel format: %d"), (uint8)(Format));
//format of pixel is PFloatRGBA
int size = Data->Mips[0].BulkData.GetElementSize();
int N = Data->Mips[0].BulkData.GetElementCount();
GLog->Logf(TEXT("Number of elements: %d, size of one element: %d"), N, size);
//i've got 1 byte size of element
const void *Table = Data->Mips[0].BulkData.LockReadOnly();
Data->Mips[0].BulkData.Unlock();
const uint16 *Tab2 = StaticCast<const uint16*>(Table);
//ok, quick calculation. I get 8*1024*1024 bytes from 1024*1024 pixels, so one pixel got 8 bytes of data. Format is RGBA, so you can figure it yourself :)
for(int i=0;i<xx;i++)
for (int j = 0; j < yy; j++) {
int k = 4*(i*yy + j);
int R = Tab2[k];
int G = Tab2[k + 1];
int B = Tab2[k + 2];
int A = Tab2[k + 3];
}
}
I guess that’s what you wanted, you get info about raw RGBA data. Probably it should work with access every frame - if not, you should probably look for function like RenderTarget->UpdateResourceImmediate();
I’m glad I could help. When I started (~2 months ago) I spend really long time trying to understand those things and I didn’t had any example codes. So let’s make it simpler for people after me
.
Which is the configuration needed for the RenderTarget?
I’ve tried RenderTarget formats: RF RGBA16f and RF RGBA8. First one generated empty images and the second random images always the same. Any idea?
Hello,
sorry to resurrect an old question, but can you give some guidance on how you created your rendertarget asset? I presume you don’t just mean adding a var to the Level Blueprint, you mean an actual asset? How is this done?
Thanks!