The proper way to tint a texture

Hi everybody,

I’ve been struggling with some transparency issues and I was wondering if anybody could shed some light on the way forward.

The code is reported below, and it does pretty much what you’d expect: it displayes the image “aTexture.png”, inclusive of its transparencies. The PNG in question is actually a 256x256 image done with Inkscape: a white frame 8 pixels thick with rounded corners, encasing an empty, black area. Notice that the image is not just b&w: the borders are antialiased as the shape is rasterized before it is saved into a PNG file.

The question is: what is the proper way to give a color to this otherwise white frame on the default grey of Panda’s background? I tried with the two commented lines at the end of the code: the result with each is identical and is largely correct, but has some unsightly dark/black pixels in the antialiased area of the rounded corners, as if the alpha-based blending of the color of the frame and that of the background behind it dind’t quite work. Strangely enough, while using this method to tint the frame in colors such as r, g, b produces the problem, choosing secondary ones (c, m, y) or white seems to render the problem imperceptible.

Now I’m not quite sure what to think. Am I choosing a bad method to tinge this texture or am I producing or using the source image incorrectly?

Any idea would be much appreciated.

Manu


from  direct.directbase.DirectStart import *
from direct.gui.DirectGui import *
from pandac.PandaModules import *

# resizing the image so that it should be pixel-perfect on screen
imgWidth, imgHeight = 256, 256
winWidth = base.win.getXSize()
winHeight = base.win.getYSize()
aspectRatio = base.getAspectRatio()
glUnitsImageHeight = 2.0 * imgHeight / winHeight
glUnitsImageWidth = 2.0 * imgWidth / winWidth * aspectRatio

# placing the texture on the card: notice that the same 
# source PNG is used for both the color and the alpha channels.
aTexture = loader.loadTexture("aTexture.png", "aTexture.png")
ts = TextureStage('ts')

cm = CardMaker('card')
aCard = render.attachNewNode(cm.generate())
aCard.setTexture(ts, aTexture)

df = DirectFrame()
df.setTransparency(TransparencyAttrib.MAlpha)
df["geom"] = aCard
df["geom_scale"] = (glUnitsImageWidth, 1.0, glUnitsImageHeight)

#aCard.setColor(VBase4(0,0,1,1))
#df.setColor(VBase4(1,0,0,1))

run()

I’ve saved in manu3d.com/tmp/ the image mentioned in the script above and an image highlighting the dark-rim problem.

Everyone gets fooled by this. By default, a DirectFrame creates two cards, stacked up behind each other: one for the geom you give it, and another one, behind your geom, that’s just a flat gray card. If you don’t want that flat gray card (and you usually don’t), specify relief = None to the DirectFrame constructor.

You should probably pass geom and geom_scale in to the DirectFrame constructor, too, rather than setting them after the fact. It’s just that this is the way the DirectGUI system is designed to work, and it tends to be more reliable this way.

David

drwr, thank you for your help. I don’t think I’ve been particularly clear in my description of the problem. I’ve therefore uploaded in manu3d.com/tmp/ both the texture file mentioned in the script and a cut&paste from a screenshot of the panda window, showing you what I see. In it you’ll notice that the round corner section of the red line has a dark rim both inside and outside the curve. What causes it?

Manu

?#@@! and also @%$&!!!

I found where the problem is. Nothing to do with Panda, my code or my texture: it’s my viewing angle in relation to my laptop’s monitor.

When the Panda window opens it is placed in the top half of the screen. And my code places the texture in the top half of the window. This means that the whole shape is somewhere in the topmost 25% of the screen. For whatever gamma-related reason, in that part of the screen the contrast between the red of the tinted texture and its alpha-blended edges is highest, with the edge pixels appearing much darker than the grey background. Simply moving the Panda windows to the mid-portion of the screen removes this issue and the edge pixels are perceived to display the right values somewhere between red and grey. Another proof of how tricky it is to do fine colour work on LCD screens.

One thing however I did get wrong in code. After reading the page:
panda3d.org/manual/index.php/T … d_Blending

in the line:
aTexture = loader.loadTexture(“aTexture.png”, “aTexture.png”)

I was using the same texture twice, as colour and as alpha, with results on the edges that could only be described as “rough”. It appears however that Inkscape is perfectly capable of generating RGBA images that Panda is then perfectly capable of digesting. In this case the following is enough:

aTexture = loader.loadTexture(“aTexture.png”)

That’s all! Sorry for the red herring case… =)

Manu