Taking a series of screenshots

Hello Unreal Community,

I am struggling to take a series of screenshots using C++.
What am I trying to accomplish?

I start the PIE, hit a button and then a objects is rotated
to certain angles and of each angle I would like to take
a screenshot.

When I try this in a loop the loop runs through but only
one screenshot is taken. This screenshot shows the object
with the last rotation of the rotation series I would like to capture.

Here is some code I wrote to automate the taking of the screenshot series:

void UCaptureImageAngleData::CaptureData()
    {
    	for (int i = start_rotation; i <= abs(start_rotation) ; i = i + delta_rotation)
    	{
    		APlayerController* PController = GetWorld()->GetFirstPlayerController();
    		if (PController) 
                {
    			FString command = TEXT("HighResShot 1920x1080");
    			PController->ConsoleCommand(command, true);
    		}
    		WriteDataToDisk();
    		current_rotation = current_rotation + delta_rotation;
    		trailer->SetActorRotation(FQuat(FRotator(0.0f, current_rotation, 0.0f)));
    	}
    }

Can you please provide some information about WriteDataToDisk(); function. Is it a custom function as I cant find it in the Unreal documentation?

I suspect this function overwrites the same file on every loop iteration.

This is a custom function. It appends some information (world position, angle etc.) about certain game objects into a text file.

Fair enough… The problem is not WriteDataToDisk();

Your PController->ConsoleCommand(command, true); should output a log in the console. Can you check that log and see if the screenshot is taken multiple times. I hope the file name is part of the log.

Can you provide the type of delta_rotation and start_rotation. I suspect there is something wrong with your loop conditions. I would strongly suggest you use “while loop” if you are working with floating point number values.

I came across a relevant tutorial that might help you.

Here’s the Blueprint part where he automates the screenshot code: Automatic navigation and screenshots posted by anonymous | blueprintUE | PasteBin For Unreal Engine

It’s part of larger tutorial on semantic image segmentation in UE4 in which he uses the script pasted above to automate how screenshots are taken.

you can navigate to the: Automatic navigation and screenshots section of the link below

It also seems as though you are writing overwriting the same file as dZh0 suggested.

Try using FilenameOverride()

documentation:FHighResScreenshotConfig | Unreal Engine Documentation

The log output:

LogRenderer: Reallocating scene render targets to support 1920x1080 Format 10 NumSamples 1 (Frame:253).

LogClient: High resolution screenshot saved as C:/Users/benja/Documents/Unreal Projects/AngleEstimation/Saved/Screenshots/Windows/HighresScreenshot00000.png

Your assumption about delta_rotation and start_rotation were correct they are both of type float.

Initialized with 60.0 (delta_rotation) and -120.0 (start_rotation).

I followed your suggestions, but the outcome is still the same.

If I use a timer I get a different result. Then only the first screenshot is not taken but the others are.

Thus I do not think what KaranMonster suggested

It also seems as though you are writing overwriting the same file as dZh0 suggested.
Try using FilenameOverride()

applies to my problem.

The altered code with your suggestions:

void UCaptureImageAngleData::BeginPlay()
{
	Super::BeginPlay();
	SetupInputComponent();
	current_rotation = start_rotation;
	trailer->SetActorRotation(FQuat(FRotator(0.0f, current_rotation, 0.0f)));
}
    
    void UCaptureImageAngleData::CaptureData()
    	while(current_rotation < abs(start_rotation))
    	{
    		APlayerController* PController = GetWorld()->GetFirstPlayerController();
    		if (PController)
    		{
    			FString command = TEXT("HighResShot 1920x1080");
    			PController->ConsoleCommand(command, true);
    		}
    		WriteDataToDisk();
    		current_rotation = current_rotation + delta_rotation;
    		trailer->SetActorRotation(FQuat(FRotator(0.0f, current_rotation, 0.0f)));
    	}
    }

Thank you for your suggestion.
The tutorial did not help directly, but it held a hint to an alternative solution using timers.
I am looking into that now as well.
So when I try it with a timer, all screenshots are taken except the first one.
Thus I do not think it is an override problem.

I got it!

I’ll write an answer shortly…

Your void UCaptureImageAngleData::CaptureData() is rotating the object and taking a screenshot. However, it is trying to do so in a single frame.

Put your PController->ConsoleCommand(command, true); in the Tick() of your Actor followed by your rotation but not in a loop. Tick() is executed before every frame so you will not need a loop. You will just need a variable to be able to stop it as it would otherwise fill your HDD with images. (be sure to stop it after several screenshots even if the angle is not reached)

If you do so you will loose the first frame because the order of operations is take screenshot → rotate → render and your first screenshot might not even have a rendered buffer to output. You might need to set your starting rotation one delta_rotation behind:

current_rotation = start_rotation - delta_rotation;

I will try this first thing tomorrow morning!

So I tried your suggestion. But it seems my component does not tick and I can’t find out why.

The constructor looks like this:

UCaptureImageAngleData::UCaptureImageAngleData()
{
	PrimaryComponentTick.bCanEverTick = true;
	PrimaryComponentTick.bStartWithTickEnabled = true;
}

The tick function looks like this:
(I know you told me only to call the console command, but I do not even see the log entries with “tick, tack”.)

void UCaptureImageAngleData::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
	UE_LOG(LogTemp, Warning, TEXT("Tick, tack ..."))
	if (counter <= ((2 * (abs(start_rotation) / delta_rotation))) + 1)
	{
		UE_LOG(LogTemp, Warning, TEXT("Counter condition is true"))
		CaptureData();
	}
}

Check if your component is attached to the actor.

Check if the actor has it’s tick enabled.

To avoid issues like this I would suggest you try this out entirely in the actor until you make it work and then separate the logic you want in a component. This is not an appropriate approach for very elaborate logic but since this is literally 10 lines you can test it in the actor.

Component is attached to the actor. Checked.
Actor’s tick enabled. Checked.

Thank you for the suggestion. But I did not know how to follow it accurately.
Instead I searched for my problem on the forum. I discovered that other people
had my problem (not ticking component) as well.
(UActorComponent not Ticking - Programming & Scripting - Unreal Engine Forums)
The solution was quite simple. Delete the component and attach it again, after this
the component ticked.

Following your advice on how to take the screenshots with the “TickComponent” function
everything went well. I just have to fix the first screenshot of the series.

Thank you for your endurance and precise instructions!

Hey dZh0, did you ever write an answer to this? I’m trying to take a series of screenshots, but without the quaternion rotation and just from a fixed angle above the object. I would like to take 1000. Thanks!