I have a need for a high-range depth buffer image with 16 or 32-bit values.
The two formats I can use that Godot will import include GL_R32F and GL_RG32F.
I imported an EXR file (with z-buffer attached, according to Blender) but it only shows 6 bytes per pixel when I examine it when loaded into Godot, which is enough for the (16-bit) HDR RGB but not an alpha OR depth pass.
So...how do I generate and import a z-depth pass? The only HDR range tools I have right now are Blender. Maybe I can write a script to extract what I need but then I need to know what to write all the headers and crap that I frankly don't want to get involved with.
Basically I need to import a file as an array of data that will never be used for display (but will be used to dynamically hide 3D objects as they cross the display of a pre-rendered 2D background)
edit: Ive decided that the only way this will work is to generate my own custom data file and import that in Godot into an array, but that sounds kind of low-level and I have no idea how complicated that can get. I'm not a power-programmer.

  • xyz replied to this.

    Have you clicked on the file and gone to the import tab next to the tree?
    I think you can disable HDR compression.
    From the docs:

    Compress > HDR Compression¶
    Note

    This option only has an effect on textures that are imported as HDR formats in Godot (.hdr and .exr files).

    If set to Disabled, never uses VRAM compression for HDR textures, regardless of whether they're opaque or transparent. Instead, the texture is converted to RGBE9995 (9-bits per channel + 5-bit exponent = 32 bits per pixel) to reduce memory usage compared to a half-float or single-precision float image format.

    If set to Opaque Only (default), only uses VRAM compression for opaque HDR textures. This is due to a limitation of HDR formats, as there is no VRAM-compressed HDR format that supports transparency at the same time.

    xyz
    Script.
    I am unsure of both how to generate the depth file and how I need to read it in Godot into an array of floats. So far the only format I can export a depth pass in floats is in an EXR file. Ive managed to save a EXR that appears to be only 16 bit depth data per pixel but it still has the exr container wrapping it and I don't know how to read that into Godot as non-image data. So maybe write a python script in Blender that extracts and serializes just the data itself into a simple array of values stored in binary. Reading the file in Godot seems straight-forward then, perhaps into a PooledByteArray? I haven't tried
    anything on the Godot-side yet.

    • xyz replied to this.

      Shadowphile Are you sure you need 32 bit float precision? Maybe you can get away with 16 bit grayscale png.

      A viable approach that lets you fully control things would be to use pyFreeImage in a standalone Python script to inspect the image saved from Blender and then write the data to whatever format (image or custom data) is most convenient for you to handle within Godot.

        xyz
        I've been assuming that I want floats since depth values can cover such an extreme range but maybe I can find a way to make the integer values of a PNG work for me.

        xyz
        Well I managed to finally get something to work without any extra processing.
        Blender Compositor has a Depth pass output. I tried to use it before but apparently didn't know what I was doing.
        Anyway, it saves as an EXR so it's a 'picture' of the depth in world coordinates (ie meters in my Blender world).
        I had problems trying to import EXR files in Godot, kept getting corrupted-file errors but I think that was how I chose to format my save EXR file.
        Anyway, the values are capped at about 216 (meters) so i think I'm ok with half-floats!

        For those interested, here is my exact work-flow: (Blender 3.6 and Godot 3.5)
        In Blender, enable Compositor in the Post-Processing Pipeline in Output properties.
        In ViewLayers tab, enable Passes/Data/Include/Z. Disable everything else.
        In the Compositor, connect the RenderLayers Depth output to an Output Node (File Output). Put in the proper path and filename pointing to a resource folder in Godot. Make sure it is selected for the next step!
        In the Compositor sidebar in the Node tab, set the Properties to:
        OpenEXR, RGB, 'half' or 'full' Color Depth (I've only tested 'half'), Codec to something lossless; I've only tested 'None' or 'ZIP' since
        get_pixel() from an Image won't work if it is compressed, but it probably needs more testing.
        Set the Color Management to Override, and set Linear. Non-Color will NOT import into Godot.
        Render and the Save File node will automatically save the depth file.
        Godot:
        If necessary, reimport the saved file as an Import type.

        My personal project is casting a panoramic image onto a sphere, allowing the camera to look around. The depthmap saved is a lower-resolution image with the same aspect ratio as the main image. You can lower or increase the resolution as you need, it will always work.
        Here are some sample codes to get the depth under the cursor of a panoramic image. These just try to show the basics; there are other things under the hood I don't need to share.

        func LoadDM():   #loads the generated depthmap
        	DIMG = g.GetPreload["DP0101"] as Image   #DP0101 is a PreLoaded resource.
        	DIMG.lock()
        	DepthMapW = DIMG.get_width()  #these are used elsewhere
        	DepthMapH = DIMG.get_height()
               
        func GetImgPixelDepth():
                # make sure the mouse is within the display window
        	var xin = g.mouse_x < g.Hrez-1 and g.mouse_x >= 0
        	var yin = g.mouse_y < g.Vrez-1 and g.mouse_y >= 0
        	if xin and yin:
                       # g.mouseaz and the other are from a routine elsewhere that detects the azimuth and elevation of the mouse cursor projected 
                               onto the panoramic background
        		var pixX = int(g.mouseaz*DepthMapW)
        		var pixY = int(g.mouseel*DepthMapH)
        		var depth = DIMG.get_pixel(pixX,pixY)
        		return depth
        	else:
        		return -1.0
        • xyz replied to this.

          Shadowphile Great! Btw range itself in an absolute sense is not really a limiting factor hare as you can always scale it. What's important is the precision, which boils down only to number of bits per pixel.

          a month later

          agreed, precision matters whether float or integer.
          I have some bad news though since I made this post.
          Godot 3.5 seems to have a bug with EXR files because they run fine in the editor but I always get an import error on those when I try to run an exported game.
          So I switched to 16-bit PNGS, which should provide enough resolution, except I discovered Godot does not recognize 16-bit PNGS.
          So now I'm reduced to a depth resolution of 256...unless I find a way to manually read a PNG file into a 2D array of values, ugh...
          We need more high-resolution image formats!