diff --git a/03-UnrealEngine/Rendering/Shader/UE5 NDI传输结果模糊问题解决.md b/03-UnrealEngine/Rendering/Shader/UE5 NDI传输结果模糊问题解决.md new file mode 100644 index 0000000..eff1208 --- /dev/null +++ b/03-UnrealEngine/Rendering/Shader/UE5 NDI传输结果模糊问题解决.md @@ -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 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 +![](https://i-blog.csdnimg.cn/blog_migrate/24b41fd36ff7902670e11a8005afb370.jpeg) \ No newline at end of file diff --git a/03-UnrealEngine/卡通渲染相关资料/渲染功能/其他渲染功能/风格化渲染.md b/03-UnrealEngine/卡通渲染相关资料/渲染功能/其他渲染功能/风格化渲染.md index 2415dcd..d3a3afb 100644 --- a/03-UnrealEngine/卡通渲染相关资料/渲染功能/其他渲染功能/风格化渲染.md +++ b/03-UnrealEngine/卡通渲染相关资料/渲染功能/其他渲染功能/风格化渲染.md @@ -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 \ No newline at end of file + 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 风 +以及阴影 + +# 岩石 \ No newline at end of file diff --git a/08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Stylized 3D Grass Tutorial.jpg b/08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Stylized 3D Grass Tutorial.jpg new file mode 100644 index 0000000..813b367 --- /dev/null +++ b/08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Stylized 3D Grass Tutorial.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50bd516fbdf42a1941610b800740fd4d48d7e92932dd1fc67349ba2f0cba36e8 +size 35343 diff --git a/08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Viktoriia Zavhorodnia.png b/08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Viktoriia Zavhorodnia.png new file mode 100644 index 0000000..127fa73 --- /dev/null +++ b/08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Viktoriia Zavhorodnia.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4ecf3290e923a30c17029098cc0522bdfd80a731fea7177435fc570f5aab6b6 +size 301552