oculus-samples / Unity-DepthAPI

Examples of using Depth API for real-time, dynamic occlusions
Other
192 stars 24 forks source link

Save depth texture as image #38

Closed Ericcsr closed 4 months ago

Ericcsr commented 5 months ago

I was trying to save depth texture obtained from DepthTextureProvider as jpg images. Here is what I did:

  1. RenderTexture.active = depthTexture.
  2. Create a Texture2D and call ReadPixels with Rect.
  3. Save image via EncodeToJPG and WriteAllBytes.

However, the image I got is either black or white, while I can visualize depth image in Quest.

Here is the script I use: `using UnityEngine; using UnityEngine.UI; using Meta.XR.Depth; using TMPro; using UnityEditor; using System.IO;

namespace SolerSoft.Customization { ///

/// Renders a Meta depth map into Unity UI /// public class RenderDepthMap : MonoBehaviour { // #region Constants // private static readonly int VirtualDepthTextureID = Shader.PropertyToID("_CameraDepthTexture"); // #endregion // Constants // Define some variables for program

region Private Variables

    private int counter = 0;
    #endregion

    #region Unity Inspector Variables
    [SerializeField]
    [Tooltip("The RawImage where the physical depth map will be displayed.")]
    private RawImage m_physicalDepthImage;

    // [SerializeField]
    // [Tooltip("The RawImage where the virtual depth map will be displayed.")]
    // private RawImage m_virtualDepthImage;

    [SerializeField]
    [Tooltip("The depth texture provider.")]
    private EnvironmentDepthTextureProvider m_depthTextureProvider;
    #endregion // Unity Inspector Variables

    #region Private Methods
    /// <summary>
    /// Attempts to get any unassigned components.
    /// </summary>
    /// <returns>
    /// <c>true</c> if all components were satisfied; otherwise <c>false</c>.
    /// </returns>
    private bool TryGetComponents()
    {
        if (m_depthTextureProvider == null) { m_depthTextureProvider = GetComponent<EnvironmentDepthTextureProvider>(); }

        // All satisfied?
        //return m_physicalDepthImage != null && m_virtualDepthImage != null && m_missingDepthText != null && m_depthTextureProvider != null;
        return m_physicalDepthImage != null && m_depthTextureProvider != null;
    }

    /// <summary>
    /// Attempts to show the depth textures.
    /// </summary>
    /// <returns>
    /// <c>true</c> if the textures were shown; otherwise <c>false</c>.
    /// </returns>
    private bool TryShowTextures()
    {
        // Attempt to get the global depth texture
        // This should be a image, get a image and send via redis?
        var physicalDepthTex = Shader.GetGlobalTexture(EnvironmentDepthTextureProvider.DepthTextureID);
        if (physicalDepthTex != null)
        {
            m_physicalDepthImage.enabled = true;
            m_physicalDepthImage.texture = physicalDepthTex;

            RenderTexture.active = (RenderTexture)physicalDepthTex;
            Texture2D copyed = new Texture2D(physicalDepthTex.width, physicalDepthTex.height);
            copyed.ReadPixels(new Rect(0, 0, physicalDepthTex.width, physicalDepthTex.height), 0, 0);
            copyed.Apply();
            RenderTexture.active = null;
            // Save the texture to a file
            string path = "DepthMap"+ counter+".png";
            counter++;
            byte[] bytes = copyed.EncodeToPNG();
            File.WriteAllBytes(path, bytes);

            // Is it possible to save raw texture data to a file?
            // Save the texture to a file

            return true;
        }
        else
        {
            m_physicalDepthImage.enabled = false;
            return false;
        }
    }

    #endregion // Private Methods

    #region Unity Message Handlers
    /// <summary>
    /// Start is called before the first frame update
    /// </summary>
    protected void Start()
    {
        if (!TryGetComponents())
        {
            Debug.LogError("Missing components, disabling.");
            enabled = false;
        }
    }

    /// <summary>
    /// Update is called once per frame
    /// </summary>
    protected void Update()
    {
        // Attempt to show the render textures
        TryShowTextures();
    }
    #endregion // Unity Message Handlers
}

}`

TudorJude commented 5 months ago

Hey,

You should be able to do this, yes. I've never done this myself. You could try to get the texture directly from xrDisplay, like we do it in DepthTextureProvider. There's a TryDepthTexture function there that does this. As far as writing it to disk, this doesn't seem relevant to this API, specifically, though. I'll leave this thread open, for now, in case someone else wants to chime in.

Ericcsr commented 5 months ago

I can get the depth map and save it locally now, the main issue I encountered is setting RenderTexture.active = DepthTexture will not work on VR. My solution uses a compute shader from: https://github.com/Orinion/RaycastTest/tree/main to save all the depth values I needed locally.

AplusX commented 4 months ago

I can get the depth map and save it locally now, the main issue I encountered is setting RenderTexture.active = DepthTexture will not work on VR. My solution uses a compute shader from: https://github.com/Orinion/RaycastTest/tree/main to save all the depth values I needed locally.

Hi! Recently, I also wanna obtain depth maps from Quest 3. Could you share the valuable codes? Thank you very much!

TudorJude commented 4 months ago

Closing due to inactivity.