You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Compute Shader中字节数组转float4写入RWTexture2D的正确实现问询

问题解决:Compute Shader中读取字节数组并转换为float写入纹理

你的核心问题是C#将byte[]直接传入int类型的Compute Buffer时,Unity会自动将4个连续byte打包为一个int,导致Compute Shader中读取的每个colorBuffer元素是4个byte的组合值,而非单个byte的0-255数值,转换float时自然出现异常。而testBuffer用int数组传入时,每个int对应单个byte值,所以能拿到正确结果。

以下是三种可行的解决方案:

方案一:使用ByteAddressBuffer直接按字节访问(推荐)

这种方式直接操作字节偏移,完全匹配原始byte数组结构,无需在CPU端转换数据。

Compute Shader 修改:

ByteAddressBuffer colorBuffer;
RWBuffer<float> testBuffer;
RWTexture2D<float4> colorTexture;
 
float rgbWidth;
float rgbHeight;
 
[numthreads(8,8,1)]
void RGBProcessing (uint3 id : SV_DispatchThreadID)
{
    const uint pixelIndex = id.y * uint(rgbWidth) + id.x;
    // 每个像素占4字节(RGBA),计算当前像素的起始字节偏移
    const uint byteOffset = pixelIndex * 4;
    
    // 按字节读取,通过位掩码提取单个byte的无符号值
    uint blue = colorBuffer.Load<uint>(byteOffset) & 0xFF;
    uint green = colorBuffer.Load<uint>(byteOffset + 1) & 0xFF;
    uint red = colorBuffer.Load<uint>(byteOffset + 2) & 0xFF;
    uint alpha = colorBuffer.Load<uint>(byteOffset + 3) & 0xFF;
   
    // 转换为0-1范围的float并写入纹理
    colorTexture[id.xy] = float4(
        float(red) / 255.0, 
        float(green) / 255.0, 
        float(blue) / 255.0, 
        float(alpha) / 255.0
    );
    testBuffer[pixelIndex] = float(blue);
}

C# 代码修改:

创建Compute Buffer时指定stride=1(按字节访问),直接传入原始byte数组:

// 直接使用byte数组的长度作为buffer元素数量,stride设为1
rgbBuffer = new ComputeBuffer(_rgbBytes.Length, 1, ComputeBufferType.Default);
rgbBuffer.SetData(_rgbBytes);

// 其余dispatch代码保持不变
rgbProcessing.SetBuffer(0, "colorBuffer", rgbBuffer);
// ... 其他参数设置与Dispatch逻辑

方案二:CPU端将byte数组转为int数组(每个int存储单个byte值)

在CPU端提前将每个byte转换为int,确保Compute Buffer中每个int对应一个原始byte的数值,避免打包问题。

C# 代码修改:

// 将byte数组转换为int数组,每个int对应单个byte的无符号值
int[] intByteData = Array.ConvertAll(_rgbBytes, b => (int)b);
// 创建对应长度的int类型Compute Buffer
rgbBuffer = new ComputeBuffer(intByteData.Length, sizeof(int));
rgbBuffer.SetData(intByteData);

Compute Shader 修改:

仅需将int转为uint避免符号问题(byte是无符号的,int是有符号,值>127时会变为负数):

Buffer<int> colorBuffer;
RWBuffer<float> testBuffer;
RWTexture2D<float4> colorTexture;
 
float rgbWidth;
float rgbHeight;
 
[numthreads(8,8,1)]
void RGBProcessing (uint3 id : SV_DispatchThreadID)
{
    const int pixelIndex = int(id.y * rgbWidth + id.x);
    
    // 转换为uint避免负数,确保数值在0-255范围内
    uint blue = (uint)colorBuffer[pixelIndex * 4];
    uint green = (uint)colorBuffer[pixelIndex * 4 + 1];
    uint red = (uint)colorBuffer[pixelIndex * 4 + 2];
    uint alpha = (uint)colorBuffer[pixelIndex * 4 + 3];
   
    colorTexture[id.xy] = float4(
        float(red) / 255.0, 
        float(green) / 255.0, 
        float(blue) / 255.0, 
        float(alpha) / 255.0
    );
    testBuffer[pixelIndex] = float(blue);
}

方案三:使用StructuredBuffer(部分平台支持)

部分平台支持直接使用StructuredBuffer<byte>读取字节数组,无需额外转换。

Compute Shader 修改:

StructuredBuffer<byte> colorBuffer;
RWBuffer<float> testBuffer;
RWTexture2D<float4> colorTexture;
 
float rgbWidth;
float rgbHeight;
 
[numthreads(8,8,1)]
void RGBProcessing (uint3 id : SV_DispatchThreadID)
{
    const int pixelIndex = int(id.y * rgbWidth + id.x);
    
    byte blue = colorBuffer[pixelIndex * 4];
    byte green = colorBuffer[pixelIndex * 4 + 1];
    byte red = colorBuffer[pixelIndex * 4 + 2];
    byte alpha = colorBuffer[pixelIndex * 4 + 3];
   
    colorTexture[id.xy] = float4(
        float(red) / 255.0, 
        float(green) / 255.0, 
        float(blue) / 255.0, 
        float(alpha) / 255.0
    );
    testBuffer[pixelIndex] = float(blue);
}

C# 代码修改:

与方案一相同,创建stride=1的Compute Buffer并传入byte数组:

rgbBuffer = new ComputeBuffer(_rgbBytes.Length, 1, ComputeBufferType.Default);
rgbBuffer.SetData(_rgbBytes);

内容的提问来源于stack exchange,提问作者arvinkx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:42:15