UE4 自定义Shader 和 RHI

UE4 自定义Shader 和 RHI

使用UE4自定义ShaderRHI绘制简单三角形,参考上一节创建RenderTarget来显示三角形。
Triangle

创建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);
}

参考链接

UE4 自定义Shader 和 RHI

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值