如何在循环中高效设置NativeArray<float4>的单个xyzw分量的值
遍历NativeArray修改单分量报错的高性能解决方案
当遍历NativeArray<float4>时,如果直接尝试设置每个float4的单个字段(比如本例的y分量)会触发编译报错,原因是索引取值得到的是结构体临时值,无法直接修改。
错误代码示例
NativeArray<float4> naFloat4s ; void Start ( ) { naFloat4s = new NativeArray<float4> ( 96000, Allocator.Persistent ) ; } void MakeNoise ( ) { for ( int i = 0 ; i < naFloat4s.Length ; i++ ) { naFloat4s[i].y = Random.Range ( - 1f, 1f ) ; } }
上述代码会触发「无法修改结构体临时值」的编译错误。
核心要求
解决方案需要满足以下条件:
- 全程无GC垃圾生成
- 可充分发挥NativeArray、Burst/Jobs的性能优势,可快速处理数万级别的数据赋值
- 必须保留
float4其余分量(x、z、w)的原有值不变 - 示例中随机数仅为演示,可兼容其他自定义数值生成逻辑
最高性能实现方案(Unsafe指针操作)
通过直接操作float4内部的float指针实现单分量修改,完全规避临时值拷贝,性能损耗最低:
void LoopDemoWithPointerToFloatOfFloat4_NativeArray() { int samples = 2000; int size_T = UnsafeUtility.SizeOf<float4> ( ) ; int size_F = UnsafeUtility.SizeOf<float> ( ) ; int mStepr = size_F * 1 ; // 1对应float4结构体中y分量的偏移索引 IntPtr dstPtr = ( IntPtr )NativeArrayUnsafeUtility .GetUnsafeBufferPointerWithoutChecks ( naFloat4s ) ; for ( int i = 0 ; i < samples ; i++ ) { unsafe { float* yOffset = (float*) (dstPtr + i * size_T + mStepr); *yOffset = (float)i ; // 此处可替换为自定义数值生成逻辑 } } }
实际使用简化示例
var p = (float4*)noizADSR.GetUnsafePtr ( ); float stepDekay = 1f / dekayLength ; ptr = (float*)(p + attakFinish); ptr += nID; j = overlapping; for ( int i = attakFinish ; i < noizeLength ; i++, j++, ptr += 4 ) { *ptr = dekayCrv.Evaluate( j * stepDekay) ; }
方案说明
- 注意该实现需要在项目设置中开启unsafe编译选项
- 该方案直接操作NativeArray的原生内存地址,无任何额外内存拷贝,性能最优
- 完全兼容Burst编译和Job System调度,处理十万级以上数据时性能优势尤为明显
- 无需修改其他分量的值,仅对目标分量做赋值操作,完全符合需求
内容的提问来源于stack exchange,提问作者Confused
相关产品推荐
相关产品推荐

