Hi in my journey to learn to script more complicated plugins, I am currently trying to have an input texture display as a Render Target when I play the game. I first got a single color working and that works like a charm but now I am having issues with loading an input texture onto a render target.
Below is my github to the complete project.
https://github.com/som1990/UE4_20ShaderPluginDev
Below is a step by step guide to my process.
I have double checked my custom HLSL Pixel Shader (By running it through a custom HLSL node in Material) and it works there but It doesn’t display the texture when I hit play(as seen in figure 1).
Figure 1: Screenshot of RenderTexture when hiting Play.
Stage 1)
I have attached the hlsl code Below (Figure 2). Here I try to blend a constant color with a texture. I got my Constant color to display but cannot get the texture to display so the blend is from black to MyColor value that I have set.
Figure 2: My HLSL PixelShader and Vertex Shaders. PSVariable is a Variable Buffer which holds my Blend Value data.
Stage2) Taking Input and Passing it from my class to my shading plugin.
Below is how I’m Converting my UTexture2D* “TextureToDisplay” to a FTexture2DRHIRef “InputTexture” so that it can be passed to my plugin from my custom c++ class.
InputTexture = static_cast<FTexture2DResource*>(TextureToDisplay->Resource)->GetTexture2DRHI();
Below is how I’m passing the Texture.
if (InputTexture && RenderTarget)
TexPixelShading->ExecutePixelShader(RenderTarget, InputTexture, ColorToBlend, BlendAmount);
Stage3) Sending my input texture to my shader class
void FTexPSImplementation::ExecutePixelShader(UTextureRenderTarget2D* RenderTarget, FTexture2DRHIRef InputTexture, FColor InputColor, float BlendAmount)
{
check(IsInGameThread());
if (bisUnloading || bIsPixelShaderExecuting)
return;
if (!RenderTarget)
return;
bIsPixelShaderExecuting = true;
if (TextureParameter != InputTexture)
bMustRegenerateSRV = true;
VariableParameters.BlendFactor = BlendAmount;
CurrentRenderTarget = RenderTarget;
TextureParameter = InputTexture;
m_startCol = FLinearColor(InputColor.R / 255.0, InputColor.G / 255.0, InputColor.B / 255.0, InputColor.A / 255.0);
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
FPixelShaderRunner,
FTexPSImplementation*, MyShader, this,
{
MyShader->ExecutePixelShaderInternal();
}
);
}
void FTexPSImplementation::ExecutePixelShaderInternal()
{
check(IsInRenderingThread());
if (bisUnloading)
{
if (NULL != TextureParameterSRV)
{
TextureParameterSRV.SafeRelease();
TextureParameterSRV = NULL;
}
return;
}
FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
//If our input texture reference has changed, we need to recreate our SRV
if (bMustRegenerateSRV)
{
bMustRegenerateSRV = false;
if (NULL != TextureParameterSRV)
{
TextureParameterSRV.SafeRelease();
TextureParameterSRV = NULL;
}
TextureParameterSRV = RHICreateShaderResourceView(TextureParameter, 0);
}
TShaderMapRef<FMyTestVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
TShaderMapRef<FMyTestPS> PixelShader(GetGlobalShaderMap(FeatureLevel));
//Way to get renderTarget Texture
CurrentTexture = CurrentRenderTarget->GetRenderTargetResource()->GetRenderTargetTexture();
SetRenderTarget(RHICmdList, CurrentTexture, FTextureRHIRef());
FGraphicsPipelineStateInitializer PSOInitializer;
RHICmdList.ApplyCachedRenderTargets(PSOInitializer);
PSOInitializer.PrimitiveType = PT_TriangleStrip;
PSOInitializer.BoundShaderState.VertexDeclarationRHI = GQuadVertexDeclaration.VertexDeclarationRHI;
PSOInitializer.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*VertexShader);
PSOInitializer.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
PSOInitializer.BlendState = TStaticBlendState<>::GetRHI();
PSOInitializer.RasterizerState = TStaticRasterizerState<>::GetRHI();
PSOInitializer.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
SetGraphicsPipelineState(RHICmdList, PSOInitializer);
//TextureParameter is a FTexture2DRHIRef
PixelShader->SetParameters(RHICmdList, m_startCol, TextureParameterSRV,TextureParameter);
PixelShader->SetUniformBuffers(RHICmdList, VariableParameters);
DrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, m_pQuadVB, sizeof(m_pQuadVB[0]));
PixelShader->UnbindBuffers(RHICmdList);
RHICmdList.CopyToResolveTarget(
CurrentRenderTarget->GetRenderTargetResource()->GetRenderTargetTexture(),
CurrentRenderTarget->GetRenderTargetResource()->TextureRHI,
FResolveParams());
if (bSave)
{
bSave = false;
SaveScreenshot(RHICmdList);
}
bIsPixelShaderExecuting = false;
}
Stage 4) Sending my Incoming to data to the Pixel Shader. Below is my Pixel Shader class
class FMyTestPS : public FGlobalShader
{
DECLARE_EXPORTED_SHADER_TYPE(FMyTestPS, Global, TEXPIXELSHADER_API);
public:
FMyTestPS() {}
FMyTestPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
:FGlobalShader(Initializer)
{
//This is used to let the shader system have parameters be available in the shader.
//The second Parameter has the name of the Parameter in the shader
//The third Parameter determines if it's optional or mandatory.
MyColorParameter.Bind(Initializer.ParameterMap, TEXT("MyColor"));
TextureParameter.Bind(Initializer.ParameterMap, TEXT("TextureParameter"));
TexMapSampler.Bind(Initializer.ParameterMap, TEXT("TexMapSampler"));
}
//This method is used to set non buffer(Texture) parameters.
void SetParameters(
FRHICommandList& RHICmdList,
const FLinearColor& Color,
FShaderResourceViewRHIRef TextureParameterSRV,
FTextureRHIParamRef InputTextureRef
)
{
FPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();
// Stores incoming color parameter to MyColorParameter
SetShaderValue(RHICmdList, PixelShaderRHI, MyColorParameter, Color);
//Store the shader resource view to the texture parameter
/*if (TextureParameter.IsBound())
{
RHICmdList.SetShaderResourceViewParameter(PixelShaderRHI,
TextureParameter.GetBaseIndex(), TextureParameterSRV);
}
*/
FSamplerStateRHIParamRef SamplerStateLinear = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
SetSamplerParameter(RHICmdList, PixelShaderRHI, TexMapSampler, SamplerStateLinear);
SetTextureParameter(RHICmdList, PixelShaderRHI, TextureParameter, InputTextureRef);
}
void SetUniformBuffers(FRHICommandList& RHICmdList, FPixelShaderVariableParameters& VariableParameters)
{
FPixelShaderVariableParameterRef VariableParametersBuffer;
VariableParametersBuffer =
FPixelShaderVariableParameterRef::CreateUniformBufferImmediate(
VariableParameters, UniformBuffer_SingleDraw);
SetUniformBufferParameter(RHICmdList, GetPixelShader(),
GetUniformBufferParameter<FPixelShaderVariableParameters>(),
VariableParametersBuffer);
}
void UnbindBuffers(FRHICommandList& RHICmdList)
{
/*FPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();
if (TextureParameter.IsBound())
{
RHICmdList.SetShaderResourceViewParameter(PixelShaderRHI,
TextureParameter.GetBaseIndex(), FShaderResourceViewRHIRef());
}*/
}
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << MyColorParameter << TextureParameter << TexMapSampler;
return bShaderHasOutdatedParameters;
}
//Required Function
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return true;
}
private:
//If using Textures use FShaderResourceParameter
FShaderParameter MyColorParameter;
FShaderResourceParameter TextureParameter;
FShaderResourceParameter TexMapSampler;
};
And finally Below is how I’m connecting my class to my PixelShader
IMPLEMENT_UNIFORM_BUFFER_STRUCT(FPixelShaderVariableParameters, TEXT("PSVariable"))
IMPLEMENT_SHADER_TYPE(, FMyTestVS, TEXT("/Plugin/TexPixelShader/Private/TexVS_PS.usf"), TEXT("MainVS"), SF_Vertex);
IMPLEMENT_SHADER_TYPE(, FMyTestPS, TEXT("/Plugin/TexPixelShader/Private/TexVS_PS.usf"), TEXT("MainPS"), SF_Pixel);
IMPLEMENT_MODULE(FDefaultModuleImpl, TexPixelShader);
I apologize for the long post but I wanted to give a complete overview of the pipeline so that I can get pointers to where I might be going wrong.
My Static mesh has UVs and is fine. As shown in the figure below.
So please if anyone can help me out it’ll be great.
Thank you for taking the time and hope you hear a quick response.
Regards,