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

Compute Shaders整数≥65535时Unity网格损坏问题求助

问题

本人对Compute Shaders经验不多,但为了性能需求编写了一段代码。以下是Compute Shader中的简单内核方法,用于将结构体缓冲区转换为Unity网格可用的多个缓冲区(triData_out是开发遗留产物,计划解决问题后移除):

#define THREADS_X 64
#define THREADS_Y 1
#define THREADS_Z 1

[numthreads(THREADS_X, THREADS_Y, THREADS_Z)]
void MMMesh(uint3 id : SV_DispatchThreadID)
{
    int index = id.x + (id.y * THREADS_X) + (id.z * THREADS_Y * THREADS_X);
    
    if (index >= allTrisCount)
        return;

    int destIndex = index * 3;
    MMTriangle srcTri = triData_in[index];

    vertData[destIndex] = srcTri.vertA.pos;
    vertData[destIndex + 1] = srcTri.vertB.pos;
    vertData[destIndex + 2] = srcTri.vertC.pos;

    uvData[destIndex] = srcTri.vertA.uv;
    uvData[destIndex + 1] = srcTri.vertB.uv;
    uvData[destIndex + 2] = srcTri.vertC.uv;

    triData_out[destIndex] = destIndex;
    triData_out[destIndex + 1] = destIndex + 1;
    triData_out[destIndex + 2] = destIndex + 2;
}

当Dispatch调用为.Dispatch(allTrisCount,1,1)时方法运行正常,但一旦destIndex≥65535,Unity网格就会出现大量三角面错乱的损坏情况(不确定是否与Dispatch单维度限制65535有关,此时维度最小值为65535/3)。此前使用Unity Jobs多线程实现时无此问题,可确定问题出在该内核方法,求排查原因。

排查分析与解决方案

核心原因

  • Dispatch维度超限导致线程重复:Unity Compute Shader的Dispatch每个维度最大值为65535,当allTrisCount超过这个值时,.Dispatch(allTrisCount,1,1)的X维度会被底层截断为低16位数值,造成大量线程的id.x重复,多个线程同时写入同一个缓冲区位置,直接覆盖数据引发网格错乱。
  • 索引类型不匹配引发溢出:代码中用int类型存储index和destIndex,但SV_DispatchThreadID是uint3类型,当线程ID超过int的正范围(或因截断出现异常值),会导致索引计算错误,甚至出现负数索引触发缓冲区越界写入。

修复步骤

  1. 修正Dispatch线程组计算逻辑
    不要直接用三角面数量作为Dispatch的X维度,而是根据线程组大小计算所需组数:

    int threadGroupsX = Mathf.CeilToInt(allTrisCount / (float)THREADS_X);
    computeShader.Dispatch(kernelIndex, threadGroupsX, 1, 1);
    

    这样既保证每个维度不超过65535限制,又能让所有三角面都被正确分配线程处理。

  2. 统一索引为uint类型
    将Shader中的索引变量改为uint,避免类型转换带来的溢出问题:

    uint index = id.x + (id.y * THREADS_X) + (id.z * THREADS_Y * THREADS_X);
    
    if (index >= allTrisCount)
        return;
    
    uint destIndex = index * 3;
    

    同时确保C#端传递的allTrisCount在Shader中声明为uint类型。

  3. 校验缓冲区容量
    确认vertData、uvData、triData_out的缓冲区容量足够容纳allTrisCount * 3个元素,避免越界写入污染内存。

内容的提问来源于stack exchange,提问作者Spring E. Thing

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:06:23