Code working with pandagl but not p3tinydisplay

Hi,

I need to render rgb and depth frames on a server, and it seems I need to use p3tinydisplay as engine. My code works fine when using pandagl, but strangely only produces binary (black/white) images using p3tinydisplay. Specifically, the depth is missing and only the silhouette is rendered. Any ideas how to fix this? Code below, simply comment the loadPrcFileData :slight_smile:

I am running Panda1.9.2 on Ubuntu 14.04 with latest nvidia drivers on a GTX 980.

Thanks!

import numpy
import os
import scipy.misc

from panda3d.core import loadPrcFileData
from pandac.PandaModules import GraphicsPipe, PerspectiveLens, FrameBufferProperties, TransformState, \
    RenderState, GraphicsOutput, Texture, VBase4, WindowProperties, TransparencyAttrib
from direct.showbase.ShowBase import ShowBase


class RGBDRenderer(ShowBase):
    def __init__(self, modelFile):
        loadPrcFileData("", "audio-library-name null")
        loadPrcFileData("", "load-display pandagl")
        # loadPrcFileData("", "load-display p3tinydisplay")
        loadPrcFileData("", "window-type offscreen")
        loadPrcFileData("", "sync-video 0")
        loadPrcFileData("", "win-size {} {}".format(128, 128))
        ShowBase.__init__(self)
        self.disableMouse()
        self.taskMgr.remove('igLoop')

        # setup buffers
        winprops = WindowProperties()
        winprops.setTitle("My Window")
        winprops.setSize(128, 128)
        props = FrameBufferProperties()
        props.setRgbColor(1)
        props.setColorBits(1)
        props.setAlphaBits(1)
        props.setDepthBits(1)
        props.setRgbaBits(8, 8, 8, 8)
        self.displayRegion = self.graphicsEngine.makeOutput(
            self.pipe, "depth buffer", 1,
            props, winprops,
            GraphicsPipe.BFSizeTrackHost | GraphicsPipe.BFCanBindEvery |
            GraphicsPipe.BFRttCumulative | GraphicsPipe.BFRefuseWindow,
            self.win.getGsg(), self.win)
        self.buffer_rgb = self.graphicsEngine.makeOutput(
            self.pipe, "rgb buffer", 2,
            props, winprops,
            GraphicsPipe.BFSizeTrackHost | GraphicsPipe.BFCanBindEvery |
            GraphicsPipe.BFRttCumulative | GraphicsPipe.BFRefuseWindow,
            self.win.getGsg(), self.win)
        if self.displayRegion is None or self.buffer_rgb is None:
            raise Exception("Failed to create buffers")
        self.graphicsEngine.renderFrame()

        # create texture for offscreen rendering
        self.texDepth = Texture()
        self.texRgb = Texture()
        self.texDepth.setFormat(Texture.FDepthStencil)
        self.texRgb.setFormat(Texture.FRgb)
        self.displayRegion.addRenderTexture(self.texDepth,
                                            GraphicsOutput.RTMBindOrCopy,
                                            GraphicsOutput.RTPDepthStencil)
        self.buffer_rgb.addRenderTexture(self.texRgb,
                                         GraphicsOutput.RTMBindOrCopy,
                                         GraphicsOutput.RTPColor)
        assert self.texDepth == self.displayRegion.getTexture(), "Texture wasn't created properly."
        assert self.texRgb == self.buffer_rgb.getTexture(), "Texture wasn't created properly."

        # create cameras
        self.perspectiveLens = PerspectiveLens()
        self.perspectiveLens.setNear(0.1)
        self.perspectiveLens.setFar(10)
        self.depth_cam = self.makeCamera(self.displayRegion,
                                         lens=self.perspectiveLens, scene=self.render)
        self.rgb_cam = self.makeCamera(self.buffer_rgb,
                                       lens=self.perspectiveLens, scene=self.render)
        self.depth_cam.setPos(0, 0, 0)
        self.rgb_cam.setPos(0, 0, 0)
        self.displayRegion.setSort(1)
        self.buffer_rgb.setSort(2)
        self.buffer_rgb.setClearColorActive(True)
        self.buffer_rgb.setClearColor(VBase4(0, 0, 0, 1))
        self.win.setSort(3)
        self.graphicsEngine.renderFrame()

        self.texture_card = self.displayRegion.getTextureCard()
        self.texture_card.reparentTo(self.render2d)
        self.displayRegion = self.win.makeDisplayRegion()
        self.displayRegion.setCamera(self.rgb_cam)
        self.graphicsEngine.renderFrame()

        if not os.path.isfile(modelFile):
            raise Exception("Model-Egg File not found: " + str(modelFile))
        objectModel = self.loader.loadModel(modelFile)
        objectModel.setTransparency(TransparencyAttrib.MAlpha)
        objectModel.reparentTo(self.render)
        objectModel.setPos(0, 0, 0)
        objectModel.show()
        self.objectModel = objectModel
        self.graphicsEngine.renderFrame()

        # make sure to setup pipeline
        self.setPose(0, 1, 2)
        self.renderDepth()

    def setPose(self, heading=0, pitch=0, roll=0):
        self.objectModel.setHpr(heading, pitch, roll)
        modelMin, modelMax = self.objectModel.getTightBounds()
        dim = modelMax - modelMin
        if dim.getX() >= dim.getZ():
            dist = (dim.getX() / 2.0) / numpy.tan(numpy.radians(self.rgb_cam.node().getLens().getFov()[0] / 2.0))
        else:
            dist = (dim.getZ() / 2.0) / numpy.tan(numpy.radians(self.rgb_cam.node().getLens().getFov()[1] / 2.0))
        cd = dist + dim.getY()
        near = cd - dim.getY()
        far = cd + dim.getY()
        self.rgb_cam.node().getLens().setNear(near)
        self.rgb_cam.node().getLens().setFar(far)
        self.depth_cam.node().getLens().setNear(near)
        self.depth_cam.node().getLens().setFar(far)
        self.rgb_cam.setY(-cd)
        self.depth_cam.setY(-cd)
        self.graphicsEngine.renderFrame()

    def renderRGB(self):
        self.texture_card.setTexture(self.texRgb, 1)
        TransformState.garbageCollect()
        RenderState.garbageCollect()
        self.graphicsEngine.renderFrame()
        tex = self.displayRegion.getScreenshot()
        buf = tex.getRamImage().getData()
        col = numpy.flipud(numpy.fromstring(buf, dtype=numpy.uint8).reshape((128, 128, 4)))
        return col[:, :, 0:3]  # RGB from RGB-A

    def renderDepth(self):
        self.texture_card.setTexture(self.texDepth, 1)
        TransformState.garbageCollect()
        RenderState.garbageCollect()
        self.graphicsEngine.renderFrame()
        tex = self.displayRegion.getScreenshot()
        buf = tex.getRamImage().getData()
        dpt = numpy.flipud(numpy.fromstring(buf, dtype=numpy.uint32).reshape((128, 128)))
        return dpt.astype('float32') / (2 ** 32 - 1)


