基础类型数据
Shader中的基础类型数据,例如:int、float4等的传入方式如下:
- 在你声明的Shader类中声明FShaderParameter变量。
- 在构造函数中绑定Shader中的变量。
- 在序列化函数中添加声明的FShaderParameter变量。
- 实现自定义的设置Shader变量函数,并在最终绘制前调用。
在构造函数中绑定Shader中的变量,其格式如下:
//其中SimpleColorVal为Shader类中声明的FShaderParameter变量,TEXT("SimpleColor")为usf声明的变量。
SimpleColorVal.Bind(Initializer.ParameterMap,TEXT("SimpleColor"));
往序列化函数中添加声明的FShaderParameter变量
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << SimpleColorVal;
return bShaderHasOutdatedParameters;
}
实现自定义的设置Shader变量函数
template<typename TShaderRHIParamRef>
void SetParameters(FRHICommandListImmediate& RHICmdList,const TShaderRHIParamRef ShaderRHI,const FLinearColor &MyColor)
{
SetShaderValue(RHICmdList, ShaderRHI, SimpleColorVal,MyColor);
}
在绘制前调用(详细代码请见github或者见上一篇文章)
static void DrawTestShaderRenderTarget_RenderThread(
FRHICommandListImmediate& RHICmdList,
FTextureRenderTargetResource* OutputRenderTargetResource,
ERHIFeatureLevel::Type FeatureLevel,
const FLinearColor MyColor,
const FTextureRHIParamRef TextureRHI,
const FSimpleUniformStruct UniformStruct
)
{
//上略
VertexShader->SetParameters(RHICmdList, VertexShader->GetVertexShader(),MyColor,TextureRHI);
PixelShader->SetParameters(RHICmdList, PixelShader->GetPixelShader(),MyColor,TextureRHI);
//下略
}
如此一来,usf中的SimpleColor就被
顶点数据
我们可以参考Ue4中的代码,搜索VertexDeclaration就可以看到官方是如何声明顶点格式的。
声明顶点格式步骤:
- 定义定点格式结构体
- 继承FRenderResource定义新的顶点声明,并且实现InitRHI与ReleaseRHI接口
- 在渲染线程的函数中给显卡管线状态指定顶点声明,GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = VertexDeclaration.VertexDeclarationRHI;
首先我们需要声明自己的顶点格式:
struct FTextureVertex{
FVector4 Position;
FVector2D UV;
};
class FTextureVertexDeclaration : public FRenderResource
{
public:
FVertexDeclarationRHIRef VertexDeclarationRHI;
virtual void InitRHI() override
{
FVertexDeclarationElementList Elements;
uint32 Stride = sizeof(FTextureVertex);
Elements.Add(FVertexElement(0, STRUCT_OFFSET(FTextureVertex, Position), VET_Float2, 0, Stride));
Elements.Add(FVertexElement(0, STRUCT_OFFSET(FTextureVertex, UV), VET_Float2, 1, Stride));
VertexDeclarationRHI = RHICreateVertexDeclaration(Elements);
}
virtual void ReleaseRHI() override
{
VertexDeclarationRHI.SafeRelease();
}
};
有需要还可以加入顶点法线或者顶点色之类的,接下来就是使用声明的顶点格式来声明顶点缓存与顶点索引:
class FRectangleVertexBuffer : public FVertexBuffer
{
public:
/** Initialize the RHI for this rendering resource */
void InitRHI() override
{
TResourceArray<FTextureVertex, VERTEXBUFFER_ALIGNMENT> Vertices;
Vertices.SetNumUninitialized(6);
Vertices[0].Position = FVector4(1, 1, 0, 1);
Vertices[0].UV = FVector2D(1, 1);
Vertices[1].Position = FVector4(-1, 1, 0, 1);
Vertices[1].UV = FVector2D(0, 1);
Vertices[2].Position = FVector4(1, -1, 0, 1);
Vertices[2].UV = FVector2D(1, 0);
Vertices[3].Position = FVector4(-1, -1, 0, 1);
Vertices[3].UV = FVector2D(0, 0);
//The final two vertices are used for the triangle optimization (a single triangle spans the entire viewport )
Vertices[4].Position = FVector4(-1, 1, 0, 1);
Vertices[4].UV = FVector2D(-1, 1);
Vertices[5].Position = FVector4(1, -1, 0, 1);
Vertices[5].UV = FVector2D(1, -1);
// Create vertex buffer. Fill buffer with initial data upon creation
FRHIResourceCreateInfo CreateInfo(&Vertices);
VertexBufferRHI = RHICreateVertexBuffer(Vertices.GetResourceDataSize(), BUF_Static, CreateInfo);
}
};
class FRectangleIndexBuffer : public FIndexBuffer
{
public:
/** Initialize the RHI for this rendering resource */
void InitRHI() override
{
// Indices 0 - 5 are used for rendering a quad. Indices 6 - 8 are used for triangle optimization.
const uint16 Indices[] = { 0, 1, 2, 2, 1, 3, 0, 4, 5 };
TResourceArray<uint16, INDEXBUFFER_ALIGNMENT> IndexBuffer;
uint32 NumIndices = ARRAY_COUNT(Indices);
IndexBuffer.AddUninitialized(NumIndices);
FMemory::Memcpy(IndexBuffer.GetData(), Indices, NumIndices * sizeof(uint16));
// Create index buffer. Fill buffer with initial data upon creation
FRHIResourceCreateInfo CreateInfo(&IndexBuffer);
IndexBufferRHI = RHICreateIndexBuffer(sizeof(uint16), IndexBuffer.GetResourceDataSize(), BUF_Static, CreateInfo);
}
};
这里我参考了
Engine\Source\Runtime\RenderCore\Private\CommonRenderResources.cpp
Engine\Source\Runtime\RenderCore\Private\PixelShaderUtils.cpp
其中PixelShaderUtils.cpp提供了绘制图元代码。
如果以前有学习过OpenGL或者Directx3D的,对这些就不会陌生。
使用以上声明
这些将会在XXXX_RenderThread渲染函数中使用:
声明的顶点格式会在设置显卡管线状态中使用
FTextureVertexDeclaration VertexDeclaration;
VertexDeclaration.InitRHI();
//设置显卡管线状态
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = VertexDeclaration.VertexDeclarationRHI;
声明的顶点缓存与顶点索引缓存将会在绘制时使用
RHICmdList.SetStreamSource(0, GRectangleVertexBuffer.VertexBufferRHI, 0);
RHICmdList.DrawIndexedPrimitive(
GRectangleIndexBuffer.IndexBufferRHI,
/*BaseVertexIndex=*/ 0,
/*MinIndex=*/ 0,
/*NumVertices=*/ 4,
/*StartIndex=*/ 0,
/*NumPrimitives=*/ 2,
/*NumInstances=*/ 1);
贴图
贴图和基础类型数据相似。
- 在你声明的Shader类中添加2个FShaderResourceParameter成员变量,分别对应了贴图对象与采样器。
- 在序列化函数中添加这两个成员变量。
- 在构造函数中绑定这两个成员变量。
使用贴图
- 在自定义的Shader变量设置函数中添加const FTextureRHIParamRef&形参,并在函数调用SetTextureParameter函数。
- 在XXX_RenderThread渲染函数中添加const FTextureRHIParamRef TextureRHI形参。
- 编写蓝图库函数用于渲染测试。
步骤1
template<typename TShaderRHIParamRef>
void SetParameters(FRHICommandListImmediate& RHICmdList,const TShaderRHIParamRef ShaderRHI, const FLinearColor &MyColor,const FTextureRHIParamRef& TextureRHI)
{
SetShaderValue(RHICmdList, ShaderRHI, SimpleColorVal, MyColor);
SetTextureParameter(RHICmdList, ShaderRHI, TextureVal, TextureSampler,TStaticSamplerState<SF_Trilinear,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),TextureRHI);
}
步骤2
static void DrawTestShaderRenderTarget_RenderThread(
FRHICommandListImmediate& RHICmdList,
FTextureRenderTargetResource* OutputRenderTargetResource,
ERHIFeatureLevel::Type FeatureLevel,
// const FName TextureRenderTargetName,
const FLinearColor MyColor,
const FTextureRHIParamRef TextureRHI,
const FSimpleUniformStruct UniformStruct
)
{
//上略
VertexShader->SetParameters(RHICmdList, VertexShader->GetVertexShader(),MyColor,TextureRHI);
PixelShader->SetParameters(RHICmdList, PixelShader->GetPixelShader(),MyColor,TextureRHI);
//下略
}
步骤3
void USimplePixelShaderBlueprintLibrary::DrawTestShaderRenderTarget(const UObject* WorldContextObject, UTextureRenderTarget2D* OutputRenderTarget, FLinearColor MyColor, UTexture* MyTexture, FSimpleUniformStruct UniformStruct)
{
check(IsInGameThread());
if (!OutputRenderTarget)
{
return;
}
FTextureRenderTargetResource* TextureRenderTargetResource = OutputRenderTarget->GameThread_GetRenderTargetResource();
FTextureRHIParamRef TextureRHI = MyTexture->TextureReference.TextureReferenceRHI;
const UWorld* World = WorldContextObject->GetWorld();
ERHIFeatureLevel::Type FeatureLevel = World->Scene->GetFeatureLevel();
/* FName TextureRenderTargetName = OutputRenderTarget->GetFName(); */
ENQUEUE_RENDER_COMMAND(CaptureCommand)(
[TextureRenderTargetResource, FeatureLevel, MyColor,TextureRHI, UniformStruct](FRHICommandListImmediate& RHICmdList)
{
DrawTestShaderRenderTarget_RenderThread(RHICmdList,TextureRenderTargetResource, FeatureLevel, MyColor,TextureRHI, UniformStruct);
}
);
}
Struct
结构体除了基础类型还可以含有贴图等类型,它是通过宏来声明的,具体的可以通过搜索宏来查看使用方式。这些宏都位于ShaderParameterMacros.h中。
//开始声明,第一种较为常用的,第二种我没研究过
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT_WITH_CONSTRUCTOR
SHADER_PARAMETER //普通类型变量
SHADER_PARAMETER_TEXTURE //贴图对象
SHADER_PARAMETER_SAMPLER //贴图采样器
SHADER_PARAMETER_EX //矩阵
SHADER_PARAMETER_SRV //没研究过
SHADER_PARAMETER_ARRAY_EX //没研究过
//结束声明
END_GLOBAL_SHADER_PARAMETER_STRUCT()
//向Ue4与usf注册
//这里我再cpp中声明了FSimpleUniformStructParameters类型;在usf中声明了SimpleUniformStruct
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FSimpleUniformStructParameters, "SimpleUniformStruct");
声明并且注册完后,结构体会生成到Common.usf中,所以我们需要在自己的usf文件中包含Common.ush。
例如我这么声明:
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FSimpleUniformStructParameters, )
SHADER_PARAMETER(FVector4, Color1)
END_GLOBAL_SHADER_PARAMETER_STRUCT()
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FSimpleUniformStructParameters, "SimpleUniformStruct");
那么在usf中,我可以通过SimpleUniformStruct.Color1来取得变量。
在渲染函数中设置Struct的值
这里的FSimpleUniformStruct是我定义的一个结构体,用于在蓝图传参给渲染函数使用。这样我们就可以通过蓝图来控制usf的结构体值了。
static void DrawTestShaderRenderTarget_RenderThread(
FRHICommandListImmediate& RHICmdList,
FTextureRenderTargetResource* OutputRenderTargetResource,
ERHIFeatureLevel::Type FeatureLevel,
const FLinearColor MyColor,
const FTextureRHIParamRef TextureRHI,
const FSimpleUniformStruct UniformStruct
)
{
//上略
FSimpleUniformStructParameters Parameters;
Parameters.Color1 = UniformStruct.Color1;
Parameters.Color2 = UniformStruct.Color2;
Parameters.Color3 = UniformStruct.Color3;
Parameters.Color4 = UniformStruct.Color4;
Parameters.ColorIndex= UniformStruct.ColorIndex;
SetUniformBufferParameterImmediate(RHICmdList, PixelShader->GetPixelShader(), PixelShader->GetUniformBufferParameter<FSimpleUniformStructParameters>(), Parameters);
//下略
设置Struct也有两个函数SetUniformBufferParameter与SetUniformBufferParameterImmediate,但是后者我没有仔细看过。