From 8ecf6172359df15b08daef9093d259299eef721b Mon Sep 17 00:00:00 2001
From: BlueRose <378100977@qq.com>
Date: Tue, 11 Mar 2025 18:33:43 +0800
Subject: [PATCH] vault backup: 2025-03-11 18:33:42

---
 .../Shader/UE5 NDI传输结果模糊问题解决.md     | 243 ++++++++++++++++++
 .../渲染功能/其他渲染功能/风格化渲染.md       |  35 ++-
 .../Video/Stylized 3D Grass Tutorial.jpg      |   3 +
 .../Grass/Video/Viktoriia Zavhorodnia.png     |   3 +
 4 files changed, 274 insertions(+), 10 deletions(-)
 create mode 100644 03-UnrealEngine/Rendering/Shader/UE5 NDI传输结果模糊问题解决.md
 create mode 100644 08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Stylized 3D Grass Tutorial.jpg
 create mode 100644 08-Assets/Images/ImageBag/StyleRendering/Grass/Video/Viktoriia Zavhorodnia.png

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<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
+![](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