GraphicsBuffer的GetData始终返回全0数组问题排查
问题
目标Mesh的Read/Write选项为false且无法修改,尝试用GraphicsBuffer克隆Mesh:测试项目中代码运行正常,但主项目里sourceDataBuffer.GetData(sourceData)和sourceIndexBuffer.GetData(sourceIndex)返回全0数组。该问题仅在包含不可读Mesh的资源包中出现,原以为GraphicsBuffer适配此类Mesh,实际不行,请问原因是什么?
测试代码
public static bool Run(Mesh sourceMesh, out Mesh generatedMesh) { GraphicsBuffer sourceDataBuffer = sourceMesh.GetVertexBuffer(0); GraphicsBuffer sourceIndexBuffer = sourceMesh.GetIndexBuffer(); var vertexCount = sourceDataBuffer.count; var indexCount = sourceIndexBuffer.count; byte[] sourceData = new byte[vertexCount * (sourceDataBuffer.stride / sizeof(byte))]; byte[] sourceIndex = new byte[(int)(indexCount * ((float)sourceIndexBuffer.stride / sizeof(byte)))]; sourceDataBuffer.GetData(sourceData); sourceIndexBuffer.GetData(sourceIndex); var attributes = sourceMesh.GetVertexAttributes(); generatedMesh = new Mesh(); generatedMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw; generatedMesh.SetVertexBufferParams(vertexCount, attributes); generatedMesh.SetVertexBufferData(sourceData, 0, 0, sourceData.Length); generatedMesh.SetIndexBufferParams(indexCount, sourceMesh.indexFormat); generatedMesh.SetIndexBufferData(sourceIndex, 0, 0, sourceIndex.Length); generatedMesh.subMeshCount = sourceMesh.subMeshCount; for (int i = 0; i < sourceMesh.subMeshCount; i++) { var subMeshDescriptor = sourceMesh.GetSubMesh(i); generatedMesh.SetSubMesh(i, subMeshDescriptor); } sourceDataBuffer.Release(); sourceIndexBuffer.Release(); generatedMesh.RecalculateBounds(); return true; // No error }
原因分析与解决方案
核心原因
- 资源包GPU优化限制:主项目资源包中的Mesh大概率开启了GPU-only内存优化,这类Mesh的顶点/索引数据仅存储在GPU显存中,没有保留CPU可访问的副本。测试项目中的Mesh未经过该优化,所以GraphicsBuffer能正常读取数据;而资源包构建时的优化逻辑会移除CPU访问权限,导致
GetData无法从显存拉取数据,只能返回全0数组。 - GraphicsBuffer权限缺失:当Mesh的Read/Write为false时,通过
GetVertexBuffer/GetIndexBuffer获取的GraphicsBuffer默认没有CPU读取权限。测试环境中Mesh可能因未打包而隐式保留了权限,资源包构建时则严格移除了该权限,导致读取操作无效。
解决办法
- 调整资源包构建设置:在资源包构建窗口中,关闭Mesh的Optimize Mesh Data选项,或勾选Keep CPU Data(不同Unity版本选项名称略有差异),确保Mesh数据保留CPU可访问的副本。
- 改用官方只读数据API:使用Unity提供的
Mesh.AcquireReadOnlyMeshData接口,专门用于读取不可读Mesh的数据,不受Read/Write选项限制,替换原有GraphicsBuffer读取逻辑:using (var dataArray = Mesh.AcquireReadOnlyMeshData(sourceMesh)) { var meshData = dataArray[0]; // 读取顶点数据示例 Vector3[] vertices = new Vector3[meshData.vertexCount]; meshData.GetVertices(vertices); // 读取索引数据示例 int[] indices = new int[meshData.indexCount]; meshData.GetIndices(indices, 0); // 后续构建新Mesh的逻辑,改用这些读取到的数据填充即可 } - 放弃GraphicsBuffer直接读取:对于不可读Mesh,GraphicsBuffer的CPU访问权限依赖资源构建配置,稳定性远低于官方只读API,优先使用
Mesh.AcquireReadOnlyMeshData更可靠。
内容的提问来源于stack exchange,提问作者Nathalia Soragge
相关产品推荐
相关产品推荐

