vault backup: 2025-03-11 18:33:42
This commit is contained in:
parent
aa9658becc
commit
8ecf617235
243
03-UnrealEngine/Rendering/Shader/UE5 NDI传输结果模糊问题解决.md
Normal file
243
03-UnrealEngine/Rendering/Shader/UE5 NDI传输结果模糊问题解决.md
Normal file
@ -0,0 +1,243 @@
|
||||
# NDI播放模糊问题解决
|
||||
- bool UNDIMediaReceiver::CaptureConnectedVideo()
|
||||
|
||||
```c++
|
||||
bool UNDIMediaReceiver::Initialize(const FNDIConnectionInformation& InConnectionInformation, UNDIMediaReceiver::EUsage InUsage)
|
||||
{
|
||||
if (this->p_receive_instance == nullptr)
|
||||
{
|
||||
if (IsValid(this->InternalVideoTexture))
|
||||
this->InternalVideoTexture->UpdateResource();
|
||||
|
||||
// create a non-connected receiver instance
|
||||
NDIlib_recv_create_v3_t settings;
|
||||
settings.allow_video_fields = false;
|
||||
settings.bandwidth = NDIlib_recv_bandwidth_highest;
|
||||
settings.color_format = NDIlib_recv_color_format_fastest;
|
||||
|
||||
p_receive_instance = NDIlib_recv_create_v3(&settings);
|
||||
|
||||
// check if it was successful
|
||||
if (p_receive_instance != nullptr)
|
||||
{
|
||||
// If the incoming connection information is valid
|
||||
if (InConnectionInformation.IsValid())
|
||||
{
|
||||
//// Alright we created a non-connected receiver. Lets actually connect
|
||||
ChangeConnection(InConnectionInformation);
|
||||
}
|
||||
|
||||
if (InUsage == UNDIMediaReceiver::EUsage::Standalone)
|
||||
{
|
||||
this->OnNDIReceiverVideoCaptureEvent.Remove(VideoCaptureEventHandle);
|
||||
VideoCaptureEventHandle = this->OnNDIReceiverVideoCaptureEvent.AddLambda([this](UNDIMediaReceiver* receiver, const NDIlib_video_frame_v2_t& video_frame)
|
||||
{
|
||||
FTextureRHIRef ConversionTexture = this->DisplayFrame(video_frame);
|
||||
if (ConversionTexture != nullptr)
|
||||
{
|
||||
if ((GetVideoTextureResource() != nullptr) && (GetVideoTextureResource()->TextureRHI != ConversionTexture))
|
||||
{
|
||||
GetVideoTextureResource()->TextureRHI = ConversionTexture;
|
||||
RHIUpdateTextureReference(this->VideoTexture->TextureReference.TextureReferenceRHI, ConversionTexture);
|
||||
}
|
||||
if ((GetInternalVideoTextureResource() != nullptr) && (GetInternalVideoTextureResource()->TextureRHI != ConversionTexture))
|
||||
{
|
||||
GetInternalVideoTextureResource()->TextureRHI = ConversionTexture;
|
||||
RHIUpdateTextureReference(this->InternalVideoTexture->TextureReference.TextureReferenceRHI, ConversionTexture);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// We don't want to limit the engine rendering speed to the sync rate of the connection hook
|
||||
// into the core delegates render thread 'EndFrame'
|
||||
FCoreDelegates::OnEndFrameRT.Remove(FrameEndRTHandle);
|
||||
FrameEndRTHandle.Reset();
|
||||
FrameEndRTHandle = FCoreDelegates::OnEndFrameRT.AddLambda([this]()
|
||||
{
|
||||
while(this->CaptureConnectedMetadata())
|
||||
; // Potential improvement: limit how much metadata is processed, to avoid appearing to lock up due to a metadata flood
|
||||
this->CaptureConnectedVideo();
|
||||
});
|
||||
|
||||
#if UE_EDITOR
|
||||
// We don't want to provide perceived issues with the plugin not working so
|
||||
// when we get a Pre-exit message, forcefully shutdown the receiver
|
||||
FCoreDelegates::OnPreExit.AddWeakLambda(this, [&]() {
|
||||
this->Shutdown();
|
||||
FCoreDelegates::OnPreExit.RemoveAll(this);
|
||||
});
|
||||
|
||||
// We handle this in the 'Play In Editor' versions as well.
|
||||
FEditorDelegates::PrePIEEnded.AddWeakLambda(this, [&](const bool) {
|
||||
this->Shutdown();
|
||||
FEditorDelegates::PrePIEEnded.RemoveAll(this);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
绘制函数
|
||||
```c++
|
||||
/**
|
||||
Attempts to immediately update the 'VideoTexture' object with the last capture video frame
|
||||
from the connected source
|
||||
*/
|
||||
FTextureRHIRef UNDIMediaReceiver::DisplayFrame(const NDIlib_video_frame_v2_t& video_frame)
|
||||
{
|
||||
// we need a command list to work with
|
||||
FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
|
||||
|
||||
// Actually draw the video frame from cpu to gpu
|
||||
switch(video_frame.frame_format_type)
|
||||
{
|
||||
case NDIlib_frame_format_type_progressive:
|
||||
if(video_frame.FourCC == NDIlib_FourCC_video_type_UYVY)
|
||||
return DrawProgressiveVideoFrame(RHICmdList, video_frame);
|
||||
else if(video_frame.FourCC == NDIlib_FourCC_video_type_UYVA)
|
||||
return DrawProgressiveVideoFrameAlpha(RHICmdList, video_frame);
|
||||
break;
|
||||
case NDIlib_frame_format_type_field_0:
|
||||
case NDIlib_frame_format_type_field_1:
|
||||
if(video_frame.FourCC == NDIlib_FourCC_video_type_UYVY)
|
||||
return DrawInterlacedVideoFrame(RHICmdList, video_frame);
|
||||
else if(video_frame.FourCC == NDIlib_FourCC_video_type_UYVA)
|
||||
return DrawInterlacedVideoFrameAlpha(RHICmdList, video_frame);
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
```
|
||||
|
||||
DrawProgressiveVideoFrame
|
||||
|
||||
|
||||
UNDIMediaReceiver::CaptureConnectedVideo
|
||||
=>
|
||||
DisplayFrame NDIlib_frame_format_type_progressive NDIlib_FourCC_video_type_UYVY
|
||||
=>
|
||||
DrawProgressiveVideoFrame
|
||||
|
||||
## Shader Binding RT
|
||||
设置RT:
|
||||
```c++
|
||||
FTextureRHIRef TargetableTexture;
|
||||
|
||||
// check for our frame sync object and that we are actually connected to the end point
|
||||
if (p_framesync_instance != nullptr)
|
||||
{
|
||||
// Initialize the frame size parameter
|
||||
FIntPoint FrameSize = FIntPoint(Result.xres, Result.yres);
|
||||
|
||||
if (!RenderTarget.IsValid() || !RenderTargetDescriptor.IsValid() ||
|
||||
RenderTargetDescriptor.GetSize() != FIntVector(FrameSize.X, FrameSize.Y, 0) ||
|
||||
DrawMode != EDrawMode::Progressive)
|
||||
{
|
||||
// Create the RenderTarget descriptor
|
||||
RenderTargetDescriptor = FPooledRenderTargetDesc::Create2DDesc(
|
||||
FrameSize, PF_B8G8R8A8, FClearValueBinding::None, TexCreate_None, TexCreate_RenderTargetable | TexCreate_SRGB, false);
|
||||
|
||||
// Update the shader resource for the 'SourceTexture'
|
||||
// The source texture will be given UYVY data, so make it half-width
|
||||
#if (ENGINE_MAJOR_VERSION > 5) || ((ENGINE_MAJOR_VERSION == 5) && (ENGINE_MINOR_VERSION >= 1))
|
||||
const FRHITextureCreateDesc CreateDesc = FRHITextureCreateDesc::Create2D(TEXT("NDIMediaReceiverProgressiveSourceTexture"))
|
||||
.SetExtent(FrameSize.X / 2, FrameSize.Y)
|
||||
.SetFormat(PF_B8G8R8A8)
|
||||
.SetNumMips(1)
|
||||
.SetFlags(ETextureCreateFlags::RenderTargetable | ETextureCreateFlags::Dynamic);
|
||||
|
||||
SourceTexture = RHICreateTexture(CreateDesc);
|
||||
#elif (ENGINE_MAJOR_VERSION == 4) || (ENGINE_MAJOR_VERSION == 5)
|
||||
FRHIResourceCreateInfo CreateInfo(TEXT("NDIMediaReceiverProgressiveSourceTexture"));
|
||||
TRefCountPtr<FRHITexture2D> DummyTexture2DRHI;
|
||||
RHICreateTargetableShaderResource2D(FrameSize.X / 2, FrameSize.Y, PF_B8G8R8A8, 1, TexCreate_Dynamic,
|
||||
TexCreate_RenderTargetable, false, CreateInfo, SourceTexture,
|
||||
DummyTexture2DRHI);
|
||||
#else
|
||||
#error "Unsupported engine major version"
|
||||
#endif
|
||||
|
||||
// Find a free target-able texture from the render pool
|
||||
GRenderTargetPool.FindFreeElement(RHICmdList, RenderTargetDescriptor, RenderTarget, TEXT("NDIIO"));
|
||||
|
||||
DrawMode = EDrawMode::Progressive;
|
||||
}
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5
|
||||
TargetableTexture = RenderTarget->GetRHI();
|
||||
#elif ENGINE_MAJOR_VERSION == 4
|
||||
TargetableTexture = RenderTarget->GetRenderTargetItem().TargetableTexture;
|
||||
...
|
||||
...
|
||||
// Initialize the Render pass with the conversion texture
|
||||
FRHITexture* ConversionTexture = TargetableTexture.GetReference();
|
||||
FRHIRenderPassInfo RPInfo(ConversionTexture, ERenderTargetActions::DontLoad_Store);
|
||||
|
||||
// Needs to be called *before* ApplyCachedRenderTargets, since BeginRenderPass is caching the render targets.
|
||||
RHICmdList.BeginRenderPass(RPInfo, TEXT("NDI Recv Color Conversion"));
|
||||
```
|
||||
|
||||
设置NDI传入的UYVY:
|
||||
```c++
|
||||
// set the texture parameter of the conversion shader
|
||||
FNDIIOShaderUYVYtoBGRAPS::Params Params(SourceTexture, SourceTexture, FrameSize,
|
||||
FVector2D(0, 0), FVector2D(1, 1),
|
||||
bPerformsRGBtoLinear ? FNDIIOShaderPS::EColorCorrection::sRGBToLinear : FNDIIOShaderPS::EColorCorrection::None,
|
||||
FVector2D(0.f, 1.f));
|
||||
ConvertShader->SetParameters(RHICmdList, Params);
|
||||
|
||||
// Create the update region structure
|
||||
FUpdateTextureRegion2D Region(0, 0, 0, 0, FrameSize.X/2, FrameSize.Y);
|
||||
|
||||
// Set the Pixel data of the NDI Frame to the SourceTexture
|
||||
RHIUpdateTexture2D(SourceTexture, 0, Region, Result.line_stride_in_bytes, (uint8*&)Result.p_data);
|
||||
```
|
||||
|
||||
## 解决方案
|
||||
[NDI plugin质量问题](https://forums.unrealengine.com/t/ndi-plugin-quality-trouble/1970097)
|
||||
|
||||
I changed only shader “NDIIO/Shaders/Private/NDIIOShaders.usf”.
|
||||
For example function **void NDIIOUYVYtoBGRAPS (// Shader from 8 bits UYVY to 8 bits RGBA (alpha set to 1)):**
|
||||
|
||||
_WAS:_
|
||||
|
||||
```c++
|
||||
float4 UYVYB = NDIIOShaderUB.InputTarget.Sample(NDIIOShaderUB.SamplerB, InUV);
|
||||
float4 UYVYT = NDIIOShaderUB.InputTarget.Sample(NDIIOShaderUB.SamplerT, InUV);
|
||||
float PosX = 2.0f * InUV.x * NDIIOShaderUB.InputWidth;
|
||||
float4 YUVA;
|
||||
float FracX = PosX % 2.0f;
|
||||
YUVA.x = (1 - FracX) * UYVYT.y + FracX * UYVYT.w;
|
||||
YUVA.yz = UYVYB.zx;
|
||||
YUVA.w = 1;
|
||||
```
|
||||
|
||||
_I DID:_
|
||||
|
||||
```c++
|
||||
float4 UYVYB = NDIIOShaderUB.InputTarget.Sample(NDIIOShaderUB.SamplerB, InUV);
|
||||
float4 UYVYT0 = NDIIOShaderUB.InputTarget.Sample(NDIIOShaderUB.SamplerT, InUV + float2(-0.25f / NDIIOShaderUB.InputWidth, 0));
|
||||
float4 UYVYT1 = NDIIOShaderUB.InputTarget.Sample(NDIIOShaderUB.SamplerT, InUV + float2(0.25f / NDIIOShaderUB.InputWidth, 0));
|
||||
float PosX = 2.0f * InUV.x * NDIIOShaderUB.InputWidth;
|
||||
float4 YUVA;
|
||||
float FracX = (PosX % 2.0f) * 0.5f;
|
||||
YUVA.x = (1 - FracX) * UYVYT1.y + FracX * UYVYT0.w;
|
||||
YUVA.yz = UYVYB.zx;
|
||||
YUVA.w = 1;
|
||||
```
|
||||
|
||||
Small changes but result is seems much more better.
|
||||
Of course, I added a bit of sharpness to the material after I changed the shader, but even without that, the result looks better than in the original version.
|
||||
|
||||
滤波资料:https://zhuanlan.zhihu.com/p/633122224
|
||||
## UYVY(YUV422)
|
||||
- https://zhuanlan.zhihu.com/p/695302926
|
||||
- https://blog.csdn.net/gsp1004/article/details/103037312
|
||||

|
@ -68,15 +68,7 @@ rating: ⭐
|
||||
2. [ ] UnityShader 基础(52)风格化模型(1)-云(法线传递) https://zhuanlan.zhihu.com/p/551289665
|
||||
1. 建模云模型后,使用一个形状类似的球体进行法线映射。
|
||||
2. 使用ceil制作分色块的Diffuse。
|
||||
3. [ ] 草
|
||||
1. [ ] 蒸汽猫虚幻4重现“哈尔的移动城堡”花园(附风格化草地制作分享) https://zhuanlan.zhihu.com/p/272734944
|
||||
1. 总结要点:
|
||||
1. 手绘贴图与颜色配比?
|
||||
2. 关闭阴影与抹平法线
|
||||
3. 通过映射Noise贴图来制作伪造阴影
|
||||
4. ...还有其他细节没有说明
|
||||
2. [ ] https://www.youtube.com/watch?v=Za3kNIJDIPU
|
||||
3. [ ] https://www.youtube.com/@akbutea_art
|
||||
3. [ ] [[#草]]
|
||||
4. [ ] 树木
|
||||
1. [ ] 《原神》卡渲效果逆向还原 【一、风格化树】 https://zhuanlan.zhihu.com/p/438178299
|
||||
2. [ ] 一些关于风格化树的学习总结 https://zhuanlan.zhihu.com/p/449599351
|
||||
@ -132,4 +124,27 @@ rating: ⭐
|
||||
1. [ ] 屏幕后处理:梯度模糊:https://zhuanlan.zhihu.com/p/693256394
|
||||
2. [ ] 各项异性Kuwahara:使用Saliency Map、 Edge Tangent Flow Map进行多重各种异性Kuwahara计算得出结果。
|
||||
1. https://zhuanlan.zhihu.com/p/368352199
|
||||
2. 论文:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8772035
|
||||
2. 论文:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8772035
|
||||
|
||||
|
||||
# 草
|
||||
相关参考资料
|
||||
1. [ ] 蒸汽猫虚幻4重现“哈尔的移动城堡”花园(附风格化草地制作分享) https://zhuanlan.zhihu.com/p/272734944
|
||||
2. [ ] 手绘贴图视频
|
||||
1. [x] https://www.youtube.com/watch?v=Za3kNIJDIPU
|
||||
- ![[Stylized 3D Grass Tutorial.jpg]]
|
||||
2. [x] https://www.youtube.com/@akbutea_art
|
||||
- ![[Viktoriia Zavhorodnia.png]]
|
||||
|
||||
## 关键点
|
||||
- 总结要点:
|
||||
1. 手绘贴图与颜色配比?
|
||||
2. 关闭阴影与抹平法线
|
||||
3. 通过映射Noise贴图来制作伪造阴影
|
||||
4. ...还有其他细节没有说明
|
||||
|
||||
## 风场效果
|
||||
WPO 风
|
||||
以及阴影
|
||||
|
||||
# 岩石
|
BIN
08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Stylized 3D Grass Tutorial.jpg
(Stored with Git LFS)
Normal file
BIN
08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Stylized 3D Grass Tutorial.jpg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Viktoriia Zavhorodnia.png
(Stored with Git LFS)
Normal file
BIN
08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Viktoriia Zavhorodnia.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user