Offscreen Rendering using Panda3D
In this post, we will explore a 3D rendering and game development library named Panda3D. One advantage of Panda3D is that the license is quite permissive (BSD-3-Clause) so that it can be used even for commercial applications without worrying about releasing our own code.
There may be a situation where we don’t need to render the scene onto a window and render it into an image in memory instead. Panda3D supports this use case, but I found that there is no complete example that can be used as a reference. Therefore, I would like share what I found while trying to perform offscreen rendering using Panda3D.
We will assume that we are developing with Python3. Install Panda3D by running the command below:
pip install panda3d
Here is an example of the basic steps required to draw to an offscreen buffer.
IMG_W = 640 IMG_H = 480 # Create offscreen window so that no window will be opened base = ShowBase(fStartDirect=True, windowType='offscreen') # Create frame buffer properties fb_prop = FrameBufferProperties() fb_prop.setRgbColor(True) # Only render RGB with 8 bit for each channel, no alpha channel fb_prop.setRgbaBits(8, 8, 8, 0) fb_prop.setDepthBits(24) # Create window properties win_prop = WindowProperties.size(IMG_W, IMG_H) # Create window (offscreen) window = base.graphicsEngine.makeOutput(base.pipe, "cameraview", 0, fb_prop, win_prop, GraphicsPipe.BFRefuseWindow) # Create display region # This is the actual region used where the image will be rendered disp_region = window.makeDisplayRegion() … … … # Load the model, add lighting, etc, # Create a camera object, etc … … … # Assign a camera for the region disp_region.setCamera(cam_obj) # Create the texture where the frame will be rendered # This is the RGB/RGBA buffer which stores the rendered data bgr_tex = Texture() window.addRenderTexture(bgr_tex, GraphicsOutput.RTMCopyRam, GraphicsOutput.RTPColor) # Now we can render the frame manually base.graphicsEngine.renderFrame() # Get the frame data as numpy array bgr_img = np.frombuffer(bgr_tex.getRamImage(), dtype=np.uint8) bgr_img.shape = (bgr_tex.getYSize(), bgr_tex.getXSize(), bgr_tex.getNumComponents()) # Do as you wish with the frame … … …