UE4 自定义Shader 和 RHI
使用UE4
自定义Shader
和RHI
绘制简单三角形,参考上一节创建RenderTarget来显示三角形。
创建shader
使用UE4创建自定义shader需要注释掉(Engine / Config / ConsoleVariables.ini)
r.ShaderDevelopmentMode = 1
Plugins\TPViewport\Shaders\Private\SimpleShader.usf
#include "/Engine/Public/Platform.ush"
//顶点着色器
/*
输入二维点和颜色;
输出四维的点和颜色。
*/
void MainVS(
in float2 InPosition : ATTRIBUTE0,
in float4 InColor : ATTRIBUTE1,
out float4 OutPosition : SV_POSITION,
out float4 OutColor : COLOR0
)
{
OutPosition = float4(InPosition, 0, 1);
OutColor = InColor;
}
//像素着色器
//输入顶点和颜色
//输出颜色
void MainPS(
in float4 InPosition : SV_POSITION,
in float4 InColor : COLOR0,
out float4 OutColor : SV_Target0)
{
OutColor = InColor;
}
创建模块Renderer
在插件中手动创建SimpleRender
模块。
\Plugins\TPViewport\Source\SimpleRender\SimpleRenderer.Build.cs
using UnrealBuildTool;
public class SimpleRenderer : ModuleRules
{
public SimpleRenderer(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string []
{
}
);
PrivateIncludePaths . AddRange (
new string []
{
}
);
PublicDependencyModuleNames.AddRange(
new string []
{
"Core",
"CoreUObject",
"Engine",
"RenderCore",
"Projects",
"RHI"
}
);
PrivateDependencyModuleNames.AddRange(
new string []
{
}
);
DynamicallyLoadedModuleNames.AddRange(
new string []
{
}
);
}
}
Plugins\TPViewport\Source\SimpleRender\Private\SimpleRenderer.h
# pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FSimpleRendererModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
Plugins\TPViewport\Source\SimpleRender\Private\SimpleRenderer.cpp
模块启动时,设置shader的映射路径。
void FSimpleRendererModule::StartupModule()
{
FString PluginShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("TPViewport"))->GetBaseDir(), TEXT("Shaders"));
AddShaderSourceDirectoryMapping(TEXT("/Plugin/TPViewport"), PluginShaderDir);
}
void FSimpleRendererModule::ShutdownModule()
{
}
Plugins\TPViewport\Source\SimpleRender\Public\SimpleShader.h
分别创建顶点和像素shader的映射类。
# pragma once
#include "CoreMinimal.h"
#include "GlobalShader.h"
class FSimpleShader : public FGlobalShader
{
public:
FSimpleShader() {}
FSimpleShader(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer) {}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
};
//顶点shader
class FSimpleShaderVS : public FSimpleShader
{
DECLARE_SHADER_TYPE(FSimpleShaderVS, Global);
public:
FSimpleShaderVS() {}
FSimpleShaderVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FSimpleShader(Initializer)
{
}
};
//像素shader
class FSimpleShaderPS : public FSimpleShader
{
DECLARE_SHADER_TYPE(FSimpleShaderPS, Global);
public:
FSimpleShaderPS() {}
FSimpleShaderPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FSimpleShader(Initializer)
{
}
};
//辅助类供外部调用
class SIMPLERENDERER_API FSimpleRenderer
{
public:
FSimpleRenderer () {};
void Render ( class UTextureRenderTarget2D * RenderTarget);
};
Plugins\TPViewport\Source\SimpleRender\Private\SimpleShader.cpp
#include "SimpleShader.h"
#include "Containers/DynamicRHIResourceArray.h"
#include "TextureResource.h"
#include "Engine/TextureRenderTarget2D.h"
#include "RHIStaticStates.h"
#include "PipelineStateCache.h"
//映射C++与Shader
IMPLEMENT_SHADER_TYPE(, FSimpleShaderVS, TEXT("/Plugin/TPViewport/Private/SimpleShader.usf"), TEXT("MainVS"), SF_Vertex)
IMPLEMENT_SHADER_TYPE(, FSimpleShaderPS, TEXT("/Plugin/TPViewport/Private/SimpleShader.usf"), TEXT("MainPS"), SF_Pixel)
//顶点shader输入
struct FColorVertex {
FVector2D Position;
FVector4 Color;
};
//顶点缓冲区
class FSimpleVertexBuffer : public FVertexBuffer
{
public:
void InitRHI() override
{
TResourceArray<FColorVertex, VERTEXBUFFER_ALIGNMENT> Vertices;
Vertices. SetNumUninitialized ( 3 );
Vertices[0].Position = FVector2D(0, 0.75);
Vertices[0].Color = FVector4(1, 0, 0, 1);
Vertices[1].Position = FVector2D(0.75, -0.75);
Vertices[1].Color = FVector4(0, 1, 0, 1);
Vertices[2].Position = FVector2D(-0.75, -0.75);
Vertices[2].Color = FVector4(0, 0, 1, 1);
FRHIResourceCreateInfo CreateInfo(&Vertices);
VertexBufferRHI = RHICreateVertexBuffer(Vertices.GetResourceDataSize(), BUF_Static, CreateInfo);
}
};
TGlobalResource<FSimpleVertexBuffer> GSimpleVertexBuffer;
//顶点缓冲区属性描述
class FColorVertexDeclaration : public FRenderResource
{
public:
FVertexDeclarationRHIRef VertexDeclarationRHI;
virtual void InitRHI() override
{
FVertexDeclarationElementList Elements;
uint32 Stride = sizeof(FColorVertex);
Elements.Add(FVertexElement(0, STRUCT_OFFSET(FColorVertex, Position), VET_Float2, 0, Stride));
Elements.Add(FVertexElement(0, STRUCT_OFFSET(FColorVertex, Color), VET_Float4, 1, Stride));
VertexDeclarationRHI = RHICreateVertexDeclaration(Elements);
}
virtual void ReleaseRHI() override
{
VertexDeclarationRHI.SafeRelease();
}
};
TGlobalResource<FColorVertexDeclaration> GSimpleVertexDeclaration;
//索引缓冲区
class FSimpleIndexBuffer : public FIndexBuffer
{
public:
void InitRHI() override
{
const uint16 Indices[] = { 0, 1, 2 };
TResourceArray <uint16, INDEXBUFFER_ALIGNMENT> IndexBuffer;
uint32 NumIndices = ARRAY_COUNT(Indices);
IndexBuffer. AddUninitialized (NumIndices);
FMemory::Memcpy(IndexBuffer.GetData(), Indices, NumIndices * sizeof(uint16));
FRHIResourceCreateInfo CreateInfo (& IndexBuffer);
IndexBufferRHI = RHICreateIndexBuffer(sizeof(uint16), IndexBuffer.GetResourceDataSize(), BUF_Static, CreateInfo);
}
};
TGlobalResource<FSimpleIndexBuffer> GSimpleIndexBuffer;
//绘制
static void DrawTestShaderRenderTarget_RenderThread(
FRHICommandListImmediate& RHICmdList,
FTextureRenderTargetResource* OutputRenderTargetResource
)
{
check(IsInRenderingThread());
FRHIRenderPassInfo RPInfo(OutputRenderTargetResource->GetRenderTargetTexture(), ERenderTargetActions::DontLoad_Store, OutputRenderTargetResource->TextureRHI);
RHICmdList.BeginRenderPass(RPInfo, TEXT("SimpleRendererShaderPass"));
{
// Get shaders.
FGlobalShaderMap* GlobalShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel);
TShaderMapRef<FSimpleShaderVS> VertexShader(GlobalShaderMap);
TShaderMapRef<FSimpleShaderPS> PixelShader(GlobalShaderMap);
// Set the graphic pipeline state.
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI();
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GSimpleVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
// Update viewport.
RHICmdList.SetViewport(
0, 0, 0.f,
OutputRenderTargetResource->GetSizeX(), OutputRenderTargetResource->GetSizeY(), 1.f);
// Set the vertextBuffer.
RHICmdList.SetStreamSource(0, GSimpleVertexBuffer.VertexBufferRHI, 0);
RHICmdList.DrawIndexedPrimitive(
GSimpleIndexBuffer.IndexBufferRHI,
/*BaseVertexIndex=*/ 0,
/* MinIndex = */ 0,
/* NumVertices = */3,
/*StartIndex=*/0,
/* NumPrimitives = */1,
/*NumInstances=*/1);
}
RHICmdList.EndRenderPass();
}
void FSimpleRenderer::Render(UTextureRenderTarget2D* RenderTarget)
{
check ( IsInGameThread ());
if (!RenderTarget)
{
return;
}
FTextureRenderTargetResource * TextureRenderTargetResource = RenderTarget-> GameThread_GetRenderTargetResource ();
//ERHIFeatureLevel::Type FeatureLevel = World->Scene->GetFeatureLevel();
ENQUEUE_RENDER_COMMAND(CaptureCommand)(
[TextureRenderTargetResource](FRHICommandListImmediate& RHICmdList)
{
DrawTestShaderRenderTarget_RenderThread(RHICmdList, TextureRenderTargetResource);
}
);
}
Plugins\TPViewport\Source\TPViewport\Public\RenderTestViewportClient.cpp
引入模块SimpleRender
后,就可以将三角形渲染到RenderTarget
。
#include "RenderTestViewportClient.h"
#include "Runtime/Engine/Public/CanvasTypes.h"
#include "Runtime/Engine/Public/CanvasItem.h"
#include "Engine/TextureRenderTarget2D.h"
#include "SimpleShader.h"
FRenderTestViewportClient::FRenderTestViewportClient()
{
RenderTarget = NewObject<UTextureRenderTarget2D>(GetTransientPackage(), NAME_None, RF_Transient);
RenderTarget->RenderTargetFormat = RTF_RGBA8;
RenderTarget->InitAutoFormat(1024, 1024);
RenderTarget->ClearColor = FLinearColor::Blue;
RenderTarget->UpdateResource();
}
void FRenderTestViewportClient::Draw(FViewport* Viewport, FCanvas* Canvas)
{
FSimpleRenderer renderer;
renderer.Render(RenderTarget);
//绘制RenderTarget
FCanvasTileItem Tile(FVector2D::ZeroVector, RenderTarget->Resource, Viewport->GetSizeXY(), FLinearColor(1, 1, 1, 1));
Canvas->DrawItem(Tile);
}
网友评论