I have created an example program that will create another window + camera, render to that window and copy the depth buffer to numpy. It seams to work but please tell me if I did something wrong.
However, the thing that confuses me is that I can set fb_prop.setDepthBits()
to 1, 16 or 24 and it works but the depth_texture is still of shape (width x height x 4) bytes (see print()
in code). Why is that?
Also if I set fb_prop.setDepthBits(32)
it crashes with:
:display(error): Could not get requested FrameBufferProperties; abandoning window.
requested: depth_bits=32 color_bits=24 red_bits=8 green_bits=8 blue_bits=8
got: depth_bits=24 color_bits=24 red_bits=8 green_bits=8 blue_bits=8 accum_bits=64 force_hardware force_software
Code:
from typing import Any
import numpy as np
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from panda3d.core import (
Camera,
FrameBufferProperties,
GraphicsOutput,
GraphicsPipe,
NodePath,
Texture,
WindowProperties,
)
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
# Load the environment model.
self.scene = self.loader.loadModel("environment")
# Reparent the model to render.
self.scene.reparentTo(self.render)
# Apply scale and position transforms on the model.
self.scene.setScale(0.25, 0.25, 0.25)
# Depth task
self.taskMgr.add(self.get_depth, "get_depth")
# Request 8 RGB bits, no alpha bits, and a depth buffer.
fb_prop = FrameBufferProperties()
fb_prop.setRgbColor(True)
fb_prop.setRgbaBits(8, 8, 8, 0)
fb_prop.setDepthBits(1) # <----
# Create a WindowProperties object set to 512x512 size.
win_prop = WindowProperties(size=(512, 512), fixed_size=True)
self.cd_window = self.graphicsEngine.makeOutput(
pipe=self.pipe,
name="My Buffer",
sort=1,
fb_prop=fb_prop,
win_prop=win_prop,
flags=0, # GraphicsPipe.BF_refuse_window,
# gsg=self.win.getGsg(),
# host=self.win,
)
self.cd_region = self.cd_window.makeDisplayRegion()
self.cd_camera = Camera("color_depth_camera")
self.cd_camera_np = NodePath(self.cd_camera)
self.cd_region.setCamera(self.cd_camera_np)
# View render, as seen by the default camera
self.cd_camera_np.reparentTo(self.camera)
# Depth texture
self.depth_texture = Texture()
self.depth_texture.setFormat(Texture.FDepthComponent)
self.cd_window.addRenderTexture(
self.depth_texture, GraphicsOutput.RTMCopyRam, GraphicsOutput.RTPDepth
)
def get_depth(self, task: Task) -> Any:
depth_data = self.depth_texture.getRamImage()
if len(depth_data) == 0:
return Task.cont
size = self.depth_texture.getXSize() * self.depth_texture.getYSize()
print(len(depth_data) / size) # >> 4
depth_image = np.frombuffer(depth_data.get_data(), np.float32)
depth_image.shape = (
self.depth_texture.getYSize(),
self.depth_texture.getXSize(),
1,
)
lens = self.cd_camera.getLens()
world_depth = lens.far * lens.near / (lens.far - (lens.far - lens.near) * depth_image)
print(world_depth.min(), world_depth.max())
return Task.cont
app = MyApp()
app.run()