Above is my button image in Panda3D, below in an image editor:
You can notice that the edges of the image get feathered in Panda.
After some trial and error, I noticed that if I disable multisampling in my program, the problem is fixed.
So If I just comment out these lines the problem is gone:
But I want multisampling, I guess just not at the GUI.
I tried disabling it with the two below ways, but neither seems to work, or at least neither works the same way as not enabling multisampling to begin with.
What happens if you manually load your GUI-textures (i.e. by calling something like “loader.loadTexture”), and in doing so pass in a second parameter of “minfilter = SamplerState.FTNearest”? (First importing “SamplerState”, of course.)
Something like this:
# In your importations:
from panda3d.core import SamplerState
texture = myShowBaseObj.loader.loadTexture(
minfilter = SamplerState.FTNearest
button = DirectButton(frameTexture = texture, <other parameters here>)
 In fact, the use of SamplerState might not be required when loading a texture manually–I think that “Nearest” might be the default for that. So it might be worth first trying manual loading without the “SamplerState”, and seeing whether that works, before trying the version with the “SamplerState”.
Well, if you are using CommonFilters already (which uses FilterManager under the hood), in fact, it is a waste of memory to have multisampling enabled on the main window at all, especially if you don’t want your GUI to be multisampled.
The only issue is that CommonFilters does not currently allow overriding the framebuffer properties requested from its FilterManager. Hmm. For now, a solution would be to copy-paste CommonFilters.py into your game’s source code and change the fbprops that are passed to renderSceneInto to include multisample bits. I will look into making this possible for the next Panda release.
I’m not currently using CommonFIlters, but was planning to to allow outline rendering for 3d models in my 3d viewer.
I think that’s only one issue with your proposal. From the looks of it if I render to my own buffer than I need to take care of host of other things, like managing resolution changes after window resizing, change of aspect ratio of the window, etc, etc.
Sounds like a better fix for Panda would be to just allow to disable multisampling for GUI, otherwise pixel2d node does not do what it claims: " It can be used if pixel-perfect layout of UI elements is desired." Built-in Global Variables — Panda3D Manual
Currently it seems like you need to jump through a bunch of hoops to get it to work as claimed, if you want something as basic as multisampling in your program alongside pixel2d.
Nope, this is all automated by FilterManager, it’s just set-up and forget, that’s the whole point of that class.
This is outside our control! Panda is already doing all it can to honour your setAntialias request, but the driver is stubbornly choosing to enable antialiasing on everything instead. All Panda can do for you is automate setting up a buffer for render-to-texture, which most games will end up having to do anyway, and this is provided by FilterManager.
I’m not sure if we’ve tested everything to come to this conclusion.
What would be the simplest test to identify this?
As a reminder, right now I’m enabling multisampling globally via the PRC settings, and then trying to disable it on one node (pixel2d).
If I enable antialias only on a child node of render, then parent another node to render, would this mean that the driver works correctly if the second node attached to render has antialiasing disabled and only the first child node has it enabled?
In OpenGL, it takes two things to enable multisample antialiasing: first, the window framebuffer needs to be allocated with the desired number of samples (which is what the PRC settings do), and secondly, you need to enable the multisample antialiasing modes (setAntialias) to take advantage of this.
The thing is, Panda doesn’t do the second automatically at all. On my NVIDIA card, I get multisample antialiasing just from enabling a multisample framebuffer, without even requesting it with an antialias mode. I verified using apitrace that Panda is indeed making glEnable(GL_MULTISAMPLE) and glDisable(GL_MULTISAMPLE) calls before rendering objects with the appropriate antialias mode set.
I tried playing with this setting in the NVIDIA Control Panel:
In the next Panda release (1.10.13), I am adding a setMSAA method to CommonFilters that enables multisample antialiasing on the offscreen buffer. This is intended as a foolproof “just works” way to set up MSAA for your main scene only. It requires leaving framebuffer-multisample off, since then you’re applying it to the main window as well, which you don’t want.
I use my own code for generating geoms from images for my GUI (I see no reason why Panda by default expects an egg or other 3d file for UI images), and also for my 3d grid. And for these, magfilter = panda3d.core.SamplerState.FT_nearest makes sense for their textures, otherwise gui graphics get feathered at their native resolution, and the grid lines also get feathered. But magfilter = panda3d.core.SamplerState.FT_nearest seems to mess up any antialiasing.
Antialiasing applies to geometry edges, not to texture alpha cutout edges. This is because the texture lookup is done per fragment, and not per sample.
There are modes that enable multisampling for transparency. These will convert an alpha value sampled from the texture into a sample mask that will be combined with the normal geometry-edge sample mask:
The problem with this (you’ll note neither mode does anything here) is that you’ll never sample an alpha value other than 0 or 1 if you don’t have any kind of texture filtering, so each fragment is either in or out. With linear sampling, you would definitely need a higher-resolution texture. Though I would suggest picking a black-white greyscale texture and setting its format to F_alpha so that the colour channel is entirely white, so you don’t get odd blending at the corners.
What you would really need to make this work with multisampling at any zoom level is a shader that calculates the appropriate sample mask based on multiple texture lookups, one for each sample. There is also an OpenGL extension that makes the fragment shader be run for every sample instead of for every fragment. Panda doesn’t currently implement it, but it would be easy to add, so I would be happy to entertain a feature request for this. It is inefficient, though, at that point it would be far more efficient to just generate your grid as geometry instead of a texture.
This is an aside, but I daresay that it’s because even UI widgets are technically 3D objects in Panda. Indeed, one can embed them into the 3D world if one desires. (Although I think that doing so complicates interacting with them, as the default interaction system is built around aspect2d, if I recall correctly.)
That said, depending on what you’re doing, you don’t necessarily need to construct this 3D geometry yourself. You can specify either the “frameTexture” keyword-argument or the “image” keyword-argument, providing them with either textures or paths to images (or tuples thereof–at least in the case of “frameTexture”; I’m not sure offhand about “image”).
Both of those approaches have their own bits of trickiness to get used to, but (again depending on your specific purposes) they may allow you to apply images to your widgets without constructing geometry yourself.