其他
UE4快速开发官方B站视频封面合成工具
前言
需求分析
不同的视频,属于不同的分类,所以需要Banner上的文字和颜色都得相应的变化。 视频的量比较多。每周平均都得新上传几部,以前已经上传过的500多个我也想重新给封面套上Banner。所以需要同时支持图片和视频。 图片和视频的分辨率不同,所以希望能尽量自动化的放缩匹配上。
希望流程尽量高效。输入一个视频或图片,输出一张封面图,中间的步骤应该尽量的高效简化。 可视化调整。加Banner条的时候,希望能实时的调整背景图样式,或者采用不同的视频帧画面。 方便扩展。可以随时更改Banner条颜色和文字内容。
技术方案选择
一,PS
PS打开比较慢。每次要制作封面图,我都得等它打开一下。 每次依然都得手动的用截图工具从视频播放器中截取画面,然后再导入PS。 每次都得在PS里缩放调整操作一番,才能对好一张封面图位置。 PS里的样式不太理想的话,还得从视频里重新截图再导入PS,流程再来一遍,很繁琐。
二,Python Pillow库
三,把UMG当做PS用!
工具演示
可以快速的切换Banner样式。 不管拖动进来的图片和视频大小如何,可以自动的匹配背景框大小。也支持一定的放大特写。 拖动进度条可以选取视频帧。 非常快速的导出结果封面图,如果是图片,最快的操作只需要一次拖动。
技术点
一,拖动文件到运行时游戏窗口中
OnDragEnter( InGeometry, InDragDropEvent, InOperation );
TSharedPtr<FUMGDragDropOp> NativeOp = DragDropEvent.GetOperationAs<FUMGDragDropOp>(); //断点
if ( NativeOp.IsValid() )
{
if ( CanRouteEvent() )
{
WidgetObject->NativeOnDragEnter( MyGeometry, DragDropEvent, NativeOp->GetOperation() );
}
}
{
SLATE_BEGIN_ARGS(SDropWidget) { }
SLATE_END_ARGS()public:
virtual void OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)override;//重载掉
TWeakObjectPtr<UBaseBannerMainWidget> mWidget;
TSharedPtr<FExternalDragOperation> op = DragDropEvent.GetOperationAs<FExternalDragOperation>();
const TArray<FString>& files = op->GetFiles(); //得到拖入的文件列表
if (files.Num() > 0)
{
mWidget->DropFile(files[0]); //一次只接收一个,这里逻辑就可以随便写了。
}
mWidget = widget;
ChildSlot[mWidget->TakeWidget()]; //添加嵌套UMG控件到Slate控件里
GEngine->GetWorldFromContextObject(this, EGetWorldErrorMode::LogAndReturnNull)->GetGameViewport()->AddViewportWidgetContent(dropWidget);
APlayerController* pc = UGameplayStatics::GetPlayerController(this, 0);//创建UMG控件
UBaseBannerMainWidget* mainWidget = CreateWidget<UBaseBannerMainWidget>(pc, BannerWidgetClass, "BannerWidget");//内嵌到Slate控件内
dropWidget->AddWidget(mainWidget);
二,加载图片生成Texture
ENGINE_API static UTexture2D* ImportFileAsTexture2D(const FString& Filename);
三,渲染UMG特定控件内容到图片
{
TSharedPtr<class SRetainerWidget> MyRetainerWidget; //老套路,内部是Slate控件
{
FRetainerWidgetRenderingResources* RenderingResources; //内部发现了这么一个东西
//搜索代码后,发现了在这个函数内,有取得RT,并且还出现了FWidgetRenderer
UTextureRenderTarget2D* RenderTarget = RenderingResources->RenderTarget;
FWidgetRenderer* WidgetRenderer = RenderingResources->WidgetRenderer;
WidgetRenderer->DrawWindow(...);
{
void DrawWidget(UTextureRenderTarget2D* RenderTarget,const TSharedRef<SWidget>& Widget,FVector2D DrawSize,float DeltaTime,bool bDeferRenderTargetUpdate = false);
ScreenshotRT = NewObject<UTextureRenderTarget2D>(this);//创建RT
ScreenshotRT->ClearColor = FLinearColor::Transparent;
ScreenshotRT->InitCustomFormat(ScreenshotSize.X, ScreenshotSize.Y, PixelFormat, !bIsSRGB);
UGameViewportClient* GameViewportClient = GEngine->GameViewport;
TSharedPtr<SViewport> ViewportWidget = GameViewportClient->GetGameViewportWidget();
FIntPoint ScreenshotSize = GameViewportClient->GetGameViewport()->GetSizeXY();
TArray<FColor> OutColorData;
// when rendering to a separate render target
FWidgetRenderer* WidgetRenderer = new FWidgetRenderer(true, false); //创建widget渲染器
//渲染到RT
WidgetRenderer->DrawWidget(ScreenshotRT, ViewportWidget.ToSharedRef(), ScreenshotSize, 0.f);
FlushRenderingCommands();
BeginCleanup(WidgetRenderer);
//读取RT像素值
ReadPixelsFromRT(ScreenshotRT, &OutColorData);
ENGINE_API static bool ExportRenderTarget2DAsPNG(UTextureRenderTarget2D* TexRT, FArchive& Ar);
{
* Exports a render target as a HDR or PNG image onto the disk (depending on the format of the render target)
*/
UFUNCTION(BlueprintCallable, Category = "Rendering", meta = (Keywords = "ExportRenderTarget", WorldContext = "WorldContextObject"))
static ENGINE_API void ExportRenderTarget(UObject* WorldContextObject, UTextureRenderTarget2D* TextureRenderTarget, const FString& FilePath, const FString& FileName);
UTextureRenderTarget2D* widgetRT = NewObject<UTextureRenderTarget2D>(this);
bool bIsSRGB = false;
EPixelFormat PixelFormat = PF_B8G8R8A8;
FIntPoint ScreenshotSize(1440, 900); //定死了就这么大
widgetRT->ClearColor = FLinearColor::Transparent;
widgetRT->RenderTargetFormat = ETextureRenderTargetFormat::RTF_RGBA8;
widgetRT->InitCustomFormat(ScreenshotSize.X, ScreenshotSize.Y, PixelFormat, !bIsSRGB);
FWidgetRenderer* WidgetRenderer = new FWidgetRenderer(true, false);
WidgetRenderer->DrawWidget(widgetRT, widget->TakeWidget(), ScreenshotSize, 0.f);
FlushRenderingCommands();
BeginCleanup(WidgetRenderer);
resultFileName += "_" + title + +"_" + channel + ".png"; //拼接一下文件名
UKismetRenderingLibrary::ExportRenderTarget(this, widgetRT, resultFilePath, resultFileName);
return FPaths::Combine(resultFilePath, resultFileName);
开源
总结
坚定信心,UE4编辑器能做到的,我们也能做到。编辑器目前不支持的,我们改改代码绕一下一般也能做到。最后还有个办法改引擎源码,那能做的东西就更多了。要充分理解到UE4编辑器本质其实也是个Game,只不过有些代码没在Runtime模式下启动,但接口功能一般都已经写好了。 UE4源码是个巨大的宝藏。游戏引擎要支持游戏里的各种功能开发,本身已经写成了个庞然大物,所以一般内部都集成了各种库和算法。所以当你想实现某个功能的时候,如果比较典型,第一个反应应该是去源码里找找看有没有现成写好的接口。 懂得追根溯源。我在一开始开发Banner工具的时候,完全不知道内部Widget的渲染细节,但通过对问题的分析和技术感觉,多用“Find All References”功能,就可以对代码的调用关系进行分析参照。可以快速的找到可供模仿的代码块。 用UE4开发小工具真的好方便!身为一个技术人员,应该多一些用工具来优化自身工作流程的意识。
近期焦点
虚幻引擎4.23现已发布!
Epic Games携虚幻引擎Unreal Engine亮相AU China 2019
虚拟制片:人人可用的表演捕捉
[活动预告]虚幻引擎Unreal Circle线下技术沙龙 | 9月21号北京站
从SketchUp到Twinmotion:网络研讨会重播
虚幻商城五周年!精选商品五折特惠!
一周综述:虚幻引擎在SIGGRAPH 2019
Twinmotion社区挑战赛公告
UE4助力通用雪佛兰打破历史销售记录
虚幻引擎Epic MegaGrant:教育工作者须知
实时渲染之Twinmotion:又好又快的建筑可视化
Modified on