To detect objects in my project, I create a “picking camera” that renders the vertex colors of those objects to a 1x1 framebuffer. Since there exist several different object types, I’ve associated each type with a different alpha value. I could have chosen a different color channel for this purpose and ignored the alpha component, but that would limit the number of available IDs for the objects themselves.
Hence the need to be able to retrieve the correct alpha value of the rendered vertex color.
There are two ways I’ve tried to get the rendered color; one involves a TexturePeeker while the other uses a PNMImage. The former no longer works for me since Panda 1.9.0 and later, so I replaced it with the latter, but that one seems to require an inefficient framebuffer setup (at least on my laptop).
(The following quotes are from this post.)
Even adding that made no difference for the TexturePeeker method.
That may be obvious to you, but I have no intimate knowledge of framebuffers so I’ll just take your word for it. Then again, the buffer I use is just a single pixel, so how much of an impact can it have? I wanted to use setFloatColor(True) to have more object IDs available, and on my laptop I need this call for the PNMImage method to work.
Tried it, didn’t help when using either a TexturePeeker or a PNMImage.
Maybe I’m doing other things wrong, so I will give you a code sample for both approaches that I have tried.
Let’s start with the working method, which makes use of a PNMImage and the unorthodox framebuffer setup:
from panda3d.core import *
from direct.showbase.ShowBase import ShowBase
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self._pixel_color = VBase4()
self._tex = Texture("picking_texture")
self._img = PNMImage(1, 1)
props = FrameBufferProperties()
if False:
props.set_rgba_bits(8, 8, 8, 8)
else:
props.set_float_color(True) # only needed when run on laptop
props.set_alpha_bits(32)
# props.set_depth_bits(32)
self._buffer = bfr = self.win.make_texture_buffer("picking_buffer",
1, 1,
self._tex,
to_ram=True,
fbp=props)
bfr.set_clear_color(VBase4(1., 128./255., 200./255, 100./255))
bfr.set_clear_color_active(True)
self._picking_cam = self.make_camera(bfr)
self.task_mgr.add(self.__get_pixel_under_mouse, "get_pixel_under_mouse", sort=0)
def __get_pixel_under_mouse(self, task):
self._tex.store(self._img)
self._pixel_color = self._img.get_xel_a(0, 0)
print "pixel color:", self._pixel_color
return task.cont
app = MyApp()
app.run()
The value stored in self._pixel_color should be the background color (1., 128./255., 200./255, 100./255). With the above code, that is what I’m getting, so that’s what I’m currently using.
Strangely, on my desktop PC I don’t need the set_float_color(True) call, but I do on my laptop, or the alpha value is zero.
With props.set_rgba_bits(8, 8, 8, 8 ), however, the alpha value is always zero.
The second code sample makes use of a TexturePeeker, which I cannot get to work no matter what I try:
from panda3d.core import *
from direct.showbase.ShowBase import ShowBase
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self._pixel_color = VBase4()
self._tex = Texture("picking_texture")
self._tex_peeker = None
props = FrameBufferProperties()
props.set_rgba_bits(8, 8, 8, 8)
self._buffer = bfr = self.win.make_texture_buffer("picking_buffer",
1, 1,
self._tex,
to_ram=True,
fbp=props)
bfr.set_clear_color(VBase4(1., 128./255., 200./255, 100./255))
bfr.set_clear_color_active(True)
self._picking_cam = self.make_camera(bfr)
self.task_mgr.add(self.__get_pixel_under_mouse, "get_pixel_under_mouse", sort=0)
def __get_pixel_under_mouse(self, task):
if not self._tex_peeker:
self._tex_peeker = self._tex.peek()
return task.cont
self._tex_peeker.lookup(self._pixel_color, .5, .5)
print "pixel color:", self._pixel_color # alpha is always 1.
return task.cont
app = MyApp()
app.run()
When I run the above code (either on desktop or laptop), the alpha component is always one.