Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save lachlansleight/1e02652bc5a298cba4004dca2a54942d to your computer and use it in GitHub Desktop.
Save lachlansleight/1e02652bc5a298cba4004dca2a54942d to your computer and use it in GitHub Desktop.
Depth Camera Image to World-Space Position (Unity Compute Shader)
// This is the old version of my shader - I'm in London atm and don't have the new project that spawns particles to hand
// In this one, there's one particl
// The particles are something like
struct Particle {
int2 PixelPosition;
float3 WorldSpacePosition;
}
// compute buffer matched to the particle struct
RWStructuredBuffer<Particle> ParticleBuffer;
// R16 depth texture from RealSense - maybe this could be Texture2D<float> idk lol
Texture2D<float4> DepthTexture;
// transform.localToWorldMatrix of the transform I use to represent the depth camera in the scene
float4x4 TransformMatrix;
// size of the depth texture in pixels
float2 FrameSize;
// literally just FrameSize.x / FrameSize.y - precomputed when we send the texture pointer
float FrameRatio;
// matched to the number of thread groups I call in dispatch - only used for mapping thread ID to particle buffer index
int3 GroupCount;
// Converts raw position into world space position
// X and Y are basically UV coordinates, but I subtract 0.5 so it's centered at 0, 0 at the frame center
// Z is the depth in world-space meters
// W is 1.0 so I can multiply with the transform matrix
float3 GetPos(float4 RawPos, float4x4 TransformMatrix) {
// Correct for aspect ratio
RawPos.x *= FrameRatio;
// Project out using depth
RawPos.x *= RawPos.z;
RawPos.y *= RawPos.z;
// Got these values through manual measurement and are specific to the RealSense D435
RawPos.x *= 1.23134;
RawPos.y *= 1.23134;
// Optional, but I have my depth camera mounted on a HMD so this is necessary for me
RawPos = mul(TransformMatrix, RawPos);
return RawPos.xyz;
}
[numthreads(32, 24, 1)]
void DepthToPositions(uint3 id : SV_DispatchThreadID)
{
uint idx = id.x + (id.y * 32 * GroupCount.x) + (id.z * 32 * GroupsX * 24 * GroupCount.y);
Particle CurrentParticle = ParticleBuffer[idx];
int2 PixelPosition = CurrentParticle.PixelPosition;
// turns depth texture value (this is from RealSense, so the format is R16 half-precision floating point) into world-space meters
// this was years ago, but I'm pretty sure I got the multiplier by experimentation via measuring with my vive controllers lol
float RawDepth = DepthTexture[int2(PixelPosition.x, PixelPosition.y)].x;
RawDepth *= DepthUnits * DepthScale;
CurrentParticle.WorldSpacePosition = GetPos(float4(
(PixelPosition.x / FrameSize.x) - 0.5,
0.5 - (PixelPosition.y / FrameSize.y), //RealSense depth textures are flipped on the y axis
RawDepth,
1.0
), TransformMatrix);
ParticleBuffer[idx] = CurrentParticle;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment