昨日不可追, 今日尤可爲.勤奮,熾誠,不忘初心
手機淘寶二維碼 掃描
或者打開連接:程序設計開發 ,掌聲鼓勵,歡迎光臨.
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!
不要將就,只願完美。