Forum Discussion
oihdfgojihdfgohljfdg
2 years agoHonored Guest
How to copy Depth API image to a PNG?
I want to use the Depth API to copy the depth image to a PNG file on Quest 3.
https://developer.oculus.com/documentation/unity/unity-depthapi/#depth-api
I'm modifying the Depth API sample:
https://github.com/oculus-samples/Unity-DepthAPI
I'm getting the RenderTexture from Util.GetEnvironmentDepthTextureId() and XRDisplaySubsystem.GetRenderTexture.RenderTexture. However, when I save the RenderTexture to a PNG image, the image is entirely gray. Each pixel color is CDCDCDCD. The image is 2000x2000.
My problem is very similar to this reddit thread:
I looked at the OpenXR Depth API Overview page and I noticed that it says:
"Depth maps should only be accessed between the xrBeginFrame and xrEndFrame calls"
https://developer.oculus.com/documentation/native/android/mobile-depth/#acquiring-depth-maps
The Unity Depth API page says:
"RenderTexture can then be used in rendering or in compute shaders."
Is this why Texture2D.ReadPixels() doesn't work? Because the RenderTexture is only usable between xrBeginFrame and xrEndFrame? How do I copy the RenderTexture to a texture that I can read and then save to a PNG file? I'm not familiar with Unity's rendering or compute shaders.
2 Replies
- RadsHonored Guest// Each kernel tells which function to compile you can have many kernels#pragma kernel CSMain// Quest3 depth texture reading ( global _EnvironmentDepthTexture)// by Radoslaw Szczygiel.// Nie wstawiac polskich znakow do shadera nawet w komentarzach !!!// Deklaracja tekstury wejsciowej (mapa glebi)Texture2DArray<float> _DepthMap ; //rs dziala bo bez RW, tu tekstura podawana jest//Texture2DArray<float> _EnvironmentDepthTexture; //rs dziala od razu na globalnej teksturze o tej nazwie dostarczanej przez Quest3 (Texture2DArray_float tez na Vulcan dziala)// Deklaracja bufora wyjsciowego (do przechowywania punktow)RWStructuredBuffer<float> _PointsBuffer; //rs tu musi byc RWfloat4 _EnvironmentDepthZBufferParams = float4(-0.2f, -1.0f, 0, 0 ); //x=0.2, y=-1.0//float _MinDistance = 6.0f;//float _MaxDistance = 0.1f;[numthreads(8,8,1)]void CSMain (uint3 id : SV_DispatchThreadID){//float depth = _EnvironmentDepthTexture.Load(int4(id.xy , 0,0)).r; // lubfloat depth = _DepthMap.Load(int4(id.xy, 0 /*array layer index*/, 0 /* z i ma byc 0 */)).r; // Odczytanie glebokosci piksela z tekstury wejsciowejfloat inputDepthNdc = depth * 2.0f - 1.0f;float linearDepth = (1.0f / (inputDepthNdc + _EnvironmentDepthZBufferParams.y)) * _EnvironmentDepthZBufferParams.x;//float linearDepth = (1.0f / (inputDepthNdc - 1.0f )) / -5 +//* (-0.2f);//float lerpFactor = (linearDepth - _MinDistance) / (_MaxDistance - _MinDistance); //rs dane do kolorowania_PointsBuffer[id.x + (id.y * 2000)] = linearDepth ; //rs 2000 to szerokosc tekstury glebi//rs todo To nie jest raczej odleglosc od kamery tylko skladowa "z" wzgledem plaszczyzny kamery co powoduje mniejsze odczyty im dalej od srodka kamery w dowolnym kierunku//rs np. podnoszac glowe do gury aby dolny punkt objal ten sam punkt sciany do wczesniej srodkowy odczyt jest mniejszy}
- RadsHonored Guestusing Unity.XR.Oculus;using UnityEngine;using UnityEngine.XR;using TMPro;public class ComputeShader1 : MonoBehaviour{public ComputeShader CompShader;// public RenderTexture DepthMap;public int BufferSize = 2000;public TextMeshProUGUI[] myDepthTextArray = new TextMeshProUGUI[9]; //rs add Tu musi być rozmiar jak ilosc el tablicy wektorow "ind" ponizejprivate ComputeBuffer m_pointsBuffer;private XRDisplaySubsystem m_xrDisplay;public float interval = 0.05f; // Interwał czasowy w sekundach// x=1250 i y=1200 to pi * drzwi = srodek. 2000 to szer tekstury głębi 2000x2000 (0..1999) pix#if true //true lub false//prawdziwe miejsca pokrywające się z ekranemconst int GORNY_Y = 1550;const int SRODEK_Y = 1100;const int DOLNY_Y = 500;const int LEWY_X = 470; const int SRODEK_X = 1270; const int PRAWY_X = 1999;#else// rozszerzenie aby wykorzystać maksymalnie pole odczytuconst int GORNY_Y = 1900;const int SRODEK_Y = 1000;const int DOLNY_Y = 300; //500;const int LEWY_X = 100; const int SRODEK_X = 1300; const int PRAWY_X = 1900;#endifprivate Vector2Int[] ind = {new Vector2Int(LEWY_X, GORNY_Y), //0 lewa góranew Vector2Int(SRODEK_X, GORNY_Y), //1 środkowa góranew Vector2Int(PRAWY_X, GORNY_Y), //2 prawa góranew Vector2Int(LEWY_X, SRODEK_Y), //3 lewy środeknew Vector2Int(SRODEK_X, SRODEK_Y), //4 środkowy środeknew Vector2Int(PRAWY_X, SRODEK_Y), //5 prawy środeknew Vector2Int(LEWY_X, DOLNY_Y), //6 lewy dółnew Vector2Int(SRODEK_X, DOLNY_Y), //7 środkowy dółnew Vector2Int(PRAWY_X, DOLNY_Y), //8 prawy dół};private void Start(){m_xrDisplay = OVRManager.GetCurrentDisplaySubsystem();// Inicjalizacja bufora dla punktówm_pointsBuffer = new ComputeBuffer(BufferSize * BufferSize, sizeof(float) );// Przypisanie bufora do Compute ShaderaCompShader.SetBuffer(0, "_PointsBuffer", m_pointsBuffer);}private void Update(){uint id = 0;// Używamy modulo, aby sprawdzić, czy przyszedł czas na wykonanie akcji. Próba bedzie podejmowana tylko w jednej klatce (max 2) a następna za kolejny interval// Tak więc opóźnione wywołanie nie wykona się i zostanie ominięte do następnego okienka// if (Time.time % interval < Time.deltaTime) // to nie jest doskonałe{if (Utils.GetEnvironmentDepthTextureId(ref id) && m_xrDisplay != null && m_xrDisplay.running){var rt = m_xrDisplay.GetRenderTexture(id);if (rt != null){// Uruchomienie Compute Shaderavar kernelID = CompShader.FindKernel("CSMain");CompShader.SetTexture(kernelID, "_DepthMap", rt /*DepthMap*/); //rs mozna tez od razu w shaderze czytac z tej textury bo globalnaCompShader.Dispatch(kernelID, BufferSize / 8, BufferSize / 8, 1);// Odczytanie danych z buforafloat[] points = new float[BufferSize * BufferSize];m_pointsBuffer.GetData(points);//2000 * 1200 + 1250 // pi * drzwi = srodek. 2000 to szer tekstury głębi. Druga liczba to pion a trzecia to poziomfor (int i = 0; i < myDepthTextArray.Length; i++){float depth = points[ind[i].y * 2000 + ind[i].x]; // 2000 to szer tekstury głębi. y to pion od dolu a x to poziom od lewejdepth = Mathf.Clamp(depth, 0.01f, 8.0f);// myDepthTextArray[i].text = $"{depth,4:0.00}\nx={ind[i].x} y={ind[i].y}";myDepthTextArray[i].text = $"{depth,4:0.00}\n";}// Przetworzenie otrzymanych punktów (przykładowe działanie)//foreach (var point in points){//Debug.Log("Point: " + point);}}}}}private void OnDestroy(){// Zwolnienie buforaif (m_pointsBuffer != null){m_pointsBuffer.Release();m_pointsBuffer = null;}}}
Quick Links
- Horizon Developer Support
- Quest User Forums
- Troubleshooting Forum for problems with a game or app
- Quest Support for problems with your device
Other Meta Support
Related Content
- 1 year ago
- 2 months ago
- 9 months ago
- 11 months ago