Calculating the total area painted in game

Hi, I’ve recently started working on a splatoon-inspired independent project as way of learning more about UE4 and all the things we can do in here. I’m using Render Targets and drawing splatter textures onto them to produce the effect of a paintball hit on the wall. I’ve hit a snag with calculating how much area each team has painted though. I’ve never worked with Render Targets before so I don’t know what all they have to offer. I also don’t suppose I could read the paint material details since there’s no communication with the Render Target? I read about ReadPixels() and used it in my code, but it was just awfully slow. Supposing it’s just one wall I’m painting on and just this wall needs to be evaluated for the amount of paint from each team, what would be the best way going about this? I also had another idea, although I don’t know whether it’d work - what if the game could “see and interpret” the wall as I do? Is there a way I could perhaps take a screenshot of the wall in game and have it process the amount of each color present in it? I looked around on the forums and I did find a way to take screenshots, but they’re just saved locally and I couldn’t find a way to process them in game.

Any thoughts or ideas or even just brainstorming would be greatly appreciated, since I’ve been stuck on this for a while. Thanks!

I’d use the render target only for rendering and the gameplay stats would be saved in a faster data structure in the cpu memory

Create a surface actor that contains a quad and a material to render your render target
When the user paints, you probably have some projectile hitting this tile from the game logic that you use to paint on your render target. Use this same logic to also “paint” on a low resolution data grid on the cpu based grid like data structure (e.g 32x32 grid in local memory for a 1024x1024 backing render target). You can find the influence each grid cell will get based on the projectile’s sphere radius and the quad’s world transform.

Calculate how much area the user has painted in by simply adding these grid cell influences for all the surface actors you’ve placed on the scene. Since all this happens in the cpu without any texture reads, it should be very fast

Hi Ali,
thanks for the input. However there are a few things that I’m confused about. Firstly, how are we “painting” on this low resolution data grid? The way I’m making the paintball splats are that I have splat textures, one of which is selected randomly and painted onto the render target using Dynamic Materials. How would this translate onto the low res data grid ? Secondly, with thousands of paintballs being fired per minute, don’t you think this process might clog things up? I’d appreciate if you could explain it a little bit. I’m still pretty much a noob.

If you have the world transform of your surface and the ball, converting them both to local space of the surface would make things simple (so you can perform the calculations in the XY plane as opposed to XYZ)

FTransform SurfaceWorldTransform = Surface->GetActorTransform();
FTransform ProjectileWorldTransform = Projectile->GetActorTransform();

FTransform WorldToLocal = SurfaceWorldTransform.Inverse()

FTransform LocalSurfaceTransform = WorldToLocal * SurfaceWorldTransform;
FTransform LocalProjectileTransform = WorldToLocal * ProjectileWorldTransform;

In your surface actor have a 2D array and some config values

const float SIZE = 32;
float Influence[SIZE][SIZE] // initialized to 0
int SurfaceWidth = 2000; // in unreal units. fill this based on your art asset
int SurfaceHeight = 2000; // in unreal units. fill this based on your art asset 
float ProjectileRadius = 100;

float ProjectileRadiusSquared = FMath::Square(ProjectileRadius);
for (int x = 0; x < SIZE; x++) {
  for (int y = 0; y < SIZE; y++) {
    // Find the position of the cell x,y in local space
    float u = x / SIZE;
    float v = y / SIZE;
    // uv is between 0..1.  convert to local space coord by multiplying with the surface size
    FVector2D LocalCellPosition = FVector2D(u * SurfaceWidth, v * SurfaceHeight);

    // Find the vector from the cell to the projectile (so we can find the distance)
    FVector2D ProjectileToCell = LocalCellPosition - LocalProjectileTransform.GetLocation();

    // Add the surface local offset as well (depends on the pivot of  your  art asset. needs to be aligned with some testing)
    ProjectileToCell += LocalSurfaceTransform.GetLocation();

    // Find the distance. check with distance squared for optimization (to avoid square root)
    float DistanceToProjectileSquared = ProjectileToCell.SizeSquared();

     if (DistanceToProjectileSquared < ProjectileRadiusSquared) {
          // The cell is close to the projectile.  apply some ramp function to get the influence, or just set it to 1 
          // to indicate the cell has been painted
          Influence[x][y] = 1.0f;
     }
  }
}

You will run this code only once when the projectile gets destroyed on impact (on the surface that it has touched). So having hundreds of projectiles won’t matter

posted as a new answer below due to character limit

Thanks for all the effort you’ve put in Ali, I really appreciate it. I went through the code you wrote and I understand the logic, seems to be a solid solution. I’ll try this out. Again, thanks a lot!