#define FORMAT_2D_FLOAT 1
#define FORMAT_3D_FLOAT 3
int _VertexBufferStride; // in bytes
int _VertexBufferPosAttributeOffset; // in bytes
RWByteAddressBuffer _VertexBuffer;
//-------------------------
// 2D Half-Precision (half2)
// Layout: 2 * 16 bits = 32 bits total = 4 bytes
//-------------------------
float2 GetPos2D_Half(uint i)
uint packed = _VertexBuffer.Load(i * _VertexBufferStride + _VertexBufferPosAttributeOffset);
uint halfX = packed & 0xFFFF;
uint halfY = (packed >> 16) & 0xFFFF;
float x = f16tof32(halfX);
float y = f16tof32(halfY);
void SetPos2D_Half(uint i, float2 position)
uint halfX = f32tof16(position.x);
uint halfY = f32tof16(position.y);
uint packed = (halfX & 0xFFFF) | ((halfY & 0xFFFF) << 16);
_VertexBuffer.Store(i * _VertexBufferStride + _VertexBufferPosAttributeOffset, packed);
//-------------------------
// 2D Full-Precision (float2)
// Layout: 2 * 32 bits = 64 bits total = 8 bytes
//-------------------------
float2 GetPos2D_Float(uint i)
uint2 data = _VertexBuffer.Load2(i * _VertexBufferStride + _VertexBufferPosAttributeOffset);
void SetPos2D_Float(uint i, float2 position)
uint2 data = asuint(position);
_VertexBuffer.Store2(i * _VertexBufferStride + _VertexBufferPosAttributeOffset, data);
//-------------------------
// 3D Half-Precision (half3)
// Layout: half3 = 3 * 16 bits = 48 bits. We store 8 bytes = 64 bits:
// packed as [hX,hY] in first uint, and [hZ, padding] in second uint.
//-------------------------
float3 GetPos3D_Half(uint i)
uint2 packed = _VertexBuffer.Load2(i * _VertexBufferStride + _VertexBufferPosAttributeOffset);
uint halfX = packed.x & 0xFFFF;
uint halfY = (packed.x >> 16) & 0xFFFF;
uint halfZ = packed.y & 0xFFFF; // upper 16 bits unused
float x = f16tof32(halfX);
float y = f16tof32(halfY);
float z = f16tof32(halfZ);
void SetPos3D_Half(uint i, float3 position)
uint halfX = f32tof16(position.x);
uint halfY = f32tof16(position.y);
uint halfZ = f32tof16(position.z);
uint packed1 = (halfX & 0xFFFF) | ((halfY & 0xFFFF) << 16);
uint packed2 = (halfZ & 0xFFFF); // upper bits padding
_VertexBuffer.Store2(i * _VertexBufferStride + _VertexBufferPosAttributeOffset, uint2(packed1, packed2));
//-------------------------
// 3D Full-Precision (float3)
// Layout: 3 * 32 bits = 96 bits = 12 bytes
//-------------------------
float3 GetPos3D_Float(uint i)
return asfloat(_VertexBuffer.Load3(i * _VertexBufferStride + _VertexBufferPosAttributeOffset));
void SetPos3D_Float(uint i, float3 position)
_VertexBuffer.Store3(i * _VertexBufferStride + _VertexBufferPosAttributeOffset, asuint(position));
//-------------------------
// Generic Get/Set Functions
//-------------------------
float2 GetPosition2D(uint i)
if (_FormatType == FORMAT_2D_HALF)
else if (_FormatType == FORMAT_2D_FLOAT)
return GetPos2D_Float(i);
// If the data is 3D, we can fallback by ignoring Y or Z.
if (_FormatType == FORMAT_3D_HALF)
float3 pos3 = GetPos3D_Half(i);
return float2(pos3.x, pos3.z);
else if (_FormatType == FORMAT_3D_FLOAT)
float3 pos3 = GetPos3D_Float(i);
return float2(pos3.x, pos3.z);
void SetPosition2D(uint i, float2 pos)
if (_FormatType == FORMAT_2D_HALF)
else if (_FormatType == FORMAT_2D_FLOAT)
else if (_FormatType == FORMAT_3D_HALF)
// If the underlying format is 3D half, store XY and 0 for Z
SetPos3D_Half(i, float3(pos.x, 0.0f, pos.y));
else if (_FormatType == FORMAT_3D_FLOAT)
SetPos3D_Float(i, float3(pos.x, 0.0f, pos.y));
float3 GetPosition3D(uint i)
if (_FormatType == FORMAT_3D_FLOAT)
return GetPos3D_Float(i);
else if (_FormatType == FORMAT_3D_HALF)
else if (_FormatType == FORMAT_2D_HALF)
float2 pos2 = GetPos2D_Half(i);
return float3(pos2.x, 0.0, pos2.y);
else if (_FormatType == FORMAT_2D_FLOAT)
float2 pos2 = GetPos2D_Float(i);
return float3(pos2.x, 0.0, pos2.y);
void SetPosition3D(uint i, float3 pos)
if (_FormatType == FORMAT_3D_FLOAT)
else if (_FormatType == FORMAT_3D_HALF)
else if (_FormatType == FORMAT_2D_HALF)
// If underlying is 2D half, just store XZ
SetPos2D_Half(i, float2(pos.x, pos.z));
else if (_FormatType == FORMAT_2D_FLOAT)
// If underlying is 2D float, just store XZ
SetPos2D_Float(i, float2(pos.x, pos.z));
// Example usage within kernels:
void UpdatePositions(uint2 id : SV_DispatchThreadID)
uint ID = id.x + res2D * id.y;
// For example, if working in 2D space:
float2 pos = GetPosition2D(ID);
// ... Perform modifications on pos ...
// float3 pos3 = GetPosition3D(ID);
// SetPosition3D(ID, pos3);
void Spawn(uint2 id : SV_DispatchThreadID)
uint ID = id.x + res2D * id.y;
if (_FormatType == FORMAT_2D_HALF || _FormatType == FORMAT_2D_FLOAT)
float2 randomPos2D = /* generate random 2D pos */;
SetPosition2D(ID, randomPos2D);
float3 randomPos3D = /* generate random 3D pos */;
SetPosition3D(ID, randomPos3D);