(Issues regarding the brightness, contrast and gamma attributes of SceneCapture2D’s texture)
Hello, the following is an issue that has stumped me for about a week.
Summary: I am attempting to create cameras in game that use SceneCapture2Ds to render to a texture whose pixels can be dumped and saved to a PNG or JPEG. The pixel buffers either end up too dark or too gray depending on use of sRGB OR artificial gamma correction I wrote based on [this equation][1] Not only this but whether the images come out “correct” or not is system dependent in that it works fine on three of my coworkers machines and has the exact same issues as mine on one coworkers system ( 3 vs 2). Both dynamic material instance and render target 2d’s are created dynamically and the texture parmeter on the material is set during construction.
- Simply put exported textures DO NOT
display as they show in game (Either
on render targets or in camera view)
and doing typical gamma correction
results in muddy textures.Even
extracting a texture from a correctly
rendered rendertarget produces bad
textures with or without correction.
Question: Is there a way to do this correctly regardless of level and hardware? If not what is the easiest most generalizable way to do it semi-specifically?
There is a link at the end of all of this to a zip file that contains much more egregiously discolored photos. Please look at those before rendering any sort of judgement.
Related posts read and whose partial solutions were attempted:
-
All of these either dont offer a solution or offer solutions they admit are partial or inferior.
-
I have tried all of these by themselves or in concert. (i do not have a precise test matrix available though)
-
TextureRenderTarget2D saved to PNG is much darker
- https://answers.unrealengine.com/questions/384499/texturerendertarget2d-saved-to-png-is-much-darker.html\
- Produces brighter textures but like other methods ends up making them pretty gray.
-
Render Texture Bug with Post Process Material when scenecapture 2D is set to “capture every frame” and “final color”.
- Render Texture Bug with Post Process Material when scenecapture 2D is set to "capture every frame" and "final color". - Rendering - Epic Developer Community Forums
- Allows for it to only update when desired but either still too dark or gray.
-
Scene Capture Image is darker than original game
- Scene Capture Image is darker than original game - Programming & Scripting - Epic Developer Community Forums
- solutions listed only work in single scenes and even then require a lot of manual twe4aking.
- this is a probloem because the mcamera is supposed to be automatic and generalizable.
-
Dark colors are displayed brighter and greyer.
- Dark colors are displayed brighter and greyer. - Rendering - Epic Developer Community Forums
- Colors are still off though this differs depnding on lighting?
-
SceneCapture2D capturing different scene than player camera
- SceneCapture2D capturing different scene than player camera - Rendering - Epic Developer Community Forums
- Did almost nothing.
- Setting the scene camera and capture component to the same post process Volume made the cmera follow the same shading as the capture component but textures rendered to another surface or saved out still came out wrong.
-
How do I disable Gamma Correction?
- How do I disable Gamma Correction? - Rendering - Epic Developer Community Forums
- interesting but involves going too deep into the engine to be…safe?
-
[UDK]: Rendering a TextureRenderTarget2D using Canvas produces a dark image
Elabortation:
[WORLD OUTLINE]
[BLUEPRINT]
[CAPTURE COMPONENT SETTINGS]
[MATERIAL BASE SETTINGS]
[RENDERTARGET]
http://s17.postimg.org/jqvuhi8in/Render_Target_Parent.png
[IMAGE METHODS]
////////////////////////////////////////////////////////////////////////
// CAMERA
UTexture2D* UREDACTEDFunctionLibrary::TakePhotoWithRenderTarget2D(UTextureRenderTarget2D* RenderTarget, ESavedImageFormat Format, bool& bIsValid, FString& FileLocation)
{
UTexture2D* Result = nullptr;
// Save Image from Render Target
FRenderTarget* TargetResource = RenderTarget->GameThread_GetRenderTargetResource();
if (TargetResource == nullptr)
{
return Result;
}
TArray<FColor> RawPixels;
bool bCopyValid = ReadTargetToBufferValidated(RawPixels, TargetResource);
if (bCopyValid == false)
{
return Result;
}
const int32 Width = RenderTarget->SizeX;
const int32 Height = RenderTarget->SizeY;
// Save Texture to jpg
SavePixelBufferToFile(RawPixels, Format, FileLocation, Width, Height);
Result = TextureFromPixelBuffer(RawPixels, Width, Height);
return Result;
}
void UREDACTEDFunctionLibrary::SavePixelBufferToFile(TArray<FColor> RawPixels, ESavedImageFormat Format, FString& FileLocation, int32 pWidth, int32 pHeight)
{
// Save Texture to jpg
FString GameDir = FPaths::ConvertRelativePathToFull(FPaths::GameDir());
FString PicsDir = FPaths::Combine(*GameDir, TEXT("PhonePics"));
FString Filename = TEXT("DC-") + FilesafeTimestamp() + TEXT("-") + FGuid::NewGuid().ToString();
FileLocation = FPaths::Combine(*PicsDir, *Filename);
IImageWrapperPtr ImageWrapper = NULL;
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
switch (Format)
{
case ESavedImageFormat::JPG:
ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);
FileLocation += ".jpg";
break;
case ESavedImageFormat::PNG:
ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
FileLocation += ".png";
break;
case ESavedImageFormat::BMP:
ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::BMP);
FileLocation += ".bmp";
break;
case ESavedImageFormat::ICO:
ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::ICO);
FileLocation += ".ico";
break;
case ESavedImageFormat::EXR:
ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::EXR);
FileLocation += ".exr";
break;
case ESavedImageFormat::ICNS:
ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::ICNS);
FileLocation += ".icns";
break;
}
if (ImageWrapper.IsValid())
{
if (ImageWrapper->SetRaw(RawPixels.GetData() , RawPixels.Num() * sizeof(FColor), pWidth, pHeight, ERGBFormat::RGBA, 8))
{
FFileHelper::SaveArrayToFile(ImageWrapper->GetCompressed(), *FileLocation);
}
}
}
bool UREDACTEDFunctionLibrary::ReadTargetToBufferValidated(TArray<FColor>& pPixelBuffer, FRenderTarget* pTargetResource)
{
if (!pTargetResource->ReadPixels(pPixelBuffer))
{
return false;
}
else
{
for (FColor& Pixel : (pPixelBuffer))
{
// ^Confirmed - S.
const uint8 R = Pixel.B;
const uint8 B = Pixel.R;
Pixel.R = R;
Pixel.B = B;
Pixel.A = 255;
//Pixel.AlignmentDummy = 0x00FF00;
// THE FOLLOWING IS GAMMA DECODE: USE IF SRGB IS ON AND ITS NOT A POSTPROCESS MATERIAL
/********************
float rFloat = ((float)R) / 255.0f;
float bFloat = ((float)B) / 255.0f;
float gFloat = ((float)Pixel.G) / 255.0f;
FLinearColor lColor = FLinearColor(rFloat, gFloat, bFloat);
Pixel = lColor.ToFColor(true);
FColor candColor = FColor();
candColor.R = 255 * (rFloat / (rFloat + 0.187f) * 1.035f);
candColor.B = 255 * (bFloat / (bFloat + 0.187f) * 1.035f);
candColor.G = 255 * (gFloat / (gFloat + 0.187f) * 1.035f);
Pixel.R = candColor.R;
Pixel.B = candColor.B;
Pixel.G = candColor.G;
*********************/
}
return true;
}
}
UTexture2D * UREDACTEDFunctionLibrary::Texture2DFromRenderTarget2D(UTextureRenderTarget2D * RenderTarget)
{
UTexture2D* Result = nullptr;
// Save Image from Render Target
FRenderTarget* TargetResource = RenderTarget->GameThread_GetRenderTargetResource();
if (TargetResource != nullptr)
{
TArray<FColor> RawPixels;
bool bCopyValid = ReadTargetToBufferValidated(RawPixels, TargetResource);
if (bCopyValid)
{
const int32 Width = RenderTarget->SizeX;
const int32 Height = RenderTarget->SizeY;
Result = TextureFromPixelBuffer(RawPixels, Width, Height);
}
}
return Result;
}
UTexture2D* UREDACTEDFunctionLibrary::TextureFromPixelBuffer(TArray<FColor> RawPixels, int32 pWidth, int32 pHeight)
{
UTexture2D* RetPtr = nullptr;
RetPtr = UTexture2D::CreateTransient(pWidth, pHeight, PF_R8G8B8A8);
void* TextureData = RetPtr->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, &RawPixels[0], RawPixels.Num() * sizeof(FColor));
RetPtr->PlatformData->Mips[0].BulkData.Unlock();
RetPtr->UpdateResource();
return RetPtr;
}
|| Computers
- Systems where there are issues:
- Mine
http://s9.postimg.org/7jz9zy7m7/PC_MINE.png
+ B
http://s27.postimg.org/yyut2x7ab/ss_2016_04_04_at_12_53_20.png
- Systems without issues:
- Jas
http://s9.postimg.org/o56wflyq7/PC_JASON.png
+ Jac
http://s9.postimg.org/woqadd72n/PC_JACK.png
+ N
http://s9.postimg.org/umpsz493j/PC_NOAH.png
[PICS (these should all be bright and realistic rather than dark and muddy)][13]