使用计算着色器将纹理转换为浮点值的一维数组
Converting a texture to a 1d array of float values using a compute shader
我对计算着色器(通过 Unity 的 DirectCompute)有一个相当简单的要求。我有一个 128x128 的纹理,我想将该纹理的红色通道变成一维浮点数组。我需要经常这样做,所以只是在每个纹素上做一个 cpu-side for 循环不会削减它。
初始化:
m_outputBuffer = new ComputeBuffer(m_renderTexture.width * m_renderTexture.height, sizeof(float));
m_kernelIndex = m_computeShader.FindKernel("CSMain");
这是 C# 方法:
/// <summary>
/// This method converts the red channel of the given RenderTexture to a
/// one dimensional array of floats of size width * height.
/// </summary>
private float[] ConvertToFloatArray(RenderTexture renderTexture)
{
m_computeShader.SetTexture(m_kernelIndex, INPUT_TEXTURE, renderTexture);
float[] result = new float[renderTexture.width * renderTexture.height];
m_outputBuffer.SetData(result);
m_computeShader.SetBuffer(m_kernelIndex, OUTPUT_BUFFER, m_outputBuffer);
m_computeShader.Dispatch(m_kernelIndex, renderTexture.width / 8, renderTexture.height / 8, 1);
m_outputBuffer.GetData(result);
return result;
}
和整个计算着色器:
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
Texture2D<float4> InputTexture;
RWBuffer<float> OutputBuffer;
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
OutputBuffer[id.x * id.y] = InputTexture[id.xy].r;
}
C# 方法 returns 一个预期大小的数组,它通常与我的预期相对应。然而,即使我的输入纹理是统一的红色,仍然会有一些零。
我重新考虑并解决了我自己的问题。答案分为两部分:我奇怪地组合了 x 和 y 坐标(id.x 和 id.y),并且我使用了错误的输入语义。 (SV_GroupThreadID 而不是 SV_DispatchThreadID)
这就是解决方案。我还翻转了 y 轴以符合我的直觉。
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
Texture2D<float4> InputTexture;
RWBuffer<float> OutputBuffer;
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
uint w, h;
InputTexture.GetDimensions(w, h);
OutputBuffer[id.x + id.y * w] = InputTexture[float2(id.x, h - 1 - id.y)].r;
}
我对计算着色器(通过 Unity 的 DirectCompute)有一个相当简单的要求。我有一个 128x128 的纹理,我想将该纹理的红色通道变成一维浮点数组。我需要经常这样做,所以只是在每个纹素上做一个 cpu-side for 循环不会削减它。
初始化:
m_outputBuffer = new ComputeBuffer(m_renderTexture.width * m_renderTexture.height, sizeof(float));
m_kernelIndex = m_computeShader.FindKernel("CSMain");
这是 C# 方法:
/// <summary>
/// This method converts the red channel of the given RenderTexture to a
/// one dimensional array of floats of size width * height.
/// </summary>
private float[] ConvertToFloatArray(RenderTexture renderTexture)
{
m_computeShader.SetTexture(m_kernelIndex, INPUT_TEXTURE, renderTexture);
float[] result = new float[renderTexture.width * renderTexture.height];
m_outputBuffer.SetData(result);
m_computeShader.SetBuffer(m_kernelIndex, OUTPUT_BUFFER, m_outputBuffer);
m_computeShader.Dispatch(m_kernelIndex, renderTexture.width / 8, renderTexture.height / 8, 1);
m_outputBuffer.GetData(result);
return result;
}
和整个计算着色器:
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
Texture2D<float4> InputTexture;
RWBuffer<float> OutputBuffer;
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
OutputBuffer[id.x * id.y] = InputTexture[id.xy].r;
}
C# 方法 returns 一个预期大小的数组,它通常与我的预期相对应。然而,即使我的输入纹理是统一的红色,仍然会有一些零。
我重新考虑并解决了我自己的问题。答案分为两部分:我奇怪地组合了 x 和 y 坐标(id.x 和 id.y),并且我使用了错误的输入语义。 (SV_GroupThreadID 而不是 SV_DispatchThreadID)
这就是解决方案。我还翻转了 y 轴以符合我的直觉。
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
Texture2D<float4> InputTexture;
RWBuffer<float> OutputBuffer;
[numthreads(8, 8, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
uint w, h;
InputTexture.GetDimensions(w, h);
OutputBuffer[id.x + id.y * w] = InputTexture[float2(id.x, h - 1 - id.y)].r;
}