UE4 添加computeshader
发布时间
阅读量:
阅读量
参考这篇文章。笔者在开发时,犯了个错误:在UseComputeShader_RenderThread函数中,得到ComputeShader之后,要把这个computeshader设置给RHICmdList,否则下面DispathComputeSHader执行的时候会找不到computeShader(该指针为空)。
static void UseComputeShader_RenderThread(
FRHICommandListImmediate& RHICmdList,
FTextureRenderTargetResource* OutputRenderTargetResource,
ERHIFeatureLevel::Type FeatureLevel
)
{
check(IsInRenderingThread());
TShaderMap<FGlobalShaderType>* GlobalShaderMap = GetGlobalShaderMap(FeatureLevel);
TShaderMapRef<FShaderTestCS> ComputeShader(GlobalShaderMap);
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
int32 SizeX = OutputRenderTargetResource->GetSizeX();
int32 SizeY = OutputRenderTargetResource->GetSizeY();
FRHIResourceCreateInfo CreateInfo;
FTexture2DRHIRef Texture = RHICreateTexture2D(SizeX, SizeY, PF_R32_UINT, 1, 1, TexCreate_ShaderResource | TexCreate_UAV, CreateInfo);
//OutputRenderTargetResource->UA
FUnorderedAccessViewRHIRef TextureUAV = RHICreateUnorderedAccessView(Texture);
ComputeShader->SetSurfaces(RHICmdList, TextureUAV);
DispatchComputeShader(RHICmdList, *ComputeShader, SizeX / 32, SizeY / 32, 1);
ComputeShader->UnbindBuffers(RHICmdList);
//create a bitmap
TArray<FColor> Bitmap;
//To access our resource we do a custom read using lockrect
uint32 LolStride = 0;
char* TextureDataPtr = (char*)RHICmdList.LockTexture2D(Texture, 0, EResourceLockMode::RLM_ReadOnly, LolStride, false);
for (uint32 Row = 0; Row < Texture->GetSizeY(); ++Row)
{
uint32* PixelPtr = (uint32*)TextureDataPtr;
//Since we are using our custom UINT format, we need to unpack it here to access the actual colors
for (uint32 Col = 0; Col < Texture->GetSizeX(); ++Col)
{
uint32 EncodedPixel = *PixelPtr;
uint8 r = (EncodedPixel & 0x000000FF);
uint8 g = (EncodedPixel & 0x0000FF00) >> 8;
uint8 b = (EncodedPixel & 0x00FF0000) >> 16;
uint8 a = (EncodedPixel & 0xFF000000) >> 24;
Bitmap.Add(FColor(r, g, b, a));
PixelPtr++;
}
// move to next row:
TextureDataPtr += LolStride;
}
RHICmdList.UnlockTexture2D(Texture, 0, false);
// if the format and texture type is supported
if (Bitmap.Num())
{
// Create screenshot folder if not already present.
const TCHAR* path = *FPaths::ScreenShotDir();
IFileManager::Get().MakeDirectory(path, true);
const FString ScreenFileName(FPaths::ScreenShotDir() / TEXT("VisualizeTexture"));
uint32 ExtendXWithMSAA = Bitmap.Num() / Texture->GetSizeY();
// Save the contents of the array to a bitmap file. (24bit only so alpha channel is dropped)
FFileHelper::CreateBitmap(*ScreenFileName, ExtendXWithMSAA, Texture->GetSizeY(), Bitmap.GetData());
UE_LOG(LogConsoleResponse, Display, TEXT("Content was saved to \"%s\""), *FPaths::ScreenShotDir());
}
else
{
UE_LOG(LogConsoleResponse, Error, TEXT("Failed to save BMP, format or texture type is not supported"));
}
}
得到的贴图存储到“const TCHAR* path = *FPaths::ScreenShotDir();
IFileManager::Get().MakeDirectory(path, true);
const FString ScreenFileName(FPaths::ScreenShotDir() / TEXT(“VisualizeTexture”));”路径下,在工程目录下的Saved/ScreenShots/windows/下。
可以参考PostprocessBloomSetup.cpp里的FPostProcessBloomSetupCS类。
computeShader代码如下:
class FShaderTestCS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FShaderTestCS, Global);
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
}
FShaderTestCS() {}
public:
FShaderResourceParameter OutputSurface;
FShaderTestCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
OutputSurface.Bind(Initializer.ParameterMap, TEXT("OutputSurface"));
}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParams = FGlobalShader::Serialize(Ar);
Ar << OutputSurface;
return bShaderHasOutdatedParams;
}
void SetSurfaces(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIRef OutputSurfaceUAV)
{
FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();
RHICmdList.SetUAVParameter(ComputeShaderRHI, OutputSurface.GetBaseIndex(), OutputSurfaceUAV);
}
void UnbindBuffers(FRHICommandList& RHICmdList)
{
const FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();
RHICmdList.SetUAVParameter(ComputeShaderRHI, OutputSurface.GetBaseIndex(), NULL);
}
};
IMPLEMENT_SHADER_TYPE(, FShaderTestVS, TEXT("/Plugin/test/Private/MyShader.usf"), TEXT("MainVS"), SF_Vertex)
IMPLEMENT_SHADER_TYPE(, FShaderTestPS, TEXT("/Plugin/test/Private/MyShader.usf"), TEXT("MainPS"), SF_Pixel)
IMPLEMENT_SHADER_TYPE(, FShaderTestCS, TEXT("/Plugin/test/Private/MyShader.usf"), TEXT("MainCS"), SF_Compute)
shader代码如下:
RWTexture2D<uint> OutputSurface;
[numthreads(32, 32, 1)]
void MainCS(uint3 ThreadId : SV_DispatchThreadID)
{
float sizeX, sizeY;
OutputSurface.GetDimensions(sizeX, sizeY);
float2 iResolution = float2(sizeX, sizeY);
float2 uv = (ThreadId.xy / iResolution.xy) - 0.5;
float iGlobalTime = 1.0f;
float t = iGlobalTime * 0.1 + ((0.25 + 0.05 * sin(iGlobalTime * 0.1)) / (length(uv.xy) + 0.07)) * 2.2;
float si = sin(t);
float co = cos(t);
float2x2 ma = { co, si, -si, co };
float v1, v2, v3;
v1 = v2 = v3 = 0.0;
float s = 0.0;
for (int i = 0; i < 90; i++)
{
float3 p = s * float3(uv, 0.0);
p.xy = mul(p.xy, ma);
p += float3(0.22, 0.3, s - 1.5 - sin(iGlobalTime * 0.13) * 0.1);
for (int i = 0; i < 8; i++)
p = abs(p) / dot(p, p) - 0.659;
v1 += dot(p, p) * 0.0015 * (1.8 + sin(length(uv.xy * 13.0) + 0.5 - iGlobalTime * 0.2));
v2 += dot(p, p) * 0.0013 * (1.5 + sin(length(uv.xy * 14.5) + 1.2 - iGlobalTime * 0.3));
v3 += length(p.xy * 10.0) * 0.0003;
s += 0.035;
}
float len = length(uv);
v1 *= lerp(0.7, 0.0, len);
v2 *= lerp(0.5, 0.0, len);
v3 *= lerp(0.9, 0.0, len);
float3 col = float3(v3 * (1.5 + sin(iGlobalTime * 0.2) * 0.4), (v1 + v3) * 0.3, v2)
+ lerp(0.2, 0.0, len) * 0.85
+ lerp(0.0, 0.6, v3) * 0.3;
float3 powered = pow(abs(col), float3(1.2, 1.2, 1.2));
float3 minimized = min(powered, 1.0);
float4 outputColor = float4(minimized, 1.0);
//Since there are limitations on operations that can be done on certain formats when using compute shaders
//I elected to go with the most flexible one (UINT 32bit) and do my packing manually to simulate an R8G8B8A8_UINT format.
//There might be better ways to do this :)
uint r = outputColor.r * 255.0;
uint g = ((uint) (outputColor.g * 255.0)) << 8;
uint b = ((uint) (outputColor.b * 255.0)) << 16;
uint a = ((uint) (outputColor.a * 255.0)) << 24;
OutputSurface[ThreadId.xy] = r | g | b | a;
}
全部评论 (0)
还没有任何评论哟~
