Hi,
I just recently started working with Panda3d to create some augmented reality application where I want to show rendered objects on top of real camera images and to make it look real I need to also add shadows.
Everything works nice when I render to a window. However, when I render to a texture the resulting image shows two strange things. First: the dark areas become transparent and second: the shadow on the ground plane disappears as shown in the following images
In window (everything works fine):
From texture (dark turns into transparent):
From texture on top of black background (shadows on floor are missing):
Here is the code that I use. I added a bool flag offscreen
to easily compare both results.
import numpy as np
from direct.showbase.ShowBase import ShowBase
from pandac.PandaModules import loadPrcFileData
from panda3d.core import AmbientLight, DirectionalLight
from panda3d.core import PandaNode, Texture, GraphicsOutput, CardMaker
import cv2
loadPrcFileData("", "win-size 1024 768")
offscreen = True
class MyApp(ShowBase):
def __init__(self):
if offscreen:
ShowBase.__init__(self, windowType='offscreen')
else:
ShowBase.__init__(self)
self.texture = Texture()
self.win.addRenderTexture(tex=self.texture, mode=GraphicsOutput.RTM_copy_ram, bitplane=GraphicsOutput.RTP_color)
def setup_scene(self):
self.render.getChildren().detach()
self.camera.reparentTo(self.render)
# self.setBackgroundColor(0,0,0,1)
# place panda model
self.panda = self.loader.loadModel("models/panda")
self.panda.reparentTo(self.render)
self.panda.setPos(0, 50, -10)
# create floor
cm = CardMaker('')
cm.setFrame(-2, 2, -2, 2)
self.floor = self.render.attachNewNode(PandaNode("floor"))
for y in range(12):
for x in range(12):
nn = self.floor.attachNewNode(cm.generate())
nn.setP(-90)
nn.setPos((x - 6) * 4, (y - 6) * 4, 0)
self.floor.setPos(0, 50, -10)
self.floor.setColor((1,1,1,1))
self.floor.flattenStrong()
# add directional light and cast shadows
self.dlight = DirectionalLight('dlight')
l = 1.0
self.dlight.setColor((l, l, l, 1.0))
self.dlnp = self.render.attachNewNode(self.dlight)
self.dlnp.setPos(-10, 50, 10)
self.dlnp.lookAt(self.panda)
self.render.setLight(self.dlnp)
#self.dlight.showFrustum()
self.dlnp.node().getLens().setFilmSize(100, 100)
self.dlnp.node().getLens().setNearFar(1, 50)
self.dlight.setShadowCaster(True, 1024, 1024)
self.render.setShaderAuto()
def get_camera_image(self):
self.graphicsEngine.renderFrame()
data = self.texture.getRamImageAs('RGBA')
image = np.frombuffer(data, np.uint8)
image.shape = (self.texture.getYSize(), self.texture.getXSize(), self.texture.getNumComponents())
image = np.flipud(image)
return image
def main():
app = MyApp()
app.setup_scene()
if not offscreen:
app.run()
else:
image = app.get_camera_image()
cv2.imwrite('/tmp/scene.png', image)
if __name__ == '__main__':
main()
I also found this post https://discourse.panda3d.org/t/shadows-in-showbase-and-offscreen-buffer/13746 from this forum but unfortunately the images are no longer available and the solution didn’t seem to help.
Also seeing the pictures side by side I noticed that I forgot to switch blue and red channels for OpenCV.