if __name__ == "__main__":
    render = RGBDRenderer('/usr/share/panda3d/samples/bump-mapping/models/icosphere.egg')
    render.setPose(10, 10, 20)
    col = render.renderRGB()
    dpt = render.renderDepth()
    scipy.misc.imshow(col)
    scipy.misc.imshow(dpt)

I’m not sure that p3tinydisplay can even render depth textures. Are you sure you can’t just use a software OpenGL implementation?

Thanks for your replay, that are bad news.
I cannot simply use a software-based OpenGL, because I am using the proprietary nvidia drivers, which do not allow to use the LIBGL_ALWAYS_SOFTWARE flag, for example. Are there other ways to force this?

You can render headless with the accelerated NVIDIA drivers in OpenGL mode, which is what I would recommend - it would give you best performance and gives you access to the widest range of supported features. I happen to have researched this in the past, so I’ve dug up my old notes. You would need to run an X11 server but with no display attached, but some trickery is needed in your Xorg configuration to make this work.

Here is the xorg.conf I used in the past to accomplish this.

Section "ServerLayout"
    Identifier "Layout0"
    Screen 0 "Screen0"
    Option "AutoAddDevices" "false"
EndSection

Section "Monitor"
    Identifier "Monitor0"
    VendorName "Unknown"
    ModelName "Unknown"
    HorizSync 28.0 - 33.0
    VertRefresh 43.0 - 72.0
    Option "DPMS"
