setColor() and setColorScale() don't work as they should

Hello, I have the following problem:

setColor(r, g, b, a) doesn’t work as it is described in the following instruction:

I made the following observations:

  1. Parameter “a” doesn’t produce any change. So for a=0.0 and a=1.0 I get the same output.

  2. setColor(r, g, b, a) basically works the same way as setColorScale(r, g, b, a) should work (setColor()does not override the model color, instead, it adds an additional layer on top of it).

  3. In setColorScale(r, g, b, a) parameter “a” doesn’t seem to have any influence on the output eather.

So, as an example I have tried to load the panda-model.egg using several different options:

  • self.actor.setColor(0, 1, 0, 1.0)
  • self.actor.setColor(0, 1, 0, 0.5)
  • self.actor.setColor(0, 1, 0, 0.0)
  • self.actor.setColorScale(0, 1, 0, 1.0)
  • self.actor.setColorScale(0, 1, 0, 0.5)
  • self.actor.setColorScale(0, 1, 0, 0.0)

and got the same output in all those cases:
panda

Does anyone has an idea why is it so? Is it a bug, or am I doing something completely wrong? Thanks in advance!

Here is a sample code I used to test those options:

from direct.showbase.ShowBase import ShowBase 
from direct.actor.Actor import Actor

class Environment(ShowBase):
  def __init__(self):
    ShowBase.__init__(self)

    self.cam.setY(-3000)
    self.cam.setZ(200)

    self.actor = Actor("models/panda-model")
    self.actor.reparentTo(self.render)
    self.actor.setPos(0, 50, 0)

    self.actor.setColor(0, 1, 0, 1.0)
    #self.actor.setColor(0, 1, 0, 0.5)
    #self.actor.setColor(0, 1, 0, 0.0)

    #self.actor.setColorScale(0, 1, 0, 1.0)
    #self.actor.setColorScale(0, 1, 0, 0.5)
    #self.actor.setColorScale(0, 1, 0, 0.0)

env = Environment()
env.run()

Alpha blending can be expensive so it is not usually enabled by default. You can enable alpha blending with

self.actor.set_transparency(panda3d.core.TransparencyAttrib.M_alpha)

As for set_color(), I suspect the default texture mode of modulate is multiplying the texture value with the color value, which makes it act like a color scale. More on texture modes can be found in the manual.

@Moguri, thank you for your suggestion! I tried it and it seems that

self.actor.set_transparency(panda3d.core.TransparencyAttrib.M_alpha)

has influence directly on the actor and not on its color. So, with self.actor.setColor(0, 1, 0, 0.3) I get the following result where the actor itself is just dimmed:
Screenshot from 2020-10-28 18-01-25

Sadly, it doesn’t solve the original problem…

What effect were you hoping to achieve? Perhaps if we have a better idea of your goal, we might see an alternate way to achieve it.

To clarify, the “alpha” value in the colour or colour-scale affects the transparency of the object’s colour. Just as the “green” value determines how green the final colour is, the “alpha” value determines how transparent the final colour is–and thus how transparent the object’s surface is. Thus an object tinted with partial alpha becomes partially-transparent.

@Thaumaturge, thanks for the response!

My goal is to apply a desired color (in this case green) to the model (including all parts of its texture). So, at the end the panda should be completely green (0, 1, 0).

I tried to follow the simple example from this page: https://docs.panda3d.org/1.10/python/programming/render-attributes/tinting-and-recoloring

tinting-and-recoloring1

Image in the middle represents my desired output. To create it, they apply:

model2.setColor(0.6, 0.6, 1.0, 1.0)

So, my expectation was that if I will apply self.actor.setColorScale(0, 1, 0, 1.0) on the panda model, it will be completely green. The problem is that in my case, the example from the link generates an unexpected output (which is described in my first question)…

Aaah, I see. In that case, the problem is that the texture applied to the model will always have an effect, if present, I believe. (And presuming that you don’t apply custom shaders.) Thus, even with a fully-green colour applied, if a texture is present it will modulate that colour.

To counter this, you could remove the texture, or perhaps apply another, flat-white texture over it. The latter might be particularly useful if you intend to fade from the original texture to flat colour.

Now, as you note, in the example above-linked example the dragon-model is re-coloured as you desire, with no such modulation. I don’t seem to have that model to hand, so I fear that I’m not in a position to verify this, but I suspect that said model responds that way because it doesn’t actually have a texture applied. Rather, I suspect that it instead uses vertex-colours to produce its colouring, and it may well be that vertex-colours are indeed overridden by a call to “setColor”.

Actually, it turns out that a second texture isn’t even really needed when using the multitexturing interpolation combine mode to implement fading.

Here is a small code sample that interpolates between the applied texture and the “primary color” (the shading of the model without any textures applied):

from panda3d.core import *
from direct.showbase.ShowBase import ShowBase


class MyApp(ShowBase):

    def __init__(self):

        ShowBase.__init__(self)

        # set up a light source
        p_light = PointLight("point_light")
        p_light.set_color((1., 1., 1., 1.))
        self.light = self.camera.attach_new_node(p_light)
        self.light.set_pos(5., -10., 7.)
        self.render.set_light(self.light)

        panda = self.loader.load_model("panda-model")
        panda.set_scale(.01)
        panda.reparent_to(self.render)
        ts_fade = TextureStage("fade")
        ts_fade.set_sort(1)
        ts_fade.set_color((1., 1., 1., 1.))
        ts_fade.set_combine_rgb(
            TextureStage.CM_interpolate,
            TextureStage.CS_previous, TextureStage.CO_src_color,
            TextureStage.CS_primary_color, TextureStage.CO_src_color,
            TextureStage.CS_constant, TextureStage.CO_src_color
        )
        self.ts_fade = ts_fade
        panda_tex = panda.find_all_textures()[0]
        panda.set_texture(ts_fade, panda_tex)
        self.lightness = 1.
        self.accept("+", self.__lighten_constant_color)
        self.accept("-", self.__darken_constant_color)

    def __lighten_constant_color(self):

        self.lightness = min(1., self.lightness + .1)
        self.ts_fade.set_color((self.lightness,) * 3 + (1.,))

    def __darken_constant_color(self):

        self.lightness = max(0., self.lightness - .1)
        self.ts_fade.set_color((self.lightness,) * 3 + (1.,))


app = MyApp()
app.run()

Press - on the keyboard to fade from texture to flat color and + to fade back to the texture.

It works by changing the color set on the new TextureStage (ts_fade) itself (the “constant color”) and using it as the source of the interpolation.
Since the texture associated with that TextureStage is never used, I’ve simply associated the already applied texture with it.

This technique won’t affect the visibility of vertex colors, though. You can indeed override them with a call to set_color, but I’m not aware of a (non-shader) way to gradually fade them to a flat color.

1 Like