UE4 如何將TextureRenderTarget2D保存爲本地圖片

     


昨日不可追, 今日尤可爲.勤奮,熾誠,不忘初心

手機淘寶二維碼 掃描      

或者打開連接:程序設計開發 ,掌聲鼓勵,歡迎光臨.


 

           UE4 如何將TextureRenderTarget2D保存爲本地圖片

關於如何保存TextureRenderTarget2D,從虛幻4的回答中心中,一搜就搜到了這篇文章:
TextureRenderTarget2D saved to PNG is much darker


裏面提供了一個保存TextureRenderTarget2D到本地PNG的方法,我把它寫進了一個藍圖函數庫裏面:
BlueprintFunctionBPLibrary.h中:

#include "Runtime/Engine/Public/ImageUtils.h"
UCLASS()
class UBlueprintFunctionBPLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_UCLASS_BODY()

	//保存UTextureRenderTarget2D到本地文件
	UFUNCTION(BlueprintCallable, meta = (DisplayName = "SaveRenderTargetToFile", Keywords = "SaveRenderTargetToFile"), Category = "SaveToFile")
		static bool SaveRenderTargetToFile(UTextureRenderTarget2D* rt, const FString& fileDestination);
};

BlueprintFunctionBPLibrary.cpp中:

#include "BlueprintFunctionBPLibrary.h"
#include "BlueprintFunction.h"
bool UBlueprintFunctionBPLibrary::SaveRenderTargetToFile(UTextureRenderTarget2D* rt, const FString& fileDestination)
{
	FTextureRenderTargetResource* rtResource = rt->GameThread_GetRenderTargetResource();
	FReadSurfaceDataFlags readPixelFlags(RCM_UNorm);

	TArray<FColor> outBMP;
	outBMP.AddUninitialized(rt->GetSurfaceWidth() * rt->GetSurfaceHeight());
	rtResource->ReadPixels(outBMP, readPixelFlags);

	FIntPoint destSize(rt->GetSurfaceWidth(), rt->GetSurfaceHeight());
	TArray<uint8> CompressedBitmap;
	FImageUtils::CompressImageArray(destSize.X, destSize.Y, outBMP, CompressedBitmap);
	bool imageSavedOk = FFileHelper::SaveArrayToFile(CompressedBitmap, *fileDestination);

	return imageSavedOk;
}

可以看到引擎中效果圖:

和保存的a.png圖:

對比上面兩張圖,感覺明顯不對。感覺透明通道有很大的問題

上面那篇文章也說了,保存的圖顏色比引擎中看到的要淡很多,如下圖:

我這邊的問題暴露的更嚴重,感覺透明通道都不正常了(很感謝暴露得很嚴重的問題)

如果,能有可以看到圖像像素數據的工具就好了…
還別說,還真有,感謝我吧。
先做一個UE4的OpenCV的插件,可以參考我這篇博客:
UE4使用第三方庫Ⅱ
https://blog.csdn.net/lunweiwangxi3/article/details/83187840

裏面就是以做OpenCV插件爲例的
OpenCV第三方庫下載地址:
https://download.csdn.net/download/lunweiwangxi3/10960604
我設置不了免費,窮人可評論發郵箱,免費傳

在OpenCV插件庫製作完成後,
在需要用到該插件的地方,打開xx. .Build.cs文件

在UBlueprintFunctionBPLibrary.cpp文件中,添加頭文件
//opencv
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"

把OpenCV的Bin目錄下的文件,全部拷貝到項目> Binaries>Wn64目錄下:

修改SaveRenderTargetToFile函數中的代碼如下所示:

bool UBlueprintFunctionBPLibrary::SaveRenderTargetToFile(UTextureRenderTarget2D* rt, const FString& fileDestination)
{
	FTextureRenderTargetResource* rtResource = rt->GameThread_GetRenderTargetResource();
	FReadSurfaceDataFlags readPixelFlags(RCM_UNorm);

	TArray<FColor> outBMP;
	outBMP.AddUninitialized(rt->GetSurfaceWidth() * rt->GetSurfaceHeight());
	rtResource->ReadPixels(outBMP, readPixelFlags);

	cv::Mat viewTmp = cv::Mat(rt->GetSurfaceHeight(), rt->GetSurfaceWidth(), CV_8UC4);
	for (int y = 0; y < rt->GetSurfaceHeight(); y++)
	{
		for (int x = 0; x < rt->GetSurfaceWidth(); x++)
		{
			int i = x + (y * rt->GetSurfaceWidth());
			viewTmp.at<cv::Vec4b>(y, x) = cv::Vec4b(outBMP[i].B, outBMP[i].G, outBMP[i].R, outBMP[i].A);
		}
	}

	return true;
}

然後安裝一個VS吊炸天的插件ImageWatch,操作如下

安裝,期間要把VS軟件關閉後才能繼續。安裝好,重新打開項目
在SaveRenderTargetToFile函數的最後一行( return true;)上下斷點

運行VS,UE4項目,在運行SaveRenderTargetToFile時會暫停到斷點處。
點擊 視圖>其他窗口>ImageWatch

RGBA四通道的值全都有!調試神器啊,僅限C++擁有。
注意:只能看到函數裏的局部cv::Mat變量,只能在C++項目中有效,C#項目中顯示不出。
結果顯示Alpha值莫名奇妙的變成了0.罪魁禍首?我們猜想測試下
強制把Alpha通道設置成255試試呢,說幹就幹,
把這行代碼:
viewTmp.at<cv::Vec4b>(y, x) = cv::Vec4b(outBMP[i].B, outBMP[i].G, outBMP[i].R, outBMP[i].A);
改成:
viewTmp.at<cv::Vec4b>(y, x) = cv::Vec4b(outBMP[i].B, outBMP[i].G, outBMP[i].R, 255);
老地方下斷點,運行vs,ue4,運行SaveRenderTargetToFile函數,

然後將函數OpenCV調試圖(左)引擎效果圖(右)作對比:

完美解決!
既然是改Alpha通道的值,那麼,OpenCV作爲我們的可視化調試工具的任務也圓滿完成了,兔死狗烹,把OpenCV模塊卸載掉,代碼刪掉。
在SaveRenderTargetToFile函數中添加代碼:
 for (FColor& color : outBMP)
  color.A = 255;

最終如下圖所示:

bool UBlueprintFunctionBPLibrary::SaveRenderTargetToFile(UTextureRenderTarget2D* rt, const FString& fileDestination)
{
	FTextureRenderTargetResource* rtResource = rt->GameThread_GetRenderTargetResource();
	FReadSurfaceDataFlags readPixelFlags(RCM_UNorm);

	TArray<FColor> outBMP;
	outBMP.AddUninitialized(rt->GetSurfaceWidth() * rt->GetSurfaceHeight());
	rtResource->ReadPixels(outBMP, readPixelFlags);

	for (FColor& color : outBMP)
		color.A = 255;

	FIntPoint destSize(rt->GetSurfaceWidth(), rt->GetSurfaceHeight());
	TArray<uint8> CompressedBitmap;
	FImageUtils::CompressImageArray(destSize.X, destSize.Y, outBMP, CompressedBitmap);
	bool imageSavedOk = FFileHelper::SaveArrayToFile(CompressedBitmap, *fileDestination);
	return imageSavedOk;

	return true;
}

最後我們運行下保存圖片,效果如下:

Perfect!
不要將就,只願完美。
 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章