項目是根據網上的教程來實現的(資源也是網上的),最終示例效果如下圖
這是網上教程的鏈接:https://www.raywenderlich.com/57-unreal-engine-4-custom-shaders-tutorial
教程使用的是后處理技術(Post Process),引用了 PPI_Blur 這個材質實例(Material Instance)
材質實例可以修改 PP_GaussianBlur 暴露的參數Radius(模糊半徑),保存后便瀏覽(Browse)不同的模糊效果。
按照教程步驟操作,遇到二個問題:
(1)#include "/Project/Gaussian.usf" 報錯
(2)SceneTextureIndex要選擇”Post Process Input 0”(后期處理輸入0,對應索引值14),教程截圖給的是 WorldNormal(場景法線)
先看如何解決無法使用 #include ‘xx.usf’這個問題
(1)先將藍圖工程轉為 C++ 工程,選中工程文件右擊“生成 Visual Studio 工程文件”
(2)在當前項目的根目錄創建 Shader 文件夾,里面編寫自定義的 shader 文件(文件以.usf或.ush為后綴)
(3)打開<
ProjectName
>.build.cs文件,為工程添加“RenderCore”組件
(4)為工程定義一個自定義的主模塊(
ProjectName
.h)
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Modules/ModuleManager.h" class FCustomShadersModule : public IModuleInterface { public: virtual void StartupModule() override; virtual void ShutdownModule() override; };
模塊名稱為 F<
ProjectName
>Module,需要覆寫二個方法:StartupModule、ShutdownModule
在對應的 cpp 文件中,映射“/Project”路徑
// Fill out your copyright notice in the Description page of Project Settings. #include "CustomShaders.h" #include "Modules/ModuleManager.h" #include "Logging/LogMacros.h" #include "Misc/Paths.h" void FCustomShadersModule::StartupModule() { #if (ENGINE_MINOR_VERSION >= 21) FString ShaderDirectory = FPaths::Combine(FPaths::ProjectDir(), TEXT("Shaders")); AddShaderSourceDirectoryMapping("/Project", ShaderDirectory); #endif } void FCustomShadersModule::ShutdownModule() { } IMPLEMENT_PRIMARY_GAME_MODULE(FCustomShadersModule, CustomShaders, "CustomShaders");
到這里便解決了 #include "/Project/Gaussian.usf" 報錯的問題。
PP_GaussianBlur 關鍵的實現部分,我用紅色線框圈了起來。
SceneTextureIndex要選擇”Post Process Input 0”(后期處理輸入0,對應索引值14),而不是 WorldNormal。
因為上面我們定義了 Global 函數(全局函數),所以具體實現的 shader 里,結合網上的其它示例,用了二種方法(等價的):一種是調用全局函數,另一種是直接調用當前 shader 內的函數。
// return SceneTextureLookup(GetDefaultSceneTextureUV(Parameters, 2), 2, false); struct FunctionStruct { //計算一維高斯模糊 float Cal_1DGaussian(float x) { return exp(-0.5f * pow(3.141 * x, 2)); } }; FunctionStruct FS; //需要獲得的場景貼圖index static const int SceneTextureID = 14; //紋素大小,比如一張512 X 512大小的紋理,那么紋素大小為(1/512) //用於UV的偏移 float2 TexelSize = View.ViewSizeAndInvSize.zw; //獲取當前像素的UV float2 UV = GetDefaultSceneTextureUV(Parameters, SceneTextureID); //用於存儲累積的顏色 float3 PixelSum = float3(0, 0, 0); //累積權重值 float WeightSum = 0; //水平與垂直模糊 for (int x = -BlurRadius; x <= BlurRadius; x++) { for (int y = -BlurRadius; y <= BlurRadius; y++) { //計算偏移的UV float2 offsetUV = UV + float2(x, y) * TexelSize; //采樣偏移后的貼圖顏色 float3 PixelColor = SceneTextureLookup(offsetUV, SceneTextureID, false).rgb; //計算采樣像素的權重,/Raduis的原因是為了限制輸入范圍為-1到1 // float weight = FS.Cal_1DGaussian(x / BlurRadius) * FS.Cal_1DGaussian(y / BlurRadius); float weight = Calculate1DGaussian(x / BlurRadius) * Calculate1DGaussian(y / BlurRadius); //累加顏色 PixelSum += PixelColor * weight; //累加權重值 WeightSum += weight; } } //返回加權平均值 return PixelSum / WeightSum;
上面的代碼注釋,參考:http://opda.tech/2021/01/03/UE4高斯模糊后處理/
參考鏈接:
- UE4 Doc :Post Process Materials
- Virtual Shader Source Path - Link custom Shaders - Shadertoy Demo download