Skip to content
Connecting DocsDocumentation
Main website
Pixel Era/Quick Setup

Read colors in C++

A quick rundown of how GPU to CPU reads are performed in C++ the UV updates are done directly on the returned handle from the manager after submitting the request, this ensures the least amount of instructions allowing it scale to tens of thousands without hindering CPU time.

1. Add and configure the example

Copy the complete header and source below into your game module, then build. Place Pixel Era Manager and the example actor. Assign its Manager and prepared Source. The actor keeps one sample handle.
C++ retained sample creation during BeginPlay
  1. Register once
    Retain the returned sample handle.
Copy the C++
// Actor header: retain one registration.
#include "PixelEraSample.h"
FPixelEraSample Sample;

// BeginPlay: Manager and Source are assigned actor properties.
if (Manager && Source)
{
    Sample = Manager->CreateTextureSample(
        GetFName(), Source, UV, EPixelEraSamplePrecision::RGBA8);
    Manager->AddTickPrerequisiteActor(this);
}

2. Update, receive, remove

Change the actor’s UV. Tick updates the retained handle, then stores the latest completed color in PixelColor. EndPlay removes the registration. Keep these calls on the game thread. Give every sample a key unique within its manager.
C++ UV update, latest-color read and EndPlay cleanup
  1. Update UV
    The handle keeps the existing registration.
  2. Remove on EndPlay
    If this read operation will not be used again, and it should not tick anymore – remove the sample from the manager’s cache.
Copy the C++
// Tick: update the retained sample.
Sample.SetUV(UV);
FLinearColor LatestColor;
int64 Sequence = 0;
if (Sample.GetPixelColorWithSequence(LatestColor, Sequence))
{
    PixelColor = LatestColor;
}

// EndPlay: remove the registration.
Sample.Remove();

Add "PixelEra" to PublicDependencyModuleNames in your module’s .Build.cs.

Complete header

PETextureReaderExample.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "PixelEraSample.h"
#include "PETextureReaderExample.generated.h"

class APixelEraCachedReader;
class UTexture;

UCLASS()
class APETextureReaderExample : public AActor
{
    GENERATED_BODY()

public:
    APETextureReaderExample();

    UPROPERTY(EditInstanceOnly, Category = "Pixel Era")
    TObjectPtr<APixelEraCachedReader> Manager;

    UPROPERTY(EditAnywhere, Category = "Pixel Era")
    TObjectPtr<UTexture> Source;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pixel Era")
    FVector2D UV = FVector2D(0.5, 0.5);

    UPROPERTY(BlueprintReadOnly, Category = "Pixel Era")
    FLinearColor PixelColor = FLinearColor::Black;

protected:
    void BeginPlay() override;
    void Tick(float DeltaSeconds) override;
    void EndPlay(const EEndPlayReason::Type Reason) override;

private:
    FPixelEraSample Sample;
};
Complete source

PETextureReaderExample.cpp

#include "PETextureReaderExample.h"
#include "PixelEraCachedReader.h"
#include "Engine/Texture.h"

APETextureReaderExample::APETextureReaderExample()
{
    PrimaryActorTick.bCanEverTick = true;
}

void APETextureReaderExample::BeginPlay()
{
    Super::BeginPlay();
    if (Manager && Source)
    {
        Sample = Manager->CreateTextureSample(
            GetFName(), Source, UV, EPixelEraSamplePrecision::RGBA8);
        Manager->AddTickPrerequisiteActor(this);
    }
}

void APETextureReaderExample::Tick(float DeltaSeconds)
{
    Super::Tick(DeltaSeconds);
    Sample.SetUV(UV);

    FLinearColor LatestColor;
    int64 Sequence = 0;
    if (Sample.GetPixelColorWithSequence(LatestColor, Sequence))
    {
        PixelColor = LatestColor;
    }
}

void APETextureReaderExample::EndPlay(const EEndPlayReason::Type Reason)
{
    Sample.Remove();
    Super::EndPlay(Reason);
}
Updated Oct 17, 2026

Search Pixel Era

Type at least two characters to search.