Hello,
I'm having difficulty porting a filter that I wrote in C# and It's pretty slow and I would like to convert it to a compute shader.
- Right now I get compilation error and I also don't know how would compute shader work on that algorithm.
- I'm not sure If doing the average calculation is correct as it is right now ?
The original code:
public unsafe void DRSFilter( byte * src, byte * dst, uint data_delta, uint history_scan_depth)
{
if (history_scan_depth > history_capacity)
{
history_scan_depth = history_capacity;
}
for (int i = 0; i < layer_size; i++)
{
byte b = src[i];
uint avrg = 0;
for (int k = 0; k < history_scan_depth; k++)
{
avrg += history[k * layer_size + i];
}
average[i] = (byte)(avrg / history_scan_depth);
if (Math.Abs(b - average[i]) < data_delta)
{
dst[i] = b;
}
history[layer * layer_size + i] = b;
}
layer++;
if (layer == history_scan_depth)
{
layer = 0;
}
}
The new trial of compute shader in unity:
Shader Initialization:
private const int width = 1280;
private const int height = 720;
private int history_capacity = 3;
private int layer_size = width * height * 6;
private int layer = 0;
public int history_scan_depth = 50;
public int data_delta = 50;
private int[] history;
private int[] average;
public ComputeShader shader;
private int handleDepthFilter;
private Texture depthFiltered;
history = new int[history_capacity * layer_size];
average = new int[layer_size];
shader.SetInt("history_scan_depth", history_scan_depth);
shader.SetInt("data_delta", data_delta);
shader.SetInt("history_capacity", history_capacity);
shader.SetInt("layer_size", layer_size);
shader.SetInt("layer", layer);
ComputeBuffer history_buffer = new ComputeBuffer(history_capacity * layer_size, sizeof(int));
ComputeBuffer average_buffer = new ComputeBuffer(layer_size, sizeof(int));
history_buffer.SetData(history);
average_buffer.SetData(average);
shader.SetBuffer(handleDepthFilter, "history_buffer", history_buffer);
shader.SetBuffer(handleDepthFilter, "average_buffer", average_buffer);
_outputTexture = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32);
_outputTexture.enableRandomWrite = true;
_outputTexture.Create()
Shader Code:
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;
Texture2D<float4> Texture;
RWStructuredBuffer<int> history_buffer;
RWStructuredBuffer<int> average_buffer;
int history_scan_depth;
int history_capacity;
int data_delta;
int layer;
int layer_size;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
// TODO: insert actual code here!
if (history_scan_depth > history_capacity)
{
history_scan_depth = history_capacity;
}
float4 b = Texture[id.xy];
uint avrg = 0;
for (int k = 0; k < history_scan_depth; k++)
{
avrg += history_buffer[k * layer_size + id.xy];
}
average_buffer[id] = (byte)(avrg / history_scan_depth);
if (abs(b - average[id.xy) < data_delta)
{
Result[id] = b;
}
history_buffer[layer * layer_size + .xy] = b;
_layer++;
if (_layer == history_scan_depth)
{
_layer = 0;
}
}
Shader dispatching:
private void ImageUpdated(ref Texture2D zedTextureDepth)
{
Texture2D copyDepthRW = duplicateTexture(zedTextureDepth);
shader.SetTexture(handleDepthFilter, "Texture", copyDepthRW);
shader.SetTexture(handleDepthFilter, "Result", _outputTexture);
shader.Dispatch(handleDepthFilter, (width) / 8,
(height) / 8, 1);}
}