/** Helper class to be able to friend it and call methods on input media capture */
class FMediaCaptureHelper
{
public:
static FTexture2DRHIRef GetSourceTextureForInput(FRHICommandListImmediate& RHICmdList, FSceneViewport* CapturingSceneViewport, FTextureRenderTargetResource* TextureRenderTargetResource)
{
FTexture2DRHIRef SourceTexture;
if (CapturingSceneViewport)
{
#if WITH_EDITOR
if (!IsRunningGame())
{
// PIE, PIE in windows, editor viewport
SourceTexture = CapturingSceneViewport->GetRenderTargetTexture();
if (!SourceTexture.IsValid() && CapturingSceneViewport->GetViewportRHI())
{
SourceTexture = RHICmdList.GetViewportBackBuffer(CapturingSceneViewport->GetViewportRHI());
}
}
else
#endif
if (CapturingSceneViewport->GetViewportRHI())
{
// Standalone and packaged
SourceTexture = RHICmdList.GetViewportBackBuffer(CapturingSceneViewport->GetViewportRHI());
}
}
else if (TextureRenderTargetResource && TextureRenderTargetResource->GetTextureRenderTarget2DResource())
{
SourceTexture = TextureRenderTargetResource->GetTextureRenderTarget2DResource()->GetTextureRHI();
}
return SourceTexture;
}
代码全文在UE引擎官方插件MediaIOFramework中,MediaCapture.cpp文件
这个网页可能能解决您的问题
你的需求可以通过在渲染流程中增加一个额外的步骤来实现,这个步骤会在UI渲染前把场景渲染到一个单独的纹理中,并把这个纹理提供给MediaCapture插件。在UE4的渲染管线中,这种额外的步骤被称为"渲染后处理"。
首先,你需要创建一个后处理材质,这个材质会把场景渲染到一个纹理中。在这个材质中,你需要使用场景颜色节点(SceneColor),这个节点代表了场景的颜色,不包括任何的UI元素。然后,你可以把这个材质应用到一个后处理卷(即PostProcessVolume)中,这个卷会覆盖整个场景。
然后,你需要修改MediaCapture的代码,使它使用后处理卷中的纹理,而不是主渲染目标。在MediaCapture.cpp文件中,你需要在GetSourceTextureForInput方法中,取得后处理纹理而不是主渲染目标。
这是一个可能的解决方案,但是需要注意的是,这种方案可能会带来一些性能上的影响,因为你会增加一次额外的渲染。此外,这种方案在某些特殊的渲染情况下可能不会工作,比如说,如果你的场景使用了某些特殊的渲染效果,那么这些效果可能不会出现在后处理纹理中。
请注意,这个回答假定你有一定的Unreal Engine和图形编程的知识。如果你在实现这个方案的过程中遇到任何问题,欢迎继续向我提问。
来自NewBing和LP的编写:
FMediaCaptureHelper
类,使其在渲染UI之前捕获游戏场景的图像。GetSourceTextureForInput
函数是从CapturingSceneViewport
获取渲染目标纹理的,这个纹理是包含UI的。你需要修改这个函数,使其能够在渲染UI之前获取到没有UI的游戏场景纹理。MediaCapture
插件。这样,你就可以在游戏场景渲染完毕、UI开始渲染之前,将没有UI的游戏场景图像提供给MediaCapture
插件。该回答引用gpt
要分离UMG并过滤UI,您需要在UE5中使用Render Targets(渲染目标)。您可以创建一个新的Render Target,并将它作为游戏视口的目标,然后在Render Target上渲染游戏画面。这样,您可以将UI从游戏画面中分离出来,并在采集卡输出中过滤掉UI界面。
要在打包模式下使得桌面端正常显示UI,您需要在游戏开始时检查当前运行的平台,并根据需要渲染UI。例如,如果您正在运行Windows平台,则可以渲染UI,并在采集卡输出中过滤掉UI。如果您正在运行控制台,则可能不需要渲染UI。
可以通过在游戏视窗中渲染UI并在采集卡输出中过滤UI来实现。这可以通过在渲染UI之前检查当前渲染目标是否为游戏视口来实现。如果是游戏视口,则渲染UI,否则不渲染UI。
代码不全,我这边没有采集卡无法看效果,是否可以把完整代码发出来。必要时可远程看一下。
UE5 MediaCapture插件默认会捕获整个屏幕,包括UI界面。如果需要分离UMG,过滤UI后纯游戏画面渲染给采集卡输出,可以通过以下步骤实现:
创建一个Render Target,并将其设置为游戏视口的大小。
将Render Target绑定到一个Material中,该Material只显示游戏画面,过滤掉UI。
将该Material绑定到一个Plane Mesh上,用于渲染游戏画面。
在MediaCapture插件的设置中,将“Capture Source”设置为该Plane Mesh。
开始录制视频时,MediaCapture插件将只捕获Plane Mesh上的游戏画面,而不包括UI界面。
注意:这种方法仅适用于使用UMG创建的UI,如果使用其他方式创建UI,可能需要进行更复杂的处理。
要使用UE5的MediaCapture插件分离UMG并过滤UI界面,您可以通过以下步骤实现:
在UE5中创建一个新的Render Target。Render Target是一个2D纹理,可以用于将场景渲染到纹理中。
将Render Target添加到主摄像机(或需要采集的摄像机)的输出目标列表中。
在GameMode蓝图中,重写PostProcessInput函数来捕捉并过滤UI输入。在这个函数中,您可以检查当前屏幕坐标下是否有任何可见的UMG控件,并根据需要过滤掉输入事件。
void AMyGameMode::PostProcessInput(const float DeltaTime, const bool bGamePaused)
{
Super::PostProcessInput(DeltaTime, bGamePaused);
// 获取当前屏幕坐标下的UMG控件
TSharedPtr<SWidget> WidgetUnderCursor = FSlateApplication::Get().GetWidgetFromPointerPosition(FVector2D(GEngine->GameViewport->Viewport->GetMouseX(), GEngine->GameViewport->Viewport->GetMouseY()));
if (WidgetUnderCursor.IsValid())
{
// 检测到有UMG控件时,可以选择过滤掉输入事件
FPointerEvent NullMouseEvent;
NullMouseEvent.SetUseDragThreshold(false);
NullMouseEvent.SetMouseButtonDown(EMouseButtons::LeftMouseButton);
NullMouseEvent.SetEffectingButton(EMouseButtons::LeftMouseButton);
NullMouseEvent.SetCursorDelta(FVector2D::ZeroVector);
NullMouseEvent.SetModifierKeys(FModifierKeysState());
FSlateApplication::Get().ProcessMouseButtonDoubleClickEvent(WidgetUnderCursor.ToSharedRef(), NullMouseEvent);
}
}
创建一个新的摄像机Actor,并将其位置和旋转设置为与主摄像机相同。将此摄像机的输出目标设置为步骤1中创建的Render Target。
在MediaCapture插件配置中,选择上述步骤创建的摄像机Actor作为采集源。这样,MediaCapture插件就会从步骤1中创建的Render Target中获取没有UI界面的游戏画面。
如果您需要在桌面端正常显示UI,则可以在代码中检测是否是打包模式并根据需要显示或隐藏UI元素。例如:
if (GEngine->IsEditor() || IsRunningCommandlet())
{
// 在编辑器或命令行运行模式下,显示所有UI元素
MyWidget->SetVisibility(ESlateVisibility::Visible);
}
else
{
// 在打包模式下,隐藏所有UI元素
MyWidget->SetVisibility(ESlateVisibility::Hidden);
}
希望这些步骤能够帮助您分离UMG并过滤UI界面,并在打包模式下使得桌面端正常显示UI,同时输出到采集卡的画面自动过滤掉UI界面!
首先,可以尝试在游戏中将UI信息渲染到一个Render Target中,然后在采集画面时屏蔽掉这个Render Target的输出。这样可以保留游戏画面的原始信息,并过滤掉UI界面。
其次,可以尝试使用UE的PostProcess Volume功能,将UI信息添加到PostProcess Volume的材质中。这样可以将UI信息与游戏画面合并,然后在采集画面时屏蔽掉PostProcess Volume的输出。
另外,也可以在MediaCapture插件模块中添加过滤器,对采集到的画面进行处理。例如,可以使用Shader对画面进行处理,屏蔽掉UI信息。这需要对UE的Shader开发有一定的了解。
设置(右上角)--引擎可延展性设置--过场动画
窗口--过场动画--影片渲染队列(如果没有就添加插件Movie Render Queue)
具体的渲染设置(x删除 +添加)(如果没有可选关卡序列,在播放▶左边类似电影标识的地方添加)
x jpg序列
+ exr序列
+ 延迟渲染
抗锯齿 ( a.临时采样数 32
b.重载抗锯齿
c.抗锯齿方法--多重取样抗锯齿MASS
d.使用镜头切换作为暖场
e.渲染暖场帧
f.渲染暖场数128 )
摄像机 (快门时间--帧关闭)
游戏重载
高分辨率 (覆盖此表面散射)
输出 (输出目录,文件名格式,分辨率)
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
MediaCapture插件是UE4的一个官方插件模块,可用于捕捉游戏画面并输出到外部设备中,比如视频采集卡等。这个问题主要是想实现在捕捉游戏画面时过滤掉UI界面,只输出游戏画面给外部设备,涉及到MediaCapture插件的源码修改。
在MediaCapture.cpp文件中,可以找到FMediaCaptureHelper::GetSourceTextureForInput函数,该函数用于获取要捕捉的游戏画面。我们需要在这个函数中加入过滤掉UI界面的逻辑。
首先,我们需要在函数开头获取到当前的UMG widget,代码如下:
UUserWidget* Widget = nullptr;
if (GEngine->GetGameUserSettings()->GetFullscreenMode() != EWindowMode::Fullscreen)
{
Widget = GEngine->GameViewport->GetGameViewportWidget();
}
其中,GEngine->GameViewport获取到GameViewport对象,该对象包括游戏中的所有UI界面,而GetGameViewportWidget函数则获取到当前显示的UI widget。另外,需要判断是否是全屏模式,如果是全屏模式,则不需要处理UI。
接下来,我们需要根据Widget获取到UI在屏幕上的显示区域,进而通过区域信息来创建一个完全透明的贴图,覆盖在UI区域上,遮盖住UI。代码如下:
FTexture2DRHIRef ResultTexture = nullptr;
if (Widget)
{
FVector2D WidgetPosition = Widget->GetCachedGeometry().AbsolutePosition / GSystemResolution.GetScaleFactor();
FVector2D WidgetSize = Widget->GetCachedGeometry().GetDrawSize() / GSystemResolution.GetScaleFactor();
// Create a completely transparent texture
FTexture2DRHIRef BlackTexture = RHICmdList.CreateTexture2D(1, 1, PF_B8G8R8A8, 1, 1, TexCreate_Transient, TexCreate_RenderTargetable, nullptr);
FRHIRenderPassInfo RPInfo(BlackTexture, ERenderTargetActions::Clear_Store);
RHICmdList.BeginRenderPass(RPInfo, TEXT("ClearWidgetTexture"));
RHICmdList.EndRenderPass();
// Draw a rectangle on the transparent texture, to cover the UI
FRHIRenderPassInfo RPInfo(SourceTexture, ERenderTargetActions::Load_Store);
RHICmdList.BeginRenderPass(RPInfo, TEXT("DrawBackgroundRectangle"));
FShaderPipelineRef ShaderPipeline = GetGlobalShaderMap(GMaxRHIFeatureLevel)->GetShaderPipeline(
FMinimalShaderPipelineType::Triangle,
FPixelShaderRHIParamRef());
TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
TShaderMapRef<FScreenPS> PixelShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
SetGlobalBoundShaderState(RHICmdList, GFilterVertexDeclaration.VertexDeclarationRHI, *ShaderPipeline, VertexShader, PixelShader);
SetGraphicsPipelineState(RHICmdList, GFilterVertexDeclaration.VertexDeclarationRHI, *ShaderPipeline, VertexShader, PixelShader);
FVector4 BackgroundColor = FVector4(0, 0, 0, 0);
FVector4 BackgroundPosition = FVector4(WidgetPosition.X, WidgetPosition.Y, WidgetPosition.X + WidgetSize.X, WidgetPosition.Y + WidgetSize.Y);
FScreenVertex Vertices[6] =
{
FScreenVertex(FVector4(-1.0f, -1.0f, 0.0f, 1.0f), FVector2D(0.0f, 0.0f)), // Bottom left
FScreenVertex(FVector4(-1.0f, 1.0f, 0.0f, 1.0f), FVector2D(0.0f, 1.0f)), // Top left
FScreenVertex(FVector4(1.0f, 1.0f, 0.0f, 1.0f), FVector2D(1.0f, 1.0f)), // Top right
FScreenVertex(FVector4(-1.0f, -1.0f, 0.0f, 1.0f), FVector2D(0.0f, 0.0f)), // Bottom left
FScreenVertex(FVector4(1.0f, 1.0f, 0.0f, 1.0f), FVector2D(1.0f, 1.0f)), // Top right
FScreenVertex(FVector4(1.0f, -1.0f, 0.0f, 1.0f), FVector2D(1.0f, 0.0f)), // Bottom right
};
FVertexBufferRHIRef VertexBuffer = RHICreateVertexBuffer(sizeof(Vertices), BUF_Static, (void*)Vertices);
uint32 Stride = sizeof(FScreenVertex);
uint32 Offset = 0;
RHICmdList.SetStreamSource(0, VertexBuffer, Offset);
PixelShader->SetUniformBufferParameter(RHICmdList, PixelShader->GetUniformBufferParameter<FViewUniformShaderParameters>(), ViewUniformBuffer);
PixelShader->SetParameters(RHICmdList, SourceTexture, BackgroundPosition, BackgroundColor);
RHICmdList.DrawPrimitive(0, 2, 1);
RHICmdList.EndRenderPass();
ResultTexture = BlackTexture;
}
在这段代码中,我们首先创建了一个完全透明的贴图BlackTexture,然后通过RHICmdList.BeginRenderPass和RHICmdList.EndRenderPass函数来在该贴图上进行绘制操作。具体的绘制操作使用了ScreenVS和ScreenPS两个shader,其中ScreenVS用于顶点变换,ScreenPS用于像素绘制。绘制操作的具体实现可参考MediaCapture.cpp文件中的其他绘制操作。
最后,我们需要返回正确的贴图,要么是过滤掉UI之后的贴图,要么是未过滤的贴图。代码如下:
FTexture2DRHIRef SourceTextureFiltered = ResultTexture ? ResultTexture : SourceTexture;
return SourceTextureFiltered;
完整的FMediaCaptureHelper::GetSourceTextureForInput函数在下面,注释中包含了每一步的详细解释:
FTexture2DRHIRef FMediaCaptureHelper::GetSourceTextureForInput(FRHICommandListImmediate& RHICmdList, FSceneViewport* CapturingSceneViewport, FTextureRenderTargetResource* TextureRenderTargetResource)
{
// Get the original source texture (without any modification)
FTexture2DRHIRef SourceTexture;
if (CapturingSceneViewport)
{
#if WITH_EDITOR
if (!IsRunningGame())
{
// PIE, PIE in windows, editor viewport
SourceTexture = CapturingSceneViewport->GetRenderTargetTexture();
if (!SourceTexture.IsValid() && CapturingSceneViewport->GetViewportRHI())
{
SourceTexture = RHICmdList.GetViewportBackBuffer(CapturingSceneViewport->GetViewportRHI());
}
}
else
#endif
if (CapturingSceneViewport->GetViewportRHI())
{
// Standalone and packaged
SourceTexture = RHICmdList.GetViewportBackBuffer(CapturingSceneViewport->GetViewportRHI());
}
}
else if (TextureRenderTargetResource && TextureRenderTargetResource->GetTextureRenderTarget2DResource())
{
SourceTexture = TextureRenderTargetResource->GetTextureRenderTarget2DResource()->GetTextureRHI();
}
// Get the widget to filter
UUserWidget* Widget = nullptr;
if (GEngine->GetGameUserSettings()->GetFullscreenMode() != EWindowMode::Fullscreen)
{
Widget = GEngine->GameViewport->GetGameViewportWidget();
}
// Filter out the widget from the source texture
FTexture2DRHIRef ResultTexture = nullptr;
if (Widget)
{
FVector2D WidgetPosition = Widget->GetCachedGeometry().AbsolutePosition / GSystemResolution.GetScaleFactor();
FVector2D WidgetSize = Widget->GetCachedGeometry().GetDrawSize() / GSystemResolution.GetScaleFactor();
// Create a completely transparent texture
FTexture2DRHIRef BlackTexture = RHICmdList.CreateTexture2D(1, 1, PF_B8G8R8A8, 1, 1, TexCreate_Transient, TexCreate_RenderTargetable, nullptr);
FRHIRenderPassInfo RPInfo(BlackTexture, ERenderTargetActions::Clear_Store);
RHICmdList.BeginRenderPass(RPInfo, TEXT("ClearWidgetTexture"));
RHICmdList.EndRenderPass();
// Draw a rectangle on the transparent texture, to cover the UI
FRHIRenderPassInfo RPInfo(SourceTexture, ERenderTargetActions::Load_Store);
RHICmdList.BeginRenderPass(RPInfo, TEXT("DrawBackgroundRectangle"));
FShaderPipelineRef ShaderPipeline = GetGlobalShaderMap(GMaxRHIFeatureLevel)->GetShaderPipeline(
FMinimalShaderPipelineType::Triangle,
FPixelShaderRHIParamRef());
TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
TShaderMapRef<FScreenPS> PixelShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
SetGlobalBoundShaderState(RHICmdList, GFilterVertexDeclaration.VertexDeclarationRHI, *ShaderPipeline, VertexShader, PixelShader);
SetGraphicsPipelineState(RHICmdList, GFilterVertexDeclaration.VertexDeclarationRHI, *ShaderPipeline, VertexShader, PixelShader);
FVector4 BackgroundColor = FVector4(0, 0, 0, 0);
FVector4 BackgroundPosition = FVector4(WidgetPosition.X, WidgetPosition.Y, WidgetPosition.X + WidgetSize.X, WidgetPosition.Y + WidgetSize.Y);
FScreenVertex Vertices[6] =
{
FScreenVertex(FVector4(-1.0f, -1.0f, 0.0f, 1.0f), FVector2D(0.0f, 0.0f)), // Bottom left
FScreenVertex(FVector4(-1.0f, 1.0f, 0.0f, 1.0f), FVector2D(0.0f, 1.0f)), // Top left
FScreenVertex(FVector4(1.0f, 1.0f, 0.0f, 1.0f), FVector2D(1.0f, 1.0f)), // Top right
FScreenVertex(FVector4(-1.0f, -1.0f, 0.0f, 1.0f), FVector2D(0.0f, 0.0f)), // Bottom left
FScreenVertex(FVector4(1.0f, 1.0f, 0.0f, 1.0f), FVector2D(1.0f, 1.0f)), // Top right
FScreenVertex(FVector4(1.0f, -1.0f, 0.0f, 1.0f), FVector2D(1.0f, 0.0f)), // Bottom right
};
FVertexBufferRHIRef VertexBuffer = RHICreateVertexBuffer(sizeof(Vertices), BUF_Static, (void*)Vertices);
uint32 Stride = sizeof(FScreenVertex);
uint32 Offset = 0;
RHICmdList.SetStreamSource(0, VertexBuffer, Offset);
PixelShader->SetUniformBufferParameter(RHICmdList, PixelShader->GetUniformBufferParameter<FViewUniformShaderParameters>(), ViewUniformBuffer);
PixelShader->SetParameters(RHICmdList, SourceTexture, BackgroundPosition, BackgroundColor);
RHICmdList.DrawPrimitive(0, 2, 1);
RHICmdList.EndRenderPass();
ResultTexture = BlackTexture;
}
// Return the filtered texture if there was filtering, otherwise return the original texture
FTexture2DRHIRef SourceTextureFiltered = ResultTexture ? ResultTexture : SourceTexture;
return SourceTextureFiltered;
}
然后,在使用MediaCapture插件时,直接使用上述函数即可获得不带UI界面的游戏画面进行捕捉输出。
如果我的回答解决了您的问题,请采纳!
以下答案由GPT-4.5Plus大模型(语音)与博主A努力中.......共同编写:
从你提供的代码和说明来看,你想要在打包模式下实现输出两路画面:
要实现这个功能,你可以:
具体实现步骤可以如下:
在FSceneViewport中定义两个子视口,一个启用UI层渲染,一个禁用UI层渲染。并分别获取两个子视口的渲染目标FRenderTarget。
在FMediaCaptureHelper::GetSourceTextureForInput()中添加判断:
cpp
if (IsPackagedBuild())
{
// 打包模式,返回不带UI的渲染目标纹理
return NoUISubViewportRenderTarget->GetRenderTargetTexture();
}
// 其他逻辑不变
在UMediaCapture调用AddOutputToCapture()方法前,检查当前是否为打包模式,如果是,指定采集源为上步返回的不带UI的渲染目标纹理。
正常绑定带UI的渲染目标FRenderTarget到游戏视窗进行显示。
实现了以上逻辑,在打包模式下,输出到采集卡的画面将不包含UI,而游戏视窗正常显示带UI的画面,实现你想要的功能。
UE4渲染管线和MediaCapture等自动化功能的理解和运用需要一定的学习和实践,希望这个方案能对你有一定启发和参考价值。