EndSection

Section "Device"
    Identifier "Device0"
    Driver "nvidia"
    VendorName "NVIDIA Corporation"
    Option "NoLogo" "true"
    Option "UseEDID" "false"
    Option "ConnectedMonitor" "DFP"
EndSection

Section "Screen"
    Identifier "Screen0"
    Device "Device0"
    Monitor "Monitor0"
    DefaultDepth 24
    SubSection "Display"
        Depth 24
    EndSubSection
EndSection

This basically tricks the NVIDIA driver by disabling the mechanism by which it checks whether a display is connected to the output connector.

To run a program from externally (eg. an ssh shell) you would have to set DISPLAY environment variable to :0.0, eg.

DISPLAY=:0.0 python test.py
1 Like

Thanks for the help. I finally made it to run on the headless server, but there are a few pitfalls on Ubuntu 16.04. So here are the details if anyone has the same troubles:

  • Copy the xorg.conf to /etc/X11/
  • restart the lightdm server:
systemctl restart lightdm
  • check in /var/log/Xorg.0.log if the configuration is loaded correctly
  • then I got the error “invalid mit-magic-cookie-1 key”. so one has to check the Xauthority:
systemctl status

and search for

lightdm.service

which has a parameter

-auth
  • run the application by passing the environment variables:
DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 sudo python test.py

(for me the Xorg is started as root)

hi, rdb, I encountered the same question on headless cluster. This solution looks great, but I don’t have the admin permission. I also tried to launch showbase in a EGL context, but still failed to open window. Could you recommend other methods to solve this problem? (Actually, our program will be open-sourced, and we hope everyone can setup the environment and run it on their cluster easily.)

Yes, you can nowadays create a headless context using EGL, by compiling Panda from the master branch without X11 support.
See https://github.com/panda3d/panda3d/issues/557

Thanks , rdb, I make it.! But an error happened to simplepbr in the EGL environment using gles2
as graphicspipe. I try to solve this, and find the makeoutput() function return None, when calling simplepbr.init(). And @Moguri , could you help me with it?

Our pandagles2 back-end isn’t as full-featured yet as our pandagl back-end, and furthermore, simplepbr does not currently support it (though this will change in a future version of Panda).

I highly recommend using pandagl instead of pandagles2. pandagl will be headless when compiling Panda without X11 support.

Ok I will try it, Thanks! rdb, you guys really help me a lot!

:sob: I still get an error “Could not open window”, after I build the master by the following command:

python ./makepanda/makepanda.py --no-gles --no-gles2 --no-x11  --no-dx9 --no-egl --thread 16 --python-incdir ~/anaconda3/envs/test_env/include/ --python-libdir ~/anaconda3/envs/test_env/lib/

and use these prc option

    loadPrcFileData("", "win-size 1200 900")
    loadPrcFileData("", "framebuffer-multisample 1")
    loadPrcFileData("", "multisamples 8")
    loadPrcFileData("", 'bullet-filter-algorithm groups-mask')
    loadPrcFileData("", "audio-library-name null")

    loadPrcFileData("", "load-display pandagl")

And the error message is

pygame 2.0.0 (SDL 2.0.12, python 3.7.0)
Hello from the pygame community. https://www.pygame.org/contribute.html
Known pipe types:
  glxGraphicsPipe
