在上一节我们大致介绍了UE4 GlobalShader的情况, 并且在引擎代码做了一些修改来阐述GlobalShader的声明-定义-使用。实际上在UE4开发中, GlobalShader不一定使用在修改引擎代码,也可能是用在插件, 比如LensDistortion插件就是使用GlobalShader定制一个RenderToTexture的功能。当然在插件中,GlobalShader的使用场景不仅仅局限于RenderToTexture, 可以ComputeShader等等来加速某些并行计算(如基于GPU的植被插件等)。(UE4 4.27)自定义GlobalShaderhttps://blog.csdn.net/qq_29523119/article/details/120573174?spm=1001.2014.3001.5501
下面做一个对图片进行调色并渲染到RenderTexture的功能
#pragma once
#include "CoreMinimal.h"
#include "GlobalShader.h"
#include "ShaderParameters.h"
#include "Shader.h"
/**
*
*/
class FDrawVS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FDrawVS, Global);
public:
FDrawVS() {};
FDrawVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
:FGlobalShader(Initializer)
{
}
static bool ShouldCompilePermutation(const FShaderPermutationParameters& Parameters)
{
return true;
}
};
class FDrawPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FDrawPS, Global);
public:
FDrawPS() {};
FDrawPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
:FGlobalShader(Initializer)
{
Color.Bind(Initializer.ParameterMap, TEXT("MyColor"));
ColorScale.Bind(Initializer.ParameterMap, TEXT("MyColorScale"));
Texture.Bind(Initializer.ParameterMap, TEXT("InTexture"));
TextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler"));
}
/** Should the shader be cached? Always. */
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
void SetParam(FRHICommandList& RHICmdList, const FTexture* TextureValue, const FLinearColor& InColor, float InColorScale)
{
FRHIPixelShader* PS = RHICmdList.GetBoundPixelShader();
SetTextureParameter(RHICmdList, PS, Texture, TextureSampler, TextureValue);
SetShaderValue(RHICmdList, PS, Color, InColor);
SetShaderValue(RHICmdList, PS, ColorScale, InColorScale);
}
private:
LAYOUT_FIELD(FShaderParameter, Color);
LAYOUT_FIELD(FShaderParameter, ColorScale);
LAYOUT_FIELD(FShaderResourceParameter, Texture);
LAYOUT_FIELD(FShaderResourceParameter, TextureSampler);
};
void FTestShader::StartupModule()
{
FString PluginShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("TestShader"))->GetBaseDir(), TEXT("Shaders"));
AddShaderSourceDirectoryMapping(TEXT("/Plugin/TestShader"), PluginShaderDir);
}
IMPLEMENT_SHADER_TYPE(, FDrawVS, TEXT("/Plugin/TestShader/DrawShader.usf"), TEXT("MainVS"), SF_Vertex);
IMPLEMENT_SHADER_TYPE(, FDrawPS, TEXT("/Plugin/TestShader/DrawShader.usf"), TEXT("MainPS"), SF_Pixel);
DrawShader.usf
#include "/Engine/Public/Platform.ush"
void MainVS(
in float3 InPostion : ATTRIBUTE0,
in float2 UV : ATTRIBUTE1,
out float2 OutUV : TEXCOORD0,
out float4 Output : SV_POSITION)
{
OutUV = UV;
Output = float4(InPostion, 1.0f);
}
Texture2D InTexture;
SamplerState InTextureSampler;
float4 MyColor;
float MyColorScale;
void MainPS(
in float2 UV : TEXCOORD0,
out float4 OutColor : SV_Target0)
{
float4 TextureColor = InTexture.Sample(InTextureSampler, UV);
OutColor = MyColor * TextureColor * MyColorScale;
//return float4(1.0f, 1.0f, 1.0f, 1.0f);
}
void UMyShaderBPFunctionLibrary::DrawTestShaderToRenderTexture(
const UObject* WorldContextObject,
const UTexture2D* InTexture,
class UTextureRenderTarget2D* OutputRenderTarget,
const FLinearColor& Color,
float ColorScale)
{
UWorld* World = WorldContextObject->GetWorld();
ERHIFeatureLevel::Type FeatureLevel = World->Scene->GetFeatureLevel();
if (FeatureLevel < ERHIFeatureLevel::SM5)
{
UE_LOG(LogTemp, Warning, TEXT("FeatureLevel < ERHIFeatureLevel::SM5"));
return;
}
if (nullptr == InTexture)
{
UE_LOG(LogTemp, Warning, TEXT("InTexture Is NULL"));
return;
}
FTextureRenderTargetResource* TextureRenderTargetSource = OutputRenderTarget->GameThread_GetRenderTargetResource();
FTexture* TextureSource = InTexture->Resource;
ENQUEUE_RENDER_COMMAND(TestShaderCommand)(
[TextureSource, TextureRenderTargetSource, FeatureLevel, Color, ColorScale](FRHICommandListImmediate& RHICmdList)
{
DrawTestShaderToRenderTexture_RenderThread(RHICmdList, TextureSource, TextureRenderTargetSource, FeatureLevel, Color, ColorScale);
}
);
}
这里 ENQUEUE_RENDER_COMMAND 表示从游戏线程向渲染线程发送渲染指令, 而FRHICommandListImmediate和上一节的FRHICommandList也有所不同,FRHICommandListImmediate代表的立即模式,代表发送到渲染线程后马上进行渲染,就能得到渲染结果。而FRHICommandList存在渲染指令的队列,会进行指令收集在进行延后的渲染有所不同。
struct FCustomVertex
{
FVector Pos;
FVector2D UV;
FCustomVertex()
{
}
FCustomVertex(const FVector& VertexPos, const FVector2D& VertexUV)
:Pos(VertexPos), UV(VertexUV)
{
}
};
//declare custom vertex format
class FMyTestVertexDeclaration : public FRenderResource
{
public:
FVertexDeclarationRHIRef VertexDeclarationRHI;
virtual void InitRHI() override
{
FVertexDeclarationElementList Elements;
uint16 Stride = sizeof(FCustomVertex);
//Pos-float3
Elements.Add(FVertexElement(0, STRUCT_OFFSET(FCustomVertex, Pos), VET_Float3, 0, Stride));
//UV-float2
Elements.Add(FVertexElement(0, STRUCT_OFFSET(FCustomVertex, UV), VET_Float2, 1, Stride));
VertexDeclarationRHI = PipelineStateCache::GetOrCreateVertexDeclaration(Elements);
}
virtual void ReleaseRHI() override
{
VertexDeclarationRHI.SafeRelease();
}
};
TGlobalResource GCustomVertexDeclaration;
static void DrawTestShaderToRenderTexture_RenderThread(
FRHICommandListImmediate& RHICmdList,
FTexture* InTextureResource,
FTextureRenderTargetResource* OutTextureRenderTargetResource,
ERHIFeatureLevel::Type FeatureLevel,
const FLinearColor& Color,
float ColorScale)
{
check(IsInRenderingThread());
FRHITexture2D* RenderTargetTexture = OutTextureRenderTargetResource->GetRenderTargetTexture();
RHICmdList.Transition(FRHITransitionInfo(RenderTargetTexture, ERHIAccess::SRVMask, ERHIAccess::RTV));
FRHIRenderPassInfo RPInfo(RenderTargetTexture, ERenderTargetActions::DontLoad_Store);
RHICmdList.BeginRenderPass(RPInfo, TEXT("Render Test Shader To Texture"));
{
FIntPoint ViewportSize(OutTextureRenderTargetResource->GetSizeX(), OutTextureRenderTargetResource->GetSizeY());
// Upate viewport
RHICmdList.SetViewport(0, 0, 0.0f, ViewportSize.X, ViewportSize.Y, 1.0f);
// Get Shaders
FGlobalShaderMap* GlobalShaderMap = GetGlobalShaderMap(FeatureLevel);
TShaderMapRef VertexShader(GlobalShaderMap);
TShaderMapRef PixelShader(GlobalShaderMap);
// Setup Pipeline state
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI();
GraphicsPSOInit.PrimitiveType = PT_TriangleStrip;
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GCustomVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
// update shader uniform parameters
PixelShader->SetParam(RHICmdList, InTextureResource, Color, ColorScale);
// Create VertexBuffer and setup
static const uint32 VERTEX_SIZE = sizeof(FCustomVertex) * 4;
FRHIResourceCreateInfo CreateInfo;
FVertexBufferRHIRef VertexBufferRHI = RHICreateVertexBuffer(VERTEX_SIZE, BUF_Static, CreateInfo);
void* VoidPtr = RHILockVertexBuffer(VertexBufferRHI, 0, VERTEX_SIZE, RLM_WriteOnly);
FCustomVertex Vertices[4];
Vertices[0] = FCustomVertex(FVector(-1.0f, 1.0f, 0.0f), FVector2D(0.0f, 0.0f));
Vertices[1] = FCustomVertex(FVector(1.0f, 1.0f, 0), FVector2D(1.0f, 0.0f));
Vertices[2] = FCustomVertex(FVector(-1.0f, -1.0f, 0), FVector2D(0.0f, 1.0f));
Vertices[3] = FCustomVertex(FVector(1.0f, -1.0f, 0), FVector2D(1.0f, 1.0f));
FMemory::Memcpy(VoidPtr, (void*)Vertices, VERTEX_SIZE);
RHIUnlockVertexBuffer(VertexBufferRHI);
RHICmdList.SetStreamSource(0, VertexBufferRHI, 0);
RHICmdList.DrawPrimitive(0, 2, 1);
}
RHICmdList.EndRenderPass();
RHICmdList.Transition(FRHITransitionInfo(RenderTargetTexture, ERHIAccess::RTV, ERHIAccess::SRVMask));
}
总体而言各种渲染数据的声明定义和Directx11非常类似.
https://download.csdn.net/download/qq_29523119/33147630
【1】https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/Rendering/ShaderInPlugin/Overview/
【2】UE4的LensDistortion插件和Texture2DPreview.cpp