Hi @_artescape,
That’s a cool tutorial! Here’s how you can build on top if it to make a dishwashing effect.
To get the plate to show either clean or dirty, you’ll use a
Lerp
node in the material that you’re drawing onto. You’ll still be drawing black images on a white canvas, but instead of rendering that directly, we’ll pipe it into Lerp to choose which of the clean or dirty textures to show at each pixel.
Calculating the surface area that’s clean is going to be a bit harder, since we’ll need to dive into C++ (I couldn’t find a way to do it in Blueprints). But we’ll keep the C++ to an absolute minimum - just one class with one function.
If you’ve got a Blueprint project, to add C++ in Unreal Engine 5.1, you can select “Tools” in the topnav, then New C++ class. I selected the parent class as “None.” At this point you’ll have to close and recompile your project with Visual Studio to keep going.
There will be two files - a .h file and a .cpp. I named mine DishUtil.h
and DishUtil.cpp
. The .h Header file will be:
#pragma once
#include "CoreMinimal.h"
#include "DishUtil.generated.h"
class UTextureRenderTarget2D;
UCLASS()
class QA_DISHWASHING_API UDishUtil : public UObject
{
public:
GENERATED_BODY()
UFUNCTION(BlueprintCallable)
static float GetAverageGrayscaleColor(UTextureRenderTarget2D* Texture);
};
This just declares the things necessary to create a new node called GetAverageGrayscaleColor that you’ll need for it to show up in the engine.
And the .cpp file will be:
#include "DishUtil.h"
#include "Engine/TextureRenderTarget2D.h"
#include "ImageUtils.h"
float UDishUtil::GetAverageGrayscaleColor(UTextureRenderTarget2D* Texture)
{
// Stick the raw data into an array
// Need to make sure the Render Target 2D format is RTF RGBA8 - 4 bytes of data
TArray64<uint8> RawData;
FImageUtils::GetRawData(Texture, RawData);
// Loop through all the Red pixels - those are ones where the indexes are divisible by 4.
// We don't need the other colors, since we're working in grayscale anyway.
// Only pulling the red pixels would be more performant, but FImageUtils::GetRawData isn't setup to do that in 5.1
float Sum = 0;
for (int i = 0; i < RawData.Num(); i += 4)
{
Sum += RawData[i];
}
// Get the average.
// We divide raw data num by 4, since we're only working with the red pixels.
// The max number is 255 per red pixel, but we'll convert it to a 0 - 1 float scale, so we divide by 255 as a float.
return (Sum / (RawData.Num() / 4)) / 255.0;
}
This actually does the work of getting the grayscale value by taking the average of all the red components of the pixels. Since we’re drawing in grayscale, we can skip doing math on the blue and green color channels, since they’ll be exactly same values for a nice little performance boost.
I know this works in Unreal 5.1, but I see some comments in the code implying they might change how it works in later versions - not sure if they did or not.
This code is also expecting the Render Target 2D to have the RTF RGBA8 format. That just means it’s going to have 4 bytes per pixel, in the order of Red, Green, Blue, and Alpha.
Once this is in your project, and you’ve compiled with Visual Studio, you’ll have access to a new node called
GetAverageGrayscaleColor
that you can plug your RenderTarget into. I tacked mine on to the end of the
Drawbrush()
function for simplicity.
GetAverageGrayscaleColor
will return a number between 0 and 1, where 1 means the texture is totally unpainted, and 0 means totally painted.
I then subtract that number from one, as I found it easier at this point to think of “Percent Clean” than “Percent Dirty”
I also divide by a hand-entered number of about 0.3. For the plate model I was using, it actually only has about a third of its texture area on the plate surface. The plate will look completely clean once the previous node is reporting about .3 (or 30%). I found this number just by printing out the value to the screen as I cleaned the plate and seeing what it said when I was done.
From there I just stuck some bells and whistles on like a progress bar.
Credit for the plate model goes to:
“Dirty Plate” (Dirty Plate - Download Free 3D model by DownRev [1bd8fe9] - Sketchfab) by DownRev is licensed under Creative Commons Attribution (Deed - Attribution 4.0 International - Creative Commons).
I tweaked the dirty texture to have a darker background, to distinguish it from the clean color.
Big thanks to DownRev for leaving us their dirty dishes