(all display modules loaded.)
:display:x11display(error): Could not open display ":0.0".
:ShowBase(warning): Unable to open 'offscreen' window.
Traceback (most recent call last):
  File "./test_generalization_env.py", line 47, in <module>
    env.reset()
  File "/home/qyli/pg-drive/pg_drive/envs/generalization_racing.py", line 178, in reset
    self.lazy_init()  # it only works the first time when reset() is called to avoid the error when render
  File "/home/qyli/pg-drive/pg_drive/envs/generalization_racing.py", line 59, in lazy_init
    self.bullet_world = BtWorld(self.bt_world_config)
  File "/home/qyli/pg-drive/pg_drive/world/bt_world.py", line 53, in __init__
    super(BtWorld, self).__init__(windowType=mode)
  File "/home/qyli/anaconda3/envs/pg-drive/lib/python3.7/site-packages/direct/showbase/ShowBase.py", line 334, in __init__
    self.openDefaultWindow(startDirect = False, props=props)
  File "/home/qyli/anaconda3/envs/pg-drive/lib/python3.7/site-packages/direct/showbase/ShowBase.py", line 1015, in openDefaultWindow
    self.openMainWindow(*args, **kw)
  File "/home/qyli/anaconda3/envs/pg-drive/lib/python3.7/site-packages/direct/showbase/ShowBase.py", line 1050, in openMainWindow
    self.openWindow(*args, **kw)
  File "/home/qyli/anaconda3/envs/pg-drive/lib/python3.7/site-packages/direct/showbase/ShowBase.py", line 795, in openWindow
    raise Exception('Could not open window.')
Exception: Could not open window.

You’ve not built without X11 support: the fact that it’s showing “glxGraphicsPipe” proves that you have a build of Panda that includes X11.

Also, your makepanda command is incorrect, because it neither contains --everything nor --nothing, and --thread is not a valid option. I suspect you have not compiled Panda3D at all, and you simply have a different installation of Panda3D still active.

I succeed ! thank you (I am careless and install/uninstall the wheel file compiled 2 days before for several times…)

Hi, rdb, it’s me… I am here to ask for your help again and hope it doesn’t bother you. I encounter a problem when using pandagl+no-x11 support.
I got the error message like this:

Known pipe types:
  eglGraphicsPipe
(all display modules loaded.)
:display:gsg:glgsg(warning): Unable to query GL_VENDOR
:display:gsg:glgsg(warning): Unable to query GL_RENDERER
:display:gsg:glgsg(warning): Unable to query GL_VERSION
:display:gsg:glgsg(error): Unable to detect OpenGL version
:display:gsg:glgsg(warning): Unable to query GL_VENDOR
:display:gsg:glgsg(warning): Unable to query GL_RENDERER
:display:gsg:glgsg(warning): Unable to query GL_VERSION
:display:gsg:glgsg(error): Unable to detect OpenGL version
:display:gsg:glgsg(warning): Unable to query GL_VENDOR
:display:gsg:glgsg(warning): Unable to query GL_RENDERER
:display:gsg:glgsg(warning): Unable to query GL_VERSION
:display:gsg:glgsg(error): Unable to detect OpenGL version
:device(warning): /dev/input/event3 is not readable, some features will be unavailable.
:display:gsg:glgsg(warning): Unable to query GL_VENDOR
:display:gsg:glgsg(warning): Unable to query GL_RENDERER
:display:gsg:glgsg(warning): Unable to query GL_VERSION
:display:gsg:glgsg(error): Unable to detect OpenGL version

...repeat for several times...

Assertion failed: n < _blends.size() at line 27 of panda/src/gobj/transformBlendTable.I
Assertion failed: n < _blends.size() at line 27 of panda/src/gobj/transformBlendTable.I
Assertion failed: n < _blends.size() at line 27 of panda/src/gobj/transformBlendTable.I
Assertion failed: n < _blends.size() at line 27 of panda/src/gobj/transformBlendTable.I
Assertion failed: n < _blends.size() at line 27 of panda/src/gobj/transformBlendTable.I
Assertion failed: n < _blends.size() at line 27 of panda/src/gobj/transformBlendTable.I
Assertion failed: n < _blends.size() at line 27 of panda/src/gobj/transformBlendTable.I
Assertion failed: n < _blends.size() at line 27 of panda/src/gobj/transformBlendTable.I

...repeat for several times...

...finally ...
Segmentation fault (core dumped)

In previous GitHub Issue, relevant to this topic,
I find another friend also got these error message on his headless machine (the last post). But I can not find your answer. Could you help me with it? Besides, we would like to know when will you release the 1.11 edition. If it comes soon, we will re-build our project on panda3d-1.11, since I find some useful features in 1.11. Thank you!

Which version of Panda3D did you compile? Did you compile from the master branch?

I don’t know when 1.11 will be finished, but it won’t be in the next few months.

yes, I compiled from the master branch, and the latest commit of the panda source code on my computer is: last commit